summaryrefslogtreecommitdiffstats
path: root/src/tools/clippy/clippy_lints
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:18:32 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:18:32 +0000
commit4547b622d8d29df964fa2914213088b148c498fc (patch)
tree9fc6b25f3c3add6b745be9a2400a6e96140046e9 /src/tools/clippy/clippy_lints
parentReleasing progress-linux version 1.66.0+dfsg1-1~progress7.99u1. (diff)
downloadrustc-4547b622d8d29df964fa2914213088b148c498fc.tar.xz
rustc-4547b622d8d29df964fa2914213088b148c498fc.zip
Merging upstream version 1.67.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/tools/clippy/clippy_lints')
-rw-r--r--src/tools/clippy/clippy_lints/Cargo.toml3
-rw-r--r--src/tools/clippy/clippy_lints/src/almost_complete_letter_range.rs30
-rw-r--r--src/tools/clippy/clippy_lints/src/approx_const.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs.rs53
-rw-r--r--src/tools/clippy/clippy_lints/src/await_holding_invalid.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs27
-rw-r--r--src/tools/clippy/clippy_lints/src/booleans.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/mod.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/checked_conversions.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/cognitive_complexity.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/collapsible_if.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/declared_lints.rs630
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs191
-rw-r--r--src/tools/clippy/clippy_lints/src/derive.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_macros.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_methods.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_types.rs44
-rw-r--r--src/tools/clippy/clippy_lints/src/doc.rs128
-rw-r--r--src/tools/clippy/clippy_lints/src/double_parens.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/enum_variants.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/equatable_if_let.rs27
-rw-r--r--src/tools/clippy/clippy_lints/src/escape.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/eta_reduction.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/excessive_bools.rs129
-rw-r--r--src/tools/clippy/clippy_lints/src/exit.rs23
-rw-r--r--src/tools/clippy/clippy_lints/src/fallible_impl_from.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/format.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/format_args.rs80
-rw-r--r--src/tools/clippy/clippy_lints/src/format_push_string.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/from_over_into.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs77
-rw-r--r--src/tools/clippy/clippy_lints/src/from_str_radix_10.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs125
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/mod.rs47
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/must_use.rs30
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/result.rs70
-rw-r--r--src/tools/clippy/clippy_lints/src/future_not_send.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_hasher.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/index_refutable_slice.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/indexing_slicing.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/inherent_to_string.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/instant_subtraction.rs182
-rw-r--r--src/tools/clippy/clippy_lints/src/int_plus_one.rs35
-rw-r--r--src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/large_enum_variant.rs60
-rw-r--r--src/tools/clippy/clippy_lints/src/len_zero.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/let_underscore.rs157
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_all.rs368
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_cargo.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_complexity.rs111
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_correctness.rs78
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_internal.rs22
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_lints.rs620
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_nursery.rs39
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs104
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_perf.rs34
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_restriction.rs90
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_style.rs131
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs38
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs371
-rw-r--r--src/tools/clippy/clippy_lints/src/lifetimes.rs165
-rw-r--r--src/tools/clippy/clippy_lints/src/literal_representation.rs36
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/mod.rs26
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/never_loop.rs114
-rw-r--r--src/tools/clippy/clippy_lints/src/macro_use.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_async_fn.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_bits.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_clamp.rs38
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_instant_elapsed.rs69
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs155
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_let_else.rs295
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs22
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_retain.rs30
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_string_new.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_strip.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/map_unit_fn.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/infallible_destructuring_match.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/manual_filter.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/mod.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/single_match.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/try_err.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/mem_replace.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/bytes_count_to_len.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/chars_last_cmp.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/chars_last_cmp_with_unwrap.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/chars_next_cmp.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/chars_next_cmp_with_unwrap.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/err_expect.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/expect_used.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filter_map.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_clone.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_collect_result_unit.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_err_ignore.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs307
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/needless_collect.rs (renamed from src/tools/clippy/clippy_lints/src/loops/needless_collect.rs)223
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/no_effect_replace.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs57
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/repeat_once.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/search_is_some.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs48
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs45
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/str_splitn.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_join.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs62
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/misc_early/literal_suffix.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/misc_early/mixed_case_hex_literals.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/misc_early/mod.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/misc_early/zero_prefixed_literal.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_doc.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs61
-rw-r--r--src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/mut_key.rs155
-rw-r--r--src/tools/clippy/clippy_lints/src/mut_mut.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs108
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_continue.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs22
-rw-r--r--src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/no_effect.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/octal_escapes.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs110
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/op_ref.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/option_env_unwrap.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/option_if_let_else.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/partialeq_to_none.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/precedence.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr.rs38
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/question_mark.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/ranges.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_clone.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_closure_call.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_field_names.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/renamed_lints.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/returns.rs29
-rw-r--r--src/tools/clippy/clippy_lints/src/single_component_path_imports.rs219
-rw-r--r--src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/strings.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs53
-rw-r--r--src/tools/clippy/clippy_lints/src/swap.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/trailing_empty_array.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/mod.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs164
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/utils.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/types/borrowed_box.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/types/box_collection.rs36
-rw-r--r--src/tools/clippy/clippy_lints/src/types/mod.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/types/rc_buffer.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs24
-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.rs467
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_self_imports.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs19
-rw-r--r--src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_async.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_peekable.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_rounding.rs28
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_unit.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/use_self.rs53
-rw-r--r--src/tools/clippy/clippy_lints/src/useless_conversion.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/conf.rs35
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs72
-rw-r--r--src/tools/clippy/clippy_lints/src/wildcard_imports.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/write.rs17
215 files changed, 4626 insertions, 4029 deletions
diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml
index 6fbd6401e..aedff24c1 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.66"
+version = "0.1.67"
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
repository = "https://github.com/rust-lang/rust-clippy"
readme = "README.md"
@@ -11,6 +11,7 @@ edition = "2021"
[dependencies]
cargo_metadata = "0.14"
clippy_utils = { path = "../clippy_utils" }
+declare_clippy_lint = { path = "../declare_clippy_lint" }
if_chain = "1.0"
itertools = "0.10.1"
pulldown-cmark = { version = "0.9", default-features = false }
diff --git a/src/tools/clippy/clippy_lints/src/almost_complete_letter_range.rs b/src/tools/clippy/clippy_lints/src/almost_complete_letter_range.rs
index 073e4af13..52beaf504 100644
--- a/src/tools/clippy/clippy_lints/src/almost_complete_letter_range.rs
+++ b/src/tools/clippy/clippy_lints/src/almost_complete_letter_range.rs
@@ -1,11 +1,10 @@
use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::{trim_span, walk_span_to_context};
-use clippy_utils::{meets_msrv, msrvs};
use rustc_ast::ast::{Expr, ExprKind, LitKind, Pat, PatKind, RangeEnd, RangeLimits};
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::Span;
@@ -33,10 +32,10 @@ declare_clippy_lint! {
impl_lint_pass!(AlmostCompleteLetterRange => [ALMOST_COMPLETE_LETTER_RANGE]);
pub struct AlmostCompleteLetterRange {
- msrv: Option<RustcVersion>,
+ msrv: Msrv,
}
impl AlmostCompleteLetterRange {
- pub fn new(msrv: Option<RustcVersion>) -> Self {
+ pub fn new(msrv: Msrv) -> Self {
Self { msrv }
}
}
@@ -46,7 +45,7 @@ impl EarlyLintPass for AlmostCompleteLetterRange {
let ctxt = e.span.ctxt();
let sugg = if let Some(start) = walk_span_to_context(start.span, ctxt)
&& let Some(end) = walk_span_to_context(end.span, ctxt)
- && meets_msrv(self.msrv, msrvs::RANGE_INCLUSIVE)
+ && self.msrv.meets(msrvs::RANGE_INCLUSIVE)
{
Some((trim_span(cx.sess().source_map(), start.between(end)), "..="))
} else {
@@ -60,7 +59,7 @@ impl EarlyLintPass for AlmostCompleteLetterRange {
if let PatKind::Range(Some(start), Some(end), kind) = &p.kind
&& matches!(kind.node, RangeEnd::Excluded)
{
- let sugg = if meets_msrv(self.msrv, msrvs::RANGE_INCLUSIVE) {
+ let sugg = if self.msrv.meets(msrvs::RANGE_INCLUSIVE) {
"..="
} else {
"..."
@@ -73,12 +72,21 @@ impl EarlyLintPass for AlmostCompleteLetterRange {
}
fn check_range(cx: &EarlyContext<'_>, span: Span, start: &Expr, end: &Expr, sugg: Option<(Span, &str)>) {
- if let ExprKind::Lit(start_lit) = &start.peel_parens().kind
- && let ExprKind::Lit(end_lit) = &end.peel_parens().kind
+ if let ExprKind::Lit(start_token_lit) = start.peel_parens().kind
+ && let ExprKind::Lit(end_token_lit) = end.peel_parens().kind
&& matches!(
- (&start_lit.kind, &end_lit.kind),
- (LitKind::Byte(b'a') | LitKind::Char('a'), LitKind::Byte(b'z') | LitKind::Char('z'))
- | (LitKind::Byte(b'A') | LitKind::Char('A'), LitKind::Byte(b'Z') | LitKind::Char('Z'))
+ (
+ LitKind::from_token_lit(start_token_lit),
+ LitKind::from_token_lit(end_token_lit),
+ ),
+ (
+ Ok(LitKind::Byte(b'a') | LitKind::Char('a')),
+ Ok(LitKind::Byte(b'z') | LitKind::Char('z'))
+ )
+ | (
+ Ok(LitKind::Byte(b'A') | LitKind::Char('A')),
+ Ok(LitKind::Byte(b'Z') | LitKind::Char('Z')),
+ )
)
&& !in_external_macro(cx.sess(), span)
{
diff --git a/src/tools/clippy/clippy_lints/src/approx_const.rs b/src/tools/clippy/clippy_lints/src/approx_const.rs
index 724490fb4..ccf82f132 100644
--- a/src/tools/clippy/clippy_lints/src/approx_const.rs
+++ b/src/tools/clippy/clippy_lints/src/approx_const.rs
@@ -1,5 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::{meets_msrv, msrvs};
+use clippy_utils::msrvs::{self, Msrv};
use rustc_ast::ast::{FloatTy, LitFloatType, LitKind};
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
@@ -63,12 +63,12 @@ const KNOWN_CONSTS: [(f64, &str, usize, Option<RustcVersion>); 19] = [
];
pub struct ApproxConstant {
- msrv: Option<RustcVersion>,
+ msrv: Msrv,
}
impl ApproxConstant {
#[must_use]
- pub fn new(msrv: Option<RustcVersion>) -> Self {
+ pub fn new(msrv: Msrv) -> Self {
Self { msrv }
}
@@ -87,7 +87,7 @@ impl ApproxConstant {
let s = s.as_str();
if s.parse::<f64>().is_ok() {
for &(constant, name, min_digits, msrv) in &KNOWN_CONSTS {
- if is_approx_const(constant, s, min_digits) && msrv.map_or(true, |msrv| meets_msrv(self.msrv, msrv)) {
+ if is_approx_const(constant, s, min_digits) && msrv.map_or(true, |msrv| self.msrv.meets(msrv)) {
span_lint_and_help(
cx,
APPROX_CONSTANT,
diff --git a/src/tools/clippy/clippy_lints/src/attrs.rs b/src/tools/clippy/clippy_lints/src/attrs.rs
index 0bd1f8b78..0710ac0bb 100644
--- a/src/tools/clippy/clippy_lints/src/attrs.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs.rs
@@ -2,23 +2,21 @@
use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
use clippy_utils::macros::{is_panic, macro_backtrace};
-use clippy_utils::msrvs;
+use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::{first_line_of_span, is_present_in_source, snippet_opt, without_block_comments};
-use clippy_utils::{extract_msrv_attr, meets_msrv};
use if_chain::if_chain;
-use rustc_ast::{AttrKind, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem};
+use rustc_ast::{AttrKind, AttrStyle, Attribute, LitKind, MetaItemKind, MetaItemLit, NestedMetaItem};
use rustc_errors::Applicability;
use rustc_hir::{
Block, Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, StmtKind, TraitFn, TraitItem, TraitItemKind,
};
-use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
+use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty;
-use rustc_semver::RustcVersion;
use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Span;
-use rustc_span::sym;
use rustc_span::symbol::Symbol;
+use rustc_span::{sym, DUMMY_SP};
use semver::Version;
static UNIX_SYSTEMS: &[&str] = &[
@@ -303,6 +301,26 @@ declare_lint_pass!(Attributes => [
]);
impl<'tcx> LateLintPass<'tcx> for Attributes {
+ fn check_crate(&mut self, cx: &LateContext<'tcx>) {
+ for (name, level) in &cx.sess().opts.lint_opts {
+ if name == "clippy::restriction" && *level > Level::Allow {
+ span_lint_and_then(
+ cx,
+ BLANKET_CLIPPY_RESTRICTION_LINTS,
+ DUMMY_SP,
+ "`clippy::restriction` is not meant to be enabled as a group",
+ |diag| {
+ diag.note(format!(
+ "because of the command line `--{} clippy::restriction`",
+ level.as_str()
+ ));
+ diag.help("enable the restriction lints you need individually");
+ },
+ );
+ }
+ }
+ }
+
fn check_attribute(&mut self, cx: &LateContext<'tcx>, attr: &'tcx Attribute) {
if let Some(items) = &attr.meta_item_list() {
if let Some(ident) = attr.ident() {
@@ -358,7 +376,9 @@ impl<'tcx> LateLintPass<'tcx> for Attributes {
| "enum_glob_use"
| "redundant_pub_crate"
| "macro_use_imports"
- | "unsafe_removed_from_name",
+ | "unsafe_removed_from_name"
+ | "module_name_repetitions"
+ | "single_component_path_imports"
)
})
{
@@ -441,9 +461,9 @@ fn check_clippy_lint_names(cx: &LateContext<'_>, name: Symbol, items: &[NestedMe
cx,
BLANKET_CLIPPY_RESTRICTION_LINTS,
lint.span(),
- "restriction lints are not meant to be all enabled",
+ "`clippy::restriction` is not meant to be enabled as a group",
None,
- "try enabling only the lints you really need",
+ "enable the restriction lints you need individually",
);
}
}
@@ -464,6 +484,11 @@ fn check_lint_reason(cx: &LateContext<'_>, name: Symbol, items: &[NestedMetaItem
return;
}
+ // Check if the attribute is in an external macro and therefore out of the developer's control
+ if in_external_macro(cx.sess(), attr.span) {
+ return;
+ }
+
span_lint_and_help(
cx,
ALLOW_ATTRIBUTES_WITHOUT_REASON,
@@ -549,7 +574,7 @@ fn check_attrs(cx: &LateContext<'_>, span: Span, name: Symbol, attrs: &[Attribut
}
}
-fn check_semver(cx: &LateContext<'_>, span: Span, lit: &Lit) {
+fn check_semver(cx: &LateContext<'_>, span: Span, lit: &MetaItemLit) {
if let LitKind::Str(is, _) = lit.kind {
if Version::parse(is.as_str()).is_ok() {
return;
@@ -572,7 +597,7 @@ fn is_word(nmi: &NestedMetaItem, expected: Symbol) -> bool {
}
pub struct EarlyAttributes {
- pub msrv: Option<RustcVersion>,
+ pub msrv: Msrv,
}
impl_lint_pass!(EarlyAttributes => [
@@ -587,7 +612,7 @@ impl EarlyLintPass for EarlyAttributes {
}
fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) {
- check_deprecated_cfg_attr(cx, attr, self.msrv);
+ check_deprecated_cfg_attr(cx, attr, &self.msrv);
check_mismatched_target_os(cx, attr);
}
@@ -627,9 +652,9 @@ fn check_empty_line_after_outer_attr(cx: &EarlyContext<'_>, item: &rustc_ast::It
}
}
-fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute, msrv: Option<RustcVersion>) {
+fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute, msrv: &Msrv) {
if_chain! {
- if meets_msrv(msrv, msrvs::TOOL_ATTRIBUTES);
+ if msrv.meets(msrvs::TOOL_ATTRIBUTES);
// check cfg_attr
if attr.has_name(sym::cfg_attr);
if let Some(items) = attr.meta_item_list();
diff --git a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
index 347178118..d40a38543 100644
--- a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
+++ b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
@@ -1,7 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::{match_def_path, paths};
use rustc_data_structures::fx::FxHashMap;
-use rustc_hir::def::{Namespace, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::{AsyncGeneratorKind, Body, BodyId, GeneratorKind};
use rustc_lint::{LateContext, LateLintPass};
@@ -189,7 +188,7 @@ impl LateLintPass<'_> for AwaitHolding {
fn check_crate(&mut self, cx: &LateContext<'_>) {
for conf in &self.conf_invalid_types {
let segs: Vec<_> = conf.path().split("::").collect();
- if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &segs, Some(Namespace::TypeNS)) {
+ for id in clippy_utils::def_path_def_ids(cx, &segs) {
self.def_ids.insert(id, conf.clone());
}
}
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 4bd55c142..82d368bb8 100644
--- a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
+++ b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
@@ -59,7 +59,7 @@ fn is_impl_not_trait_with_bool_out(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
)
})
.map_or(false, |assoc_item| {
- let proj = cx.tcx.mk_projection(assoc_item.def_id, cx.tcx.mk_substs_trait(ty, &[]));
+ let proj = cx.tcx.mk_projection(assoc_item.def_id, cx.tcx.mk_substs_trait(ty, []));
let nty = cx.tcx.normalize_erasing_regions(cx.param_env, proj);
nty.is_bool()
diff --git a/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs b/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs
index 001d74c26..bdb3a0116 100644
--- a/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs
+++ b/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs
@@ -1,9 +1,10 @@
+use clippy_utils::higher::If;
use rustc_ast::LitKind;
use rustc_hir::{Block, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
-use clippy_utils::{diagnostics::span_lint_and_then, is_else_clause, is_integer_literal, sugg::Sugg};
+use clippy_utils::{diagnostics::span_lint_and_then, in_constant, is_else_clause, is_integer_literal, sugg::Sugg};
use rustc_errors::Applicability;
declare_clippy_lint! {
@@ -12,7 +13,7 @@ declare_clippy_lint! {
/// this lint suggests using a `from()` function or an `as` coercion.
///
/// ### Why is this bad?
- /// Coercion or `from()` is idiomatic way to convert bool to a number.
+ /// Coercion or `from()` is another way to convert bool to a number.
/// Both methods are guaranteed to return 1 for true, and 0 for false.
///
/// See https://doc.rust-lang.org/std/primitive.bool.html#impl-From%3Cbool%3E
@@ -38,23 +39,23 @@ declare_clippy_lint! {
/// ```
#[clippy::version = "1.65.0"]
pub BOOL_TO_INT_WITH_IF,
- style,
+ pedantic,
"using if to convert bool to int"
}
declare_lint_pass!(BoolToIntWithIf => [BOOL_TO_INT_WITH_IF]);
impl<'tcx> LateLintPass<'tcx> for BoolToIntWithIf {
- fn check_expr(&mut self, ctx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) {
- if !expr.span.from_expansion() {
- check_if_else(ctx, expr);
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) {
+ if !expr.span.from_expansion() && !in_constant(cx, expr.hir_id) {
+ check_if_else(cx, expr);
}
}
}
-fn check_if_else<'tcx>(ctx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) {
- if let ExprKind::If(check, then, Some(else_)) = expr.kind
+fn check_if_else<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) {
+ if let Some(If { cond, then, r#else: Some(r#else) }) = If::hir(expr)
&& let Some(then_lit) = int_literal(then)
- && let Some(else_lit) = int_literal(else_)
+ && let Some(else_lit) = int_literal(r#else)
{
let inverted = if is_integer_literal(then_lit, 1) && is_integer_literal(else_lit, 0) {
false
@@ -66,17 +67,17 @@ fn check_if_else<'tcx>(ctx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx
};
let mut applicability = Applicability::MachineApplicable;
let snippet = {
- let mut sugg = Sugg::hir_with_applicability(ctx, check, "..", &mut applicability);
+ let mut sugg = Sugg::hir_with_applicability(cx, cond, "..", &mut applicability);
if inverted {
sugg = !sugg;
}
sugg
};
- let ty = ctx.typeck_results().expr_ty(then_lit); // then and else must be of same type
+ let ty = cx.typeck_results().expr_ty(then_lit); // then and else must be of same type
let suggestion = {
- let wrap_in_curly = is_else_clause(ctx.tcx, expr);
+ let wrap_in_curly = is_else_clause(cx.tcx, expr);
let mut s = Sugg::NonParen(format!("{ty}::from({snippet})").into());
if wrap_in_curly {
s = s.blockify();
@@ -87,7 +88,7 @@ fn check_if_else<'tcx>(ctx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx
let into_snippet = snippet.clone().maybe_par();
let as_snippet = snippet.as_ty(ty);
- span_lint_and_then(ctx,
+ span_lint_and_then(cx,
BOOL_TO_INT_WITH_IF,
expr.span,
"boolean to int conversion using if",
diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs
index 08164c0b6..939bdbcdc 100644
--- a/src/tools/clippy/clippy_lints/src/booleans.rs
+++ b/src/tools/clippy/clippy_lints/src/booleans.rs
@@ -481,7 +481,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'a, 'tcx> {
}
}
-fn implements_ord<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> bool {
+fn implements_ord(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
let ty = cx.typeck_results().expr_ty(expr);
cx.tcx
.get_diagnostic_item(sym::Ord)
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs b/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs
index 3f1edabe6..442262983 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs
@@ -1,11 +1,10 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::sugg::Sugg;
-use clippy_utils::{meets_msrv, msrvs};
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::LateContext;
use rustc_middle::ty::{self, Ty};
-use rustc_semver::RustcVersion;
use super::CAST_ABS_TO_UNSIGNED;
@@ -15,9 +14,9 @@ pub(super) fn check(
cast_expr: &Expr<'_>,
cast_from: Ty<'_>,
cast_to: Ty<'_>,
- msrv: Option<RustcVersion>,
+ msrv: &Msrv,
) {
- if meets_msrv(msrv, msrvs::UNSIGNED_ABS)
+ if msrv.meets(msrvs::UNSIGNED_ABS)
&& let ty::Int(from) = cast_from.kind()
&& let ty::Uint(to) = cast_to.kind()
&& let ExprKind::MethodCall(method_path, receiver, ..) = cast_expr.kind
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs b/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs
index 13c403234..cf07e050c 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs
@@ -1,12 +1,12 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::in_constant;
+use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_opt;
use clippy_utils::ty::is_isize_or_usize;
-use clippy_utils::{in_constant, meets_msrv, msrvs};
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::LateContext;
use rustc_middle::ty::{self, FloatTy, Ty};
-use rustc_semver::RustcVersion;
use super::{utils, CAST_LOSSLESS};
@@ -16,7 +16,7 @@ pub(super) fn check(
cast_op: &Expr<'_>,
cast_from: Ty<'_>,
cast_to: Ty<'_>,
- msrv: Option<RustcVersion>,
+ msrv: &Msrv,
) {
if !should_lint(cx, expr, cast_from, cast_to, msrv) {
return;
@@ -57,13 +57,7 @@ pub(super) fn check(
);
}
-fn should_lint(
- cx: &LateContext<'_>,
- expr: &Expr<'_>,
- cast_from: Ty<'_>,
- cast_to: Ty<'_>,
- msrv: Option<RustcVersion>,
-) -> bool {
+fn should_lint(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>, msrv: &Msrv) -> bool {
// Do not suggest using From in consts/statics until it is valid to do so (see #2267).
if in_constant(cx, expr.hir_id) {
return false;
@@ -89,7 +83,7 @@ fn should_lint(
};
!is_isize_or_usize(cast_from) && from_nbits < to_nbits
},
- (false, true) if matches!(cast_from.kind(), ty::Bool) && meets_msrv(msrv, msrvs::FROM_BOOL) => true,
+ (false, true) if matches!(cast_from.kind(), ty::Bool) && msrv.meets(msrvs::FROM_BOOL) => true,
(_, _) => {
matches!(cast_from.kind(), ty::Float(FloatTy::F32)) && matches!(cast_to.kind(), ty::Float(FloatTy::F64))
},
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 88deb4565..a63764849 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
@@ -2,12 +2,11 @@ use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::span_lint;
use clippy_utils::expr_or_init;
use clippy_utils::ty::{get_discriminant_value, is_isize_or_usize};
-use rustc_ast::ast;
-use rustc_attr::IntType;
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_target::abi::IntegerType;
use super::{utils, CAST_ENUM_TRUNCATION, CAST_POSSIBLE_TRUNCATION};
@@ -119,12 +118,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
};
let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx);
- let cast_from_ptr_size = def.repr().int.map_or(true, |ty| {
- matches!(
- ty,
- IntType::SignedInt(ast::IntTy::Isize) | IntType::UnsignedInt(ast::UintTy::Usize)
- )
- });
+ let cast_from_ptr_size = def.repr().int.map_or(true, |ty| matches!(ty, IntegerType::Pointer(_),));
let suffix = match (cast_from_ptr_size, is_isize_or_usize(cast_to)) {
(false, false) if from_nbits > to_nbits => "",
(true, false) if from_nbits > to_nbits => "",
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs b/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs
index d31d10d22..e862f13e6 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs
@@ -1,16 +1,16 @@
-use clippy_utils::{diagnostics::span_lint_and_then, meets_msrv, msrvs, source};
+use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::{diagnostics::span_lint_and_then, source};
use if_chain::if_chain;
use rustc_ast::Mutability;
use rustc_hir::{Expr, ExprKind, Node};
use rustc_lint::LateContext;
use rustc_middle::ty::{self, layout::LayoutOf, Ty, TypeAndMut};
-use rustc_semver::RustcVersion;
use super::CAST_SLICE_DIFFERENT_SIZES;
-pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: Option<RustcVersion>) {
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: &Msrv) {
// suggestion is invalid if `ptr::slice_from_raw_parts` does not exist
- if !meets_msrv(msrv, msrvs::PTR_SLICE_RAW_PARTS) {
+ if !msrv.meets(msrvs::PTR_SLICE_RAW_PARTS) {
return;
}
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs b/src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs
index 284ef1659..627b795d6 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs
@@ -1,12 +1,12 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{match_def_path, meets_msrv, msrvs, paths};
+use clippy_utils::{match_def_path, paths};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{def_id::DefId, Expr, ExprKind};
use rustc_lint::LateContext;
use rustc_middle::ty::{self, Ty};
-use rustc_semver::RustcVersion;
use super::CAST_SLICE_FROM_RAW_PARTS;
@@ -25,15 +25,9 @@ fn raw_parts_kind(cx: &LateContext<'_>, did: DefId) -> Option<RawPartsKind> {
}
}
-pub(super) fn check(
- cx: &LateContext<'_>,
- expr: &Expr<'_>,
- cast_expr: &Expr<'_>,
- cast_to: Ty<'_>,
- msrv: Option<RustcVersion>,
-) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_to: Ty<'_>, msrv: &Msrv) {
if_chain! {
- if meets_msrv(msrv, msrvs::PTR_SLICE_RAW_PARTS);
+ if msrv.meets(msrvs::PTR_SLICE_RAW_PARTS);
if let ty::RawPtr(ptrty) = cast_to.kind();
if let ty::Slice(_) = ptrty.ty.kind();
if let ExprKind::Call(fun, [ptr_arg, len_arg]) = cast_expr.peel_blocks().kind;
diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs
index b72c4c772..c6d505c4a 100644
--- a/src/tools/clippy/clippy_lints/src/casts/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs
@@ -21,11 +21,11 @@ mod ptr_as_ptr;
mod unnecessary_cast;
mod utils;
-use clippy_utils::{is_hir_ty_cfg_dependant, meets_msrv, msrvs};
+use clippy_utils::is_hir_ty_cfg_dependant;
+use clippy_utils::msrvs::{self, Msrv};
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass};
declare_clippy_lint! {
@@ -593,7 +593,7 @@ declare_clippy_lint! {
/// let _: *mut [u8] = std::ptr::slice_from_raw_parts_mut(ptr, len);
/// ```
/// [safety requirements]: https://doc.rust-lang.org/std/slice/fn.from_raw_parts.html#safety
- #[clippy::version = "1.64.0"]
+ #[clippy::version = "1.65.0"]
pub CAST_SLICE_FROM_RAW_PARTS,
suspicious,
"casting a slice created from a pointer and length to a slice pointer"
@@ -648,12 +648,12 @@ declare_clippy_lint! {
}
pub struct Casts {
- msrv: Option<RustcVersion>,
+ msrv: Msrv,
}
impl Casts {
#[must_use]
- pub fn new(msrv: Option<RustcVersion>) -> Self {
+ pub fn new(msrv: Msrv) -> Self {
Self { msrv }
}
}
@@ -686,7 +686,7 @@ impl_lint_pass!(Casts => [
impl<'tcx> LateLintPass<'tcx> for Casts {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if !in_external_macro(cx.sess(), expr.span) {
- ptr_as_ptr::check(cx, expr, self.msrv);
+ ptr_as_ptr::check(cx, expr, &self.msrv);
}
if expr.span.from_expansion() {
@@ -705,7 +705,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
if unnecessary_cast::check(cx, expr, cast_expr, cast_from, cast_to) {
return;
}
- cast_slice_from_raw_parts::check(cx, expr, cast_expr, cast_to, self.msrv);
+ cast_slice_from_raw_parts::check(cx, expr, cast_expr, cast_to, &self.msrv);
as_ptr_cast_mut::check(cx, expr, cast_expr, cast_to);
fn_to_numeric_cast_any::check(cx, expr, cast_expr, cast_from, cast_to);
fn_to_numeric_cast::check(cx, expr, cast_expr, cast_from, cast_to);
@@ -717,16 +717,16 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
cast_possible_wrap::check(cx, expr, cast_from, cast_to);
cast_precision_loss::check(cx, expr, cast_from, cast_to);
cast_sign_loss::check(cx, expr, cast_expr, cast_from, cast_to);
- cast_abs_to_unsigned::check(cx, expr, cast_expr, cast_from, cast_to, self.msrv);
+ cast_abs_to_unsigned::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv);
cast_nan_to_int::check(cx, expr, cast_expr, cast_from, cast_to);
}
- cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to, self.msrv);
+ cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv);
cast_enum_constructor::check(cx, expr, cast_expr, cast_from);
}
as_underscore::check(cx, expr, cast_to_hir);
- if meets_msrv(self.msrv, msrvs::BORROW_AS_PTR) {
+ if self.msrv.meets(msrvs::BORROW_AS_PTR) {
borrow_as_ptr::check(cx, expr, cast_expr, cast_to_hir);
}
}
@@ -734,8 +734,8 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
cast_ref_to_mut::check(cx, expr);
cast_ptr_alignment::check(cx, expr);
char_lit_as_u8::check(cx, expr);
- ptr_as_ptr::check(cx, expr, self.msrv);
- cast_slice_different_sizes::check(cx, expr, self.msrv);
+ ptr_as_ptr::check(cx, expr, &self.msrv);
+ cast_slice_different_sizes::check(cx, expr, &self.msrv);
}
extract_msrv_attr!(LateContext);
diff --git a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
index b9509ca65..15ffb00da 100644
--- a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
@@ -1,19 +1,18 @@
use std::borrow::Cow;
use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::sugg::Sugg;
-use clippy_utils::{meets_msrv, msrvs};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, Mutability, TyKind};
use rustc_lint::LateContext;
use rustc_middle::ty::{self, TypeAndMut};
-use rustc_semver::RustcVersion;
use super::PTR_AS_PTR;
-pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: Option<RustcVersion>) {
- if !meets_msrv(msrv, msrvs::POINTER_CAST) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Msrv) {
+ if !msrv.meets(msrvs::POINTER_CAST) {
return;
}
diff --git a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
index c8596987e..7e2331807 100644
--- a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::get_parent_expr;
use clippy_utils::numeric_literal::NumericLiteral;
use clippy_utils::source::snippet_opt;
+use clippy_utils::{get_parent_expr, path_to_local};
use if_chain::if_chain;
use rustc_ast::{LitFloatType, LitIntType, LitKind};
use rustc_errors::Applicability;
@@ -75,13 +75,26 @@ pub(super) fn check<'tcx>(
}
if cast_from.kind() == cast_to.kind() && !in_external_macro(cx.sess(), expr.span) {
+ if let Some(id) = path_to_local(cast_expr)
+ && let Some(span) = cx.tcx.hir().opt_span(id)
+ && span.ctxt() != cast_expr.span.ctxt()
+ {
+ // Binding context is different than the identifiers context.
+ // Weird macro wizardry could be involved here.
+ return false;
+ }
+
span_lint_and_sugg(
cx,
UNNECESSARY_CAST,
expr.span,
&format!("casting to the same type is unnecessary (`{cast_from}` -> `{cast_to}`)"),
"try",
- cast_str,
+ if get_parent_expr(cx, expr).map_or(false, |e| matches!(e.kind, ExprKind::AddrOf(..))) {
+ format!("{{ {cast_str} }}")
+ } else {
+ cast_str
+ },
Applicability::MachineApplicable,
);
return true;
diff --git a/src/tools/clippy/clippy_lints/src/checked_conversions.rs b/src/tools/clippy/clippy_lints/src/checked_conversions.rs
index 78e9921f0..9102a89e3 100644
--- a/src/tools/clippy/clippy_lints/src/checked_conversions.rs
+++ b/src/tools/clippy/clippy_lints/src/checked_conversions.rs
@@ -1,14 +1,14 @@
//! lint on manually implemented checked conversions that could be transformed into `try_from`
use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{in_constant, is_integer_literal, meets_msrv, msrvs, SpanlessEq};
+use clippy_utils::{in_constant, is_integer_literal, SpanlessEq};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind, QPath, TyKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass};
declare_clippy_lint! {
@@ -37,12 +37,12 @@ declare_clippy_lint! {
}
pub struct CheckedConversions {
- msrv: Option<RustcVersion>,
+ msrv: Msrv,
}
impl CheckedConversions {
#[must_use]
- pub fn new(msrv: Option<RustcVersion>) -> Self {
+ pub fn new(msrv: Msrv) -> Self {
Self { msrv }
}
}
@@ -51,7 +51,7 @@ impl_lint_pass!(CheckedConversions => [CHECKED_CONVERSIONS]);
impl<'tcx> LateLintPass<'tcx> for CheckedConversions {
fn check_expr(&mut self, cx: &LateContext<'_>, item: &Expr<'_>) {
- if !meets_msrv(self.msrv, msrvs::TRY_FROM) {
+ if !self.msrv.meets(msrvs::TRY_FROM) {
return;
}
diff --git a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
index 77af3b53d..1c3a89a97 100644
--- a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
+++ b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
@@ -4,11 +4,11 @@ use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::source::snippet_opt;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::visitors::for_each_expr;
-use clippy_utils::LimitStack;
+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, ExprKind, FnDecl, HirId};
+use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirId};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Span;
@@ -56,15 +56,13 @@ impl CognitiveComplexity {
cx: &LateContext<'tcx>,
kind: FnKind<'tcx>,
decl: &'tcx FnDecl<'_>,
- body: &'tcx Body<'_>,
+ expr: &'tcx Expr<'_>,
body_span: Span,
) {
if body_span.from_expansion() {
return;
}
- let expr = body.value;
-
let mut cc = 1u64;
let mut returns = 0u64;
let _: Option<!> = for_each_expr(expr, |e| {
@@ -146,7 +144,18 @@ impl<'tcx> LateLintPass<'tcx> for CognitiveComplexity {
) {
let def_id = cx.tcx.hir().local_def_id(hir_id);
if !cx.tcx.has_attr(def_id.to_def_id(), sym::test) {
- self.check(cx, kind, decl, body, span);
+ let expr = if is_async_fn(kind) {
+ match get_async_fn_body(cx.tcx, body) {
+ Some(b) => b,
+ None => {
+ return;
+ },
+ }
+ } else {
+ body.value
+ };
+
+ self.check(cx, kind, decl, expr, span);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/collapsible_if.rs b/src/tools/clippy/clippy_lints/src/collapsible_if.rs
index 90430b71a..b38e09dc0 100644
--- a/src/tools/clippy/clippy_lints/src/collapsible_if.rs
+++ b/src/tools/clippy/clippy_lints/src/collapsible_if.rs
@@ -160,11 +160,13 @@ fn check_collapsible_no_if_let(cx: &EarlyContext<'_>, expr: &ast::Expr, check: &
if let ast::ExprKind::If(ref check_inner, ref content, None) = inner.kind;
// Prevent triggering on `if c { if let a = b { .. } }`.
if !matches!(check_inner.kind, ast::ExprKind::Let(..));
- if expr.span.ctxt() == inner.span.ctxt();
+ let ctxt = expr.span.ctxt();
+ if inner.span.ctxt() == ctxt;
then {
span_lint_and_then(cx, COLLAPSIBLE_IF, expr.span, "this `if` statement can be collapsed", |diag| {
- let lhs = Sugg::ast(cx, check, "..");
- let rhs = Sugg::ast(cx, check_inner, "..");
+ let mut app = Applicability::MachineApplicable;
+ let lhs = Sugg::ast(cx, check, "..", ctxt, &mut app);
+ let rhs = Sugg::ast(cx, check_inner, "..", ctxt, &mut app);
diag.span_suggestion(
expr.span,
"collapse nested if block",
@@ -173,7 +175,7 @@ fn check_collapsible_no_if_let(cx: &EarlyContext<'_>, expr: &ast::Expr, check: &
lhs.and(&rhs),
snippet_block(cx, content.span, "..", Some(expr.span)),
),
- Applicability::MachineApplicable, // snippet
+ app, // snippet
);
});
}
diff --git a/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs b/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs
index 20cc330e0..b2fe0386f 100644
--- a/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs
+++ b/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs
@@ -55,7 +55,7 @@ impl EarlyLintPass for CrateInMacroDef {
if_chain! {
if item.attrs.iter().any(is_macro_export);
if let ItemKind::MacroDef(macro_def) = &item.kind;
- let tts = macro_def.body.inner_tokens();
+ let tts = macro_def.body.tokens.clone();
if let Some(span) = contains_unhygienic_crate_reference(&tts);
then {
span_lint_and_sugg(
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
new file mode 100644
index 000000000..e4d76f07d
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -0,0 +1,630 @@
+// This file was generated by `cargo dev update_lints`.
+// Use that command to update this file and do not edit by hand.
+// Manual edits will be overwritten.
+
+pub(crate) static LINTS: &[&crate::LintInfo] = &[
+ #[cfg(feature = "internal")]
+ crate::utils::internal_lints::clippy_lints_internal::CLIPPY_LINTS_INTERNAL_INFO,
+ #[cfg(feature = "internal")]
+ crate::utils::internal_lints::collapsible_calls::COLLAPSIBLE_SPAN_LINT_CALLS_INFO,
+ #[cfg(feature = "internal")]
+ crate::utils::internal_lints::compiler_lint_functions::COMPILER_LINT_FUNCTIONS_INFO,
+ #[cfg(feature = "internal")]
+ crate::utils::internal_lints::if_chain_style::IF_CHAIN_STYLE_INFO,
+ #[cfg(feature = "internal")]
+ crate::utils::internal_lints::interning_defined_symbol::INTERNING_DEFINED_SYMBOL_INFO,
+ #[cfg(feature = "internal")]
+ crate::utils::internal_lints::interning_defined_symbol::UNNECESSARY_SYMBOL_STR_INFO,
+ #[cfg(feature = "internal")]
+ crate::utils::internal_lints::invalid_paths::INVALID_PATHS_INFO,
+ #[cfg(feature = "internal")]
+ crate::utils::internal_lints::lint_without_lint_pass::DEFAULT_DEPRECATION_REASON_INFO,
+ #[cfg(feature = "internal")]
+ crate::utils::internal_lints::lint_without_lint_pass::DEFAULT_LINT_INFO,
+ #[cfg(feature = "internal")]
+ crate::utils::internal_lints::lint_without_lint_pass::INVALID_CLIPPY_VERSION_ATTRIBUTE_INFO,
+ #[cfg(feature = "internal")]
+ crate::utils::internal_lints::lint_without_lint_pass::LINT_WITHOUT_LINT_PASS_INFO,
+ #[cfg(feature = "internal")]
+ crate::utils::internal_lints::lint_without_lint_pass::MISSING_CLIPPY_VERSION_ATTRIBUTE_INFO,
+ #[cfg(feature = "internal")]
+ crate::utils::internal_lints::msrv_attr_impl::MISSING_MSRV_ATTR_IMPL_INFO,
+ #[cfg(feature = "internal")]
+ crate::utils::internal_lints::outer_expn_data_pass::OUTER_EXPN_EXPN_DATA_INFO,
+ #[cfg(feature = "internal")]
+ crate::utils::internal_lints::produce_ice::PRODUCE_ICE_INFO,
+ #[cfg(feature = "internal")]
+ crate::utils::internal_lints::unnecessary_def_path::UNNECESSARY_DEF_PATH_INFO,
+ crate::almost_complete_letter_range::ALMOST_COMPLETE_LETTER_RANGE_INFO,
+ crate::approx_const::APPROX_CONSTANT_INFO,
+ crate::as_conversions::AS_CONVERSIONS_INFO,
+ crate::asm_syntax::INLINE_ASM_X86_ATT_SYNTAX_INFO,
+ crate::asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX_INFO,
+ crate::assertions_on_constants::ASSERTIONS_ON_CONSTANTS_INFO,
+ crate::assertions_on_result_states::ASSERTIONS_ON_RESULT_STATES_INFO,
+ crate::async_yields_async::ASYNC_YIELDS_ASYNC_INFO,
+ crate::attrs::ALLOW_ATTRIBUTES_WITHOUT_REASON_INFO,
+ crate::attrs::BLANKET_CLIPPY_RESTRICTION_LINTS_INFO,
+ crate::attrs::DEPRECATED_CFG_ATTR_INFO,
+ crate::attrs::DEPRECATED_SEMVER_INFO,
+ crate::attrs::EMPTY_LINE_AFTER_OUTER_ATTR_INFO,
+ crate::attrs::INLINE_ALWAYS_INFO,
+ crate::attrs::MISMATCHED_TARGET_OS_INFO,
+ crate::attrs::USELESS_ATTRIBUTE_INFO,
+ crate::await_holding_invalid::AWAIT_HOLDING_INVALID_TYPE_INFO,
+ crate::await_holding_invalid::AWAIT_HOLDING_LOCK_INFO,
+ crate::await_holding_invalid::AWAIT_HOLDING_REFCELL_REF_INFO,
+ crate::blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS_INFO,
+ crate::bool_assert_comparison::BOOL_ASSERT_COMPARISON_INFO,
+ crate::bool_to_int_with_if::BOOL_TO_INT_WITH_IF_INFO,
+ crate::booleans::NONMINIMAL_BOOL_INFO,
+ crate::booleans::OVERLY_COMPLEX_BOOL_EXPR_INFO,
+ crate::borrow_deref_ref::BORROW_DEREF_REF_INFO,
+ crate::box_default::BOX_DEFAULT_INFO,
+ crate::cargo::CARGO_COMMON_METADATA_INFO,
+ crate::cargo::MULTIPLE_CRATE_VERSIONS_INFO,
+ crate::cargo::NEGATIVE_FEATURE_NAMES_INFO,
+ crate::cargo::REDUNDANT_FEATURE_NAMES_INFO,
+ crate::cargo::WILDCARD_DEPENDENCIES_INFO,
+ crate::casts::AS_PTR_CAST_MUT_INFO,
+ crate::casts::AS_UNDERSCORE_INFO,
+ crate::casts::BORROW_AS_PTR_INFO,
+ crate::casts::CAST_ABS_TO_UNSIGNED_INFO,
+ crate::casts::CAST_ENUM_CONSTRUCTOR_INFO,
+ crate::casts::CAST_ENUM_TRUNCATION_INFO,
+ crate::casts::CAST_LOSSLESS_INFO,
+ crate::casts::CAST_NAN_TO_INT_INFO,
+ crate::casts::CAST_POSSIBLE_TRUNCATION_INFO,
+ crate::casts::CAST_POSSIBLE_WRAP_INFO,
+ crate::casts::CAST_PRECISION_LOSS_INFO,
+ crate::casts::CAST_PTR_ALIGNMENT_INFO,
+ crate::casts::CAST_REF_TO_MUT_INFO,
+ crate::casts::CAST_SIGN_LOSS_INFO,
+ crate::casts::CAST_SLICE_DIFFERENT_SIZES_INFO,
+ crate::casts::CAST_SLICE_FROM_RAW_PARTS_INFO,
+ crate::casts::CHAR_LIT_AS_U8_INFO,
+ crate::casts::FN_TO_NUMERIC_CAST_INFO,
+ crate::casts::FN_TO_NUMERIC_CAST_ANY_INFO,
+ crate::casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION_INFO,
+ crate::casts::PTR_AS_PTR_INFO,
+ crate::casts::UNNECESSARY_CAST_INFO,
+ crate::checked_conversions::CHECKED_CONVERSIONS_INFO,
+ crate::cognitive_complexity::COGNITIVE_COMPLEXITY_INFO,
+ crate::collapsible_if::COLLAPSIBLE_ELSE_IF_INFO,
+ crate::collapsible_if::COLLAPSIBLE_IF_INFO,
+ crate::comparison_chain::COMPARISON_CHAIN_INFO,
+ crate::copies::BRANCHES_SHARING_CODE_INFO,
+ crate::copies::IFS_SAME_COND_INFO,
+ crate::copies::IF_SAME_THEN_ELSE_INFO,
+ crate::copies::SAME_FUNCTIONS_IN_IF_CONDITION_INFO,
+ crate::copy_iterator::COPY_ITERATOR_INFO,
+ crate::crate_in_macro_def::CRATE_IN_MACRO_DEF_INFO,
+ crate::create_dir::CREATE_DIR_INFO,
+ crate::dbg_macro::DBG_MACRO_INFO,
+ crate::default::DEFAULT_TRAIT_ACCESS_INFO,
+ crate::default::FIELD_REASSIGN_WITH_DEFAULT_INFO,
+ crate::default_instead_of_iter_empty::DEFAULT_INSTEAD_OF_ITER_EMPTY_INFO,
+ crate::default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK_INFO,
+ crate::default_union_representation::DEFAULT_UNION_REPRESENTATION_INFO,
+ crate::dereference::EXPLICIT_AUTO_DEREF_INFO,
+ crate::dereference::EXPLICIT_DEREF_METHODS_INFO,
+ crate::dereference::NEEDLESS_BORROW_INFO,
+ crate::dereference::REF_BINDING_TO_REFERENCE_INFO,
+ crate::derivable_impls::DERIVABLE_IMPLS_INFO,
+ crate::derive::DERIVE_HASH_XOR_EQ_INFO,
+ crate::derive::DERIVE_ORD_XOR_PARTIAL_ORD_INFO,
+ crate::derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ_INFO,
+ crate::derive::EXPL_IMPL_CLONE_ON_COPY_INFO,
+ crate::derive::UNSAFE_DERIVE_DESERIALIZE_INFO,
+ crate::disallowed_macros::DISALLOWED_MACROS_INFO,
+ crate::disallowed_methods::DISALLOWED_METHODS_INFO,
+ crate::disallowed_names::DISALLOWED_NAMES_INFO,
+ crate::disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS_INFO,
+ crate::disallowed_types::DISALLOWED_TYPES_INFO,
+ crate::doc::DOC_LINK_WITH_QUOTES_INFO,
+ crate::doc::DOC_MARKDOWN_INFO,
+ crate::doc::MISSING_ERRORS_DOC_INFO,
+ crate::doc::MISSING_PANICS_DOC_INFO,
+ crate::doc::MISSING_SAFETY_DOC_INFO,
+ crate::doc::NEEDLESS_DOCTEST_MAIN_INFO,
+ crate::doc::UNNECESSARY_SAFETY_DOC_INFO,
+ crate::double_parens::DOUBLE_PARENS_INFO,
+ crate::drop_forget_ref::DROP_COPY_INFO,
+ crate::drop_forget_ref::DROP_NON_DROP_INFO,
+ crate::drop_forget_ref::DROP_REF_INFO,
+ crate::drop_forget_ref::FORGET_COPY_INFO,
+ crate::drop_forget_ref::FORGET_NON_DROP_INFO,
+ crate::drop_forget_ref::FORGET_REF_INFO,
+ crate::drop_forget_ref::UNDROPPED_MANUALLY_DROPS_INFO,
+ crate::duplicate_mod::DUPLICATE_MOD_INFO,
+ crate::else_if_without_else::ELSE_IF_WITHOUT_ELSE_INFO,
+ crate::empty_drop::EMPTY_DROP_INFO,
+ crate::empty_enum::EMPTY_ENUM_INFO,
+ crate::empty_structs_with_brackets::EMPTY_STRUCTS_WITH_BRACKETS_INFO,
+ crate::entry::MAP_ENTRY_INFO,
+ crate::enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT_INFO,
+ crate::enum_variants::ENUM_VARIANT_NAMES_INFO,
+ crate::enum_variants::MODULE_INCEPTION_INFO,
+ crate::enum_variants::MODULE_NAME_REPETITIONS_INFO,
+ crate::equatable_if_let::EQUATABLE_IF_LET_INFO,
+ crate::escape::BOXED_LOCAL_INFO,
+ crate::eta_reduction::REDUNDANT_CLOSURE_INFO,
+ crate::eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS_INFO,
+ crate::excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS_INFO,
+ crate::excessive_bools::STRUCT_EXCESSIVE_BOOLS_INFO,
+ crate::exhaustive_items::EXHAUSTIVE_ENUMS_INFO,
+ crate::exhaustive_items::EXHAUSTIVE_STRUCTS_INFO,
+ crate::exit::EXIT_INFO,
+ crate::explicit_write::EXPLICIT_WRITE_INFO,
+ crate::fallible_impl_from::FALLIBLE_IMPL_FROM_INFO,
+ crate::float_literal::EXCESSIVE_PRECISION_INFO,
+ crate::float_literal::LOSSY_FLOAT_LITERAL_INFO,
+ crate::floating_point_arithmetic::IMPRECISE_FLOPS_INFO,
+ crate::floating_point_arithmetic::SUBOPTIMAL_FLOPS_INFO,
+ crate::format::USELESS_FORMAT_INFO,
+ crate::format_args::FORMAT_IN_FORMAT_ARGS_INFO,
+ crate::format_args::TO_STRING_IN_FORMAT_ARGS_INFO,
+ crate::format_args::UNINLINED_FORMAT_ARGS_INFO,
+ crate::format_args::UNUSED_FORMAT_SPECS_INFO,
+ crate::format_impl::PRINT_IN_FORMAT_IMPL_INFO,
+ crate::format_impl::RECURSIVE_FORMAT_IMPL_INFO,
+ crate::format_push_string::FORMAT_PUSH_STRING_INFO,
+ crate::formatting::POSSIBLE_MISSING_COMMA_INFO,
+ crate::formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING_INFO,
+ crate::formatting::SUSPICIOUS_ELSE_FORMATTING_INFO,
+ crate::formatting::SUSPICIOUS_UNARY_OP_FORMATTING_INFO,
+ crate::from_over_into::FROM_OVER_INTO_INFO,
+ crate::from_raw_with_void_ptr::FROM_RAW_WITH_VOID_PTR_INFO,
+ crate::from_str_radix_10::FROM_STR_RADIX_10_INFO,
+ crate::functions::DOUBLE_MUST_USE_INFO,
+ crate::functions::MISNAMED_GETTERS_INFO,
+ crate::functions::MUST_USE_CANDIDATE_INFO,
+ crate::functions::MUST_USE_UNIT_INFO,
+ crate::functions::NOT_UNSAFE_PTR_ARG_DEREF_INFO,
+ crate::functions::RESULT_LARGE_ERR_INFO,
+ crate::functions::RESULT_UNIT_ERR_INFO,
+ crate::functions::TOO_MANY_ARGUMENTS_INFO,
+ crate::functions::TOO_MANY_LINES_INFO,
+ crate::future_not_send::FUTURE_NOT_SEND_INFO,
+ crate::if_let_mutex::IF_LET_MUTEX_INFO,
+ crate::if_not_else::IF_NOT_ELSE_INFO,
+ crate::if_then_some_else_none::IF_THEN_SOME_ELSE_NONE_INFO,
+ crate::implicit_hasher::IMPLICIT_HASHER_INFO,
+ crate::implicit_return::IMPLICIT_RETURN_INFO,
+ crate::implicit_saturating_add::IMPLICIT_SATURATING_ADD_INFO,
+ crate::implicit_saturating_sub::IMPLICIT_SATURATING_SUB_INFO,
+ crate::inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR_INFO,
+ crate::index_refutable_slice::INDEX_REFUTABLE_SLICE_INFO,
+ crate::indexing_slicing::INDEXING_SLICING_INFO,
+ crate::indexing_slicing::OUT_OF_BOUNDS_INDEXING_INFO,
+ crate::infinite_iter::INFINITE_ITER_INFO,
+ crate::infinite_iter::MAYBE_INFINITE_ITER_INFO,
+ crate::inherent_impl::MULTIPLE_INHERENT_IMPL_INFO,
+ crate::inherent_to_string::INHERENT_TO_STRING_INFO,
+ crate::inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY_INFO,
+ crate::init_numbered_fields::INIT_NUMBERED_FIELDS_INFO,
+ crate::inline_fn_without_body::INLINE_FN_WITHOUT_BODY_INFO,
+ crate::instant_subtraction::MANUAL_INSTANT_ELAPSED_INFO,
+ crate::instant_subtraction::UNCHECKED_DURATION_SUBTRACTION_INFO,
+ crate::int_plus_one::INT_PLUS_ONE_INFO,
+ crate::invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS_INFO,
+ crate::invalid_utf8_in_unchecked::INVALID_UTF8_IN_UNCHECKED_INFO,
+ crate::items_after_statements::ITEMS_AFTER_STATEMENTS_INFO,
+ crate::iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR_INFO,
+ crate::large_const_arrays::LARGE_CONST_ARRAYS_INFO,
+ crate::large_enum_variant::LARGE_ENUM_VARIANT_INFO,
+ crate::large_include_file::LARGE_INCLUDE_FILE_INFO,
+ crate::large_stack_arrays::LARGE_STACK_ARRAYS_INFO,
+ crate::len_zero::COMPARISON_TO_EMPTY_INFO,
+ crate::len_zero::LEN_WITHOUT_IS_EMPTY_INFO,
+ crate::len_zero::LEN_ZERO_INFO,
+ crate::let_if_seq::USELESS_LET_IF_SEQ_INFO,
+ crate::let_underscore::LET_UNDERSCORE_FUTURE_INFO,
+ crate::let_underscore::LET_UNDERSCORE_LOCK_INFO,
+ crate::let_underscore::LET_UNDERSCORE_MUST_USE_INFO,
+ crate::lifetimes::EXTRA_UNUSED_LIFETIMES_INFO,
+ crate::lifetimes::NEEDLESS_LIFETIMES_INFO,
+ crate::literal_representation::DECIMAL_LITERAL_REPRESENTATION_INFO,
+ crate::literal_representation::INCONSISTENT_DIGIT_GROUPING_INFO,
+ crate::literal_representation::LARGE_DIGIT_GROUPS_INFO,
+ crate::literal_representation::MISTYPED_LITERAL_SUFFIXES_INFO,
+ crate::literal_representation::UNREADABLE_LITERAL_INFO,
+ crate::literal_representation::UNUSUAL_BYTE_GROUPINGS_INFO,
+ crate::loops::EMPTY_LOOP_INFO,
+ crate::loops::EXPLICIT_COUNTER_LOOP_INFO,
+ crate::loops::EXPLICIT_INTO_ITER_LOOP_INFO,
+ crate::loops::EXPLICIT_ITER_LOOP_INFO,
+ crate::loops::FOR_KV_MAP_INFO,
+ crate::loops::ITER_NEXT_LOOP_INFO,
+ crate::loops::MANUAL_FIND_INFO,
+ crate::loops::MANUAL_FLATTEN_INFO,
+ crate::loops::MANUAL_MEMCPY_INFO,
+ crate::loops::MISSING_SPIN_LOOP_INFO,
+ crate::loops::MUT_RANGE_BOUND_INFO,
+ crate::loops::NEEDLESS_RANGE_LOOP_INFO,
+ crate::loops::NEVER_LOOP_INFO,
+ crate::loops::SAME_ITEM_PUSH_INFO,
+ crate::loops::SINGLE_ELEMENT_LOOP_INFO,
+ crate::loops::WHILE_IMMUTABLE_CONDITION_INFO,
+ crate::loops::WHILE_LET_LOOP_INFO,
+ crate::loops::WHILE_LET_ON_ITERATOR_INFO,
+ crate::macro_use::MACRO_USE_IMPORTS_INFO,
+ crate::main_recursion::MAIN_RECURSION_INFO,
+ crate::manual_assert::MANUAL_ASSERT_INFO,
+ crate::manual_async_fn::MANUAL_ASYNC_FN_INFO,
+ crate::manual_bits::MANUAL_BITS_INFO,
+ crate::manual_clamp::MANUAL_CLAMP_INFO,
+ crate::manual_is_ascii_check::MANUAL_IS_ASCII_CHECK_INFO,
+ crate::manual_let_else::MANUAL_LET_ELSE_INFO,
+ crate::manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE_INFO,
+ crate::manual_rem_euclid::MANUAL_REM_EUCLID_INFO,
+ crate::manual_retain::MANUAL_RETAIN_INFO,
+ crate::manual_string_new::MANUAL_STRING_NEW_INFO,
+ crate::manual_strip::MANUAL_STRIP_INFO,
+ crate::map_unit_fn::OPTION_MAP_UNIT_FN_INFO,
+ crate::map_unit_fn::RESULT_MAP_UNIT_FN_INFO,
+ crate::match_result_ok::MATCH_RESULT_OK_INFO,
+ crate::matches::COLLAPSIBLE_MATCH_INFO,
+ crate::matches::INFALLIBLE_DESTRUCTURING_MATCH_INFO,
+ crate::matches::MANUAL_FILTER_INFO,
+ crate::matches::MANUAL_MAP_INFO,
+ crate::matches::MANUAL_UNWRAP_OR_INFO,
+ crate::matches::MATCH_AS_REF_INFO,
+ crate::matches::MATCH_BOOL_INFO,
+ crate::matches::MATCH_LIKE_MATCHES_MACRO_INFO,
+ crate::matches::MATCH_ON_VEC_ITEMS_INFO,
+ crate::matches::MATCH_OVERLAPPING_ARM_INFO,
+ crate::matches::MATCH_REF_PATS_INFO,
+ crate::matches::MATCH_SAME_ARMS_INFO,
+ crate::matches::MATCH_SINGLE_BINDING_INFO,
+ crate::matches::MATCH_STR_CASE_MISMATCH_INFO,
+ crate::matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS_INFO,
+ crate::matches::MATCH_WILD_ERR_ARM_INFO,
+ crate::matches::NEEDLESS_MATCH_INFO,
+ crate::matches::REDUNDANT_PATTERN_MATCHING_INFO,
+ crate::matches::REST_PAT_IN_FULLY_BOUND_STRUCTS_INFO,
+ crate::matches::SIGNIFICANT_DROP_IN_SCRUTINEE_INFO,
+ crate::matches::SINGLE_MATCH_INFO,
+ crate::matches::SINGLE_MATCH_ELSE_INFO,
+ crate::matches::TRY_ERR_INFO,
+ crate::matches::WILDCARD_ENUM_MATCH_ARM_INFO,
+ crate::matches::WILDCARD_IN_OR_PATTERNS_INFO,
+ crate::mem_forget::MEM_FORGET_INFO,
+ crate::mem_replace::MEM_REPLACE_OPTION_WITH_NONE_INFO,
+ crate::mem_replace::MEM_REPLACE_WITH_DEFAULT_INFO,
+ crate::mem_replace::MEM_REPLACE_WITH_UNINIT_INFO,
+ crate::methods::BIND_INSTEAD_OF_MAP_INFO,
+ crate::methods::BYTES_COUNT_TO_LEN_INFO,
+ crate::methods::BYTES_NTH_INFO,
+ crate::methods::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS_INFO,
+ crate::methods::CHARS_LAST_CMP_INFO,
+ crate::methods::CHARS_NEXT_CMP_INFO,
+ crate::methods::CLONED_INSTEAD_OF_COPIED_INFO,
+ crate::methods::CLONE_DOUBLE_REF_INFO,
+ crate::methods::CLONE_ON_COPY_INFO,
+ crate::methods::CLONE_ON_REF_PTR_INFO,
+ crate::methods::COLLAPSIBLE_STR_REPLACE_INFO,
+ crate::methods::ERR_EXPECT_INFO,
+ crate::methods::EXPECT_FUN_CALL_INFO,
+ crate::methods::EXPECT_USED_INFO,
+ crate::methods::EXTEND_WITH_DRAIN_INFO,
+ crate::methods::FILETYPE_IS_FILE_INFO,
+ crate::methods::FILTER_MAP_IDENTITY_INFO,
+ crate::methods::FILTER_MAP_NEXT_INFO,
+ crate::methods::FILTER_NEXT_INFO,
+ crate::methods::FLAT_MAP_IDENTITY_INFO,
+ crate::methods::FLAT_MAP_OPTION_INFO,
+ crate::methods::FROM_ITER_INSTEAD_OF_COLLECT_INFO,
+ crate::methods::GET_FIRST_INFO,
+ crate::methods::GET_LAST_WITH_LEN_INFO,
+ crate::methods::GET_UNWRAP_INFO,
+ crate::methods::IMPLICIT_CLONE_INFO,
+ crate::methods::INEFFICIENT_TO_STRING_INFO,
+ crate::methods::INSPECT_FOR_EACH_INFO,
+ crate::methods::INTO_ITER_ON_REF_INFO,
+ crate::methods::IS_DIGIT_ASCII_RADIX_INFO,
+ crate::methods::ITERATOR_STEP_BY_ZERO_INFO,
+ crate::methods::ITER_CLONED_COLLECT_INFO,
+ crate::methods::ITER_COUNT_INFO,
+ crate::methods::ITER_KV_MAP_INFO,
+ crate::methods::ITER_NEXT_SLICE_INFO,
+ crate::methods::ITER_NTH_INFO,
+ crate::methods::ITER_NTH_ZERO_INFO,
+ crate::methods::ITER_ON_EMPTY_COLLECTIONS_INFO,
+ crate::methods::ITER_ON_SINGLE_ITEMS_INFO,
+ crate::methods::ITER_OVEREAGER_CLONED_INFO,
+ crate::methods::ITER_SKIP_NEXT_INFO,
+ crate::methods::ITER_WITH_DRAIN_INFO,
+ crate::methods::MANUAL_FILTER_MAP_INFO,
+ crate::methods::MANUAL_FIND_MAP_INFO,
+ crate::methods::MANUAL_OK_OR_INFO,
+ crate::methods::MANUAL_SATURATING_ARITHMETIC_INFO,
+ crate::methods::MANUAL_SPLIT_ONCE_INFO,
+ crate::methods::MANUAL_STR_REPEAT_INFO,
+ crate::methods::MAP_CLONE_INFO,
+ crate::methods::MAP_COLLECT_RESULT_UNIT_INFO,
+ crate::methods::MAP_ERR_IGNORE_INFO,
+ crate::methods::MAP_FLATTEN_INFO,
+ crate::methods::MAP_IDENTITY_INFO,
+ crate::methods::MAP_UNWRAP_OR_INFO,
+ crate::methods::MUT_MUTEX_LOCK_INFO,
+ crate::methods::NAIVE_BYTECOUNT_INFO,
+ crate::methods::NEEDLESS_COLLECT_INFO,
+ crate::methods::NEEDLESS_OPTION_AS_DEREF_INFO,
+ crate::methods::NEEDLESS_OPTION_TAKE_INFO,
+ crate::methods::NEEDLESS_SPLITN_INFO,
+ crate::methods::NEW_RET_NO_SELF_INFO,
+ crate::methods::NONSENSICAL_OPEN_OPTIONS_INFO,
+ crate::methods::NO_EFFECT_REPLACE_INFO,
+ crate::methods::OBFUSCATED_IF_ELSE_INFO,
+ crate::methods::OK_EXPECT_INFO,
+ crate::methods::OPTION_AS_REF_DEREF_INFO,
+ crate::methods::OPTION_FILTER_MAP_INFO,
+ crate::methods::OPTION_MAP_OR_NONE_INFO,
+ crate::methods::OR_FUN_CALL_INFO,
+ crate::methods::OR_THEN_UNWRAP_INFO,
+ crate::methods::PATH_BUF_PUSH_OVERWRITE_INFO,
+ crate::methods::RANGE_ZIP_WITH_LEN_INFO,
+ crate::methods::REPEAT_ONCE_INFO,
+ crate::methods::RESULT_MAP_OR_INTO_OPTION_INFO,
+ crate::methods::SEARCH_IS_SOME_INFO,
+ crate::methods::SEEK_FROM_CURRENT_INFO,
+ crate::methods::SEEK_TO_START_INSTEAD_OF_REWIND_INFO,
+ crate::methods::SHOULD_IMPLEMENT_TRAIT_INFO,
+ crate::methods::SINGLE_CHAR_ADD_STR_INFO,
+ crate::methods::SINGLE_CHAR_PATTERN_INFO,
+ crate::methods::SKIP_WHILE_NEXT_INFO,
+ crate::methods::STABLE_SORT_PRIMITIVE_INFO,
+ crate::methods::STRING_EXTEND_CHARS_INFO,
+ crate::methods::SUSPICIOUS_MAP_INFO,
+ crate::methods::SUSPICIOUS_SPLITN_INFO,
+ crate::methods::SUSPICIOUS_TO_OWNED_INFO,
+ crate::methods::UNINIT_ASSUMED_INIT_INFO,
+ crate::methods::UNIT_HASH_INFO,
+ crate::methods::UNNECESSARY_FILTER_MAP_INFO,
+ crate::methods::UNNECESSARY_FIND_MAP_INFO,
+ crate::methods::UNNECESSARY_FOLD_INFO,
+ crate::methods::UNNECESSARY_JOIN_INFO,
+ crate::methods::UNNECESSARY_LAZY_EVALUATIONS_INFO,
+ crate::methods::UNNECESSARY_SORT_BY_INFO,
+ crate::methods::UNNECESSARY_TO_OWNED_INFO,
+ crate::methods::UNWRAP_OR_ELSE_DEFAULT_INFO,
+ crate::methods::UNWRAP_USED_INFO,
+ crate::methods::USELESS_ASREF_INFO,
+ crate::methods::VEC_RESIZE_TO_ZERO_INFO,
+ crate::methods::VERBOSE_FILE_READS_INFO,
+ crate::methods::WRONG_SELF_CONVENTION_INFO,
+ crate::methods::ZST_OFFSET_INFO,
+ crate::minmax::MIN_MAX_INFO,
+ crate::misc::SHORT_CIRCUIT_STATEMENT_INFO,
+ crate::misc::TOPLEVEL_REF_ARG_INFO,
+ crate::misc::USED_UNDERSCORE_BINDING_INFO,
+ crate::misc::ZERO_PTR_INFO,
+ crate::misc_early::BUILTIN_TYPE_SHADOW_INFO,
+ crate::misc_early::DOUBLE_NEG_INFO,
+ crate::misc_early::DUPLICATE_UNDERSCORE_ARGUMENT_INFO,
+ crate::misc_early::MIXED_CASE_HEX_LITERALS_INFO,
+ crate::misc_early::REDUNDANT_PATTERN_INFO,
+ crate::misc_early::SEPARATED_LITERAL_SUFFIX_INFO,
+ crate::misc_early::UNNEEDED_FIELD_PATTERN_INFO,
+ crate::misc_early::UNNEEDED_WILDCARD_PATTERN_INFO,
+ crate::misc_early::UNSEPARATED_LITERAL_SUFFIX_INFO,
+ crate::misc_early::ZERO_PREFIXED_LITERAL_INFO,
+ crate::mismatching_type_param_order::MISMATCHING_TYPE_PARAM_ORDER_INFO,
+ crate::missing_const_for_fn::MISSING_CONST_FOR_FN_INFO,
+ crate::missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS_INFO,
+ crate::missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES_INFO,
+ crate::missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS_INFO,
+ crate::missing_trait_methods::MISSING_TRAIT_METHODS_INFO,
+ crate::mixed_read_write_in_expression::DIVERGING_SUB_EXPRESSION_INFO,
+ crate::mixed_read_write_in_expression::MIXED_READ_WRITE_IN_EXPRESSION_INFO,
+ crate::module_style::MOD_MODULE_FILES_INFO,
+ crate::module_style::SELF_NAMED_MODULE_FILES_INFO,
+ crate::multi_assignments::MULTI_ASSIGNMENTS_INFO,
+ crate::mut_key::MUTABLE_KEY_TYPE_INFO,
+ crate::mut_mut::MUT_MUT_INFO,
+ crate::mut_reference::UNNECESSARY_MUT_PASSED_INFO,
+ crate::mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL_INFO,
+ crate::mutex_atomic::MUTEX_ATOMIC_INFO,
+ crate::mutex_atomic::MUTEX_INTEGER_INFO,
+ crate::needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE_INFO,
+ crate::needless_bool::BOOL_COMPARISON_INFO,
+ crate::needless_bool::NEEDLESS_BOOL_INFO,
+ crate::needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE_INFO,
+ crate::needless_continue::NEEDLESS_CONTINUE_INFO,
+ crate::needless_for_each::NEEDLESS_FOR_EACH_INFO,
+ crate::needless_late_init::NEEDLESS_LATE_INIT_INFO,
+ crate::needless_parens_on_range_literals::NEEDLESS_PARENS_ON_RANGE_LITERALS_INFO,
+ crate::needless_pass_by_value::NEEDLESS_PASS_BY_VALUE_INFO,
+ crate::needless_question_mark::NEEDLESS_QUESTION_MARK_INFO,
+ crate::needless_update::NEEDLESS_UPDATE_INFO,
+ crate::neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD_INFO,
+ crate::neg_multiply::NEG_MULTIPLY_INFO,
+ crate::new_without_default::NEW_WITHOUT_DEFAULT_INFO,
+ crate::no_effect::NO_EFFECT_INFO,
+ crate::no_effect::NO_EFFECT_UNDERSCORE_BINDING_INFO,
+ crate::no_effect::UNNECESSARY_OPERATION_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,
+ crate::non_expressive_names::MANY_SINGLE_CHAR_NAMES_INFO,
+ crate::non_expressive_names::SIMILAR_NAMES_INFO,
+ crate::non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS_INFO,
+ crate::non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY_INFO,
+ crate::nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES_INFO,
+ crate::octal_escapes::OCTAL_ESCAPES_INFO,
+ crate::only_used_in_recursion::ONLY_USED_IN_RECURSION_INFO,
+ crate::operators::ABSURD_EXTREME_COMPARISONS_INFO,
+ crate::operators::ARITHMETIC_SIDE_EFFECTS_INFO,
+ crate::operators::ASSIGN_OP_PATTERN_INFO,
+ crate::operators::BAD_BIT_MASK_INFO,
+ crate::operators::CMP_NAN_INFO,
+ crate::operators::CMP_OWNED_INFO,
+ crate::operators::DOUBLE_COMPARISONS_INFO,
+ crate::operators::DURATION_SUBSEC_INFO,
+ crate::operators::EQ_OP_INFO,
+ crate::operators::ERASING_OP_INFO,
+ crate::operators::FLOAT_ARITHMETIC_INFO,
+ crate::operators::FLOAT_CMP_INFO,
+ crate::operators::FLOAT_CMP_CONST_INFO,
+ crate::operators::FLOAT_EQUALITY_WITHOUT_ABS_INFO,
+ crate::operators::IDENTITY_OP_INFO,
+ crate::operators::INEFFECTIVE_BIT_MASK_INFO,
+ crate::operators::INTEGER_ARITHMETIC_INFO,
+ crate::operators::INTEGER_DIVISION_INFO,
+ crate::operators::MISREFACTORED_ASSIGN_OP_INFO,
+ crate::operators::MODULO_ARITHMETIC_INFO,
+ crate::operators::MODULO_ONE_INFO,
+ crate::operators::NEEDLESS_BITWISE_BOOL_INFO,
+ crate::operators::OP_REF_INFO,
+ crate::operators::PTR_EQ_INFO,
+ crate::operators::SELF_ASSIGNMENT_INFO,
+ crate::operators::VERBOSE_BIT_MASK_INFO,
+ crate::option_env_unwrap::OPTION_ENV_UNWRAP_INFO,
+ crate::option_if_let_else::OPTION_IF_LET_ELSE_INFO,
+ crate::overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL_INFO,
+ crate::panic_in_result_fn::PANIC_IN_RESULT_FN_INFO,
+ crate::panic_unimplemented::PANIC_INFO,
+ crate::panic_unimplemented::TODO_INFO,
+ crate::panic_unimplemented::UNIMPLEMENTED_INFO,
+ crate::panic_unimplemented::UNREACHABLE_INFO,
+ crate::partial_pub_fields::PARTIAL_PUB_FIELDS_INFO,
+ crate::partialeq_ne_impl::PARTIALEQ_NE_IMPL_INFO,
+ crate::partialeq_to_none::PARTIALEQ_TO_NONE_INFO,
+ crate::pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE_INFO,
+ crate::pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF_INFO,
+ crate::pattern_type_mismatch::PATTERN_TYPE_MISMATCH_INFO,
+ crate::precedence::PRECEDENCE_INFO,
+ crate::ptr::CMP_NULL_INFO,
+ crate::ptr::INVALID_NULL_PTR_USAGE_INFO,
+ crate::ptr::MUT_FROM_REF_INFO,
+ crate::ptr::PTR_ARG_INFO,
+ crate::ptr_offset_with_cast::PTR_OFFSET_WITH_CAST_INFO,
+ crate::pub_use::PUB_USE_INFO,
+ crate::question_mark::QUESTION_MARK_INFO,
+ crate::ranges::MANUAL_RANGE_CONTAINS_INFO,
+ crate::ranges::RANGE_MINUS_ONE_INFO,
+ crate::ranges::RANGE_PLUS_ONE_INFO,
+ crate::ranges::REVERSED_EMPTY_RANGES_INFO,
+ crate::rc_clone_in_vec_init::RC_CLONE_IN_VEC_INIT_INFO,
+ crate::read_zero_byte_vec::READ_ZERO_BYTE_VEC_INFO,
+ crate::redundant_clone::REDUNDANT_CLONE_INFO,
+ crate::redundant_closure_call::REDUNDANT_CLOSURE_CALL_INFO,
+ crate::redundant_else::REDUNDANT_ELSE_INFO,
+ crate::redundant_field_names::REDUNDANT_FIELD_NAMES_INFO,
+ crate::redundant_pub_crate::REDUNDANT_PUB_CRATE_INFO,
+ crate::redundant_slicing::DEREF_BY_SLICING_INFO,
+ crate::redundant_slicing::REDUNDANT_SLICING_INFO,
+ crate::redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES_INFO,
+ crate::ref_option_ref::REF_OPTION_REF_INFO,
+ crate::reference::DEREF_ADDROF_INFO,
+ crate::regex::INVALID_REGEX_INFO,
+ crate::regex::TRIVIAL_REGEX_INFO,
+ crate::return_self_not_must_use::RETURN_SELF_NOT_MUST_USE_INFO,
+ crate::returns::LET_AND_RETURN_INFO,
+ crate::returns::NEEDLESS_RETURN_INFO,
+ crate::same_name_method::SAME_NAME_METHOD_INFO,
+ crate::self_named_constructors::SELF_NAMED_CONSTRUCTORS_INFO,
+ crate::semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED_INFO,
+ crate::serde_api::SERDE_API_MISUSE_INFO,
+ crate::shadow::SHADOW_REUSE_INFO,
+ crate::shadow::SHADOW_SAME_INFO,
+ crate::shadow::SHADOW_UNRELATED_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,
+ crate::slow_vector_initialization::SLOW_VECTOR_INITIALIZATION_INFO,
+ crate::std_instead_of_core::ALLOC_INSTEAD_OF_CORE_INFO,
+ crate::std_instead_of_core::STD_INSTEAD_OF_ALLOC_INFO,
+ crate::std_instead_of_core::STD_INSTEAD_OF_CORE_INFO,
+ crate::strings::STRING_ADD_INFO,
+ crate::strings::STRING_ADD_ASSIGN_INFO,
+ crate::strings::STRING_FROM_UTF8_AS_BYTES_INFO,
+ crate::strings::STRING_LIT_AS_BYTES_INFO,
+ crate::strings::STRING_SLICE_INFO,
+ crate::strings::STRING_TO_STRING_INFO,
+ crate::strings::STR_TO_STRING_INFO,
+ crate::strings::TRIM_SPLIT_WHITESPACE_INFO,
+ crate::strlen_on_c_strings::STRLEN_ON_C_STRINGS_INFO,
+ crate::suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS_INFO,
+ crate::suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL_INFO,
+ crate::suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL_INFO,
+ crate::suspicious_xor_used_as_pow::SUSPICIOUS_XOR_USED_AS_POW_INFO,
+ crate::swap::ALMOST_SWAPPED_INFO,
+ crate::swap::MANUAL_SWAP_INFO,
+ crate::swap_ptr_to_ref::SWAP_PTR_TO_REF_INFO,
+ crate::tabs_in_doc_comments::TABS_IN_DOC_COMMENTS_INFO,
+ crate::temporary_assignment::TEMPORARY_ASSIGNMENT_INFO,
+ crate::to_digit_is_some::TO_DIGIT_IS_SOME_INFO,
+ crate::trailing_empty_array::TRAILING_EMPTY_ARRAY_INFO,
+ crate::trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS_INFO,
+ crate::trait_bounds::TYPE_REPETITION_IN_BOUNDS_INFO,
+ crate::transmute::CROSSPOINTER_TRANSMUTE_INFO,
+ crate::transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS_INFO,
+ crate::transmute::TRANSMUTE_BYTES_TO_STR_INFO,
+ crate::transmute::TRANSMUTE_FLOAT_TO_INT_INFO,
+ crate::transmute::TRANSMUTE_INT_TO_BOOL_INFO,
+ crate::transmute::TRANSMUTE_INT_TO_CHAR_INFO,
+ crate::transmute::TRANSMUTE_INT_TO_FLOAT_INFO,
+ crate::transmute::TRANSMUTE_NUM_TO_BYTES_INFO,
+ crate::transmute::TRANSMUTE_PTR_TO_PTR_INFO,
+ crate::transmute::TRANSMUTE_PTR_TO_REF_INFO,
+ crate::transmute::TRANSMUTE_UNDEFINED_REPR_INFO,
+ crate::transmute::TRANSMUTING_NULL_INFO,
+ crate::transmute::UNSOUND_COLLECTION_TRANSMUTE_INFO,
+ crate::transmute::USELESS_TRANSMUTE_INFO,
+ crate::transmute::WRONG_TRANSMUTE_INFO,
+ crate::types::BORROWED_BOX_INFO,
+ crate::types::BOX_COLLECTION_INFO,
+ crate::types::LINKEDLIST_INFO,
+ crate::types::OPTION_OPTION_INFO,
+ crate::types::RC_BUFFER_INFO,
+ crate::types::RC_MUTEX_INFO,
+ crate::types::REDUNDANT_ALLOCATION_INFO,
+ crate::types::TYPE_COMPLEXITY_INFO,
+ crate::types::VEC_BOX_INFO,
+ crate::undocumented_unsafe_blocks::UNDOCUMENTED_UNSAFE_BLOCKS_INFO,
+ crate::undocumented_unsafe_blocks::UNNECESSARY_SAFETY_COMMENT_INFO,
+ crate::unicode::INVISIBLE_CHARACTERS_INFO,
+ crate::unicode::NON_ASCII_LITERAL_INFO,
+ crate::unicode::UNICODE_NOT_NFC_INFO,
+ crate::uninit_vec::UNINIT_VEC_INFO,
+ crate::unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD_INFO,
+ crate::unit_types::LET_UNIT_VALUE_INFO,
+ crate::unit_types::UNIT_ARG_INFO,
+ crate::unit_types::UNIT_CMP_INFO,
+ crate::unnamed_address::FN_ADDRESS_COMPARISONS_INFO,
+ crate::unnamed_address::VTABLE_ADDRESS_COMPARISONS_INFO,
+ crate::unnecessary_owned_empty_strings::UNNECESSARY_OWNED_EMPTY_STRINGS_INFO,
+ crate::unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS_INFO,
+ crate::unnecessary_wraps::UNNECESSARY_WRAPS_INFO,
+ crate::unnested_or_patterns::UNNESTED_OR_PATTERNS_INFO,
+ crate::unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME_INFO,
+ crate::unused_async::UNUSED_ASYNC_INFO,
+ crate::unused_io_amount::UNUSED_IO_AMOUNT_INFO,
+ crate::unused_peekable::UNUSED_PEEKABLE_INFO,
+ crate::unused_rounding::UNUSED_ROUNDING_INFO,
+ crate::unused_self::UNUSED_SELF_INFO,
+ crate::unused_unit::UNUSED_UNIT_INFO,
+ crate::unwrap::PANICKING_UNWRAP_INFO,
+ crate::unwrap::UNNECESSARY_UNWRAP_INFO,
+ crate::unwrap_in_result::UNWRAP_IN_RESULT_INFO,
+ crate::upper_case_acronyms::UPPER_CASE_ACRONYMS_INFO,
+ crate::use_self::USE_SELF_INFO,
+ crate::useless_conversion::USELESS_CONVERSION_INFO,
+ crate::vec::USELESS_VEC_INFO,
+ crate::vec_init_then_push::VEC_INIT_THEN_PUSH_INFO,
+ crate::wildcard_imports::ENUM_GLOB_USE_INFO,
+ crate::wildcard_imports::WILDCARD_IMPORTS_INFO,
+ crate::write::PRINTLN_EMPTY_STRING_INFO,
+ crate::write::PRINT_LITERAL_INFO,
+ crate::write::PRINT_STDERR_INFO,
+ crate::write::PRINT_STDOUT_INFO,
+ crate::write::PRINT_WITH_NEWLINE_INFO,
+ crate::write::USE_DEBUG_INFO,
+ crate::write::WRITELN_EMPTY_STRING_INFO,
+ crate::write::WRITE_LITERAL_INFO,
+ crate::write::WRITE_WITH_NEWLINE_INFO,
+ crate::zero_div_zero::ZERO_DIVIDED_BY_ZERO_INFO,
+ crate::zero_sized_map_values::ZERO_SIZED_MAP_VALUES_INFO,
+];
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index a37ee82d4..38329659e 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -1,14 +1,16 @@
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
use clippy_utils::mir::{enclosing_mir, expr_local, local_assignments, used_exactly_once, PossibleBorrowerMap};
+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::{
- fn_def_id, get_parent_expr, get_parent_expr_for_hir, is_lint_allowed, meets_msrv, msrvs, path_to_local,
- walk_to_expr_usage,
+ fn_def_id, get_parent_expr, get_parent_expr_for_hir, is_lint_allowed, path_to_local, walk_to_expr_usage,
};
+
use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX};
use rustc_data_structures::fx::FxIndexMap;
+use rustc_data_structures::graph::iterate::{CycleDetector, TriColorDepthFirstSearch};
use rustc_errors::Applicability;
use rustc_hir::intravisit::{walk_ty, Visitor};
use rustc_hir::{
@@ -24,10 +26,9 @@ 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, EarlyBinder, FnSig, GenericArgKind, List, ParamTy, PredicateKind,
+ self, Binder, BoundVariableKind, Clause, EarlyBinder, FnSig, GenericArgKind, List, ParamTy, PredicateKind,
ProjectionPredicate, Ty, TyCtxt, TypeVisitable, TypeckResults,
};
-use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{symbol::sym, Span, Symbol};
use rustc_trait_selection::infer::InferCtxtExt as _;
@@ -180,12 +181,12 @@ pub struct Dereferencing<'tcx> {
possible_borrowers: Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>,
// `IntoIterator` for arrays requires Rust 1.53.
- msrv: Option<RustcVersion>,
+ msrv: Msrv,
}
impl<'tcx> Dereferencing<'tcx> {
#[must_use]
- pub fn new(msrv: Option<RustcVersion>) -> Self {
+ pub fn new(msrv: Msrv) -> Self {
Self {
msrv,
..Dereferencing::default()
@@ -274,9 +275,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
}
let typeck = cx.typeck_results();
- let (kind, sub_expr) = if let Some(x) = try_parse_ref_op(cx.tcx, typeck, expr) {
- x
- } else {
+ let Some((kind, sub_expr)) = try_parse_ref_op(cx.tcx, typeck, expr) else {
// The whole chain of reference operations has been seen
if let Some((state, data)) = self.state.take() {
report(cx, expr, state, data);
@@ -287,26 +286,27 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
match (self.state.take(), kind) {
(None, kind) => {
let expr_ty = typeck.expr_ty(expr);
- let (position, adjustments) = walk_parents(cx, &mut self.possible_borrowers, expr, self.msrv);
+ let (position, adjustments) = walk_parents(cx, &mut self.possible_borrowers, expr, &self.msrv);
match kind {
RefOp::Deref => {
+ let sub_ty = typeck.expr_ty(sub_expr);
if let Position::FieldAccess {
name,
of_union: false,
} = position
- && !ty_contains_field(typeck.expr_ty(sub_expr), name)
+ && !ty_contains_field(sub_ty, name)
{
self.state = Some((
State::ExplicitDerefField { name },
StateData { span: expr.span, hir_id: expr.hir_id, position },
));
- } else if position.is_deref_stable() {
+ } else if position.is_deref_stable() && sub_ty.is_ref() {
self.state = Some((
State::ExplicitDeref { mutability: None },
StateData { span: expr.span, hir_id: expr.hir_id, position },
));
}
- }
+ },
RefOp::Method(target_mut)
if !is_lint_allowed(cx, EXPLICIT_DEREF_METHODS, expr.hir_id)
&& position.lint_explicit_deref() =>
@@ -321,7 +321,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
StateData {
span: expr.span,
hir_id: expr.hir_id,
- position
+ position,
},
));
},
@@ -395,7 +395,11 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
msg,
snip_expr,
}),
- StateData { span: expr.span, hir_id: expr.hir_id, position },
+ StateData {
+ span: expr.span,
+ hir_id: expr.hir_id,
+ position,
+ },
));
} else if position.is_deref_stable()
// Auto-deref doesn't combine with other adjustments
@@ -407,7 +411,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
StateData {
span: expr.span,
hir_id: expr.hir_id,
- position
+ position,
},
));
}
@@ -699,7 +703,7 @@ fn walk_parents<'tcx>(
cx: &LateContext<'tcx>,
possible_borrowers: &mut Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>,
e: &'tcx Expr<'_>,
- msrv: Option<RustcVersion>,
+ msrv: &Msrv,
) -> (Position, &'tcx [Adjustment<'tcx>]) {
let mut adjustments = [].as_slice();
let mut precedence = 0i8;
@@ -806,30 +810,39 @@ fn walk_parents<'tcx>(
.position(|arg| arg.hir_id == child_id)
.zip(expr_sig(cx, func))
.and_then(|(i, sig)| {
- sig.input_with_hir(i).map(|(hir_ty, ty)| match hir_ty {
- // Type inference for closures can depend on how they're called. Only go by the explicit
- // types here.
- Some(hir_ty) => binding_ty_auto_deref_stability(cx, hir_ty, precedence, ty.bound_vars()),
- None => {
- if let ty::Param(param_ty) = ty.skip_binder().kind() {
- needless_borrow_impl_arg_position(
- cx,
- possible_borrowers,
- parent,
- i,
- *param_ty,
- e,
- precedence,
- msrv,
- )
- } else {
- ty_auto_deref_stability(cx, cx.tcx.erase_late_bound_regions(ty), precedence)
- .position_for_arg()
- }
- },
+ sig.input_with_hir(i).map(|(hir_ty, ty)| {
+ match hir_ty {
+ // Type inference for closures can depend on how they're called. Only go by the explicit
+ // types here.
+ Some(hir_ty) => {
+ binding_ty_auto_deref_stability(cx, hir_ty, precedence, ty.bound_vars())
+ },
+ None => {
+ // `e.hir_id == child_id` for https://github.com/rust-lang/rust-clippy/issues/9739
+ // `!call_is_qualified(func)` for https://github.com/rust-lang/rust-clippy/issues/9782
+ if e.hir_id == child_id
+ && !call_is_qualified(func)
+ && let ty::Param(param_ty) = ty.skip_binder().kind()
+ {
+ needless_borrow_impl_arg_position(
+ cx,
+ possible_borrowers,
+ parent,
+ i,
+ *param_ty,
+ e,
+ precedence,
+ msrv,
+ )
+ } else {
+ ty_auto_deref_stability(cx, cx.tcx.erase_late_bound_regions(ty), precedence)
+ .position_for_arg()
+ }
+ },
+ }
})
}),
- ExprKind::MethodCall(_, receiver, args, _) => {
+ ExprKind::MethodCall(method, receiver, args, _) => {
let 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.
@@ -842,14 +855,10 @@ fn walk_parents<'tcx>(
} else if let Some(trait_id) = cx.tcx.trait_of_item(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 = match cx
+ && let subs = cx
.typeck_results()
- .node_substs_opt(parent.hir_id)
- .and_then(|subs| subs.get(1..))
- {
- Some(subs) => cx.tcx.mk_substs(subs.iter().copied()),
- None => cx.tcx.mk_substs(std::iter::empty::<ty::subst::GenericArg<'_>>()),
- } && let impl_ty = if cx.tcx.fn_sig(id).skip_binder().inputs()[0].is_ref() {
+ .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() {
// Trait methods taking `&self`
sub_ty
} else {
@@ -858,7 +867,11 @@ fn walk_parents<'tcx>(
} && impl_ty.is_ref()
&& let infcx = cx.tcx.infer_ctxt().build()
&& infcx
- .type_implements_trait(trait_id, impl_ty, subs, cx.param_env)
+ .type_implements_trait(
+ trait_id,
+ [impl_ty.into()].into_iter().chain(subs.iter().copied()),
+ cx.param_env,
+ )
.must_apply_modulo_regions()
{
return Some(Position::MethodReceiverRefImpl)
@@ -867,7 +880,9 @@ fn walk_parents<'tcx>(
}
args.iter().position(|arg| arg.hir_id == child_id).map(|i| {
let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i + 1];
- if let ty::Param(param_ty) = ty.kind() {
+ // `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() {
needless_borrow_impl_arg_position(
cx,
possible_borrowers,
@@ -1045,13 +1060,25 @@ fn ty_contains_infer(ty: &hir::Ty<'_>) -> bool {
v.0
}
+fn call_is_qualified(expr: &Expr<'_>) -> bool {
+ if let ExprKind::Path(path) = &expr.kind {
+ match path {
+ QPath::Resolved(_, path) => path.segments.last().map_or(false, |segment| segment.args.is_some()),
+ QPath::TypeRelative(_, segment) => segment.args.is_some(),
+ QPath::LangItem(..) => false,
+ }
+ } else {
+ false
+ }
+}
+
// Checks whether:
// * child is an expression of the form `&e` in an argument position requiring an `impl Trait`
// * `e`'s type implements `Trait` and is copyable
// If the conditions are met, returns `Some(Position::ImplArg(..))`; otherwise, returns `None`.
// The "is copyable" condition is to avoid the case where removing the `&` means `e` would have to
// be moved, but it cannot be.
-#[expect(clippy::too_many_arguments)]
+#[expect(clippy::too_many_arguments, clippy::too_many_lines)]
fn needless_borrow_impl_arg_position<'tcx>(
cx: &LateContext<'tcx>,
possible_borrowers: &mut Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>,
@@ -1060,7 +1087,7 @@ fn needless_borrow_impl_arg_position<'tcx>(
param_ty: ParamTy,
mut expr: &Expr<'tcx>,
precedence: i8,
- msrv: Option<RustcVersion>,
+ msrv: &Msrv,
) -> Position {
let destruct_trait_def_id = cx.tcx.lang_items().destruct_trait();
let sized_trait_def_id = cx.tcx.lang_items().sized_trait();
@@ -1079,7 +1106,7 @@ fn needless_borrow_impl_arg_position<'tcx>(
let projection_predicates = predicates
.iter()
.filter_map(|predicate| {
- if let PredicateKind::Projection(projection_predicate) = predicate.kind().skip_binder() {
+ if let PredicateKind::Clause(Clause::Projection(projection_predicate)) = predicate.kind().skip_binder() {
Some(projection_predicate)
} else {
None
@@ -1093,7 +1120,7 @@ fn needless_borrow_impl_arg_position<'tcx>(
if predicates
.iter()
.filter_map(|predicate| {
- if let PredicateKind::Trait(trait_predicate) = predicate.kind().skip_binder()
+ if let PredicateKind::Clause(Clause::Trait(trait_predicate)) = predicate.kind().skip_binder()
&& trait_predicate.trait_ref.self_ty() == param_ty.to_ty(cx.tcx)
{
Some(trait_predicate.trait_ref.def_id)
@@ -1113,6 +1140,16 @@ fn needless_borrow_impl_arg_position<'tcx>(
return Position::Other(precedence);
}
+ // See:
+ // - https://github.com/rust-lang/rust-clippy/pull/9674#issuecomment-1289294201
+ // - https://github.com/rust-lang/rust-clippy/pull/9674#issuecomment-1292225232
+ if projection_predicates
+ .iter()
+ .any(|projection_predicate| is_mixed_projection_predicate(cx, callee_def_id, projection_predicate))
+ {
+ return Position::Other(precedence);
+ }
+
// `substs_with_referent_ty` can be constructed outside of `check_referent` because the same
// elements are modified each time `check_referent` is called.
let mut substs_with_referent_ty = substs_with_expr_ty.to_vec();
@@ -1145,18 +1182,18 @@ fn needless_borrow_impl_arg_position<'tcx>(
}
predicates.iter().all(|predicate| {
- if let PredicateKind::Trait(trait_predicate) = predicate.kind().skip_binder()
+ if let PredicateKind::Clause(Clause::Trait(trait_predicate)) = predicate.kind().skip_binder()
&& cx.tcx.is_diagnostic_item(sym::IntoIterator, trait_predicate.trait_ref.def_id)
&& let ty::Param(param_ty) = trait_predicate.self_ty().kind()
&& let GenericArgKind::Type(ty) = substs_with_referent_ty[param_ty.index as usize].unpack()
&& ty.is_array()
- && !meets_msrv(msrv, msrvs::ARRAY_INTO_ITERATOR)
+ && !msrv.meets(msrvs::ARRAY_INTO_ITERATOR)
{
return false;
}
let predicate = EarlyBinder(predicate).subst(cx.tcx, &substs_with_referent_ty);
- let obligation = Obligation::new(ObligationCause::dummy(), cx.param_env, predicate);
+ let obligation = Obligation::new(cx.tcx, ObligationCause::dummy(), cx.param_env, predicate);
let infcx = cx.tcx.infer_ctxt().build();
infcx.predicate_must_hold_modulo_regions(&obligation)
})
@@ -1192,6 +1229,37 @@ fn has_ref_mut_self_method(cx: &LateContext<'_>, trait_def_id: DefId) -> bool {
})
}
+fn is_mixed_projection_predicate<'tcx>(
+ cx: &LateContext<'tcx>,
+ callee_def_id: DefId,
+ projection_predicate: &ProjectionPredicate<'tcx>,
+) -> bool {
+ let generics = cx.tcx.generics_of(callee_def_id);
+ // The predicate requires the projected type to equal a type parameter from the parent context.
+ if let Some(term_ty) = projection_predicate.term.ty()
+ && let ty::Param(term_param_ty) = term_ty.kind()
+ && (term_param_ty.index as usize) < generics.parent_count
+ {
+ // The inner-most self type is a type parameter from the current function.
+ let mut projection_ty = projection_predicate.projection_ty;
+ loop {
+ match projection_ty.self_ty().kind() {
+ ty::Projection(inner_projection_ty) => {
+ projection_ty = *inner_projection_ty;
+ }
+ ty::Param(param_ty) => {
+ return (param_ty.index as usize) >= generics.parent_count;
+ }
+ _ => {
+ return false;
+ }
+ }
+ }
+ } else {
+ false
+ }
+}
+
fn referent_used_exactly_once<'tcx>(
cx: &LateContext<'tcx>,
possible_borrowers: &mut Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>,
@@ -1203,6 +1271,8 @@ fn referent_used_exactly_once<'tcx>(
&& let Some(statement) = mir.basic_blocks[location.block].statements.get(location.statement_index)
&& let StatementKind::Assign(box (_, Rvalue::Ref(_, _, place))) = statement.kind
&& !place.has_deref()
+ // Ensure not in a loop (https://github.com/rust-lang/rust-clippy/issues/9710)
+ && TriColorDepthFirstSearch::new(&mir.basic_blocks).run_from(location.block, &mut CycleDetector).is_none()
{
let body_owner_local_def_id = cx.tcx.hir().enclosing_body_owner(reference.hir_id);
if possible_borrowers
@@ -1263,7 +1333,7 @@ fn replace_types<'tcx>(
let item_def_id = projection_predicate.projection_ty.item_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, &[]));
+ .mk_projection(assoc_item.def_id, cx.tcx.mk_substs_trait(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)
@@ -1320,6 +1390,7 @@ fn ty_auto_deref_stability<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, precedenc
continue;
},
ty::Param(_) => TyPosition::new_deref_stable_for_result(precedence, ty),
+ ty::Projection(_) if ty.has_non_region_param() => TyPosition::new_deref_stable_for_result(precedence, ty),
ty::Infer(_) | ty::Error(_) | ty::Bound(..) | ty::Opaque(..) | ty::Placeholder(_) | ty::Dynamic(..) => {
Position::ReborrowStable(precedence).into()
},
@@ -1346,11 +1417,9 @@ fn ty_auto_deref_stability<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, precedenc
| ty::Closure(..)
| ty::Never
| ty::Tuple(_)
- | ty::Projection(_) => Position::DerefStable(
- precedence,
- ty.is_sized(cx.tcx, cx.param_env.without_caller_bounds()),
- )
- .into(),
+ | ty::Projection(_) => {
+ Position::DerefStable(precedence, ty.is_sized(cx.tcx, cx.param_env.without_caller_bounds())).into()
+ },
};
}
}
diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs
index 102a02138..9e596ca81 100644
--- a/src/tools/clippy/clippy_lints/src/derive.rs
+++ b/src/tools/clippy/clippy_lints/src/derive.rs
@@ -14,8 +14,8 @@ use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter;
use rustc_middle::traits::Reveal;
use rustc_middle::ty::{
- self, Binder, BoundConstness, GenericParamDefKind, ImplPolarity, ParamEnv, PredicateKind, TraitPredicate, TraitRef,
- Ty, TyCtxt,
+ self, Binder, BoundConstness, Clause, GenericParamDefKind, ImplPolarity, ParamEnv, PredicateKind, TraitPredicate,
+ TraitRef, Ty, TyCtxt,
};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;
@@ -466,12 +466,12 @@ fn check_partial_eq_without_eq<'tcx>(cx: &LateContext<'tcx>, span: Span, trait_r
if let Some(def_id) = trait_ref.trait_def_id();
if cx.tcx.is_diagnostic_item(sym::PartialEq, def_id);
let param_env = param_env_for_derived_eq(cx.tcx, adt.did(), eq_trait_def_id);
- if !implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, &[]);
+ if !implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, []);
// If all of our fields implement `Eq`, we can implement `Eq` too
if adt
.all_fields()
.map(|f| f.ty(cx.tcx, substs))
- .all(|ty| implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, &[]));
+ .all(|ty| implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, []));
then {
span_lint_and_sugg(
cx,
@@ -499,7 +499,7 @@ fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) ->
let ty_predicates = tcx.predicates_of(did).predicates;
for (p, _) in ty_predicates {
- if let PredicateKind::Trait(p) = p.kind().skip_binder()
+ if let PredicateKind::Clause(Clause::Trait(p)) = p.kind().skip_binder()
&& p.trait_ref.def_id == eq_trait_id
&& let ty::Param(self_ty) = p.trait_ref.self_ty().kind()
&& p.constness == BoundConstness::NotConst
@@ -512,14 +512,14 @@ 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(
params.iter().filter(|&&(_, needs_eq)| needs_eq).map(|&(param, _)| {
- tcx.mk_predicate(Binder::dummy(PredicateKind::Trait(TraitPredicate {
+ tcx.mk_predicate(Binder::dummy(PredicateKind::Clause(Clause::Trait(TraitPredicate {
trait_ref: TraitRef::new(
eq_trait_id,
tcx.mk_substs(std::iter::once(tcx.mk_param_from_def(param))),
),
constness: BoundConstness::NotConst,
polarity: ImplPolarity::Positive,
- })))
+ }))))
}),
)),
Reveal::UserFacing,
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
index 5ab7144e2..68122b4ce 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
@@ -1,7 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::macros::macro_backtrace;
use rustc_data_structures::fx::FxHashSet;
-use rustc_hir::def::{Namespace, Res};
use rustc_hir::def_id::DefIdMap;
use rustc_hir::{Expr, ForeignItem, HirId, ImplItem, Item, Pat, Path, Stmt, TraitItem, Ty};
use rustc_lint::{LateContext, LateLintPass};
@@ -89,7 +88,7 @@ impl DisallowedMacros {
&format!("use of a disallowed macro `{}`", conf.path()),
|diag| {
if let Some(reason) = conf.reason() {
- diag.note(&format!("{reason} (from clippy.toml)"));
+ diag.note(reason);
}
},
);
@@ -104,7 +103,7 @@ impl LateLintPass<'_> for DisallowedMacros {
fn check_crate(&mut self, cx: &LateContext<'_>) {
for (index, conf) in self.conf_disallowed.iter().enumerate() {
let segs: Vec<_> = conf.path().split("::").collect();
- if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &segs, Some(Namespace::MacroNS)) {
+ for id in clippy_utils::def_path_def_ids(cx, &segs) {
self.disallowed.insert(id, index);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_methods.rs b/src/tools/clippy/clippy_lints/src/disallowed_methods.rs
index 6ac85606d..ca8671c8f 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_methods.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_methods.rs
@@ -1,7 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::{fn_def_id, get_parent_expr, path_def_id};
-use rustc_hir::def::{Namespace, Res};
use rustc_hir::def_id::DefIdMap;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
@@ -79,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods {
fn check_crate(&mut self, cx: &LateContext<'_>) {
for (index, conf) in self.conf_disallowed.iter().enumerate() {
let segs: Vec<_> = conf.path().split("::").collect();
- if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &segs, Some(Namespace::ValueNS)) {
+ for id in clippy_utils::def_path_def_ids(cx, &segs) {
self.disallowed.insert(id, index);
}
}
@@ -104,7 +103,7 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods {
let msg = format!("use of a disallowed method `{}`", conf.path());
span_lint_and_then(cx, DISALLOWED_METHODS, expr.span, &msg, |diag| {
if let Some(reason) = conf.reason() {
- diag.note(&format!("{reason} (from clippy.toml)"));
+ diag.note(reason);
}
});
}
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_types.rs b/src/tools/clippy/clippy_lints/src/disallowed_types.rs
index c7131fc16..1f56d0118 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_types.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_types.rs
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_then;
use rustc_data_structures::fx::FxHashMap;
-use rustc_hir::def::{Namespace, Res};
+use rustc_hir::def::Res;
use rustc_hir::def_id::DefId;
use rustc_hir::{Item, ItemKind, PolyTraitRef, PrimTy, Ty, TyKind, UseKind};
use rustc_lint::{LateContext, LateLintPass};
@@ -53,8 +53,8 @@ declare_clippy_lint! {
#[derive(Clone, Debug)]
pub struct DisallowedTypes {
conf_disallowed: Vec<conf::DisallowedPath>,
- def_ids: FxHashMap<DefId, Option<String>>,
- prim_tys: FxHashMap<PrimTy, Option<String>>,
+ def_ids: FxHashMap<DefId, usize>,
+ prim_tys: FxHashMap<PrimTy, usize>,
}
impl DisallowedTypes {
@@ -69,13 +69,13 @@ impl DisallowedTypes {
fn check_res_emit(&self, cx: &LateContext<'_>, res: &Res, span: Span) {
match res {
Res::Def(_, did) => {
- if let Some(reason) = self.def_ids.get(did) {
- emit(cx, &cx.tcx.def_path_str(*did), span, reason.as_deref());
+ if let Some(&index) = self.def_ids.get(did) {
+ emit(cx, &cx.tcx.def_path_str(*did), span, &self.conf_disallowed[index]);
}
},
Res::PrimTy(prim) => {
- if let Some(reason) = self.prim_tys.get(prim) {
- emit(cx, prim.name_str(), span, reason.as_deref());
+ if let Some(&index) = self.prim_tys.get(prim) {
+ emit(cx, prim.name_str(), span, &self.conf_disallowed[index]);
}
},
_ => {},
@@ -87,24 +87,28 @@ impl_lint_pass!(DisallowedTypes => [DISALLOWED_TYPES]);
impl<'tcx> LateLintPass<'tcx> for DisallowedTypes {
fn check_crate(&mut self, cx: &LateContext<'_>) {
- for conf in &self.conf_disallowed {
+ for (index, conf) in self.conf_disallowed.iter().enumerate() {
let segs: Vec<_> = conf.path().split("::").collect();
- let reason = conf.reason().map(|reason| format!("{reason} (from clippy.toml)"));
- match clippy_utils::def_path_res(cx, &segs, Some(Namespace::TypeNS)) {
- Res::Def(_, id) => {
- self.def_ids.insert(id, reason);
- },
- Res::PrimTy(ty) => {
- self.prim_tys.insert(ty, reason);
- },
- _ => {},
+
+ for res in clippy_utils::def_path_res(cx, &segs) {
+ match res {
+ Res::Def(_, id) => {
+ self.def_ids.insert(id, index);
+ },
+ Res::PrimTy(ty) => {
+ self.prim_tys.insert(ty, index);
+ },
+ _ => {},
+ }
}
}
}
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
if let ItemKind::Use(path, UseKind::Single) = &item.kind {
- self.check_res_emit(cx, &path.res, item.span);
+ for res in &path.res {
+ self.check_res_emit(cx, res, item.span);
+ }
}
}
@@ -119,14 +123,14 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedTypes {
}
}
-fn emit(cx: &LateContext<'_>, name: &str, span: Span, reason: Option<&str>) {
+fn emit(cx: &LateContext<'_>, name: &str, span: Span, conf: &conf::DisallowedPath) {
span_lint_and_then(
cx,
DISALLOWED_TYPES,
span,
&format!("`{name}` is not allowed according to config"),
|diag| {
- if let Some(reason) = reason {
+ if let Some(reason) = conf.reason() {
diag.note(reason);
}
},
diff --git a/src/tools/clippy/clippy_lints/src/doc.rs b/src/tools/clippy/clippy_lints/src/doc.rs
index 24d6a6951..cdc23a4d2 100644
--- a/src/tools/clippy/clippy_lints/src/doc.rs
+++ b/src/tools/clippy/clippy_lints/src/doc.rs
@@ -11,7 +11,7 @@ use rustc_ast::token::CommentKind;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::sync::Lrc;
use rustc_errors::emitter::EmitterWriter;
-use rustc_errors::{Applicability, Handler, MultiSpan, SuggestionStyle};
+use rustc_errors::{Applicability, Handler, SuggestionStyle};
use rustc_hir as hir;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{AnonConst, Expr};
@@ -221,6 +221,42 @@ declare_clippy_lint! {
"possible typo for an intra-doc link"
}
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for the doc comments of publicly visible
+ /// safe functions and traits and warns if there is a `# Safety` section.
+ ///
+ /// ### Why is this bad?
+ /// Safe functions and traits are safe to implement and therefore do not
+ /// need to describe safety preconditions that users are required to uphold.
+ ///
+ /// ### Examples
+ /// ```rust
+ ///# type Universe = ();
+ /// /// # Safety
+ /// ///
+ /// /// This function should not be called before the horsemen are ready.
+ /// pub fn start_apocalypse_but_safely(u: &mut Universe) {
+ /// unimplemented!();
+ /// }
+ /// ```
+ ///
+ /// The function is safe, so there shouldn't be any preconditions
+ /// that have to be explained for safety reasons.
+ ///
+ /// ```rust
+ ///# type Universe = ();
+ /// /// This function should really be documented
+ /// pub fn start_apocalypse(u: &mut Universe) {
+ /// unimplemented!();
+ /// }
+ /// ```
+ #[clippy::version = "1.66.0"]
+ pub UNNECESSARY_SAFETY_DOC,
+ restriction,
+ "`pub fn` or `pub trait` with `# Safety` docs"
+}
+
#[expect(clippy::module_name_repetitions)]
#[derive(Clone)]
pub struct DocMarkdown {
@@ -243,7 +279,8 @@ impl_lint_pass!(DocMarkdown => [
MISSING_SAFETY_DOC,
MISSING_ERRORS_DOC,
MISSING_PANICS_DOC,
- NEEDLESS_DOCTEST_MAIN
+ NEEDLESS_DOCTEST_MAIN,
+ UNNECESSARY_SAFETY_DOC,
]);
impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
@@ -254,7 +291,7 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
let attrs = cx.tcx.hir().attrs(item.hir_id());
- let headers = check_attrs(cx, &self.valid_idents, attrs);
+ let Some(headers) = check_attrs(cx, &self.valid_idents, attrs) else { return };
match item.kind {
hir::ItemKind::Fn(ref sig, _, body_id) => {
if !(is_entrypoint_fn(cx, item.owner_id.to_def_id()) || in_external_macro(cx.tcx.sess, item.span)) {
@@ -265,29 +302,26 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
panic_span: None,
};
fpu.visit_expr(body.value);
- lint_for_missing_headers(
- cx,
- item.owner_id.def_id,
- item.span,
- sig,
- headers,
- Some(body_id),
- fpu.panic_span,
- );
+ lint_for_missing_headers(cx, item.owner_id.def_id, sig, headers, Some(body_id), fpu.panic_span);
}
},
hir::ItemKind::Impl(impl_) => {
self.in_trait_impl = impl_.of_trait.is_some();
},
- hir::ItemKind::Trait(_, unsafety, ..) => {
- if !headers.safety && unsafety == hir::Unsafety::Unsafe {
- span_lint(
- cx,
- MISSING_SAFETY_DOC,
- item.span,
- "docs for unsafe trait missing `# Safety` section",
- );
- }
+ hir::ItemKind::Trait(_, unsafety, ..) => match (headers.safety, unsafety) {
+ (false, hir::Unsafety::Unsafe) => span_lint(
+ cx,
+ MISSING_SAFETY_DOC,
+ cx.tcx.def_span(item.owner_id),
+ "docs for unsafe trait missing `# Safety` section",
+ ),
+ (true, hir::Unsafety::Normal) => span_lint(
+ cx,
+ UNNECESSARY_SAFETY_DOC,
+ cx.tcx.def_span(item.owner_id),
+ "docs for safe trait have unnecessary `# Safety` section",
+ ),
+ _ => (),
},
_ => (),
}
@@ -301,17 +335,17 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
let attrs = cx.tcx.hir().attrs(item.hir_id());
- let headers = check_attrs(cx, &self.valid_idents, attrs);
+ 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, item.span, sig, headers, None, None);
+ lint_for_missing_headers(cx, item.owner_id.def_id, sig, headers, None, None);
}
}
}
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) {
let attrs = cx.tcx.hir().attrs(item.hir_id());
- let headers = check_attrs(cx, &self.valid_idents, attrs);
+ let Some(headers) = check_attrs(cx, &self.valid_idents, attrs) else { return };
if self.in_trait_impl || in_external_macro(cx.tcx.sess, item.span) {
return;
}
@@ -323,23 +357,14 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
panic_span: None,
};
fpu.visit_expr(body.value);
- lint_for_missing_headers(
- cx,
- item.owner_id.def_id,
- item.span,
- sig,
- headers,
- Some(body_id),
- fpu.panic_span,
- );
+ lint_for_missing_headers(cx, item.owner_id.def_id, sig, headers, Some(body_id), fpu.panic_span);
}
}
}
-fn lint_for_missing_headers<'tcx>(
- cx: &LateContext<'tcx>,
+fn lint_for_missing_headers(
+ cx: &LateContext<'_>,
def_id: LocalDefId,
- span: impl Into<MultiSpan> + Copy,
sig: &hir::FnSig<'_>,
headers: DocHeaders,
body_id: Option<hir::BodyId>,
@@ -359,13 +384,21 @@ fn lint_for_missing_headers<'tcx>(
return;
}
- if !headers.safety && sig.header.unsafety == hir::Unsafety::Unsafe {
- span_lint(
+ let span = cx.tcx.def_span(def_id);
+ match (headers.safety, sig.header.unsafety) {
+ (false, hir::Unsafety::Unsafe) => span_lint(
cx,
MISSING_SAFETY_DOC,
span,
"unsafe function's docs miss `# Safety` section",
- );
+ ),
+ (true, hir::Unsafety::Normal) => span_lint(
+ cx,
+ UNNECESSARY_SAFETY_DOC,
+ span,
+ "safe function's docs have unnecessary `# Safety` section",
+ ),
+ _ => (),
}
if !headers.panics && panic_span.is_some() {
span_lint_and_note(
@@ -394,9 +427,7 @@ fn lint_for_missing_headers<'tcx>(
let body = cx.tcx.hir().body(body_id);
let ret_ty = typeck.expr_ty(body.value);
if implements_trait(cx, ret_ty, future, &[]);
- if let ty::Opaque(_, subs) = ret_ty.kind();
- if let Some(gen) = subs.types().next();
- if let ty::Generator(_, subs, _) = gen.kind();
+ if let ty::Generator(_, subs, _) = ret_ty.kind();
if is_type_diagnostic_item(cx, subs.as_generator().return_ty(), sym::Result);
then {
span_lint(
@@ -467,7 +498,7 @@ struct DocHeaders {
panics: bool,
}
-fn check_attrs<'a>(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &'a [Attribute]) -> 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
@@ -488,11 +519,7 @@ fn check_attrs<'a>(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs
} else if attr.has_name(sym::doc) {
// ignore mix of sugared and non-sugared doc
// don't trigger the safety or errors check
- return DocHeaders {
- safety: true,
- errors: true,
- panics: true,
- };
+ return None;
}
}
@@ -504,7 +531,7 @@ fn check_attrs<'a>(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs
}
if doc.is_empty() {
- return DocHeaders::default();
+ return Some(DocHeaders::default());
}
let mut cb = fake_broken_link_callback;
@@ -527,7 +554,7 @@ fn check_attrs<'a>(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs
(previous, current) => Err(((previous, previous_range), (current, current_range))),
}
});
- check_doc(cx, valid_idents, events, &spans)
+ Some(check_doc(cx, valid_idents, events, &spans))
}
const RUST_CODE: &[&str] = &["rust", "no_run", "should_panic", "compile_fail"];
@@ -691,6 +718,7 @@ fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, span: Span) {
false,
None,
false,
+ false,
);
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/double_parens.rs b/src/tools/clippy/clippy_lints/src/double_parens.rs
index 0f1d70186..29425b2e5 100644
--- a/src/tools/clippy/clippy_lints/src/double_parens.rs
+++ b/src/tools/clippy/clippy_lints/src/double_parens.rs
@@ -61,10 +61,10 @@ impl EarlyLintPass for DoubleParens {
}
}
},
- ExprKind::MethodCall(_, _, ref params, _) => {
- if let [ref param] = params[..] {
- if let ExprKind::Paren(_) = param.kind {
- span_lint(cx, DOUBLE_PARENS, param.span, msg);
+ ExprKind::MethodCall(ref call) => {
+ if let [ref arg] = call.args[..] {
+ if let ExprKind::Paren(_) = arg.kind {
+ span_lint(cx, DOUBLE_PARENS, arg.span, msg);
}
}
},
diff --git a/src/tools/clippy/clippy_lints/src/enum_variants.rs b/src/tools/clippy/clippy_lints/src/enum_variants.rs
index 223545fa7..b77b5621b 100644
--- a/src/tools/clippy/clippy_lints/src/enum_variants.rs
+++ b/src/tools/clippy/clippy_lints/src/enum_variants.rs
@@ -250,7 +250,7 @@ impl LateLintPass<'_> for EnumVariantNames {
let item_name = item.ident.name.as_str();
let item_camel = to_camel_case(item_name);
if !item.span.from_expansion() && is_present_in_source(cx, item.span) {
- if let Some(&(ref mod_name, ref mod_camel)) = self.modules.last() {
+ if let Some((mod_name, mod_camel)) = self.modules.last() {
// constants don't have surrounding modules
if !mod_camel.is_empty() {
if mod_name == &item.ident.name {
diff --git a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
index b40cb7cdd..c691e6c54 100644
--- a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
+++ b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
@@ -1,7 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_context;
use clippy_utils::ty::implements_trait;
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, Pat, PatKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -67,16 +66,14 @@ fn is_structural_partial_eq<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: T
impl<'tcx> LateLintPass<'tcx> for PatternEquality {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
- if_chain! {
- if !in_external_macro(cx.sess(), expr.span);
- if let ExprKind::Let(let_expr) = expr.kind;
- if unary_pattern(let_expr.pat);
+ if !in_external_macro(cx.sess(), expr.span)
+ && let ExprKind::Let(let_expr) = expr.kind
+ && unary_pattern(let_expr.pat) {
let exp_ty = cx.typeck_results().expr_ty(let_expr.init);
let pat_ty = cx.typeck_results().pat_ty(let_expr.pat);
- if is_structural_partial_eq(cx, exp_ty, pat_ty);
- then {
+ let mut applicability = Applicability::MachineApplicable;
- let mut applicability = Applicability::MachineApplicable;
+ if is_structural_partial_eq(cx, exp_ty, pat_ty) {
let pat_str = match let_expr.pat.kind {
PatKind::Struct(..) => format!(
"({})",
@@ -96,6 +93,20 @@ impl<'tcx> LateLintPass<'tcx> for PatternEquality {
),
applicability,
);
+ } else {
+ span_lint_and_sugg(
+ cx,
+ EQUATABLE_IF_LET,
+ expr.span,
+ "this pattern matching can be expressed using `matches!`",
+ "try",
+ format!(
+ "matches!({}, {})",
+ snippet_with_context(cx, let_expr.init.span, expr.span.ctxt(), "..", &mut applicability).0,
+ snippet_with_context(cx, let_expr.pat.span, expr.span.ctxt(), "..", &mut applicability).0,
+ ),
+ applicability,
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs
index 7f1a4c4be..1d09adec1 100644
--- a/src/tools/clippy/clippy_lints/src/escape.rs
+++ b/src/tools/clippy/clippy_lints/src/escape.rs
@@ -176,13 +176,7 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
}
}
- fn fake_read(
- &mut self,
- _: &rustc_hir_typeck::expr_use_visitor::PlaceWithHirId<'tcx>,
- _: FakeReadCause,
- _: HirId,
- ) {
- }
+ fn fake_read(&mut self, _: &rustc_hir_typeck::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
}
impl<'a, 'tcx> EscapeDelegate<'a, 'tcx> {
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index 7b9786d7e..3543910c3 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, Ty, TypeVisitable};
+use rustc_middle::ty::{self, EarlyBinder, SubstsRef, Ty, TypeVisitable};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::symbol::sym;
@@ -119,11 +119,18 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
let callee_ty_unadjusted = cx.typeck_results().expr_ty(callee).peel_refs();
if !is_type_diagnostic_item(cx, callee_ty_unadjusted, sym::Arc);
if !is_type_diagnostic_item(cx, callee_ty_unadjusted, sym::Rc);
+ if let ty::Closure(_, substs) = *closure_ty.kind();
then {
span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure", |diag| {
if let Some(mut snippet) = snippet_opt(cx, callee.span) {
if let Some(fn_mut_id) = cx.tcx.lang_items().fn_mut_trait()
- && implements_trait(cx, callee_ty.peel_refs(), fn_mut_id, &[])
+ && let args = cx.tcx.erase_late_bound_regions(substs.as_closure().sig()).inputs()
+ && implements_trait(
+ cx,
+ callee_ty.peel_refs(),
+ fn_mut_id,
+ &args.iter().copied().map(Into::into).collect::<Vec<_>>(),
+ )
&& path_to_local(callee).map_or(false, |l| local_used_after_expr(cx, l, expr))
{
// Mutable closure is used after current expr; we cannot consume it.
@@ -150,7 +157,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
if check_sig(cx, closure_ty, call_ty);
then {
span_lint_and_then(cx, REDUNDANT_CLOSURE_FOR_METHOD_CALLS, expr.span, "redundant closure", |diag| {
- let name = get_ufcs_type_name(cx, method_def_id);
+ let name = get_ufcs_type_name(cx, method_def_id, substs);
diag.span_suggestion(
expr.span,
"replace the closure with the method itself",
@@ -220,7 +227,7 @@ fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure_ty: Ty<'tcx>, call_ty: Ty<'tc
cx.tcx.erase_late_bound_regions(closure_sig) == cx.tcx.erase_late_bound_regions(call_sig)
}
-fn get_ufcs_type_name(cx: &LateContext<'_>, method_def_id: DefId) -> String {
+fn get_ufcs_type_name<'tcx>(cx: &LateContext<'tcx>, method_def_id: DefId, substs: SubstsRef<'tcx>) -> String {
let assoc_item = cx.tcx.associated_item(method_def_id);
let def_id = assoc_item.container_id(cx.tcx);
match assoc_item.container {
@@ -229,6 +236,15 @@ fn get_ufcs_type_name(cx: &LateContext<'_>, method_def_id: DefId) -> String {
let ty = cx.tcx.type_of(def_id);
match ty.kind() {
ty::Adt(adt, _) => cx.tcx.def_path_str(adt.did()),
+ ty::Array(..)
+ | ty::Dynamic(..)
+ | ty::Never
+ | ty::RawPtr(_)
+ | ty::Ref(..)
+ | ty::Slice(_)
+ | ty::Tuple(_) => {
+ format!("<{}>", EarlyBinder(ty).subst(cx.tcx, substs))
+ },
_ => ty.to_string(),
}
},
diff --git a/src/tools/clippy/clippy_lints/src/excessive_bools.rs b/src/tools/clippy/clippy_lints/src/excessive_bools.rs
index 453471c8c..fc2912f69 100644
--- a/src/tools/clippy/clippy_lints/src/excessive_bools.rs
+++ b/src/tools/clippy/clippy_lints/src/excessive_bools.rs
@@ -1,8 +1,11 @@
use clippy_utils::diagnostics::span_lint_and_help;
-use rustc_ast::ast::{AssocItemKind, Extern, Fn, FnSig, Impl, Item, ItemKind, Trait, Ty, TyKind};
-use rustc_lint::{EarlyContext, EarlyLintPass};
+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_lint::{LateContext, LateLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::{sym, Span};
+use rustc_span::Span;
+use rustc_target::spec::abi::Abi;
declare_clippy_lint! {
/// ### What it does
@@ -83,6 +86,12 @@ pub struct ExcessiveBools {
max_fn_params_bools: u64,
}
+#[derive(Eq, PartialEq, Debug, Copy, Clone)]
+enum Kind {
+ Struct,
+ Fn,
+}
+
impl ExcessiveBools {
#[must_use]
pub fn new(max_struct_bools: u64, max_fn_params_bools: u64) -> Self {
@@ -92,21 +101,20 @@ impl ExcessiveBools {
}
}
- fn check_fn_sig(&self, cx: &EarlyContext<'_>, fn_sig: &FnSig, span: Span) {
- match fn_sig.header.ext {
- Extern::Implicit(_) | Extern::Explicit(_, _) => return,
- Extern::None => (),
+ fn too_many_bools<'tcx>(&self, tys: impl Iterator<Item = &'tcx Ty<'tcx>>, kind: Kind) -> bool {
+ if let Ok(bools) = tys.filter(|ty| is_bool(ty)).count().try_into() {
+ (if Kind::Fn == kind {
+ self.max_fn_params_bools
+ } else {
+ self.max_struct_bools
+ }) < bools
+ } else {
+ false
}
+ }
- let fn_sig_bools = fn_sig
- .decl
- .inputs
- .iter()
- .filter(|param| is_bool_ty(&param.ty))
- .count()
- .try_into()
- .unwrap();
- if self.max_fn_params_bools < fn_sig_bools {
+ fn check_fn_sig(&self, cx: &LateContext<'_>, fn_decl: &FnDecl<'_>, span: Span) {
+ if !span.from_expansion() && self.too_many_bools(fn_decl.inputs.iter(), Kind::Fn) {
span_lint_and_help(
cx,
FN_PARAMS_EXCESSIVE_BOOLS,
@@ -121,56 +129,55 @@ impl ExcessiveBools {
impl_lint_pass!(ExcessiveBools => [STRUCT_EXCESSIVE_BOOLS, FN_PARAMS_EXCESSIVE_BOOLS]);
-fn is_bool_ty(ty: &Ty) -> bool {
- if let TyKind::Path(None, path) = &ty.kind {
- if let [name] = path.segments.as_slice() {
- return name.ident.name == sym::bool;
+impl<'tcx> LateLintPass<'tcx> for ExcessiveBools {
+ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
+ if item.span.from_expansion() {
+ return;
+ }
+ if let ItemKind::Struct(variant_data, _) = &item.kind {
+ if has_repr_attr(cx, item.hir_id()) {
+ return;
+ }
+
+ if self.too_many_bools(variant_data.fields().iter().map(|field| field.ty), Kind::Struct) {
+ span_lint_and_help(
+ cx,
+ STRUCT_EXCESSIVE_BOOLS,
+ item.span,
+ &format!("more than {} bools in a struct", self.max_struct_bools),
+ None,
+ "consider using a state machine or refactoring bools into two-variant enums",
+ );
+ }
}
}
- false
-}
-impl EarlyLintPass for ExcessiveBools {
- fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
- if item.span.from_expansion() {
- return;
+ fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx TraitItem<'tcx>) {
+ // functions with a body are already checked by `check_fn`
+ if let TraitItemKind::Fn(fn_sig, TraitFn::Required(_)) = &trait_item.kind
+ && fn_sig.header.abi == Abi::Rust
+ {
+ self.check_fn_sig(cx, fn_sig.decl, fn_sig.span);
}
- match &item.kind {
- ItemKind::Struct(variant_data, _) => {
- if item.attrs.iter().any(|attr| attr.has_name(sym::repr)) {
- return;
- }
+ }
- let struct_bools = variant_data
- .fields()
- .iter()
- .filter(|field| is_bool_ty(&field.ty))
- .count()
- .try_into()
- .unwrap();
- if self.max_struct_bools < struct_bools {
- span_lint_and_help(
- cx,
- STRUCT_EXCESSIVE_BOOLS,
- item.span,
- &format!("more than {} bools in a struct", self.max_struct_bools),
- None,
- "consider using a state machine or refactoring bools into two-variant enums",
- );
- }
- },
- ItemKind::Impl(box Impl {
- of_trait: None, items, ..
- })
- | ItemKind::Trait(box Trait { items, .. }) => {
- for item in items {
- if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
- self.check_fn_sig(cx, sig, item.span);
- }
- }
- },
- ItemKind::Fn(box Fn { sig, .. }) => self.check_fn_sig(cx, sig, item.span),
- _ => (),
+ fn check_fn(
+ &mut self,
+ cx: &LateContext<'tcx>,
+ fn_kind: FnKind<'tcx>,
+ fn_decl: &'tcx FnDecl<'tcx>,
+ _: &'tcx Body<'tcx>,
+ span: Span,
+ hir_id: HirId,
+ ) {
+ if let Some(fn_header) = fn_kind.header()
+ && fn_header.abi == Abi::Rust
+ && get_parent_as_impl(cx.tcx, hir_id)
+ .map_or(true,
+ |impl_item| impl_item.of_trait.is_none()
+ )
+ {
+ self.check_fn_sig(cx, fn_decl, span);
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/exit.rs b/src/tools/clippy/clippy_lints/src/exit.rs
index 407dd1b39..9c8b0d076 100644
--- a/src/tools/clippy/clippy_lints/src/exit.rs
+++ b/src/tools/clippy/clippy_lints/src/exit.rs
@@ -7,21 +7,34 @@ use rustc_session::{declare_lint_pass, declare_tool_lint};
declare_clippy_lint! {
/// ### What it does
- /// `exit()` terminates the program and doesn't provide a
- /// stack trace.
+ /// Detects calls to the `exit()` function which terminates the program.
///
/// ### Why is this bad?
- /// Ideally a program is terminated by finishing
+ /// Exit terminates the program at the location it is called. For unrecoverable
+ /// errors `panics` should be used to provide a stacktrace and potentualy other
+ /// information. A normal termination or one with an error code should happen in
/// the main function.
///
/// ### Example
- /// ```ignore
+ /// ```
/// std::process::exit(0)
/// ```
+ ///
+ /// Use instead:
+ ///
+ /// ```ignore
+ /// // To provide a stacktrace and additional information
+ /// panic!("message");
+ ///
+ /// // or a main method with a return
+ /// fn main() -> Result<(), i32> {
+ /// Ok(())
+ /// }
+ /// ```
#[clippy::version = "1.41.0"]
pub EXIT,
restriction,
- "`std::process::exit` is called, terminating the program"
+ "detects `std::process::exit` calls"
}
declare_lint_pass!(Exit => [EXIT]);
diff --git a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
index 0a633f242..9a1058470 100644
--- a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
+++ b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
@@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for FallibleImplFrom {
}
}
-fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_items: &[hir::ImplItemRef]) {
+fn lint_impl_body(cx: &LateContext<'_>, impl_span: Span, impl_items: &[hir::ImplItemRef]) {
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{Expr, ImplItemKind};
diff --git a/src/tools/clippy/clippy_lints/src/format.rs b/src/tools/clippy/clippy_lints/src/format.rs
index bc0c68f53..d0fab6949 100644
--- a/src/tools/clippy/clippy_lints/src/format.rs
+++ b/src/tools/clippy/clippy_lints/src/format.rs
@@ -73,7 +73,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat {
if format_args.format_string.parts == [kw::Empty];
if arg.format.is_default();
if match cx.typeck_results().expr_ty(value).peel_refs().kind() {
- ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(sym::String, adt.did()),
+ ty::Adt(adt, _) => Some(adt.did()) == cx.tcx.lang_items().string(),
ty::Str => true,
_ => false,
};
diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs
index f0fe845d3..658fe2680 100644
--- a/src/tools/clippy/clippy_lints/src/format_args.rs
+++ b/src/tools/clippy/clippy_lints/src/format_args.rs
@@ -1,19 +1,22 @@
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
-use clippy_utils::macros::FormatParamKind::{Implicit, Named, Numbered, Starred};
+use clippy_utils::is_diag_trait_item;
+use clippy_utils::macros::FormatParamKind::{Implicit, Named, NamedInline, Numbered, Starred};
use clippy_utils::macros::{
is_format_macro, is_panic, root_macro_call, Count, FormatArg, FormatArgsExpn, FormatParam, FormatParamUsage,
};
+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::{is_diag_trait_item, meets_msrv, msrvs};
use if_chain::if_chain;
use itertools::Itertools;
-use rustc_errors::Applicability;
+use rustc_errors::{
+ Applicability,
+ SuggestionStyle::{CompletelyHidden, ShowCode},
+};
use rustc_hir::{Expr, ExprKind, HirId, QPath};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::ty::adjustment::{Adjust, Adjustment};
use rustc_middle::ty::Ty;
-use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::def_id::DefId;
use rustc_span::edition::Edition::Edition2021;
@@ -103,14 +106,20 @@ declare_clippy_lint! {
/// format!("{var:.prec$}");
/// ```
///
- /// ### Known Problems
- ///
- /// There may be a false positive if the format string is expanded from certain proc macros:
- ///
- /// ```ignore
- /// println!(indoc!("{}"), var);
+ /// If allow-mixed-uninlined-format-args is set to false in clippy.toml,
+ /// the following code will also trigger the lint:
+ /// ```rust
+ /// # let var = 42;
+ /// format!("{} {}", var, 1+2);
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// # let var = 42;
+ /// format!("{var} {}", 1+2);
/// ```
///
+ /// ### Known Problems
+ ///
/// If a format string contains a numbered argument that cannot be inlined
/// nothing will be suggested, e.g. `println!("{0}={1}", var, 1+2)`.
#[clippy::version = "1.65.0"]
@@ -158,13 +167,17 @@ impl_lint_pass!(FormatArgs => [
]);
pub struct FormatArgs {
- msrv: Option<RustcVersion>,
+ msrv: Msrv,
+ ignore_mixed: bool,
}
impl FormatArgs {
#[must_use]
- pub fn new(msrv: Option<RustcVersion>) -> Self {
- Self { msrv }
+ pub fn new(msrv: Msrv, allow_mixed_uninlined_format_args: bool) -> Self {
+ Self {
+ msrv,
+ ignore_mixed: allow_mixed_uninlined_format_args,
+ }
}
}
@@ -188,8 +201,8 @@ impl<'tcx> LateLintPass<'tcx> for FormatArgs {
check_format_in_format_args(cx, outermost_expn_data.call_site, name, arg.param.value);
check_to_string_in_format_args(cx, name, arg.param.value);
}
- if meets_msrv(self.msrv, msrvs::FORMAT_ARGS_CAPTURE) {
- check_uninlined_args(cx, &format_args, outermost_expn_data.call_site, macro_def_id);
+ if self.msrv.meets(msrvs::FORMAT_ARGS_CAPTURE) {
+ check_uninlined_args(cx, &format_args, outermost_expn_data.call_site, macro_def_id, self.ignore_mixed);
}
}
}
@@ -267,7 +280,13 @@ fn check_unused_format_specifier(cx: &LateContext<'_>, arg: &FormatArg<'_>) {
}
}
-fn check_uninlined_args(cx: &LateContext<'_>, args: &FormatArgsExpn<'_>, call_site: Span, def_id: DefId) {
+fn check_uninlined_args(
+ cx: &LateContext<'_>,
+ args: &FormatArgsExpn<'_>,
+ call_site: Span,
+ def_id: DefId,
+ ignore_mixed: bool,
+) {
if args.format_string.span.from_expansion() {
return;
}
@@ -282,14 +301,13 @@ fn check_uninlined_args(cx: &LateContext<'_>, args: &FormatArgsExpn<'_>, call_si
// we cannot remove any other arguments in the format string,
// because the index numbers might be wrong after inlining.
// Example of an un-inlinable format: print!("{}{1}", foo, 2)
- if !args.params().all(|p| check_one_arg(args, &p, &mut fixes)) || fixes.is_empty() {
+ if !args.params().all(|p| check_one_arg(args, &p, &mut fixes, ignore_mixed)) || fixes.is_empty() {
return;
}
- // Temporarily ignore multiline spans: https://github.com/rust-lang/rust/pull/102729#discussion_r988704308
- if fixes.iter().any(|(span, _)| cx.sess().source_map().is_multiline(*span)) {
- return;
- }
+ // multiline span display suggestion is sometimes broken: https://github.com/rust-lang/rust/pull/102729#discussion_r988704308
+ // in those cases, make the code suggestion hidden
+ let multiline_fix = fixes.iter().any(|(span, _)| cx.sess().source_map().is_multiline(*span));
span_lint_and_then(
cx,
@@ -297,12 +315,22 @@ fn check_uninlined_args(cx: &LateContext<'_>, args: &FormatArgsExpn<'_>, call_si
call_site,
"variables can be used directly in the `format!` string",
|diag| {
- diag.multipart_suggestion("change this to", fixes, Applicability::MachineApplicable);
+ diag.multipart_suggestion_with_style(
+ "change this to",
+ fixes,
+ Applicability::MachineApplicable,
+ if multiline_fix { CompletelyHidden } else { ShowCode },
+ );
},
);
}
-fn check_one_arg(args: &FormatArgsExpn<'_>, param: &FormatParam<'_>, fixes: &mut Vec<(Span, String)>) -> bool {
+fn check_one_arg(
+ args: &FormatArgsExpn<'_>,
+ param: &FormatParam<'_>,
+ fixes: &mut Vec<(Span, String)>,
+ ignore_mixed: bool,
+) -> bool {
if matches!(param.kind, Implicit | Starred | Named(_) | Numbered)
&& let ExprKind::Path(QPath::Resolved(None, path)) = param.value.kind
&& let [segment] = path.segments
@@ -317,8 +345,10 @@ fn check_one_arg(args: &FormatArgsExpn<'_>, param: &FormatParam<'_>, fixes: &mut
fixes.push((arg_span, String::new()));
true // successful inlining, continue checking
} else {
- // if we can't inline a numbered argument, we can't continue
- param.kind != Numbered
+ // Do not continue inlining (return false) in case
+ // * if we can't inline a numbered argument, e.g. `print!("{0} ...", foo.bar, ...)`
+ // * if allow_mixed_uninlined_format_args is false and this arg hasn't been inlined already
+ param.kind != Numbered && (!ignore_mixed || matches!(param.kind, NamedInline(_)))
}
}
diff --git a/src/tools/clippy/clippy_lints/src/format_push_string.rs b/src/tools/clippy/clippy_lints/src/format_push_string.rs
index 9b9f1872b..68c5c3673 100644
--- a/src/tools/clippy/clippy_lints/src/format_push_string.rs
+++ b/src/tools/clippy/clippy_lints/src/format_push_string.rs
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::ty::is_type_lang_item;
use clippy_utils::{match_def_path, paths, peel_hir_expr_refs};
-use rustc_hir::{BinOpKind, Expr, ExprKind};
+use rustc_hir::{BinOpKind, Expr, ExprKind, LangItem};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::sym;
@@ -41,7 +41,7 @@ declare_clippy_lint! {
declare_lint_pass!(FormatPushString => [FORMAT_PUSH_STRING]);
fn is_string(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
- is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(e).peel_refs(), sym::String)
+ is_type_lang_item(cx, cx.typeck_results().expr_ty(e).peel_refs(), LangItem::String)
}
fn is_format(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
if let Some(macro_def_id) = e.span.ctxt().outer_expn_data().macro_def_id {
diff --git a/src/tools/clippy/clippy_lints/src/from_over_into.rs b/src/tools/clippy/clippy_lints/src/from_over_into.rs
index 8b24a4962..0634b2798 100644
--- a/src/tools/clippy/clippy_lints/src/from_over_into.rs
+++ b/src/tools/clippy/clippy_lints/src/from_over_into.rs
@@ -1,7 +1,8 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::macros::span_is_local;
+use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::path_def_id;
use clippy_utils::source::snippet_opt;
-use clippy_utils::{meets_msrv, msrvs, path_def_id};
use rustc_errors::Applicability;
use rustc_hir::intravisit::{walk_path, Visitor};
use rustc_hir::{
@@ -10,7 +11,6 @@ use rustc_hir::{
};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter::OnlyBodies;
-use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::symbol::{kw, sym};
use rustc_span::{Span, Symbol};
@@ -49,12 +49,12 @@ declare_clippy_lint! {
}
pub struct FromOverInto {
- msrv: Option<RustcVersion>,
+ msrv: Msrv,
}
impl FromOverInto {
#[must_use]
- pub fn new(msrv: Option<RustcVersion>) -> Self {
+ pub fn new(msrv: Msrv) -> Self {
FromOverInto { msrv }
}
}
@@ -63,7 +63,7 @@ impl_lint_pass!(FromOverInto => [FROM_OVER_INTO]);
impl<'tcx> LateLintPass<'tcx> for FromOverInto {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
- if !meets_msrv(self.msrv, msrvs::RE_REBALANCING_COHERENCE) || !span_is_local(item.span) {
+ if !self.msrv.meets(msrvs::RE_REBALANCING_COHERENCE) || !span_is_local(item.span) {
return;
}
@@ -126,7 +126,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SelfFinder<'a, 'tcx> {
self.cx.tcx.hir()
}
- fn visit_path(&mut self, path: &'tcx Path<'tcx>, _id: HirId) {
+ fn visit_path(&mut self, path: &Path<'tcx>, _id: HirId) {
for segment in path.segments {
match segment.ident.name {
kw::SelfLower => self.lower.push(segment.ident.span),
diff --git a/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs b/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs
new file mode 100644
index 000000000..00f5ba564
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs
@@ -0,0 +1,77 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::ty::is_c_void;
+use clippy_utils::{match_def_path, path_def_id, paths};
+use rustc_hir::def_id::DefId;
+use rustc_hir::{Expr, ExprKind, QPath};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::RawPtr;
+use rustc_middle::ty::TypeAndMut;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks if we're passing a `c_void` raw pointer to `{Box,Rc,Arc,Weak}::from_raw(_)`
+ ///
+ /// ### Why is this bad?
+ /// When dealing with `c_void` raw pointers in FFI, it is easy to run into the pitfall of calling `from_raw` with the `c_void` pointer.
+ /// The type signature of `Box::from_raw` is `fn from_raw(raw: *mut T) -> Box<T>`, so if you pass a `*mut c_void` you will get a `Box<c_void>` (and similarly for `Rc`, `Arc` and `Weak`).
+ /// For this to be safe, `c_void` would need to have the same memory layout as the original type, which is often not the case.
+ ///
+ /// ### Example
+ /// ```rust
+ /// # use std::ffi::c_void;
+ /// let ptr = Box::into_raw(Box::new(42usize)) as *mut c_void;
+ /// let _ = unsafe { Box::from_raw(ptr) };
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// # use std::ffi::c_void;
+ /// # let ptr = Box::into_raw(Box::new(42usize)) as *mut c_void;
+ /// let _ = unsafe { Box::from_raw(ptr as *mut usize) };
+ /// ```
+ ///
+ #[clippy::version = "1.66.0"]
+ pub FROM_RAW_WITH_VOID_PTR,
+ suspicious,
+ "creating a `Box` from a void raw pointer"
+}
+declare_lint_pass!(FromRawWithVoidPtr => [FROM_RAW_WITH_VOID_PTR]);
+
+impl LateLintPass<'_> for FromRawWithVoidPtr {
+ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+ if let ExprKind::Call(box_from_raw, [arg]) = expr.kind
+ && let ExprKind::Path(QPath::TypeRelative(ty, seg)) = box_from_raw.kind
+ && seg.ident.name == sym!(from_raw)
+ && let Some(type_str) = path_def_id(cx, ty).and_then(|id| def_id_matches_type(cx, id))
+ && let arg_kind = cx.typeck_results().expr_ty(arg).kind()
+ && let RawPtr(TypeAndMut { ty, .. }) = arg_kind
+ && is_c_void(cx, *ty) {
+ let msg = format!("creating a `{type_str}` from a void raw pointer");
+ span_lint_and_help(cx, FROM_RAW_WITH_VOID_PTR, expr.span, &msg, Some(arg.span), "cast this to a pointer of the appropriate type");
+ }
+ }
+}
+
+/// Checks whether a `DefId` matches `Box`, `Rc`, `Arc`, or one of the `Weak` types.
+/// Returns a static string slice with the name of the type, if one was found.
+fn def_id_matches_type(cx: &LateContext<'_>, def_id: DefId) -> Option<&'static str> {
+ // Box
+ if Some(def_id) == cx.tcx.lang_items().owned_box() {
+ return Some("Box");
+ }
+
+ if let Some(symbol) = cx.tcx.get_diagnostic_name(def_id) {
+ if symbol == sym::Arc {
+ return Some("Arc");
+ } else if symbol == sym::Rc {
+ return Some("Rc");
+ }
+ }
+
+ if match_def_path(cx, def_id, &paths::WEAK_RC) || match_def_path(cx, def_id, &paths::WEAK_ARC) {
+ Some("Weak")
+ } else {
+ None
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs b/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs
index cf8b7acd6..74a60b6a0 100644
--- a/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs
+++ b/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs
@@ -1,10 +1,10 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::is_integer_literal;
use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
use if_chain::if_chain;
use rustc_errors::Applicability;
-use rustc_hir::{def, Expr, ExprKind, PrimTy, QPath, TyKind};
+use rustc_hir::{def, Expr, ExprKind, LangItem, PrimTy, QPath, TyKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::Ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -98,5 +98,5 @@ impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 {
/// Checks if a Ty is `String` or `&str`
fn is_ty_stringish(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
- is_type_diagnostic_item(cx, ty, sym::String) || is_type_diagnostic_item(cx, ty, sym::str)
+ is_type_lang_item(cx, ty, LangItem::String) || is_type_diagnostic_item(cx, ty, sym::str)
}
diff --git a/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs b/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs
new file mode 100644
index 000000000..27acad45c
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs
@@ -0,0 +1,125 @@
+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_lint::LateContext;
+use rustc_middle::ty;
+use rustc_span::Span;
+
+use std::iter;
+
+use super::MISNAMED_GETTERS;
+
+pub fn check_fn(
+ cx: &LateContext<'_>,
+ kind: FnKind<'_>,
+ decl: &FnDecl<'_>,
+ body: &Body<'_>,
+ span: Span,
+ _hir_id: HirId,
+) {
+ let FnKind::Method(ref ident, sig) = kind else {
+ return;
+ };
+
+ // Takes only &(mut) self
+ if decl.inputs.len() != 1 {
+ return;
+ }
+
+ let name = ident.name.as_str();
+
+ let name = match decl.implicit_self {
+ ImplicitSelfKind::MutRef => {
+ let Some(name) = name.strip_suffix("_mut") else {
+ return;
+ };
+ name
+ },
+ ImplicitSelfKind::Imm | ImplicitSelfKind::Mut | ImplicitSelfKind::ImmRef => name,
+ ImplicitSelfKind::None => return,
+ };
+
+ let name = if sig.header.unsafety == Unsafety::Unsafe {
+ name.strip_suffix("_unchecked").unwrap_or(name)
+ } else {
+ name
+ };
+
+ // Body must be &(mut) <self_data>.name
+ // self_data is not neccessarilly self, to also lint sub-getters, etc…
+
+ let block_expr = if_chain! {
+ if let ExprKind::Block(block,_) = body.value.kind;
+ if block.stmts.is_empty();
+ if let Some(block_expr) = block.expr;
+ then {
+ block_expr
+ } else {
+ return;
+ }
+ };
+ let expr_span = block_expr.span;
+
+ // Accept &<expr>, &mut <expr> and <expr>
+ let expr = if let ExprKind::AddrOf(_, _, tmp) = block_expr.kind {
+ tmp
+ } else {
+ block_expr
+ };
+ let (self_data, used_ident) = if_chain! {
+ if let ExprKind::Field(self_data, ident) = expr.kind;
+ if ident.name.as_str() != name;
+ then {
+ (self_data, ident)
+ } else {
+ return;
+ }
+ };
+
+ let mut used_field = None;
+ let mut correct_field = None;
+ let typeck_results = cx.typeck_results();
+ for adjusted_type in iter::once(typeck_results.expr_ty(self_data))
+ .chain(typeck_results.expr_adjustments(self_data).iter().map(|adj| adj.target))
+ {
+ let ty::Adt(def,_) = adjusted_type.kind() else {
+ continue;
+ };
+
+ for f in def.all_fields() {
+ if f.name.as_str() == name {
+ correct_field = Some(f);
+ }
+ if f.name == used_ident.name {
+ used_field = Some(f);
+ }
+ }
+ }
+
+ let Some(used_field) = used_field else {
+ // Can happen if the field access is a tuple. We don't lint those because the getter name could not start with a number.
+ return;
+ };
+
+ let Some(correct_field) = correct_field else {
+ // There is no field corresponding to the getter name.
+ // FIXME: This can be a false positive if the correct field is reachable trought deeper autodereferences than used_field is
+ return;
+ };
+
+ if cx.tcx.type_of(used_field.did) == cx.tcx.type_of(correct_field.did) {
+ let left_span = block_expr.span.until(used_ident.span);
+ let snippet = snippet(cx, left_span, "..");
+ let sugg = format!("{snippet}{name}");
+ span_lint_and_then(
+ cx,
+ MISNAMED_GETTERS,
+ span,
+ "getter function appears to return the wrong field",
+ |diag| {
+ diag.span_suggestion(expr_span, "consider using", sugg, Applicability::MaybeIncorrect);
+ },
+ );
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/functions/mod.rs b/src/tools/clippy/clippy_lints/src/functions/mod.rs
index 90911e0bf..91e6ffe64 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 misnamed_getters;
mod must_use;
mod not_unsafe_ptr_arg_deref;
mod result;
@@ -254,12 +255,54 @@ declare_clippy_lint! {
/// Ok(())
/// }
/// ```
- #[clippy::version = "1.64.0"]
+ #[clippy::version = "1.65.0"]
pub RESULT_LARGE_ERR,
perf,
"function returning `Result` with large `Err` type"
}
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for getter methods that return a field that doesn't correspond
+ /// to the name of the method, when there is a field's whose name matches that of the method.
+ ///
+ /// ### Why is this bad?
+ /// It is most likely that such a method is a bug caused by a typo or by copy-pasting.
+ ///
+ /// ### Example
+
+ /// ```rust
+ /// struct A {
+ /// a: String,
+ /// b: String,
+ /// }
+ ///
+ /// impl A {
+ /// fn a(&self) -> &str{
+ /// &self.b
+ /// }
+ /// }
+
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// struct A {
+ /// a: String,
+ /// b: String,
+ /// }
+ ///
+ /// impl A {
+ /// fn a(&self) -> &str{
+ /// &self.a
+ /// }
+ /// }
+ /// ```
+ #[clippy::version = "1.67.0"]
+ pub MISNAMED_GETTERS,
+ suspicious,
+ "getter method returning the wrong field"
+}
+
#[derive(Copy, Clone)]
pub struct Functions {
too_many_arguments_threshold: u64,
@@ -286,6 +329,7 @@ impl_lint_pass!(Functions => [
MUST_USE_CANDIDATE,
RESULT_UNIT_ERR,
RESULT_LARGE_ERR,
+ MISNAMED_GETTERS,
]);
impl<'tcx> LateLintPass<'tcx> for Functions {
@@ -301,6 +345,7 @@ impl<'tcx> LateLintPass<'tcx> for Functions {
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);
}
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 bff69f915..d22bede36 100644
--- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
@@ -50,7 +50,9 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp
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);
- } else if is_public && !is_proc_macro(cx.sess(), attrs) && trait_ref_of_method(cx, item.owner_id.def_id).is_none()
+ } else if is_public
+ && !is_proc_macro(cx.sess(), attrs)
+ && trait_ref_of_method(cx, item.owner_id.def_id).is_none()
{
check_must_use_candidate(
cx,
@@ -175,7 +177,7 @@ fn is_mutable_pat(cx: &LateContext<'_>, pat: &hir::Pat<'_>, tys: &mut DefIdSet)
return false; // ignore `_` patterns
}
if cx.tcx.has_typeck_results(pat.hir_id.owner.to_def_id()) {
- is_mutable_ty(cx, cx.tcx.typeck(pat.hir_id.owner.def_id).pat_ty(pat), pat.span, tys)
+ is_mutable_ty(cx, cx.tcx.typeck(pat.hir_id.owner.def_id).pat_ty(pat), tys)
} else {
false
}
@@ -183,7 +185,7 @@ fn is_mutable_pat(cx: &LateContext<'_>, pat: &hir::Pat<'_>, tys: &mut DefIdSet)
static KNOWN_WRAPPER_TYS: &[Symbol] = &[sym::Rc, sym::Arc];
-fn is_mutable_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Span, tys: &mut DefIdSet) -> bool {
+fn is_mutable_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, tys: &mut DefIdSet) -> bool {
match *ty.kind() {
// primitive types are never mutable
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => false,
@@ -192,12 +194,12 @@ fn is_mutable_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Span, tys: &m
|| KNOWN_WRAPPER_TYS
.iter()
.any(|&sym| cx.tcx.is_diagnostic_item(sym, adt.did()))
- && substs.types().any(|ty| is_mutable_ty(cx, ty, span, tys))
+ && substs.types().any(|ty| is_mutable_ty(cx, ty, tys))
},
- ty::Tuple(substs) => substs.iter().any(|ty| is_mutable_ty(cx, ty, span, tys)),
- ty::Array(ty, _) | ty::Slice(ty) => is_mutable_ty(cx, ty, span, tys),
+ ty::Tuple(substs) => substs.iter().any(|ty| is_mutable_ty(cx, ty, tys)),
+ ty::Array(ty, _) | ty::Slice(ty) => is_mutable_ty(cx, ty, tys),
ty::RawPtr(ty::TypeAndMut { ty, mutbl }) | ty::Ref(_, ty, mutbl) => {
- mutbl == hir::Mutability::Mut || is_mutable_ty(cx, ty, span, tys)
+ mutbl == hir::Mutability::Mut || is_mutable_ty(cx, ty, tys)
},
// calling something constitutes a side effect, so return true on all callables
// also never calls need not be used, so return true for them, too
@@ -225,12 +227,7 @@ fn mutates_static<'tcx>(cx: &LateContext<'tcx>, body: &'tcx hir::Body<'_>) -> bo
let mut tys = DefIdSet::default();
for arg in args {
if cx.tcx.has_typeck_results(arg.hir_id.owner.to_def_id())
- && is_mutable_ty(
- cx,
- cx.tcx.typeck(arg.hir_id.owner.def_id).expr_ty(arg),
- arg.span,
- &mut tys,
- )
+ && is_mutable_ty(cx, cx.tcx.typeck(arg.hir_id.owner.def_id).expr_ty(arg), &mut tys)
&& is_mutated_static(arg)
{
return ControlFlow::Break(());
@@ -243,12 +240,7 @@ fn mutates_static<'tcx>(cx: &LateContext<'tcx>, body: &'tcx hir::Body<'_>) -> bo
let mut tys = DefIdSet::default();
for arg in std::iter::once(receiver).chain(args.iter()) {
if cx.tcx.has_typeck_results(arg.hir_id.owner.to_def_id())
- && is_mutable_ty(
- cx,
- cx.tcx.typeck(arg.hir_id.owner.def_id).expr_ty(arg),
- arg.span,
- &mut tys,
- )
+ && is_mutable_ty(cx, cx.tcx.typeck(arg.hir_id.owner.def_id).expr_ty(arg), &mut tys)
&& is_mutated_static(arg)
{
return ControlFlow::Break(());
diff --git a/src/tools/clippy/clippy_lints/src/functions/result.rs b/src/tools/clippy/clippy_lints/src/functions/result.rs
index 5c63fb2ac..23da145d0 100644
--- a/src/tools/clippy/clippy_lints/src/functions/result.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/result.rs
@@ -2,12 +2,12 @@ use rustc_errors::Diagnostic;
use rustc_hir as hir;
use rustc_lint::{LateContext, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{self, Adt, Ty};
use rustc_span::{sym, Span};
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then};
use clippy_utils::trait_ref_of_method;
-use clippy_utils::ty::{approx_ty_size, is_type_diagnostic_item};
+use clippy_utils::ty::{approx_ty_size, is_type_diagnostic_item, AdtVariantInfo};
use super::{RESULT_LARGE_ERR, RESULT_UNIT_ERR};
@@ -84,17 +84,59 @@ fn check_result_unit_err(cx: &LateContext<'_>, err_ty: Ty<'_>, fn_header_span: S
}
fn check_result_large_err<'tcx>(cx: &LateContext<'tcx>, err_ty: Ty<'tcx>, hir_ty_span: Span, large_err_threshold: u64) {
- let ty_size = approx_ty_size(cx, err_ty);
- if ty_size >= large_err_threshold {
- span_lint_and_then(
- cx,
- RESULT_LARGE_ERR,
- hir_ty_span,
- "the `Err`-variant returned from this function is very large",
- |diag: &mut Diagnostic| {
- diag.span_label(hir_ty_span, format!("the `Err`-variant is at least {ty_size} bytes"));
- diag.help(format!("try reducing the size of `{err_ty}`, for example by boxing large elements or replacing it with `Box<{err_ty}>`"));
- },
- );
+ if_chain! {
+ if let Adt(adt, subst) = err_ty.kind();
+ if let Some(local_def_id) = err_ty.ty_adt_def().expect("already checked this is adt").did().as_local();
+ if let Some(hir::Node::Item(item)) = cx
+ .tcx
+ .hir()
+ .find_by_def_id(local_def_id);
+ if let hir::ItemKind::Enum(ref def, _) = item.kind;
+ then {
+ let variants_size = AdtVariantInfo::new(cx, *adt, subst);
+ if let Some((first_variant, variants)) = variants_size.split_first()
+ && first_variant.size >= large_err_threshold
+ {
+ span_lint_and_then(
+ cx,
+ RESULT_LARGE_ERR,
+ hir_ty_span,
+ "the `Err`-variant returned from this function is very large",
+ |diag| {
+ diag.span_label(
+ def.variants[first_variant.ind].span,
+ format!("the largest variant contains at least {} bytes", variants_size[0].size),
+ );
+
+ for variant in variants {
+ if variant.size >= large_err_threshold {
+ let variant_def = &def.variants[variant.ind];
+ diag.span_label(
+ variant_def.span,
+ format!("the variant `{}` contains at least {} bytes", variant_def.ident, variant.size),
+ );
+ }
+ }
+
+ diag.help(format!("try reducing the size of `{err_ty}`, for example by boxing large elements or replacing it with `Box<{err_ty}>`"));
+ }
+ );
+ }
+ }
+ else {
+ let ty_size = approx_ty_size(cx, err_ty);
+ if ty_size >= large_err_threshold {
+ span_lint_and_then(
+ cx,
+ RESULT_LARGE_ERR,
+ hir_ty_span,
+ "the `Err`-variant returned from this function is very large",
+ |diag: &mut Diagnostic| {
+ diag.span_label(hir_ty_span, format!("the `Err`-variant is at least {ty_size} bytes"));
+ diag.help(format!("try reducing the size of `{err_ty}`, for example by boxing large elements or replacing it with `Box<{err_ty}>`"));
+ },
+ );
+ }
+ }
}
}
diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs
index 0519f9ac2..61934a914 100644
--- a/src/tools/clippy/clippy_lints/src/future_not_send.rs
+++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs
@@ -4,7 +4,7 @@ use rustc_hir::intravisit::FnKind;
use rustc_hir::{Body, FnDecl, HirId};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::{EarlyBinder, Opaque, PredicateKind::Trait};
+use rustc_middle::ty::{Clause, EarlyBinder, Opaque, PredicateKind};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::{sym, Span};
use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt;
@@ -91,7 +91,9 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend {
infcx
.err_ctxt()
.maybe_note_obligation_cause_for_async_await(db, &obligation);
- if let Trait(trait_pred) = obligation.predicate.kind().skip_binder() {
+ if let PredicateKind::Clause(Clause::Trait(trait_pred)) =
+ obligation.predicate.kind().skip_binder()
+ {
db.note(&format!(
"`{}` doesn't implement `{}`",
trait_pred.self_ty(),
diff --git a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
index 0d6718c16..9cadaaa49 100644
--- a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
+++ b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
@@ -1,14 +1,12 @@
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::eager_or_lazy::switch_to_eager_eval;
+use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_macro_callsite;
-use clippy_utils::{
- contains_return, higher, is_else_clause, is_res_lang_ctor, meets_msrv, msrvs, path_res, peel_blocks,
-};
+use clippy_utils::{contains_return, higher, is_else_clause, is_res_lang_ctor, path_res, peel_blocks};
use rustc_hir::LangItem::{OptionNone, OptionSome};
use rustc_hir::{Expr, ExprKind, Stmt, StmtKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass};
declare_clippy_lint! {
@@ -47,12 +45,12 @@ declare_clippy_lint! {
}
pub struct IfThenSomeElseNone {
- msrv: Option<RustcVersion>,
+ msrv: Msrv,
}
impl IfThenSomeElseNone {
#[must_use]
- pub fn new(msrv: Option<RustcVersion>) -> Self {
+ pub fn new(msrv: Msrv) -> Self {
Self { msrv }
}
}
@@ -61,7 +59,7 @@ impl_lint_pass!(IfThenSomeElseNone => [IF_THEN_SOME_ELSE_NONE]);
impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
- if !meets_msrv(self.msrv, msrvs::BOOL_THEN) {
+ if !self.msrv.meets(msrvs::BOOL_THEN) {
return;
}
@@ -94,7 +92,7 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone {
} else {
format!("{{ /* snippet */ {arg_snip} }}")
};
- let method_name = if switch_to_eager_eval(cx, expr) && meets_msrv(self.msrv, msrvs::BOOL_THEN_SOME) {
+ let method_name = if switch_to_eager_eval(cx, expr) && self.msrv.meets(msrvs::BOOL_THEN_SOME) {
"then_some"
} else {
method_body.insert_str(0, "|| ");
diff --git a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
index 94e06cf70..64a4a3fa7 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
@@ -66,8 +66,8 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
use rustc_span::BytePos;
- fn suggestion<'tcx>(
- cx: &LateContext<'tcx>,
+ fn suggestion(
+ cx: &LateContext<'_>,
diag: &mut Diagnostic,
generics_span: Span,
generics_suggestion_span: Span,
diff --git a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
index c7b5badaa..cf35b1f17 100644
--- a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
+++ b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
@@ -1,8 +1,9 @@
use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::higher::IfLet;
+use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::ty::is_copy;
-use clippy_utils::{is_expn_of, is_lint_allowed, meets_msrv, msrvs, path_to_local};
+use clippy_utils::{is_expn_of, is_lint_allowed, path_to_local};
use if_chain::if_chain;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
use rustc_errors::Applicability;
@@ -11,7 +12,6 @@ use rustc_hir::intravisit::{self, Visitor};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter;
use rustc_middle::ty;
-use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{symbol::Ident, Span};
@@ -47,18 +47,17 @@ declare_clippy_lint! {
/// ```
#[clippy::version = "1.59.0"]
pub INDEX_REFUTABLE_SLICE,
- nursery,
+ pedantic,
"avoid indexing on slices which could be destructed"
}
-#[derive(Copy, Clone)]
pub struct IndexRefutableSlice {
max_suggested_slice: u64,
- msrv: Option<RustcVersion>,
+ msrv: Msrv,
}
impl IndexRefutableSlice {
- pub fn new(max_suggested_slice_pattern_length: u64, msrv: Option<RustcVersion>) -> Self {
+ pub fn new(max_suggested_slice_pattern_length: u64, msrv: Msrv) -> Self {
Self {
max_suggested_slice: max_suggested_slice_pattern_length,
msrv,
@@ -74,7 +73,7 @@ impl<'tcx> LateLintPass<'tcx> for IndexRefutableSlice {
if !expr.span.from_expansion() || is_expn_of(expr.span, "if_chain").is_some();
if let Some(IfLet {let_pat, if_then, ..}) = IfLet::hir(cx, expr);
if !is_lint_allowed(cx, INDEX_REFUTABLE_SLICE, expr.hir_id);
- if meets_msrv(self.msrv, msrvs::SLICE_PATTERNS);
+ if self.msrv.meets(msrvs::SLICE_PATTERNS);
let found_slices = find_slice_values(cx, let_pat);
if !found_slices.is_empty();
@@ -207,8 +206,8 @@ impl SliceLintInformation {
}
}
-fn filter_lintable_slices<'a, 'tcx>(
- cx: &'a LateContext<'tcx>,
+fn filter_lintable_slices<'tcx>(
+ cx: &LateContext<'tcx>,
slice_lint_info: FxIndexMap<hir::HirId, SliceLintInformation>,
max_suggested_slice: u64,
scope: &'tcx hir::Expr<'tcx>,
diff --git a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
index af40a5a81..4cd7dff4c 100644
--- a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
+++ b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
@@ -171,11 +171,7 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
/// Returns a tuple of options with the start and end (exclusive) values of
/// the range. If the start or end is not constant, None is returned.
-fn to_const_range<'tcx>(
- cx: &LateContext<'tcx>,
- range: higher::Range<'_>,
- array_size: u128,
-) -> (Option<u128>, Option<u128>) {
+fn to_const_range(cx: &LateContext<'_>, range: higher::Range<'_>, array_size: u128) -> (Option<u128>, Option<u128>) {
let s = range
.start
.map(|expr| constant(cx, cx.typeck_results(), expr).map(|(c, _)| c));
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 14a37f535..aaecc4fa8 100644
--- a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
+++ b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
@@ -1,8 +1,8 @@
use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
+use clippy_utils::ty::{implements_trait, is_type_lang_item};
use clippy_utils::{return_ty, trait_ref_of_method};
use if_chain::if_chain;
-use rustc_hir::{GenericParamKind, ImplItem, ImplItemKind};
+use rustc_hir::{GenericParamKind, ImplItem, ImplItemKind, LangItem};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::sym;
@@ -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_diagnostic_item(cx, return_ty(cx, impl_item.hir_id()), sym::String);
+ if is_type_lang_item(cx, return_ty(cx, impl_item.hir_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();
diff --git a/src/tools/clippy/clippy_lints/src/instant_subtraction.rs b/src/tools/clippy/clippy_lints/src/instant_subtraction.rs
new file mode 100644
index 000000000..dd1b23e7d
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/instant_subtraction.rs
@@ -0,0 +1,182 @@
+use clippy_utils::diagnostics::{self, span_lint_and_sugg};
+use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::source;
+use clippy_utils::sugg::Sugg;
+use clippy_utils::ty;
+use rustc_errors::Applicability;
+use rustc_hir::{BinOpKind, Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::{source_map::Spanned, sym};
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Lints subtraction between `Instant::now()` and another `Instant`.
+ ///
+ /// ### Why is this bad?
+ /// It is easy to accidentally write `prev_instant - Instant::now()`, which will always be 0ns
+ /// as `Instant` subtraction saturates.
+ ///
+ /// `prev_instant.elapsed()` also more clearly signals intention.
+ ///
+ /// ### Example
+ /// ```rust
+ /// use std::time::Instant;
+ /// let prev_instant = Instant::now();
+ /// let duration = Instant::now() - prev_instant;
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// use std::time::Instant;
+ /// let prev_instant = Instant::now();
+ /// let duration = prev_instant.elapsed();
+ /// ```
+ #[clippy::version = "1.65.0"]
+ pub MANUAL_INSTANT_ELAPSED,
+ pedantic,
+ "subtraction between `Instant::now()` and previous `Instant`"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Lints subtraction between an [`Instant`] and a [`Duration`].
+ ///
+ /// ### Why is this bad?
+ /// Unchecked subtraction could cause underflow on certain platforms, leading to
+ /// unintentional panics.
+ ///
+ /// ### Example
+ /// ```rust
+ /// # use std::time::{Instant, Duration};
+ /// let time_passed = Instant::now() - Duration::from_secs(5);
+ /// ```
+ ///
+ /// Use instead:
+ /// ```rust
+ /// # use std::time::{Instant, Duration};
+ /// let time_passed = Instant::now().checked_sub(Duration::from_secs(5));
+ /// ```
+ ///
+ /// [`Duration`]: std::time::Duration
+ /// [`Instant::now()`]: std::time::Instant::now;
+ #[clippy::version = "1.65.0"]
+ pub UNCHECKED_DURATION_SUBTRACTION,
+ suspicious,
+ "finds unchecked subtraction of a 'Duration' from an 'Instant'"
+}
+
+pub struct InstantSubtraction {
+ msrv: Msrv,
+}
+
+impl InstantSubtraction {
+ #[must_use]
+ pub fn new(msrv: Msrv) -> Self {
+ Self { msrv }
+ }
+}
+
+impl_lint_pass!(InstantSubtraction => [MANUAL_INSTANT_ELAPSED, UNCHECKED_DURATION_SUBTRACTION]);
+
+impl LateLintPass<'_> for InstantSubtraction {
+ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
+ if let ExprKind::Binary(
+ Spanned {
+ node: BinOpKind::Sub, ..
+ },
+ lhs,
+ rhs,
+ ) = expr.kind
+ {
+ if_chain! {
+ if is_instant_now_call(cx, lhs);
+
+ if is_an_instant(cx, rhs);
+ if let Some(sugg) = Sugg::hir_opt(cx, rhs);
+
+ then {
+ print_manual_instant_elapsed_sugg(cx, expr, sugg)
+ } else {
+ if_chain! {
+ if !expr.span.from_expansion();
+ if self.msrv.meets(msrvs::TRY_FROM);
+
+ if is_an_instant(cx, lhs);
+ if is_a_duration(cx, rhs);
+
+ then {
+ print_unchecked_duration_subtraction_sugg(cx, lhs, rhs, expr)
+ }
+ }
+ }
+ }
+ }
+ }
+
+ extract_msrv_attr!(LateContext);
+}
+
+fn is_instant_now_call(cx: &LateContext<'_>, expr_block: &'_ Expr<'_>) -> bool {
+ if let ExprKind::Call(fn_expr, []) = expr_block.kind
+ && let Some(fn_id) = clippy_utils::path_def_id(cx, fn_expr)
+ && clippy_utils::match_def_path(cx, fn_id, &clippy_utils::paths::INSTANT_NOW)
+ {
+ true
+ } else {
+ false
+ }
+}
+
+fn is_an_instant(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+ let expr_ty = cx.typeck_results().expr_ty(expr);
+
+ match expr_ty.kind() {
+ rustc_middle::ty::Adt(def, _) => clippy_utils::match_def_path(cx, def.did(), &clippy_utils::paths::INSTANT),
+ _ => false,
+ }
+}
+
+fn is_a_duration(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+ let expr_ty = cx.typeck_results().expr_ty(expr);
+ ty::is_type_diagnostic_item(cx, expr_ty, sym::Duration)
+}
+
+fn print_manual_instant_elapsed_sugg(cx: &LateContext<'_>, expr: &Expr<'_>, sugg: Sugg<'_>) {
+ span_lint_and_sugg(
+ cx,
+ MANUAL_INSTANT_ELAPSED,
+ expr.span,
+ "manual implementation of `Instant::elapsed`",
+ "try",
+ format!("{}.elapsed()", sugg.maybe_par()),
+ Applicability::MachineApplicable,
+ );
+}
+
+fn print_unchecked_duration_subtraction_sugg(
+ cx: &LateContext<'_>,
+ left_expr: &Expr<'_>,
+ right_expr: &Expr<'_>,
+ expr: &Expr<'_>,
+) {
+ let mut applicability = Applicability::MachineApplicable;
+
+ let left_expr =
+ source::snippet_with_applicability(cx, left_expr.span, "std::time::Instant::now()", &mut applicability);
+ let right_expr = source::snippet_with_applicability(
+ cx,
+ right_expr.span,
+ "std::time::Duration::from_secs(1)",
+ &mut applicability,
+ );
+
+ diagnostics::span_lint_and_sugg(
+ cx,
+ UNCHECKED_DURATION_SUBTRACTION,
+ expr.span,
+ "unchecked subtraction of a 'Duration' from an 'Instant'",
+ "try",
+ format!("{left_expr}.checked_sub({right_expr}).unwrap()"),
+ applicability,
+ );
+}
diff --git a/src/tools/clippy/clippy_lints/src/int_plus_one.rs b/src/tools/clippy/clippy_lints/src/int_plus_one.rs
index 33491da3f..1b14e525d 100644
--- a/src/tools/clippy/clippy_lints/src/int_plus_one.rs
+++ b/src/tools/clippy/clippy_lints/src/int_plus_one.rs
@@ -2,7 +2,8 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_opt;
-use rustc_ast::ast::{BinOpKind, Expr, ExprKind, Lit, LitKind};
+use rustc_ast::ast::{BinOpKind, Expr, ExprKind, LitKind};
+use rustc_ast::token;
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -52,8 +53,8 @@ enum Side {
impl IntPlusOne {
#[expect(clippy::cast_sign_loss)]
- fn check_lit(lit: &Lit, target_value: i128) -> bool {
- if let LitKind::Int(value, ..) = lit.kind {
+ fn check_lit(token_lit: token::Lit, target_value: i128) -> bool {
+ if let Ok(LitKind::Int(value, ..)) = LitKind::from_token_lit(token_lit) {
return value == (target_value as u128);
}
false
@@ -62,58 +63,54 @@ impl IntPlusOne {
fn check_binop(cx: &EarlyContext<'_>, binop: BinOpKind, lhs: &Expr, rhs: &Expr) -> Option<String> {
match (binop, &lhs.kind, &rhs.kind) {
// case where `x - 1 >= ...` or `-1 + x >= ...`
- (BinOpKind::Ge, &ExprKind::Binary(ref lhskind, ref lhslhs, ref lhsrhs), _) => {
+ (BinOpKind::Ge, ExprKind::Binary(lhskind, lhslhs, lhsrhs), _) => {
match (lhskind.node, &lhslhs.kind, &lhsrhs.kind) {
// `-1 + x`
- (BinOpKind::Add, &ExprKind::Lit(ref lit), _) if Self::check_lit(lit, -1) => {
+ (BinOpKind::Add, ExprKind::Lit(lit), _) if Self::check_lit(*lit, -1) => {
Self::generate_recommendation(cx, binop, lhsrhs, rhs, Side::Lhs)
},
// `x - 1`
- (BinOpKind::Sub, _, &ExprKind::Lit(ref lit)) if Self::check_lit(lit, 1) => {
+ (BinOpKind::Sub, _, ExprKind::Lit(lit)) if Self::check_lit(*lit, 1) => {
Self::generate_recommendation(cx, binop, lhslhs, rhs, Side::Lhs)
},
_ => None,
}
},
// case where `... >= y + 1` or `... >= 1 + y`
- (BinOpKind::Ge, _, &ExprKind::Binary(ref rhskind, ref rhslhs, ref rhsrhs))
- if rhskind.node == BinOpKind::Add =>
- {
+ (BinOpKind::Ge, _, ExprKind::Binary(rhskind, rhslhs, rhsrhs)) if rhskind.node == BinOpKind::Add => {
match (&rhslhs.kind, &rhsrhs.kind) {
// `y + 1` and `1 + y`
- (&ExprKind::Lit(ref lit), _) if Self::check_lit(lit, 1) => {
+ (ExprKind::Lit(lit), _) if Self::check_lit(*lit, 1) => {
Self::generate_recommendation(cx, binop, rhsrhs, lhs, Side::Rhs)
},
- (_, &ExprKind::Lit(ref lit)) if Self::check_lit(lit, 1) => {
+ (_, ExprKind::Lit(lit)) if Self::check_lit(*lit, 1) => {
Self::generate_recommendation(cx, binop, rhslhs, lhs, Side::Rhs)
},
_ => None,
}
},
// case where `x + 1 <= ...` or `1 + x <= ...`
- (BinOpKind::Le, &ExprKind::Binary(ref lhskind, ref lhslhs, ref lhsrhs), _)
- if lhskind.node == BinOpKind::Add =>
- {
+ (BinOpKind::Le, ExprKind::Binary(lhskind, lhslhs, lhsrhs), _) if lhskind.node == BinOpKind::Add => {
match (&lhslhs.kind, &lhsrhs.kind) {
// `1 + x` and `x + 1`
- (&ExprKind::Lit(ref lit), _) if Self::check_lit(lit, 1) => {
+ (ExprKind::Lit(lit), _) if Self::check_lit(*lit, 1) => {
Self::generate_recommendation(cx, binop, lhsrhs, rhs, Side::Lhs)
},
- (_, &ExprKind::Lit(ref lit)) if Self::check_lit(lit, 1) => {
+ (_, ExprKind::Lit(lit)) if Self::check_lit(*lit, 1) => {
Self::generate_recommendation(cx, binop, lhslhs, rhs, Side::Lhs)
},
_ => None,
}
},
// case where `... >= y - 1` or `... >= -1 + y`
- (BinOpKind::Le, _, &ExprKind::Binary(ref rhskind, ref rhslhs, ref rhsrhs)) => {
+ (BinOpKind::Le, _, ExprKind::Binary(rhskind, rhslhs, rhsrhs)) => {
match (rhskind.node, &rhslhs.kind, &rhsrhs.kind) {
// `-1 + y`
- (BinOpKind::Add, &ExprKind::Lit(ref lit), _) if Self::check_lit(lit, -1) => {
+ (BinOpKind::Add, ExprKind::Lit(lit), _) if Self::check_lit(*lit, -1) => {
Self::generate_recommendation(cx, binop, rhsrhs, lhs, Side::Rhs)
},
// `y - 1`
- (BinOpKind::Sub, _, &ExprKind::Lit(ref lit)) if Self::check_lit(lit, 1) => {
+ (BinOpKind::Sub, _, ExprKind::Lit(lit)) if Self::check_lit(*lit, 1) => {
Self::generate_recommendation(cx, binop, rhslhs, lhs, Side::Rhs)
},
_ => None,
diff --git a/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs b/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs
index 0ef77e03d..6ea637412 100644
--- a/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs
+++ b/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs
@@ -38,7 +38,7 @@ declare_clippy_lint! {
declare_lint_pass!(InvalidUpcastComparisons => [INVALID_UPCAST_COMPARISONS]);
-fn numeric_cast_precast_bounds<'a>(cx: &LateContext<'_>, expr: &'a Expr<'_>) -> Option<(FullInt, FullInt)> {
+fn numeric_cast_precast_bounds(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<(FullInt, FullInt)> {
if let ExprKind::Cast(cast_exp, _) = expr.kind {
let pre_cast_ty = cx.typeck_results().expr_ty(cast_exp);
let cast_ty = cx.typeck_results().expr_ty(expr);
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 06e957285..b18456ee5 100644
--- a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
+++ b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
@@ -1,12 +1,15 @@
//! lint when there is a large size difference between variants on an enum
use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{diagnostics::span_lint_and_then, ty::approx_ty_size, ty::is_copy};
+use clippy_utils::{
+ diagnostics::span_lint_and_then,
+ ty::{approx_ty_size, is_copy, AdtVariantInfo},
+};
use rustc_errors::Applicability;
use rustc_hir::{Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty::{Adt, AdtDef, GenericArg, List, Ty};
+use rustc_middle::ty::{Adt, Ty};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Span;
@@ -72,49 +75,6 @@ impl LargeEnumVariant {
}
}
-struct FieldInfo {
- ind: usize,
- size: u64,
-}
-
-struct VariantInfo {
- ind: usize,
- size: u64,
- fields_size: Vec<FieldInfo>,
-}
-
-fn variants_size<'tcx>(
- cx: &LateContext<'tcx>,
- adt: AdtDef<'tcx>,
- subst: &'tcx List<GenericArg<'tcx>>,
-) -> Vec<VariantInfo> {
- let mut variants_size = adt
- .variants()
- .iter()
- .enumerate()
- .map(|(i, variant)| {
- let mut fields_size = variant
- .fields
- .iter()
- .enumerate()
- .map(|(i, f)| FieldInfo {
- ind: i,
- size: approx_ty_size(cx, f.ty(cx.tcx, subst)),
- })
- .collect::<Vec<_>>();
- fields_size.sort_by(|a, b| (a.size.cmp(&b.size)));
-
- VariantInfo {
- ind: i,
- size: fields_size.iter().map(|info| info.size).sum(),
- fields_size,
- }
- })
- .collect::<Vec<_>>();
- variants_size.sort_by(|a, b| (b.size.cmp(&a.size)));
- variants_size
-}
-
impl_lint_pass!(LargeEnumVariant => [LARGE_ENUM_VARIANT]);
impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
@@ -130,7 +90,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
if adt.variants().len() <= 1 {
return;
}
- let variants_size = variants_size(cx, *adt, subst);
+ let variants_size = AdtVariantInfo::new(cx, *adt, subst);
let mut difference = variants_size[0].size - variants_size[1].size;
if difference > self.maximum_size_difference_allowed {
@@ -173,16 +133,16 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
.fields_size
.iter()
.rev()
- .map_while(|val| {
+ .map_while(|&(ind, size)| {
if difference > self.maximum_size_difference_allowed {
- difference = difference.saturating_sub(val.size);
+ difference = difference.saturating_sub(size);
Some((
- fields[val.ind].ty.span,
+ fields[ind].ty.span,
format!(
"Box<{}>",
snippet_with_applicability(
cx,
- fields[val.ind].ty.span,
+ fields[ind].ty.span,
"..",
&mut applicability
)
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index b0cba40c2..4c133c06a 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -366,8 +366,7 @@ fn check_for_is_empty<'tcx>(
}
fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>, op: &str, compare_to: u32) {
- if let (&ExprKind::MethodCall(method_path, receiver, args, _), &ExprKind::Lit(ref lit)) = (&method.kind, &lit.kind)
- {
+ if let (&ExprKind::MethodCall(method_path, receiver, args, _), ExprKind::Lit(lit)) = (&method.kind, &lit.kind) {
// check if we are in an is_empty() method
if let Some(name) = get_item_name(cx, method) {
if name.as_str() == "is_empty" {
diff --git a/src/tools/clippy/clippy_lints/src/let_underscore.rs b/src/tools/clippy/clippy_lints/src/let_underscore.rs
index b7798b1c1..61f87b914 100644
--- a/src/tools/clippy/clippy_lints/src/let_underscore.rs
+++ b/src/tools/clippy/clippy_lints/src/let_underscore.rs
@@ -1,13 +1,11 @@
use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::ty::{is_must_use_ty, is_type_diagnostic_item, match_type};
+use clippy_utils::ty::{implements_trait, is_must_use_ty, match_type};
use clippy_utils::{is_must_use_func_call, paths};
-use if_chain::if_chain;
use rustc_hir::{Local, PatKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::subst::GenericArgKind;
use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::{sym, Symbol};
declare_clippy_lint! {
/// ### What it does
@@ -30,13 +28,14 @@ declare_clippy_lint! {
#[clippy::version = "1.42.0"]
pub LET_UNDERSCORE_MUST_USE,
restriction,
- "non-binding let on a `#[must_use]` expression"
+ "non-binding `let` on a `#[must_use]` expression"
}
declare_clippy_lint! {
/// ### What it does
- /// Checks for `let _ = sync_lock`.
- /// This supports `mutex` and `rwlock` in `std::sync` and `parking_lot`.
+ /// Checks for `let _ = sync_lock`. This supports `mutex` and `rwlock` in
+ /// `parking_lot`. For `std` locks see the `rustc` lint
+ /// [`let_underscore_lock`](https://doc.rust-lang.org/nightly/rustc/lints/listing/deny-by-default.html#let-underscore-lock)
///
/// ### Why is this bad?
/// This statement immediately drops the lock instead of
@@ -57,50 +56,41 @@ declare_clippy_lint! {
#[clippy::version = "1.43.0"]
pub LET_UNDERSCORE_LOCK,
correctness,
- "non-binding let on a synchronization lock"
+ "non-binding `let` on a synchronization lock"
}
declare_clippy_lint! {
/// ### What it does
- /// Checks for `let _ = <expr>`
- /// where expr has a type that implements `Drop`
+ /// Checks for `let _ = <expr>` where the resulting type of expr implements `Future`
///
/// ### Why is this bad?
- /// This statement immediately drops the initializer
- /// expression instead of extending its lifetime to the end of the scope, which
- /// is often not intended. To extend the expression's lifetime to the end of the
- /// scope, use an underscore-prefixed name instead (i.e. _var). If you want to
- /// explicitly drop the expression, `std::mem::drop` conveys your intention
- /// better and is less error-prone.
+ /// Futures must be polled for work to be done. The original intention was most likely to await the future
+ /// and ignore the resulting value.
///
/// ### Example
/// ```rust
- /// # struct DroppableItem;
- /// {
- /// let _ = DroppableItem;
- /// // ^ dropped here
- /// /* more code */
+ /// async fn foo() -> Result<(), ()> {
+ /// Ok(())
/// }
+ /// let _ = foo();
/// ```
///
/// Use instead:
/// ```rust
- /// # struct DroppableItem;
- /// {
- /// let _droppable = DroppableItem;
- /// /* more code */
- /// // dropped at end of scope
+ /// # async fn context() {
+ /// async fn foo() -> Result<(), ()> {
+ /// Ok(())
/// }
+ /// let _ = foo().await;
+ /// # }
/// ```
- #[clippy::version = "1.50.0"]
- pub LET_UNDERSCORE_DROP,
- pedantic,
- "non-binding let on a type that implements `Drop`"
+ #[clippy::version = "1.66"]
+ pub LET_UNDERSCORE_FUTURE,
+ suspicious,
+ "non-binding `let` on a future"
}
-declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_MUST_USE, LET_UNDERSCORE_LOCK, LET_UNDERSCORE_DROP]);
-
-const SYNC_GUARD_SYMS: [Symbol; 3] = [sym::MutexGuard, sym::RwLockReadGuard, sym::RwLockWriteGuard];
+declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_MUST_USE, LET_UNDERSCORE_LOCK, LET_UNDERSCORE_FUTURE]);
const SYNC_GUARD_PATHS: [&[&str]; 3] = [
&paths::PARKING_LOT_MUTEX_GUARD,
@@ -110,64 +100,53 @@ const SYNC_GUARD_PATHS: [&[&str]; 3] = [
impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) {
- if in_external_macro(cx.tcx.sess, local.span) {
- return;
- }
-
- if_chain! {
- if let PatKind::Wild = local.pat.kind;
- if let Some(init) = local.init;
- then {
- let init_ty = cx.typeck_results().expr_ty(init);
- let contains_sync_guard = init_ty.walk().any(|inner| match inner.unpack() {
- GenericArgKind::Type(inner_ty) => {
- SYNC_GUARD_SYMS
- .iter()
- .any(|&sym| is_type_diagnostic_item(cx, inner_ty, sym))
- || SYNC_GUARD_PATHS.iter().any(|path| match_type(cx, inner_ty, path))
- },
-
- GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
- });
- if contains_sync_guard {
- span_lint_and_help(
- cx,
- LET_UNDERSCORE_LOCK,
- local.span,
- "non-binding let on a synchronization lock",
- None,
- "consider using an underscore-prefixed named \
- binding or dropping explicitly with `std::mem::drop`",
- );
- } else if init_ty.needs_drop(cx.tcx, cx.param_env) {
- span_lint_and_help(
- cx,
- LET_UNDERSCORE_DROP,
- local.span,
- "non-binding `let` on a type that implements `Drop`",
- None,
- "consider using an underscore-prefixed named \
+ if !in_external_macro(cx.tcx.sess, local.span)
+ && let PatKind::Wild = local.pat.kind
+ && let Some(init) = local.init
+ {
+ let init_ty = cx.typeck_results().expr_ty(init);
+ let contains_sync_guard = init_ty.walk().any(|inner| match inner.unpack() {
+ GenericArgKind::Type(inner_ty) => SYNC_GUARD_PATHS.iter().any(|path| match_type(cx, inner_ty, path)),
+ GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
+ });
+ if contains_sync_guard {
+ span_lint_and_help(
+ cx,
+ LET_UNDERSCORE_LOCK,
+ local.span,
+ "non-binding `let` on a synchronization lock",
+ None,
+ "consider using an underscore-prefixed named \
binding or dropping explicitly with `std::mem::drop`",
- );
- } else if is_must_use_ty(cx, cx.typeck_results().expr_ty(init)) {
- span_lint_and_help(
- cx,
- LET_UNDERSCORE_MUST_USE,
- local.span,
- "non-binding let on an expression with `#[must_use]` type",
- None,
- "consider explicitly using expression value",
- );
- } else if is_must_use_func_call(cx, init) {
- span_lint_and_help(
- cx,
- LET_UNDERSCORE_MUST_USE,
- local.span,
- "non-binding let on a result of a `#[must_use]` function",
- None,
- "consider explicitly using function result",
- );
- }
+ );
+ } else if let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait()
+ && implements_trait(cx, cx.typeck_results().expr_ty(init), future_trait_def_id, &[]) {
+ span_lint_and_help(
+ cx,
+ LET_UNDERSCORE_FUTURE,
+ local.span,
+ "non-binding `let` on a future",
+ None,
+ "consider awaiting the future or dropping explicitly with `std::mem::drop`"
+ );
+ } else if is_must_use_ty(cx, cx.typeck_results().expr_ty(init)) {
+ span_lint_and_help(
+ cx,
+ LET_UNDERSCORE_MUST_USE,
+ local.span,
+ "non-binding `let` on an expression with `#[must_use]` type",
+ None,
+ "consider explicitly using expression value",
+ );
+ } else if is_must_use_func_call(cx, init) {
+ span_lint_and_help(
+ cx,
+ LET_UNDERSCORE_MUST_USE,
+ local.span,
+ "non-binding `let` on a result of a `#[must_use]` function",
+ None,
+ "consider explicitly using function result",
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_all.rs b/src/tools/clippy/clippy_lints/src/lib.register_all.rs
deleted file mode 100644
index c455e1561..000000000
--- a/src/tools/clippy/clippy_lints/src/lib.register_all.rs
+++ /dev/null
@@ -1,368 +0,0 @@
-// This file was generated by `cargo dev update_lints`.
-// Use that command to update this file and do not edit by hand.
-// Manual edits will be overwritten.
-
-store.register_group(true, "clippy::all", Some("clippy_all"), vec![
- LintId::of(almost_complete_letter_range::ALMOST_COMPLETE_LETTER_RANGE),
- LintId::of(approx_const::APPROX_CONSTANT),
- LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS),
- LintId::of(async_yields_async::ASYNC_YIELDS_ASYNC),
- LintId::of(attrs::BLANKET_CLIPPY_RESTRICTION_LINTS),
- LintId::of(attrs::DEPRECATED_CFG_ATTR),
- LintId::of(attrs::DEPRECATED_SEMVER),
- LintId::of(attrs::MISMATCHED_TARGET_OS),
- LintId::of(attrs::USELESS_ATTRIBUTE),
- LintId::of(await_holding_invalid::AWAIT_HOLDING_INVALID_TYPE),
- LintId::of(await_holding_invalid::AWAIT_HOLDING_LOCK),
- LintId::of(await_holding_invalid::AWAIT_HOLDING_REFCELL_REF),
- LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS),
- LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON),
- LintId::of(bool_to_int_with_if::BOOL_TO_INT_WITH_IF),
- LintId::of(booleans::NONMINIMAL_BOOL),
- LintId::of(booleans::OVERLY_COMPLEX_BOOL_EXPR),
- LintId::of(borrow_deref_ref::BORROW_DEREF_REF),
- LintId::of(box_default::BOX_DEFAULT),
- LintId::of(casts::CAST_ABS_TO_UNSIGNED),
- LintId::of(casts::CAST_ENUM_CONSTRUCTOR),
- LintId::of(casts::CAST_ENUM_TRUNCATION),
- LintId::of(casts::CAST_NAN_TO_INT),
- LintId::of(casts::CAST_REF_TO_MUT),
- LintId::of(casts::CAST_SLICE_DIFFERENT_SIZES),
- LintId::of(casts::CAST_SLICE_FROM_RAW_PARTS),
- LintId::of(casts::CHAR_LIT_AS_U8),
- LintId::of(casts::FN_TO_NUMERIC_CAST),
- LintId::of(casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION),
- LintId::of(casts::UNNECESSARY_CAST),
- LintId::of(collapsible_if::COLLAPSIBLE_ELSE_IF),
- LintId::of(collapsible_if::COLLAPSIBLE_IF),
- LintId::of(comparison_chain::COMPARISON_CHAIN),
- LintId::of(copies::IFS_SAME_COND),
- LintId::of(copies::IF_SAME_THEN_ELSE),
- LintId::of(crate_in_macro_def::CRATE_IN_MACRO_DEF),
- LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT),
- LintId::of(default_instead_of_iter_empty::DEFAULT_INSTEAD_OF_ITER_EMPTY),
- LintId::of(dereference::EXPLICIT_AUTO_DEREF),
- LintId::of(dereference::NEEDLESS_BORROW),
- LintId::of(derivable_impls::DERIVABLE_IMPLS),
- LintId::of(derive::DERIVE_HASH_XOR_EQ),
- LintId::of(derive::DERIVE_ORD_XOR_PARTIAL_ORD),
- LintId::of(disallowed_macros::DISALLOWED_MACROS),
- LintId::of(disallowed_methods::DISALLOWED_METHODS),
- LintId::of(disallowed_names::DISALLOWED_NAMES),
- LintId::of(disallowed_types::DISALLOWED_TYPES),
- LintId::of(doc::MISSING_SAFETY_DOC),
- LintId::of(doc::NEEDLESS_DOCTEST_MAIN),
- LintId::of(double_parens::DOUBLE_PARENS),
- LintId::of(drop_forget_ref::DROP_COPY),
- LintId::of(drop_forget_ref::DROP_NON_DROP),
- LintId::of(drop_forget_ref::DROP_REF),
- LintId::of(drop_forget_ref::FORGET_COPY),
- LintId::of(drop_forget_ref::FORGET_NON_DROP),
- LintId::of(drop_forget_ref::FORGET_REF),
- LintId::of(drop_forget_ref::UNDROPPED_MANUALLY_DROPS),
- LintId::of(duplicate_mod::DUPLICATE_MOD),
- LintId::of(entry::MAP_ENTRY),
- LintId::of(enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT),
- LintId::of(enum_variants::ENUM_VARIANT_NAMES),
- LintId::of(enum_variants::MODULE_INCEPTION),
- LintId::of(escape::BOXED_LOCAL),
- LintId::of(eta_reduction::REDUNDANT_CLOSURE),
- LintId::of(explicit_write::EXPLICIT_WRITE),
- LintId::of(float_literal::EXCESSIVE_PRECISION),
- LintId::of(format::USELESS_FORMAT),
- LintId::of(format_args::FORMAT_IN_FORMAT_ARGS),
- LintId::of(format_args::TO_STRING_IN_FORMAT_ARGS),
- LintId::of(format_args::UNUSED_FORMAT_SPECS),
- LintId::of(format_impl::PRINT_IN_FORMAT_IMPL),
- LintId::of(format_impl::RECURSIVE_FORMAT_IMPL),
- LintId::of(formatting::POSSIBLE_MISSING_COMMA),
- LintId::of(formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING),
- LintId::of(formatting::SUSPICIOUS_ELSE_FORMATTING),
- LintId::of(formatting::SUSPICIOUS_UNARY_OP_FORMATTING),
- LintId::of(from_over_into::FROM_OVER_INTO),
- LintId::of(from_str_radix_10::FROM_STR_RADIX_10),
- LintId::of(functions::DOUBLE_MUST_USE),
- LintId::of(functions::MUST_USE_UNIT),
- LintId::of(functions::NOT_UNSAFE_PTR_ARG_DEREF),
- LintId::of(functions::RESULT_LARGE_ERR),
- LintId::of(functions::RESULT_UNIT_ERR),
- LintId::of(functions::TOO_MANY_ARGUMENTS),
- LintId::of(if_let_mutex::IF_LET_MUTEX),
- LintId::of(implicit_saturating_add::IMPLICIT_SATURATING_ADD),
- LintId::of(implicit_saturating_sub::IMPLICIT_SATURATING_SUB),
- LintId::of(indexing_slicing::OUT_OF_BOUNDS_INDEXING),
- LintId::of(infinite_iter::INFINITE_ITER),
- LintId::of(inherent_to_string::INHERENT_TO_STRING),
- LintId::of(inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY),
- LintId::of(init_numbered_fields::INIT_NUMBERED_FIELDS),
- LintId::of(inline_fn_without_body::INLINE_FN_WITHOUT_BODY),
- LintId::of(int_plus_one::INT_PLUS_ONE),
- LintId::of(invalid_utf8_in_unchecked::INVALID_UTF8_IN_UNCHECKED),
- LintId::of(large_const_arrays::LARGE_CONST_ARRAYS),
- LintId::of(large_enum_variant::LARGE_ENUM_VARIANT),
- LintId::of(len_zero::COMPARISON_TO_EMPTY),
- LintId::of(len_zero::LEN_WITHOUT_IS_EMPTY),
- LintId::of(len_zero::LEN_ZERO),
- LintId::of(let_underscore::LET_UNDERSCORE_LOCK),
- LintId::of(lifetimes::EXTRA_UNUSED_LIFETIMES),
- LintId::of(lifetimes::NEEDLESS_LIFETIMES),
- LintId::of(literal_representation::INCONSISTENT_DIGIT_GROUPING),
- LintId::of(literal_representation::MISTYPED_LITERAL_SUFFIXES),
- LintId::of(literal_representation::UNUSUAL_BYTE_GROUPINGS),
- LintId::of(loops::EMPTY_LOOP),
- LintId::of(loops::EXPLICIT_COUNTER_LOOP),
- LintId::of(loops::FOR_KV_MAP),
- LintId::of(loops::ITER_NEXT_LOOP),
- LintId::of(loops::MANUAL_FIND),
- LintId::of(loops::MANUAL_FLATTEN),
- LintId::of(loops::MANUAL_MEMCPY),
- LintId::of(loops::MISSING_SPIN_LOOP),
- LintId::of(loops::MUT_RANGE_BOUND),
- LintId::of(loops::NEEDLESS_COLLECT),
- LintId::of(loops::NEEDLESS_RANGE_LOOP),
- LintId::of(loops::NEVER_LOOP),
- LintId::of(loops::SAME_ITEM_PUSH),
- LintId::of(loops::SINGLE_ELEMENT_LOOP),
- LintId::of(loops::WHILE_IMMUTABLE_CONDITION),
- LintId::of(loops::WHILE_LET_LOOP),
- LintId::of(loops::WHILE_LET_ON_ITERATOR),
- LintId::of(main_recursion::MAIN_RECURSION),
- LintId::of(manual_async_fn::MANUAL_ASYNC_FN),
- LintId::of(manual_bits::MANUAL_BITS),
- LintId::of(manual_clamp::MANUAL_CLAMP),
- LintId::of(manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
- LintId::of(manual_rem_euclid::MANUAL_REM_EUCLID),
- LintId::of(manual_retain::MANUAL_RETAIN),
- LintId::of(manual_strip::MANUAL_STRIP),
- LintId::of(map_unit_fn::OPTION_MAP_UNIT_FN),
- LintId::of(map_unit_fn::RESULT_MAP_UNIT_FN),
- LintId::of(match_result_ok::MATCH_RESULT_OK),
- LintId::of(matches::COLLAPSIBLE_MATCH),
- LintId::of(matches::INFALLIBLE_DESTRUCTURING_MATCH),
- LintId::of(matches::MANUAL_FILTER),
- LintId::of(matches::MANUAL_MAP),
- LintId::of(matches::MANUAL_UNWRAP_OR),
- LintId::of(matches::MATCH_AS_REF),
- LintId::of(matches::MATCH_LIKE_MATCHES_MACRO),
- LintId::of(matches::MATCH_OVERLAPPING_ARM),
- LintId::of(matches::MATCH_REF_PATS),
- LintId::of(matches::MATCH_SINGLE_BINDING),
- LintId::of(matches::MATCH_STR_CASE_MISMATCH),
- LintId::of(matches::NEEDLESS_MATCH),
- LintId::of(matches::REDUNDANT_PATTERN_MATCHING),
- LintId::of(matches::SINGLE_MATCH),
- LintId::of(matches::WILDCARD_IN_OR_PATTERNS),
- LintId::of(mem_replace::MEM_REPLACE_OPTION_WITH_NONE),
- LintId::of(mem_replace::MEM_REPLACE_WITH_DEFAULT),
- LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT),
- LintId::of(methods::BIND_INSTEAD_OF_MAP),
- LintId::of(methods::BYTES_COUNT_TO_LEN),
- LintId::of(methods::BYTES_NTH),
- LintId::of(methods::CHARS_LAST_CMP),
- LintId::of(methods::CHARS_NEXT_CMP),
- LintId::of(methods::CLONE_DOUBLE_REF),
- LintId::of(methods::CLONE_ON_COPY),
- LintId::of(methods::COLLAPSIBLE_STR_REPLACE),
- LintId::of(methods::ERR_EXPECT),
- LintId::of(methods::EXPECT_FUN_CALL),
- LintId::of(methods::EXTEND_WITH_DRAIN),
- LintId::of(methods::FILTER_MAP_IDENTITY),
- LintId::of(methods::FILTER_NEXT),
- LintId::of(methods::FLAT_MAP_IDENTITY),
- LintId::of(methods::GET_FIRST),
- LintId::of(methods::GET_LAST_WITH_LEN),
- LintId::of(methods::INSPECT_FOR_EACH),
- LintId::of(methods::INTO_ITER_ON_REF),
- LintId::of(methods::IS_DIGIT_ASCII_RADIX),
- LintId::of(methods::ITERATOR_STEP_BY_ZERO),
- LintId::of(methods::ITER_CLONED_COLLECT),
- LintId::of(methods::ITER_COUNT),
- LintId::of(methods::ITER_KV_MAP),
- LintId::of(methods::ITER_NEXT_SLICE),
- LintId::of(methods::ITER_NTH),
- LintId::of(methods::ITER_NTH_ZERO),
- LintId::of(methods::ITER_OVEREAGER_CLONED),
- LintId::of(methods::ITER_SKIP_NEXT),
- LintId::of(methods::MANUAL_FILTER_MAP),
- LintId::of(methods::MANUAL_FIND_MAP),
- LintId::of(methods::MANUAL_SATURATING_ARITHMETIC),
- LintId::of(methods::MANUAL_SPLIT_ONCE),
- LintId::of(methods::MANUAL_STR_REPEAT),
- LintId::of(methods::MAP_CLONE),
- LintId::of(methods::MAP_COLLECT_RESULT_UNIT),
- LintId::of(methods::MAP_FLATTEN),
- LintId::of(methods::MAP_IDENTITY),
- LintId::of(methods::MUT_MUTEX_LOCK),
- LintId::of(methods::NEEDLESS_OPTION_AS_DEREF),
- LintId::of(methods::NEEDLESS_OPTION_TAKE),
- LintId::of(methods::NEEDLESS_SPLITN),
- LintId::of(methods::NEW_RET_NO_SELF),
- LintId::of(methods::NONSENSICAL_OPEN_OPTIONS),
- LintId::of(methods::NO_EFFECT_REPLACE),
- LintId::of(methods::OBFUSCATED_IF_ELSE),
- LintId::of(methods::OK_EXPECT),
- LintId::of(methods::OPTION_AS_REF_DEREF),
- LintId::of(methods::OPTION_FILTER_MAP),
- LintId::of(methods::OPTION_MAP_OR_NONE),
- LintId::of(methods::OR_FUN_CALL),
- LintId::of(methods::OR_THEN_UNWRAP),
- LintId::of(methods::RANGE_ZIP_WITH_LEN),
- LintId::of(methods::REPEAT_ONCE),
- LintId::of(methods::RESULT_MAP_OR_INTO_OPTION),
- LintId::of(methods::SEARCH_IS_SOME),
- LintId::of(methods::SHOULD_IMPLEMENT_TRAIT),
- LintId::of(methods::SINGLE_CHAR_ADD_STR),
- LintId::of(methods::SINGLE_CHAR_PATTERN),
- LintId::of(methods::SKIP_WHILE_NEXT),
- LintId::of(methods::STRING_EXTEND_CHARS),
- LintId::of(methods::SUSPICIOUS_MAP),
- LintId::of(methods::SUSPICIOUS_SPLITN),
- LintId::of(methods::SUSPICIOUS_TO_OWNED),
- LintId::of(methods::UNINIT_ASSUMED_INIT),
- LintId::of(methods::UNIT_HASH),
- LintId::of(methods::UNNECESSARY_FILTER_MAP),
- LintId::of(methods::UNNECESSARY_FIND_MAP),
- LintId::of(methods::UNNECESSARY_FOLD),
- LintId::of(methods::UNNECESSARY_LAZY_EVALUATIONS),
- LintId::of(methods::UNNECESSARY_SORT_BY),
- LintId::of(methods::UNNECESSARY_TO_OWNED),
- LintId::of(methods::UNWRAP_OR_ELSE_DEFAULT),
- LintId::of(methods::USELESS_ASREF),
- LintId::of(methods::VEC_RESIZE_TO_ZERO),
- LintId::of(methods::WRONG_SELF_CONVENTION),
- LintId::of(methods::ZST_OFFSET),
- LintId::of(minmax::MIN_MAX),
- LintId::of(misc::SHORT_CIRCUIT_STATEMENT),
- LintId::of(misc::TOPLEVEL_REF_ARG),
- LintId::of(misc::ZERO_PTR),
- LintId::of(misc_early::BUILTIN_TYPE_SHADOW),
- LintId::of(misc_early::DOUBLE_NEG),
- LintId::of(misc_early::DUPLICATE_UNDERSCORE_ARGUMENT),
- LintId::of(misc_early::MIXED_CASE_HEX_LITERALS),
- LintId::of(misc_early::REDUNDANT_PATTERN),
- LintId::of(misc_early::UNNEEDED_WILDCARD_PATTERN),
- LintId::of(misc_early::ZERO_PREFIXED_LITERAL),
- LintId::of(mixed_read_write_in_expression::DIVERGING_SUB_EXPRESSION),
- LintId::of(multi_assignments::MULTI_ASSIGNMENTS),
- LintId::of(mut_key::MUTABLE_KEY_TYPE),
- LintId::of(mut_reference::UNNECESSARY_MUT_PASSED),
- LintId::of(needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE),
- LintId::of(needless_bool::BOOL_COMPARISON),
- LintId::of(needless_bool::NEEDLESS_BOOL),
- LintId::of(needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE),
- LintId::of(needless_late_init::NEEDLESS_LATE_INIT),
- LintId::of(needless_parens_on_range_literals::NEEDLESS_PARENS_ON_RANGE_LITERALS),
- LintId::of(needless_question_mark::NEEDLESS_QUESTION_MARK),
- LintId::of(needless_update::NEEDLESS_UPDATE),
- LintId::of(neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD),
- LintId::of(neg_multiply::NEG_MULTIPLY),
- LintId::of(new_without_default::NEW_WITHOUT_DEFAULT),
- LintId::of(no_effect::NO_EFFECT),
- LintId::of(no_effect::UNNECESSARY_OPERATION),
- LintId::of(non_copy_const::BORROW_INTERIOR_MUTABLE_CONST),
- LintId::of(non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST),
- LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS),
- LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS),
- LintId::of(octal_escapes::OCTAL_ESCAPES),
- LintId::of(only_used_in_recursion::ONLY_USED_IN_RECURSION),
- LintId::of(operators::ABSURD_EXTREME_COMPARISONS),
- LintId::of(operators::ASSIGN_OP_PATTERN),
- LintId::of(operators::BAD_BIT_MASK),
- LintId::of(operators::CMP_NAN),
- LintId::of(operators::CMP_OWNED),
- LintId::of(operators::DOUBLE_COMPARISONS),
- LintId::of(operators::DURATION_SUBSEC),
- LintId::of(operators::EQ_OP),
- LintId::of(operators::ERASING_OP),
- LintId::of(operators::FLOAT_EQUALITY_WITHOUT_ABS),
- LintId::of(operators::IDENTITY_OP),
- LintId::of(operators::INEFFECTIVE_BIT_MASK),
- LintId::of(operators::MISREFACTORED_ASSIGN_OP),
- LintId::of(operators::MODULO_ONE),
- LintId::of(operators::OP_REF),
- LintId::of(operators::PTR_EQ),
- LintId::of(operators::SELF_ASSIGNMENT),
- LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP),
- LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL),
- LintId::of(partialeq_ne_impl::PARTIALEQ_NE_IMPL),
- LintId::of(partialeq_to_none::PARTIALEQ_TO_NONE),
- LintId::of(precedence::PRECEDENCE),
- LintId::of(ptr::CMP_NULL),
- LintId::of(ptr::INVALID_NULL_PTR_USAGE),
- LintId::of(ptr::MUT_FROM_REF),
- LintId::of(ptr::PTR_ARG),
- LintId::of(ptr_offset_with_cast::PTR_OFFSET_WITH_CAST),
- LintId::of(question_mark::QUESTION_MARK),
- LintId::of(ranges::MANUAL_RANGE_CONTAINS),
- LintId::of(ranges::REVERSED_EMPTY_RANGES),
- LintId::of(rc_clone_in_vec_init::RC_CLONE_IN_VEC_INIT),
- LintId::of(read_zero_byte_vec::READ_ZERO_BYTE_VEC),
- LintId::of(redundant_clone::REDUNDANT_CLONE),
- LintId::of(redundant_closure_call::REDUNDANT_CLOSURE_CALL),
- LintId::of(redundant_field_names::REDUNDANT_FIELD_NAMES),
- LintId::of(redundant_slicing::REDUNDANT_SLICING),
- LintId::of(redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES),
- LintId::of(reference::DEREF_ADDROF),
- LintId::of(regex::INVALID_REGEX),
- LintId::of(returns::LET_AND_RETURN),
- LintId::of(returns::NEEDLESS_RETURN),
- LintId::of(self_named_constructors::SELF_NAMED_CONSTRUCTORS),
- LintId::of(serde_api::SERDE_API_MISUSE),
- LintId::of(single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
- LintId::of(size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT),
- LintId::of(slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
- LintId::of(strings::STRING_FROM_UTF8_AS_BYTES),
- LintId::of(strings::TRIM_SPLIT_WHITESPACE),
- LintId::of(strlen_on_c_strings::STRLEN_ON_C_STRINGS),
- LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
- LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
- LintId::of(swap::ALMOST_SWAPPED),
- LintId::of(swap::MANUAL_SWAP),
- LintId::of(swap_ptr_to_ref::SWAP_PTR_TO_REF),
- LintId::of(tabs_in_doc_comments::TABS_IN_DOC_COMMENTS),
- LintId::of(temporary_assignment::TEMPORARY_ASSIGNMENT),
- LintId::of(to_digit_is_some::TO_DIGIT_IS_SOME),
- LintId::of(transmute::CROSSPOINTER_TRANSMUTE),
- LintId::of(transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS),
- LintId::of(transmute::TRANSMUTE_BYTES_TO_STR),
- LintId::of(transmute::TRANSMUTE_FLOAT_TO_INT),
- LintId::of(transmute::TRANSMUTE_INT_TO_BOOL),
- LintId::of(transmute::TRANSMUTE_INT_TO_CHAR),
- LintId::of(transmute::TRANSMUTE_INT_TO_FLOAT),
- LintId::of(transmute::TRANSMUTE_NUM_TO_BYTES),
- LintId::of(transmute::TRANSMUTE_PTR_TO_REF),
- LintId::of(transmute::TRANSMUTING_NULL),
- LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE),
- LintId::of(transmute::USELESS_TRANSMUTE),
- LintId::of(transmute::WRONG_TRANSMUTE),
- LintId::of(types::BORROWED_BOX),
- LintId::of(types::BOX_COLLECTION),
- LintId::of(types::REDUNDANT_ALLOCATION),
- LintId::of(types::TYPE_COMPLEXITY),
- LintId::of(types::VEC_BOX),
- LintId::of(unicode::INVISIBLE_CHARACTERS),
- LintId::of(uninit_vec::UNINIT_VEC),
- LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
- LintId::of(unit_types::LET_UNIT_VALUE),
- LintId::of(unit_types::UNIT_ARG),
- LintId::of(unit_types::UNIT_CMP),
- LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS),
- LintId::of(unnamed_address::VTABLE_ADDRESS_COMPARISONS),
- LintId::of(unnecessary_owned_empty_strings::UNNECESSARY_OWNED_EMPTY_STRINGS),
- LintId::of(unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME),
- LintId::of(unused_io_amount::UNUSED_IO_AMOUNT),
- LintId::of(unused_unit::UNUSED_UNIT),
- LintId::of(unwrap::PANICKING_UNWRAP),
- LintId::of(unwrap::UNNECESSARY_UNWRAP),
- LintId::of(upper_case_acronyms::UPPER_CASE_ACRONYMS),
- LintId::of(useless_conversion::USELESS_CONVERSION),
- LintId::of(vec::USELESS_VEC),
- LintId::of(vec_init_then_push::VEC_INIT_THEN_PUSH),
- LintId::of(write::PRINTLN_EMPTY_STRING),
- LintId::of(write::PRINT_LITERAL),
- LintId::of(write::PRINT_WITH_NEWLINE),
- LintId::of(write::WRITELN_EMPTY_STRING),
- LintId::of(write::WRITE_LITERAL),
- LintId::of(write::WRITE_WITH_NEWLINE),
- LintId::of(zero_div_zero::ZERO_DIVIDED_BY_ZERO),
-])
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_cargo.rs b/src/tools/clippy/clippy_lints/src/lib.register_cargo.rs
deleted file mode 100644
index c890523fe..000000000
--- a/src/tools/clippy/clippy_lints/src/lib.register_cargo.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-// This file was generated by `cargo dev update_lints`.
-// Use that command to update this file and do not edit by hand.
-// Manual edits will be overwritten.
-
-store.register_group(true, "clippy::cargo", Some("clippy_cargo"), vec![
- LintId::of(cargo::CARGO_COMMON_METADATA),
- LintId::of(cargo::MULTIPLE_CRATE_VERSIONS),
- LintId::of(cargo::NEGATIVE_FEATURE_NAMES),
- LintId::of(cargo::REDUNDANT_FEATURE_NAMES),
- LintId::of(cargo::WILDCARD_DEPENDENCIES),
-])
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_complexity.rs b/src/tools/clippy/clippy_lints/src/lib.register_complexity.rs
deleted file mode 100644
index 8be9dc4ba..000000000
--- a/src/tools/clippy/clippy_lints/src/lib.register_complexity.rs
+++ /dev/null
@@ -1,111 +0,0 @@
-// This file was generated by `cargo dev update_lints`.
-// Use that command to update this file and do not edit by hand.
-// Manual edits will be overwritten.
-
-store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec![
- LintId::of(attrs::DEPRECATED_CFG_ATTR),
- LintId::of(booleans::NONMINIMAL_BOOL),
- LintId::of(borrow_deref_ref::BORROW_DEREF_REF),
- LintId::of(casts::CHAR_LIT_AS_U8),
- LintId::of(casts::UNNECESSARY_CAST),
- LintId::of(dereference::EXPLICIT_AUTO_DEREF),
- LintId::of(derivable_impls::DERIVABLE_IMPLS),
- LintId::of(double_parens::DOUBLE_PARENS),
- LintId::of(explicit_write::EXPLICIT_WRITE),
- LintId::of(format::USELESS_FORMAT),
- LintId::of(format_args::UNUSED_FORMAT_SPECS),
- LintId::of(functions::TOO_MANY_ARGUMENTS),
- LintId::of(int_plus_one::INT_PLUS_ONE),
- LintId::of(lifetimes::EXTRA_UNUSED_LIFETIMES),
- LintId::of(lifetimes::NEEDLESS_LIFETIMES),
- LintId::of(loops::EXPLICIT_COUNTER_LOOP),
- LintId::of(loops::MANUAL_FIND),
- LintId::of(loops::MANUAL_FLATTEN),
- LintId::of(loops::SINGLE_ELEMENT_LOOP),
- LintId::of(loops::WHILE_LET_LOOP),
- LintId::of(manual_clamp::MANUAL_CLAMP),
- LintId::of(manual_rem_euclid::MANUAL_REM_EUCLID),
- LintId::of(manual_strip::MANUAL_STRIP),
- LintId::of(map_unit_fn::OPTION_MAP_UNIT_FN),
- LintId::of(map_unit_fn::RESULT_MAP_UNIT_FN),
- LintId::of(matches::MANUAL_FILTER),
- LintId::of(matches::MANUAL_UNWRAP_OR),
- LintId::of(matches::MATCH_AS_REF),
- LintId::of(matches::MATCH_SINGLE_BINDING),
- LintId::of(matches::NEEDLESS_MATCH),
- LintId::of(matches::WILDCARD_IN_OR_PATTERNS),
- LintId::of(methods::BIND_INSTEAD_OF_MAP),
- LintId::of(methods::BYTES_COUNT_TO_LEN),
- LintId::of(methods::CLONE_ON_COPY),
- LintId::of(methods::FILTER_MAP_IDENTITY),
- LintId::of(methods::FILTER_NEXT),
- LintId::of(methods::FLAT_MAP_IDENTITY),
- LintId::of(methods::GET_LAST_WITH_LEN),
- LintId::of(methods::INSPECT_FOR_EACH),
- LintId::of(methods::ITER_COUNT),
- LintId::of(methods::ITER_KV_MAP),
- LintId::of(methods::MANUAL_FILTER_MAP),
- LintId::of(methods::MANUAL_FIND_MAP),
- LintId::of(methods::MANUAL_SPLIT_ONCE),
- LintId::of(methods::MAP_FLATTEN),
- LintId::of(methods::MAP_IDENTITY),
- LintId::of(methods::NEEDLESS_OPTION_AS_DEREF),
- LintId::of(methods::NEEDLESS_OPTION_TAKE),
- LintId::of(methods::NEEDLESS_SPLITN),
- LintId::of(methods::OPTION_AS_REF_DEREF),
- LintId::of(methods::OPTION_FILTER_MAP),
- LintId::of(methods::OR_THEN_UNWRAP),
- LintId::of(methods::RANGE_ZIP_WITH_LEN),
- LintId::of(methods::REPEAT_ONCE),
- LintId::of(methods::SEARCH_IS_SOME),
- LintId::of(methods::SKIP_WHILE_NEXT),
- LintId::of(methods::UNNECESSARY_FILTER_MAP),
- LintId::of(methods::UNNECESSARY_FIND_MAP),
- LintId::of(methods::UNNECESSARY_SORT_BY),
- LintId::of(methods::USELESS_ASREF),
- LintId::of(misc::SHORT_CIRCUIT_STATEMENT),
- LintId::of(misc_early::UNNEEDED_WILDCARD_PATTERN),
- LintId::of(misc_early::ZERO_PREFIXED_LITERAL),
- LintId::of(mixed_read_write_in_expression::DIVERGING_SUB_EXPRESSION),
- LintId::of(needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE),
- LintId::of(needless_bool::BOOL_COMPARISON),
- LintId::of(needless_bool::NEEDLESS_BOOL),
- LintId::of(needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE),
- LintId::of(needless_question_mark::NEEDLESS_QUESTION_MARK),
- LintId::of(needless_update::NEEDLESS_UPDATE),
- LintId::of(neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD),
- LintId::of(no_effect::NO_EFFECT),
- LintId::of(no_effect::UNNECESSARY_OPERATION),
- LintId::of(only_used_in_recursion::ONLY_USED_IN_RECURSION),
- LintId::of(operators::DOUBLE_COMPARISONS),
- LintId::of(operators::DURATION_SUBSEC),
- LintId::of(operators::IDENTITY_OP),
- LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL),
- LintId::of(partialeq_ne_impl::PARTIALEQ_NE_IMPL),
- LintId::of(precedence::PRECEDENCE),
- LintId::of(ptr_offset_with_cast::PTR_OFFSET_WITH_CAST),
- LintId::of(redundant_closure_call::REDUNDANT_CLOSURE_CALL),
- LintId::of(redundant_slicing::REDUNDANT_SLICING),
- LintId::of(reference::DEREF_ADDROF),
- LintId::of(strings::STRING_FROM_UTF8_AS_BYTES),
- LintId::of(strlen_on_c_strings::STRLEN_ON_C_STRINGS),
- LintId::of(swap::MANUAL_SWAP),
- LintId::of(temporary_assignment::TEMPORARY_ASSIGNMENT),
- LintId::of(transmute::CROSSPOINTER_TRANSMUTE),
- LintId::of(transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS),
- LintId::of(transmute::TRANSMUTE_BYTES_TO_STR),
- LintId::of(transmute::TRANSMUTE_FLOAT_TO_INT),
- LintId::of(transmute::TRANSMUTE_INT_TO_BOOL),
- LintId::of(transmute::TRANSMUTE_INT_TO_CHAR),
- LintId::of(transmute::TRANSMUTE_INT_TO_FLOAT),
- LintId::of(transmute::TRANSMUTE_NUM_TO_BYTES),
- LintId::of(transmute::TRANSMUTE_PTR_TO_REF),
- LintId::of(transmute::USELESS_TRANSMUTE),
- LintId::of(types::BORROWED_BOX),
- LintId::of(types::TYPE_COMPLEXITY),
- LintId::of(types::VEC_BOX),
- LintId::of(unit_types::UNIT_ARG),
- LintId::of(unwrap::UNNECESSARY_UNWRAP),
- LintId::of(useless_conversion::USELESS_CONVERSION),
- LintId::of(zero_div_zero::ZERO_DIVIDED_BY_ZERO),
-])
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_correctness.rs b/src/tools/clippy/clippy_lints/src/lib.register_correctness.rs
deleted file mode 100644
index bb94037ec..000000000
--- a/src/tools/clippy/clippy_lints/src/lib.register_correctness.rs
+++ /dev/null
@@ -1,78 +0,0 @@
-// This file was generated by `cargo dev update_lints`.
-// Use that command to update this file and do not edit by hand.
-// Manual edits will be overwritten.
-
-store.register_group(true, "clippy::correctness", Some("clippy_correctness"), vec![
- LintId::of(approx_const::APPROX_CONSTANT),
- LintId::of(async_yields_async::ASYNC_YIELDS_ASYNC),
- LintId::of(attrs::DEPRECATED_SEMVER),
- LintId::of(attrs::MISMATCHED_TARGET_OS),
- LintId::of(attrs::USELESS_ATTRIBUTE),
- LintId::of(booleans::OVERLY_COMPLEX_BOOL_EXPR),
- LintId::of(casts::CAST_REF_TO_MUT),
- LintId::of(casts::CAST_SLICE_DIFFERENT_SIZES),
- LintId::of(copies::IFS_SAME_COND),
- LintId::of(copies::IF_SAME_THEN_ELSE),
- LintId::of(derive::DERIVE_HASH_XOR_EQ),
- LintId::of(derive::DERIVE_ORD_XOR_PARTIAL_ORD),
- LintId::of(drop_forget_ref::DROP_COPY),
- LintId::of(drop_forget_ref::DROP_REF),
- LintId::of(drop_forget_ref::FORGET_COPY),
- LintId::of(drop_forget_ref::FORGET_REF),
- LintId::of(drop_forget_ref::UNDROPPED_MANUALLY_DROPS),
- LintId::of(enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT),
- LintId::of(format_impl::RECURSIVE_FORMAT_IMPL),
- LintId::of(formatting::POSSIBLE_MISSING_COMMA),
- LintId::of(functions::NOT_UNSAFE_PTR_ARG_DEREF),
- LintId::of(if_let_mutex::IF_LET_MUTEX),
- LintId::of(indexing_slicing::OUT_OF_BOUNDS_INDEXING),
- LintId::of(infinite_iter::INFINITE_ITER),
- LintId::of(inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY),
- LintId::of(inline_fn_without_body::INLINE_FN_WITHOUT_BODY),
- LintId::of(invalid_utf8_in_unchecked::INVALID_UTF8_IN_UNCHECKED),
- LintId::of(let_underscore::LET_UNDERSCORE_LOCK),
- LintId::of(literal_representation::MISTYPED_LITERAL_SUFFIXES),
- LintId::of(loops::ITER_NEXT_LOOP),
- LintId::of(loops::NEVER_LOOP),
- LintId::of(loops::WHILE_IMMUTABLE_CONDITION),
- LintId::of(matches::MATCH_STR_CASE_MISMATCH),
- LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT),
- LintId::of(methods::CLONE_DOUBLE_REF),
- LintId::of(methods::ITERATOR_STEP_BY_ZERO),
- LintId::of(methods::NONSENSICAL_OPEN_OPTIONS),
- LintId::of(methods::SUSPICIOUS_SPLITN),
- LintId::of(methods::UNINIT_ASSUMED_INIT),
- LintId::of(methods::UNIT_HASH),
- LintId::of(methods::VEC_RESIZE_TO_ZERO),
- LintId::of(methods::ZST_OFFSET),
- LintId::of(minmax::MIN_MAX),
- LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS),
- LintId::of(operators::ABSURD_EXTREME_COMPARISONS),
- LintId::of(operators::BAD_BIT_MASK),
- LintId::of(operators::CMP_NAN),
- LintId::of(operators::EQ_OP),
- LintId::of(operators::ERASING_OP),
- LintId::of(operators::INEFFECTIVE_BIT_MASK),
- LintId::of(operators::MODULO_ONE),
- LintId::of(operators::SELF_ASSIGNMENT),
- LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP),
- LintId::of(ptr::INVALID_NULL_PTR_USAGE),
- LintId::of(ptr::MUT_FROM_REF),
- LintId::of(ranges::REVERSED_EMPTY_RANGES),
- LintId::of(read_zero_byte_vec::READ_ZERO_BYTE_VEC),
- LintId::of(regex::INVALID_REGEX),
- LintId::of(serde_api::SERDE_API_MISUSE),
- LintId::of(size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT),
- LintId::of(swap::ALMOST_SWAPPED),
- LintId::of(transmute::TRANSMUTING_NULL),
- LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE),
- LintId::of(transmute::WRONG_TRANSMUTE),
- LintId::of(unicode::INVISIBLE_CHARACTERS),
- LintId::of(uninit_vec::UNINIT_VEC),
- LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
- LintId::of(unit_types::UNIT_CMP),
- LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS),
- LintId::of(unnamed_address::VTABLE_ADDRESS_COMPARISONS),
- LintId::of(unused_io_amount::UNUSED_IO_AMOUNT),
- LintId::of(unwrap::PANICKING_UNWRAP),
-])
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_internal.rs b/src/tools/clippy/clippy_lints/src/lib.register_internal.rs
deleted file mode 100644
index 40c94c6e8..000000000
--- a/src/tools/clippy/clippy_lints/src/lib.register_internal.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-// This file was generated by `cargo dev update_lints`.
-// Use that command to update this file and do not edit by hand.
-// Manual edits will be overwritten.
-
-store.register_group(true, "clippy::internal", Some("clippy_internal"), vec![
- LintId::of(utils::internal_lints::clippy_lints_internal::CLIPPY_LINTS_INTERNAL),
- LintId::of(utils::internal_lints::collapsible_calls::COLLAPSIBLE_SPAN_LINT_CALLS),
- LintId::of(utils::internal_lints::compiler_lint_functions::COMPILER_LINT_FUNCTIONS),
- LintId::of(utils::internal_lints::if_chain_style::IF_CHAIN_STYLE),
- LintId::of(utils::internal_lints::interning_defined_symbol::INTERNING_DEFINED_SYMBOL),
- LintId::of(utils::internal_lints::interning_defined_symbol::UNNECESSARY_SYMBOL_STR),
- LintId::of(utils::internal_lints::invalid_paths::INVALID_PATHS),
- LintId::of(utils::internal_lints::lint_without_lint_pass::DEFAULT_DEPRECATION_REASON),
- LintId::of(utils::internal_lints::lint_without_lint_pass::DEFAULT_LINT),
- LintId::of(utils::internal_lints::lint_without_lint_pass::INVALID_CLIPPY_VERSION_ATTRIBUTE),
- LintId::of(utils::internal_lints::lint_without_lint_pass::LINT_WITHOUT_LINT_PASS),
- LintId::of(utils::internal_lints::lint_without_lint_pass::MISSING_CLIPPY_VERSION_ATTRIBUTE),
- LintId::of(utils::internal_lints::msrv_attr_impl::MISSING_MSRV_ATTR_IMPL),
- LintId::of(utils::internal_lints::outer_expn_data_pass::OUTER_EXPN_EXPN_DATA),
- LintId::of(utils::internal_lints::produce_ice::PRODUCE_ICE),
- LintId::of(utils::internal_lints::unnecessary_def_path::UNNECESSARY_DEF_PATH),
-])
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_lints.rs b/src/tools/clippy/clippy_lints/src/lib.register_lints.rs
deleted file mode 100644
index 800e3a876..000000000
--- a/src/tools/clippy/clippy_lints/src/lib.register_lints.rs
+++ /dev/null
@@ -1,620 +0,0 @@
-// This file was generated by `cargo dev update_lints`.
-// Use that command to update this file and do not edit by hand.
-// Manual edits will be overwritten.
-
-store.register_lints(&[
- #[cfg(feature = "internal")]
- utils::internal_lints::clippy_lints_internal::CLIPPY_LINTS_INTERNAL,
- #[cfg(feature = "internal")]
- utils::internal_lints::collapsible_calls::COLLAPSIBLE_SPAN_LINT_CALLS,
- #[cfg(feature = "internal")]
- utils::internal_lints::compiler_lint_functions::COMPILER_LINT_FUNCTIONS,
- #[cfg(feature = "internal")]
- utils::internal_lints::if_chain_style::IF_CHAIN_STYLE,
- #[cfg(feature = "internal")]
- utils::internal_lints::interning_defined_symbol::INTERNING_DEFINED_SYMBOL,
- #[cfg(feature = "internal")]
- utils::internal_lints::interning_defined_symbol::UNNECESSARY_SYMBOL_STR,
- #[cfg(feature = "internal")]
- utils::internal_lints::invalid_paths::INVALID_PATHS,
- #[cfg(feature = "internal")]
- utils::internal_lints::lint_without_lint_pass::DEFAULT_DEPRECATION_REASON,
- #[cfg(feature = "internal")]
- utils::internal_lints::lint_without_lint_pass::DEFAULT_LINT,
- #[cfg(feature = "internal")]
- utils::internal_lints::lint_without_lint_pass::INVALID_CLIPPY_VERSION_ATTRIBUTE,
- #[cfg(feature = "internal")]
- utils::internal_lints::lint_without_lint_pass::LINT_WITHOUT_LINT_PASS,
- #[cfg(feature = "internal")]
- utils::internal_lints::lint_without_lint_pass::MISSING_CLIPPY_VERSION_ATTRIBUTE,
- #[cfg(feature = "internal")]
- utils::internal_lints::msrv_attr_impl::MISSING_MSRV_ATTR_IMPL,
- #[cfg(feature = "internal")]
- utils::internal_lints::outer_expn_data_pass::OUTER_EXPN_EXPN_DATA,
- #[cfg(feature = "internal")]
- utils::internal_lints::produce_ice::PRODUCE_ICE,
- #[cfg(feature = "internal")]
- utils::internal_lints::unnecessary_def_path::UNNECESSARY_DEF_PATH,
- almost_complete_letter_range::ALMOST_COMPLETE_LETTER_RANGE,
- approx_const::APPROX_CONSTANT,
- as_conversions::AS_CONVERSIONS,
- asm_syntax::INLINE_ASM_X86_ATT_SYNTAX,
- asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX,
- assertions_on_constants::ASSERTIONS_ON_CONSTANTS,
- assertions_on_result_states::ASSERTIONS_ON_RESULT_STATES,
- async_yields_async::ASYNC_YIELDS_ASYNC,
- attrs::ALLOW_ATTRIBUTES_WITHOUT_REASON,
- attrs::BLANKET_CLIPPY_RESTRICTION_LINTS,
- attrs::DEPRECATED_CFG_ATTR,
- attrs::DEPRECATED_SEMVER,
- attrs::EMPTY_LINE_AFTER_OUTER_ATTR,
- attrs::INLINE_ALWAYS,
- attrs::MISMATCHED_TARGET_OS,
- attrs::USELESS_ATTRIBUTE,
- await_holding_invalid::AWAIT_HOLDING_INVALID_TYPE,
- await_holding_invalid::AWAIT_HOLDING_LOCK,
- await_holding_invalid::AWAIT_HOLDING_REFCELL_REF,
- blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS,
- bool_assert_comparison::BOOL_ASSERT_COMPARISON,
- bool_to_int_with_if::BOOL_TO_INT_WITH_IF,
- booleans::NONMINIMAL_BOOL,
- booleans::OVERLY_COMPLEX_BOOL_EXPR,
- borrow_deref_ref::BORROW_DEREF_REF,
- box_default::BOX_DEFAULT,
- cargo::CARGO_COMMON_METADATA,
- cargo::MULTIPLE_CRATE_VERSIONS,
- cargo::NEGATIVE_FEATURE_NAMES,
- cargo::REDUNDANT_FEATURE_NAMES,
- cargo::WILDCARD_DEPENDENCIES,
- casts::AS_PTR_CAST_MUT,
- casts::AS_UNDERSCORE,
- casts::BORROW_AS_PTR,
- casts::CAST_ABS_TO_UNSIGNED,
- casts::CAST_ENUM_CONSTRUCTOR,
- casts::CAST_ENUM_TRUNCATION,
- casts::CAST_LOSSLESS,
- casts::CAST_NAN_TO_INT,
- casts::CAST_POSSIBLE_TRUNCATION,
- casts::CAST_POSSIBLE_WRAP,
- casts::CAST_PRECISION_LOSS,
- casts::CAST_PTR_ALIGNMENT,
- casts::CAST_REF_TO_MUT,
- casts::CAST_SIGN_LOSS,
- casts::CAST_SLICE_DIFFERENT_SIZES,
- casts::CAST_SLICE_FROM_RAW_PARTS,
- casts::CHAR_LIT_AS_U8,
- casts::FN_TO_NUMERIC_CAST,
- casts::FN_TO_NUMERIC_CAST_ANY,
- casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
- casts::PTR_AS_PTR,
- casts::UNNECESSARY_CAST,
- checked_conversions::CHECKED_CONVERSIONS,
- cognitive_complexity::COGNITIVE_COMPLEXITY,
- collapsible_if::COLLAPSIBLE_ELSE_IF,
- collapsible_if::COLLAPSIBLE_IF,
- comparison_chain::COMPARISON_CHAIN,
- copies::BRANCHES_SHARING_CODE,
- copies::IFS_SAME_COND,
- copies::IF_SAME_THEN_ELSE,
- copies::SAME_FUNCTIONS_IN_IF_CONDITION,
- copy_iterator::COPY_ITERATOR,
- crate_in_macro_def::CRATE_IN_MACRO_DEF,
- create_dir::CREATE_DIR,
- dbg_macro::DBG_MACRO,
- default::DEFAULT_TRAIT_ACCESS,
- default::FIELD_REASSIGN_WITH_DEFAULT,
- default_instead_of_iter_empty::DEFAULT_INSTEAD_OF_ITER_EMPTY,
- default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK,
- default_union_representation::DEFAULT_UNION_REPRESENTATION,
- dereference::EXPLICIT_AUTO_DEREF,
- dereference::EXPLICIT_DEREF_METHODS,
- dereference::NEEDLESS_BORROW,
- dereference::REF_BINDING_TO_REFERENCE,
- derivable_impls::DERIVABLE_IMPLS,
- derive::DERIVE_HASH_XOR_EQ,
- derive::DERIVE_ORD_XOR_PARTIAL_ORD,
- derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ,
- derive::EXPL_IMPL_CLONE_ON_COPY,
- derive::UNSAFE_DERIVE_DESERIALIZE,
- disallowed_macros::DISALLOWED_MACROS,
- disallowed_methods::DISALLOWED_METHODS,
- disallowed_names::DISALLOWED_NAMES,
- disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS,
- disallowed_types::DISALLOWED_TYPES,
- doc::DOC_LINK_WITH_QUOTES,
- doc::DOC_MARKDOWN,
- doc::MISSING_ERRORS_DOC,
- doc::MISSING_PANICS_DOC,
- doc::MISSING_SAFETY_DOC,
- doc::NEEDLESS_DOCTEST_MAIN,
- double_parens::DOUBLE_PARENS,
- drop_forget_ref::DROP_COPY,
- drop_forget_ref::DROP_NON_DROP,
- drop_forget_ref::DROP_REF,
- drop_forget_ref::FORGET_COPY,
- drop_forget_ref::FORGET_NON_DROP,
- drop_forget_ref::FORGET_REF,
- drop_forget_ref::UNDROPPED_MANUALLY_DROPS,
- duplicate_mod::DUPLICATE_MOD,
- else_if_without_else::ELSE_IF_WITHOUT_ELSE,
- empty_drop::EMPTY_DROP,
- empty_enum::EMPTY_ENUM,
- empty_structs_with_brackets::EMPTY_STRUCTS_WITH_BRACKETS,
- entry::MAP_ENTRY,
- enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT,
- enum_variants::ENUM_VARIANT_NAMES,
- enum_variants::MODULE_INCEPTION,
- enum_variants::MODULE_NAME_REPETITIONS,
- equatable_if_let::EQUATABLE_IF_LET,
- escape::BOXED_LOCAL,
- eta_reduction::REDUNDANT_CLOSURE,
- eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS,
- excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS,
- excessive_bools::STRUCT_EXCESSIVE_BOOLS,
- exhaustive_items::EXHAUSTIVE_ENUMS,
- exhaustive_items::EXHAUSTIVE_STRUCTS,
- exit::EXIT,
- explicit_write::EXPLICIT_WRITE,
- fallible_impl_from::FALLIBLE_IMPL_FROM,
- float_literal::EXCESSIVE_PRECISION,
- float_literal::LOSSY_FLOAT_LITERAL,
- floating_point_arithmetic::IMPRECISE_FLOPS,
- floating_point_arithmetic::SUBOPTIMAL_FLOPS,
- format::USELESS_FORMAT,
- format_args::FORMAT_IN_FORMAT_ARGS,
- format_args::TO_STRING_IN_FORMAT_ARGS,
- format_args::UNINLINED_FORMAT_ARGS,
- format_args::UNUSED_FORMAT_SPECS,
- format_impl::PRINT_IN_FORMAT_IMPL,
- format_impl::RECURSIVE_FORMAT_IMPL,
- format_push_string::FORMAT_PUSH_STRING,
- formatting::POSSIBLE_MISSING_COMMA,
- formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING,
- formatting::SUSPICIOUS_ELSE_FORMATTING,
- formatting::SUSPICIOUS_UNARY_OP_FORMATTING,
- from_over_into::FROM_OVER_INTO,
- from_str_radix_10::FROM_STR_RADIX_10,
- functions::DOUBLE_MUST_USE,
- functions::MUST_USE_CANDIDATE,
- functions::MUST_USE_UNIT,
- functions::NOT_UNSAFE_PTR_ARG_DEREF,
- functions::RESULT_LARGE_ERR,
- functions::RESULT_UNIT_ERR,
- functions::TOO_MANY_ARGUMENTS,
- functions::TOO_MANY_LINES,
- future_not_send::FUTURE_NOT_SEND,
- if_let_mutex::IF_LET_MUTEX,
- if_not_else::IF_NOT_ELSE,
- if_then_some_else_none::IF_THEN_SOME_ELSE_NONE,
- implicit_hasher::IMPLICIT_HASHER,
- implicit_return::IMPLICIT_RETURN,
- implicit_saturating_add::IMPLICIT_SATURATING_ADD,
- implicit_saturating_sub::IMPLICIT_SATURATING_SUB,
- inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR,
- index_refutable_slice::INDEX_REFUTABLE_SLICE,
- indexing_slicing::INDEXING_SLICING,
- indexing_slicing::OUT_OF_BOUNDS_INDEXING,
- infinite_iter::INFINITE_ITER,
- infinite_iter::MAYBE_INFINITE_ITER,
- inherent_impl::MULTIPLE_INHERENT_IMPL,
- inherent_to_string::INHERENT_TO_STRING,
- inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY,
- init_numbered_fields::INIT_NUMBERED_FIELDS,
- inline_fn_without_body::INLINE_FN_WITHOUT_BODY,
- int_plus_one::INT_PLUS_ONE,
- invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS,
- invalid_utf8_in_unchecked::INVALID_UTF8_IN_UNCHECKED,
- items_after_statements::ITEMS_AFTER_STATEMENTS,
- iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR,
- large_const_arrays::LARGE_CONST_ARRAYS,
- large_enum_variant::LARGE_ENUM_VARIANT,
- large_include_file::LARGE_INCLUDE_FILE,
- large_stack_arrays::LARGE_STACK_ARRAYS,
- len_zero::COMPARISON_TO_EMPTY,
- len_zero::LEN_WITHOUT_IS_EMPTY,
- len_zero::LEN_ZERO,
- let_if_seq::USELESS_LET_IF_SEQ,
- let_underscore::LET_UNDERSCORE_DROP,
- let_underscore::LET_UNDERSCORE_LOCK,
- let_underscore::LET_UNDERSCORE_MUST_USE,
- lifetimes::EXTRA_UNUSED_LIFETIMES,
- lifetimes::NEEDLESS_LIFETIMES,
- literal_representation::DECIMAL_LITERAL_REPRESENTATION,
- literal_representation::INCONSISTENT_DIGIT_GROUPING,
- literal_representation::LARGE_DIGIT_GROUPS,
- literal_representation::MISTYPED_LITERAL_SUFFIXES,
- literal_representation::UNREADABLE_LITERAL,
- literal_representation::UNUSUAL_BYTE_GROUPINGS,
- loops::EMPTY_LOOP,
- loops::EXPLICIT_COUNTER_LOOP,
- loops::EXPLICIT_INTO_ITER_LOOP,
- loops::EXPLICIT_ITER_LOOP,
- loops::FOR_KV_MAP,
- loops::ITER_NEXT_LOOP,
- loops::MANUAL_FIND,
- loops::MANUAL_FLATTEN,
- loops::MANUAL_MEMCPY,
- loops::MISSING_SPIN_LOOP,
- loops::MUT_RANGE_BOUND,
- loops::NEEDLESS_COLLECT,
- loops::NEEDLESS_RANGE_LOOP,
- loops::NEVER_LOOP,
- loops::SAME_ITEM_PUSH,
- loops::SINGLE_ELEMENT_LOOP,
- loops::WHILE_IMMUTABLE_CONDITION,
- loops::WHILE_LET_LOOP,
- loops::WHILE_LET_ON_ITERATOR,
- macro_use::MACRO_USE_IMPORTS,
- main_recursion::MAIN_RECURSION,
- manual_assert::MANUAL_ASSERT,
- manual_async_fn::MANUAL_ASYNC_FN,
- manual_bits::MANUAL_BITS,
- manual_clamp::MANUAL_CLAMP,
- manual_instant_elapsed::MANUAL_INSTANT_ELAPSED,
- manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE,
- manual_rem_euclid::MANUAL_REM_EUCLID,
- manual_retain::MANUAL_RETAIN,
- manual_string_new::MANUAL_STRING_NEW,
- manual_strip::MANUAL_STRIP,
- map_unit_fn::OPTION_MAP_UNIT_FN,
- map_unit_fn::RESULT_MAP_UNIT_FN,
- match_result_ok::MATCH_RESULT_OK,
- matches::COLLAPSIBLE_MATCH,
- matches::INFALLIBLE_DESTRUCTURING_MATCH,
- matches::MANUAL_FILTER,
- matches::MANUAL_MAP,
- matches::MANUAL_UNWRAP_OR,
- matches::MATCH_AS_REF,
- matches::MATCH_BOOL,
- matches::MATCH_LIKE_MATCHES_MACRO,
- matches::MATCH_ON_VEC_ITEMS,
- matches::MATCH_OVERLAPPING_ARM,
- matches::MATCH_REF_PATS,
- matches::MATCH_SAME_ARMS,
- matches::MATCH_SINGLE_BINDING,
- matches::MATCH_STR_CASE_MISMATCH,
- matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS,
- matches::MATCH_WILD_ERR_ARM,
- matches::NEEDLESS_MATCH,
- matches::REDUNDANT_PATTERN_MATCHING,
- matches::REST_PAT_IN_FULLY_BOUND_STRUCTS,
- matches::SIGNIFICANT_DROP_IN_SCRUTINEE,
- matches::SINGLE_MATCH,
- matches::SINGLE_MATCH_ELSE,
- matches::TRY_ERR,
- matches::WILDCARD_ENUM_MATCH_ARM,
- matches::WILDCARD_IN_OR_PATTERNS,
- mem_forget::MEM_FORGET,
- mem_replace::MEM_REPLACE_OPTION_WITH_NONE,
- mem_replace::MEM_REPLACE_WITH_DEFAULT,
- mem_replace::MEM_REPLACE_WITH_UNINIT,
- methods::BIND_INSTEAD_OF_MAP,
- methods::BYTES_COUNT_TO_LEN,
- methods::BYTES_NTH,
- methods::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
- methods::CHARS_LAST_CMP,
- methods::CHARS_NEXT_CMP,
- methods::CLONED_INSTEAD_OF_COPIED,
- methods::CLONE_DOUBLE_REF,
- methods::CLONE_ON_COPY,
- methods::CLONE_ON_REF_PTR,
- methods::COLLAPSIBLE_STR_REPLACE,
- methods::ERR_EXPECT,
- methods::EXPECT_FUN_CALL,
- methods::EXPECT_USED,
- methods::EXTEND_WITH_DRAIN,
- methods::FILETYPE_IS_FILE,
- methods::FILTER_MAP_IDENTITY,
- methods::FILTER_MAP_NEXT,
- methods::FILTER_NEXT,
- methods::FLAT_MAP_IDENTITY,
- methods::FLAT_MAP_OPTION,
- methods::FROM_ITER_INSTEAD_OF_COLLECT,
- methods::GET_FIRST,
- methods::GET_LAST_WITH_LEN,
- methods::GET_UNWRAP,
- methods::IMPLICIT_CLONE,
- methods::INEFFICIENT_TO_STRING,
- methods::INSPECT_FOR_EACH,
- methods::INTO_ITER_ON_REF,
- methods::IS_DIGIT_ASCII_RADIX,
- methods::ITERATOR_STEP_BY_ZERO,
- methods::ITER_CLONED_COLLECT,
- methods::ITER_COUNT,
- methods::ITER_KV_MAP,
- methods::ITER_NEXT_SLICE,
- methods::ITER_NTH,
- methods::ITER_NTH_ZERO,
- methods::ITER_ON_EMPTY_COLLECTIONS,
- methods::ITER_ON_SINGLE_ITEMS,
- methods::ITER_OVEREAGER_CLONED,
- methods::ITER_SKIP_NEXT,
- methods::ITER_WITH_DRAIN,
- methods::MANUAL_FILTER_MAP,
- methods::MANUAL_FIND_MAP,
- methods::MANUAL_OK_OR,
- methods::MANUAL_SATURATING_ARITHMETIC,
- methods::MANUAL_SPLIT_ONCE,
- methods::MANUAL_STR_REPEAT,
- methods::MAP_CLONE,
- methods::MAP_COLLECT_RESULT_UNIT,
- methods::MAP_ERR_IGNORE,
- methods::MAP_FLATTEN,
- methods::MAP_IDENTITY,
- methods::MAP_UNWRAP_OR,
- methods::MUT_MUTEX_LOCK,
- methods::NAIVE_BYTECOUNT,
- methods::NEEDLESS_OPTION_AS_DEREF,
- methods::NEEDLESS_OPTION_TAKE,
- methods::NEEDLESS_SPLITN,
- methods::NEW_RET_NO_SELF,
- methods::NONSENSICAL_OPEN_OPTIONS,
- methods::NO_EFFECT_REPLACE,
- methods::OBFUSCATED_IF_ELSE,
- methods::OK_EXPECT,
- methods::OPTION_AS_REF_DEREF,
- methods::OPTION_FILTER_MAP,
- methods::OPTION_MAP_OR_NONE,
- methods::OR_FUN_CALL,
- methods::OR_THEN_UNWRAP,
- methods::PATH_BUF_PUSH_OVERWRITE,
- methods::RANGE_ZIP_WITH_LEN,
- methods::REPEAT_ONCE,
- methods::RESULT_MAP_OR_INTO_OPTION,
- methods::SEARCH_IS_SOME,
- methods::SHOULD_IMPLEMENT_TRAIT,
- methods::SINGLE_CHAR_ADD_STR,
- methods::SINGLE_CHAR_PATTERN,
- methods::SKIP_WHILE_NEXT,
- methods::STABLE_SORT_PRIMITIVE,
- methods::STRING_EXTEND_CHARS,
- methods::SUSPICIOUS_MAP,
- methods::SUSPICIOUS_SPLITN,
- methods::SUSPICIOUS_TO_OWNED,
- methods::UNINIT_ASSUMED_INIT,
- methods::UNIT_HASH,
- methods::UNNECESSARY_FILTER_MAP,
- methods::UNNECESSARY_FIND_MAP,
- methods::UNNECESSARY_FOLD,
- methods::UNNECESSARY_JOIN,
- methods::UNNECESSARY_LAZY_EVALUATIONS,
- methods::UNNECESSARY_SORT_BY,
- methods::UNNECESSARY_TO_OWNED,
- methods::UNWRAP_OR_ELSE_DEFAULT,
- methods::UNWRAP_USED,
- methods::USELESS_ASREF,
- methods::VEC_RESIZE_TO_ZERO,
- methods::VERBOSE_FILE_READS,
- methods::WRONG_SELF_CONVENTION,
- methods::ZST_OFFSET,
- minmax::MIN_MAX,
- misc::SHORT_CIRCUIT_STATEMENT,
- misc::TOPLEVEL_REF_ARG,
- misc::USED_UNDERSCORE_BINDING,
- misc::ZERO_PTR,
- misc_early::BUILTIN_TYPE_SHADOW,
- misc_early::DOUBLE_NEG,
- misc_early::DUPLICATE_UNDERSCORE_ARGUMENT,
- misc_early::MIXED_CASE_HEX_LITERALS,
- misc_early::REDUNDANT_PATTERN,
- misc_early::SEPARATED_LITERAL_SUFFIX,
- misc_early::UNNEEDED_FIELD_PATTERN,
- misc_early::UNNEEDED_WILDCARD_PATTERN,
- misc_early::UNSEPARATED_LITERAL_SUFFIX,
- misc_early::ZERO_PREFIXED_LITERAL,
- mismatching_type_param_order::MISMATCHING_TYPE_PARAM_ORDER,
- missing_const_for_fn::MISSING_CONST_FOR_FN,
- missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS,
- missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES,
- missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS,
- missing_trait_methods::MISSING_TRAIT_METHODS,
- mixed_read_write_in_expression::DIVERGING_SUB_EXPRESSION,
- mixed_read_write_in_expression::MIXED_READ_WRITE_IN_EXPRESSION,
- module_style::MOD_MODULE_FILES,
- module_style::SELF_NAMED_MODULE_FILES,
- multi_assignments::MULTI_ASSIGNMENTS,
- mut_key::MUTABLE_KEY_TYPE,
- mut_mut::MUT_MUT,
- mut_reference::UNNECESSARY_MUT_PASSED,
- mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL,
- mutex_atomic::MUTEX_ATOMIC,
- mutex_atomic::MUTEX_INTEGER,
- needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE,
- needless_bool::BOOL_COMPARISON,
- needless_bool::NEEDLESS_BOOL,
- needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE,
- needless_continue::NEEDLESS_CONTINUE,
- needless_for_each::NEEDLESS_FOR_EACH,
- needless_late_init::NEEDLESS_LATE_INIT,
- needless_parens_on_range_literals::NEEDLESS_PARENS_ON_RANGE_LITERALS,
- needless_pass_by_value::NEEDLESS_PASS_BY_VALUE,
- needless_question_mark::NEEDLESS_QUESTION_MARK,
- needless_update::NEEDLESS_UPDATE,
- neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD,
- neg_multiply::NEG_MULTIPLY,
- new_without_default::NEW_WITHOUT_DEFAULT,
- no_effect::NO_EFFECT,
- no_effect::NO_EFFECT_UNDERSCORE_BINDING,
- no_effect::UNNECESSARY_OPERATION,
- non_copy_const::BORROW_INTERIOR_MUTABLE_CONST,
- non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST,
- non_expressive_names::JUST_UNDERSCORES_AND_DIGITS,
- non_expressive_names::MANY_SINGLE_CHAR_NAMES,
- non_expressive_names::SIMILAR_NAMES,
- non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS,
- non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY,
- nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES,
- octal_escapes::OCTAL_ESCAPES,
- only_used_in_recursion::ONLY_USED_IN_RECURSION,
- operators::ABSURD_EXTREME_COMPARISONS,
- operators::ARITHMETIC_SIDE_EFFECTS,
- operators::ASSIGN_OP_PATTERN,
- operators::BAD_BIT_MASK,
- operators::CMP_NAN,
- operators::CMP_OWNED,
- operators::DOUBLE_COMPARISONS,
- operators::DURATION_SUBSEC,
- operators::EQ_OP,
- operators::ERASING_OP,
- operators::FLOAT_ARITHMETIC,
- operators::FLOAT_CMP,
- operators::FLOAT_CMP_CONST,
- operators::FLOAT_EQUALITY_WITHOUT_ABS,
- operators::IDENTITY_OP,
- operators::INEFFECTIVE_BIT_MASK,
- operators::INTEGER_ARITHMETIC,
- operators::INTEGER_DIVISION,
- operators::MISREFACTORED_ASSIGN_OP,
- operators::MODULO_ARITHMETIC,
- operators::MODULO_ONE,
- operators::NEEDLESS_BITWISE_BOOL,
- operators::OP_REF,
- operators::PTR_EQ,
- operators::SELF_ASSIGNMENT,
- operators::VERBOSE_BIT_MASK,
- option_env_unwrap::OPTION_ENV_UNWRAP,
- option_if_let_else::OPTION_IF_LET_ELSE,
- overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL,
- panic_in_result_fn::PANIC_IN_RESULT_FN,
- panic_unimplemented::PANIC,
- panic_unimplemented::TODO,
- panic_unimplemented::UNIMPLEMENTED,
- panic_unimplemented::UNREACHABLE,
- partial_pub_fields::PARTIAL_PUB_FIELDS,
- partialeq_ne_impl::PARTIALEQ_NE_IMPL,
- partialeq_to_none::PARTIALEQ_TO_NONE,
- pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE,
- pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF,
- pattern_type_mismatch::PATTERN_TYPE_MISMATCH,
- precedence::PRECEDENCE,
- ptr::CMP_NULL,
- ptr::INVALID_NULL_PTR_USAGE,
- ptr::MUT_FROM_REF,
- ptr::PTR_ARG,
- ptr_offset_with_cast::PTR_OFFSET_WITH_CAST,
- pub_use::PUB_USE,
- question_mark::QUESTION_MARK,
- ranges::MANUAL_RANGE_CONTAINS,
- ranges::RANGE_MINUS_ONE,
- ranges::RANGE_PLUS_ONE,
- ranges::REVERSED_EMPTY_RANGES,
- rc_clone_in_vec_init::RC_CLONE_IN_VEC_INIT,
- read_zero_byte_vec::READ_ZERO_BYTE_VEC,
- redundant_clone::REDUNDANT_CLONE,
- redundant_closure_call::REDUNDANT_CLOSURE_CALL,
- redundant_else::REDUNDANT_ELSE,
- redundant_field_names::REDUNDANT_FIELD_NAMES,
- redundant_pub_crate::REDUNDANT_PUB_CRATE,
- redundant_slicing::DEREF_BY_SLICING,
- redundant_slicing::REDUNDANT_SLICING,
- redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES,
- ref_option_ref::REF_OPTION_REF,
- reference::DEREF_ADDROF,
- regex::INVALID_REGEX,
- regex::TRIVIAL_REGEX,
- return_self_not_must_use::RETURN_SELF_NOT_MUST_USE,
- returns::LET_AND_RETURN,
- returns::NEEDLESS_RETURN,
- same_name_method::SAME_NAME_METHOD,
- self_named_constructors::SELF_NAMED_CONSTRUCTORS,
- semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED,
- serde_api::SERDE_API_MISUSE,
- shadow::SHADOW_REUSE,
- shadow::SHADOW_SAME,
- shadow::SHADOW_UNRELATED,
- single_char_lifetime_names::SINGLE_CHAR_LIFETIME_NAMES,
- single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS,
- size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT,
- slow_vector_initialization::SLOW_VECTOR_INITIALIZATION,
- std_instead_of_core::ALLOC_INSTEAD_OF_CORE,
- std_instead_of_core::STD_INSTEAD_OF_ALLOC,
- std_instead_of_core::STD_INSTEAD_OF_CORE,
- strings::STRING_ADD,
- strings::STRING_ADD_ASSIGN,
- strings::STRING_FROM_UTF8_AS_BYTES,
- strings::STRING_LIT_AS_BYTES,
- strings::STRING_SLICE,
- strings::STRING_TO_STRING,
- strings::STR_TO_STRING,
- strings::TRIM_SPLIT_WHITESPACE,
- strlen_on_c_strings::STRLEN_ON_C_STRINGS,
- suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS,
- suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL,
- suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL,
- swap::ALMOST_SWAPPED,
- swap::MANUAL_SWAP,
- swap_ptr_to_ref::SWAP_PTR_TO_REF,
- tabs_in_doc_comments::TABS_IN_DOC_COMMENTS,
- temporary_assignment::TEMPORARY_ASSIGNMENT,
- to_digit_is_some::TO_DIGIT_IS_SOME,
- trailing_empty_array::TRAILING_EMPTY_ARRAY,
- trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS,
- trait_bounds::TYPE_REPETITION_IN_BOUNDS,
- transmute::CROSSPOINTER_TRANSMUTE,
- transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
- transmute::TRANSMUTE_BYTES_TO_STR,
- transmute::TRANSMUTE_FLOAT_TO_INT,
- transmute::TRANSMUTE_INT_TO_BOOL,
- transmute::TRANSMUTE_INT_TO_CHAR,
- transmute::TRANSMUTE_INT_TO_FLOAT,
- transmute::TRANSMUTE_NUM_TO_BYTES,
- transmute::TRANSMUTE_PTR_TO_PTR,
- transmute::TRANSMUTE_PTR_TO_REF,
- transmute::TRANSMUTE_UNDEFINED_REPR,
- transmute::TRANSMUTING_NULL,
- transmute::UNSOUND_COLLECTION_TRANSMUTE,
- transmute::USELESS_TRANSMUTE,
- transmute::WRONG_TRANSMUTE,
- types::BORROWED_BOX,
- types::BOX_COLLECTION,
- types::LINKEDLIST,
- types::OPTION_OPTION,
- types::RC_BUFFER,
- types::RC_MUTEX,
- types::REDUNDANT_ALLOCATION,
- types::TYPE_COMPLEXITY,
- types::VEC_BOX,
- undocumented_unsafe_blocks::UNDOCUMENTED_UNSAFE_BLOCKS,
- unicode::INVISIBLE_CHARACTERS,
- unicode::NON_ASCII_LITERAL,
- unicode::UNICODE_NOT_NFC,
- uninit_vec::UNINIT_VEC,
- unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD,
- unit_types::LET_UNIT_VALUE,
- unit_types::UNIT_ARG,
- unit_types::UNIT_CMP,
- unnamed_address::FN_ADDRESS_COMPARISONS,
- unnamed_address::VTABLE_ADDRESS_COMPARISONS,
- unnecessary_owned_empty_strings::UNNECESSARY_OWNED_EMPTY_STRINGS,
- unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS,
- unnecessary_wraps::UNNECESSARY_WRAPS,
- unnested_or_patterns::UNNESTED_OR_PATTERNS,
- unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME,
- unused_async::UNUSED_ASYNC,
- unused_io_amount::UNUSED_IO_AMOUNT,
- unused_peekable::UNUSED_PEEKABLE,
- unused_rounding::UNUSED_ROUNDING,
- unused_self::UNUSED_SELF,
- unused_unit::UNUSED_UNIT,
- unwrap::PANICKING_UNWRAP,
- unwrap::UNNECESSARY_UNWRAP,
- unwrap_in_result::UNWRAP_IN_RESULT,
- upper_case_acronyms::UPPER_CASE_ACRONYMS,
- use_self::USE_SELF,
- useless_conversion::USELESS_CONVERSION,
- vec::USELESS_VEC,
- vec_init_then_push::VEC_INIT_THEN_PUSH,
- wildcard_imports::ENUM_GLOB_USE,
- wildcard_imports::WILDCARD_IMPORTS,
- write::PRINTLN_EMPTY_STRING,
- write::PRINT_LITERAL,
- write::PRINT_STDERR,
- write::PRINT_STDOUT,
- write::PRINT_WITH_NEWLINE,
- write::USE_DEBUG,
- write::WRITELN_EMPTY_STRING,
- write::WRITE_LITERAL,
- write::WRITE_WITH_NEWLINE,
- zero_div_zero::ZERO_DIVIDED_BY_ZERO,
- zero_sized_map_values::ZERO_SIZED_MAP_VALUES,
-])
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_nursery.rs b/src/tools/clippy/clippy_lints/src/lib.register_nursery.rs
deleted file mode 100644
index 65616d28d..000000000
--- a/src/tools/clippy/clippy_lints/src/lib.register_nursery.rs
+++ /dev/null
@@ -1,39 +0,0 @@
-// This file was generated by `cargo dev update_lints`.
-// Use that command to update this file and do not edit by hand.
-// Manual edits will be overwritten.
-
-store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![
- LintId::of(attrs::EMPTY_LINE_AFTER_OUTER_ATTR),
- LintId::of(casts::AS_PTR_CAST_MUT),
- LintId::of(cognitive_complexity::COGNITIVE_COMPLEXITY),
- LintId::of(copies::BRANCHES_SHARING_CODE),
- LintId::of(derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ),
- LintId::of(equatable_if_let::EQUATABLE_IF_LET),
- LintId::of(fallible_impl_from::FALLIBLE_IMPL_FROM),
- LintId::of(floating_point_arithmetic::IMPRECISE_FLOPS),
- LintId::of(floating_point_arithmetic::SUBOPTIMAL_FLOPS),
- LintId::of(future_not_send::FUTURE_NOT_SEND),
- LintId::of(index_refutable_slice::INDEX_REFUTABLE_SLICE),
- LintId::of(let_if_seq::USELESS_LET_IF_SEQ),
- LintId::of(matches::SIGNIFICANT_DROP_IN_SCRUTINEE),
- LintId::of(methods::ITER_ON_EMPTY_COLLECTIONS),
- LintId::of(methods::ITER_ON_SINGLE_ITEMS),
- LintId::of(methods::ITER_WITH_DRAIN),
- LintId::of(methods::PATH_BUF_PUSH_OVERWRITE),
- LintId::of(missing_const_for_fn::MISSING_CONST_FOR_FN),
- LintId::of(mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL),
- LintId::of(mutex_atomic::MUTEX_ATOMIC),
- LintId::of(mutex_atomic::MUTEX_INTEGER),
- LintId::of(non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY),
- LintId::of(nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES),
- LintId::of(option_if_let_else::OPTION_IF_LET_ELSE),
- LintId::of(redundant_pub_crate::REDUNDANT_PUB_CRATE),
- LintId::of(regex::TRIVIAL_REGEX),
- LintId::of(strings::STRING_LIT_AS_BYTES),
- LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS),
- LintId::of(trailing_empty_array::TRAILING_EMPTY_ARRAY),
- LintId::of(transmute::TRANSMUTE_UNDEFINED_REPR),
- LintId::of(unused_peekable::UNUSED_PEEKABLE),
- LintId::of(unused_rounding::UNUSED_ROUNDING),
- LintId::of(use_self::USE_SELF),
-])
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs b/src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs
deleted file mode 100644
index 44e969585..000000000
--- a/src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs
+++ /dev/null
@@ -1,104 +0,0 @@
-// This file was generated by `cargo dev update_lints`.
-// Use that command to update this file and do not edit by hand.
-// Manual edits will be overwritten.
-
-store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
- LintId::of(attrs::INLINE_ALWAYS),
- LintId::of(casts::BORROW_AS_PTR),
- LintId::of(casts::CAST_LOSSLESS),
- LintId::of(casts::CAST_POSSIBLE_TRUNCATION),
- LintId::of(casts::CAST_POSSIBLE_WRAP),
- LintId::of(casts::CAST_PRECISION_LOSS),
- LintId::of(casts::CAST_PTR_ALIGNMENT),
- LintId::of(casts::CAST_SIGN_LOSS),
- LintId::of(casts::PTR_AS_PTR),
- LintId::of(checked_conversions::CHECKED_CONVERSIONS),
- LintId::of(copies::SAME_FUNCTIONS_IN_IF_CONDITION),
- LintId::of(copy_iterator::COPY_ITERATOR),
- LintId::of(default::DEFAULT_TRAIT_ACCESS),
- LintId::of(dereference::EXPLICIT_DEREF_METHODS),
- LintId::of(dereference::REF_BINDING_TO_REFERENCE),
- LintId::of(derive::EXPL_IMPL_CLONE_ON_COPY),
- LintId::of(derive::UNSAFE_DERIVE_DESERIALIZE),
- LintId::of(doc::DOC_LINK_WITH_QUOTES),
- LintId::of(doc::DOC_MARKDOWN),
- LintId::of(doc::MISSING_ERRORS_DOC),
- LintId::of(doc::MISSING_PANICS_DOC),
- LintId::of(empty_enum::EMPTY_ENUM),
- LintId::of(enum_variants::MODULE_NAME_REPETITIONS),
- LintId::of(eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS),
- LintId::of(excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS),
- LintId::of(excessive_bools::STRUCT_EXCESSIVE_BOOLS),
- LintId::of(format_args::UNINLINED_FORMAT_ARGS),
- LintId::of(functions::MUST_USE_CANDIDATE),
- LintId::of(functions::TOO_MANY_LINES),
- LintId::of(if_not_else::IF_NOT_ELSE),
- LintId::of(implicit_hasher::IMPLICIT_HASHER),
- LintId::of(inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR),
- LintId::of(infinite_iter::MAYBE_INFINITE_ITER),
- LintId::of(invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS),
- LintId::of(items_after_statements::ITEMS_AFTER_STATEMENTS),
- LintId::of(iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR),
- LintId::of(large_stack_arrays::LARGE_STACK_ARRAYS),
- LintId::of(let_underscore::LET_UNDERSCORE_DROP),
- LintId::of(literal_representation::LARGE_DIGIT_GROUPS),
- LintId::of(literal_representation::UNREADABLE_LITERAL),
- LintId::of(loops::EXPLICIT_INTO_ITER_LOOP),
- LintId::of(loops::EXPLICIT_ITER_LOOP),
- LintId::of(macro_use::MACRO_USE_IMPORTS),
- LintId::of(manual_assert::MANUAL_ASSERT),
- LintId::of(manual_instant_elapsed::MANUAL_INSTANT_ELAPSED),
- LintId::of(manual_string_new::MANUAL_STRING_NEW),
- LintId::of(matches::MATCH_BOOL),
- LintId::of(matches::MATCH_ON_VEC_ITEMS),
- LintId::of(matches::MATCH_SAME_ARMS),
- LintId::of(matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS),
- LintId::of(matches::MATCH_WILD_ERR_ARM),
- LintId::of(matches::SINGLE_MATCH_ELSE),
- LintId::of(methods::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS),
- LintId::of(methods::CLONED_INSTEAD_OF_COPIED),
- LintId::of(methods::FILTER_MAP_NEXT),
- LintId::of(methods::FLAT_MAP_OPTION),
- LintId::of(methods::FROM_ITER_INSTEAD_OF_COLLECT),
- LintId::of(methods::IMPLICIT_CLONE),
- LintId::of(methods::INEFFICIENT_TO_STRING),
- LintId::of(methods::MANUAL_OK_OR),
- LintId::of(methods::MAP_UNWRAP_OR),
- LintId::of(methods::NAIVE_BYTECOUNT),
- LintId::of(methods::STABLE_SORT_PRIMITIVE),
- LintId::of(methods::UNNECESSARY_JOIN),
- LintId::of(misc::USED_UNDERSCORE_BINDING),
- LintId::of(mismatching_type_param_order::MISMATCHING_TYPE_PARAM_ORDER),
- LintId::of(mut_mut::MUT_MUT),
- LintId::of(needless_continue::NEEDLESS_CONTINUE),
- LintId::of(needless_for_each::NEEDLESS_FOR_EACH),
- LintId::of(needless_pass_by_value::NEEDLESS_PASS_BY_VALUE),
- LintId::of(no_effect::NO_EFFECT_UNDERSCORE_BINDING),
- LintId::of(non_expressive_names::MANY_SINGLE_CHAR_NAMES),
- LintId::of(non_expressive_names::SIMILAR_NAMES),
- LintId::of(operators::FLOAT_CMP),
- LintId::of(operators::NEEDLESS_BITWISE_BOOL),
- LintId::of(operators::VERBOSE_BIT_MASK),
- LintId::of(pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE),
- LintId::of(pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF),
- LintId::of(ranges::RANGE_MINUS_ONE),
- LintId::of(ranges::RANGE_PLUS_ONE),
- LintId::of(redundant_else::REDUNDANT_ELSE),
- LintId::of(ref_option_ref::REF_OPTION_REF),
- LintId::of(return_self_not_must_use::RETURN_SELF_NOT_MUST_USE),
- LintId::of(semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED),
- LintId::of(strings::STRING_ADD_ASSIGN),
- LintId::of(trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS),
- LintId::of(trait_bounds::TYPE_REPETITION_IN_BOUNDS),
- LintId::of(transmute::TRANSMUTE_PTR_TO_PTR),
- LintId::of(types::LINKEDLIST),
- LintId::of(types::OPTION_OPTION),
- LintId::of(unicode::UNICODE_NOT_NFC),
- LintId::of(unnecessary_wraps::UNNECESSARY_WRAPS),
- LintId::of(unnested_or_patterns::UNNESTED_OR_PATTERNS),
- LintId::of(unused_async::UNUSED_ASYNC),
- LintId::of(unused_self::UNUSED_SELF),
- LintId::of(wildcard_imports::ENUM_GLOB_USE),
- LintId::of(wildcard_imports::WILDCARD_IMPORTS),
- LintId::of(zero_sized_map_values::ZERO_SIZED_MAP_VALUES),
-])
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_perf.rs b/src/tools/clippy/clippy_lints/src/lib.register_perf.rs
deleted file mode 100644
index 8e927470e..000000000
--- a/src/tools/clippy/clippy_lints/src/lib.register_perf.rs
+++ /dev/null
@@ -1,34 +0,0 @@
-// This file was generated by `cargo dev update_lints`.
-// Use that command to update this file and do not edit by hand.
-// Manual edits will be overwritten.
-
-store.register_group(true, "clippy::perf", Some("clippy_perf"), vec![
- LintId::of(box_default::BOX_DEFAULT),
- LintId::of(entry::MAP_ENTRY),
- LintId::of(escape::BOXED_LOCAL),
- LintId::of(format_args::FORMAT_IN_FORMAT_ARGS),
- LintId::of(format_args::TO_STRING_IN_FORMAT_ARGS),
- LintId::of(functions::RESULT_LARGE_ERR),
- LintId::of(large_const_arrays::LARGE_CONST_ARRAYS),
- LintId::of(large_enum_variant::LARGE_ENUM_VARIANT),
- LintId::of(loops::MANUAL_MEMCPY),
- LintId::of(loops::MISSING_SPIN_LOOP),
- LintId::of(loops::NEEDLESS_COLLECT),
- LintId::of(manual_retain::MANUAL_RETAIN),
- LintId::of(methods::COLLAPSIBLE_STR_REPLACE),
- LintId::of(methods::EXPECT_FUN_CALL),
- LintId::of(methods::EXTEND_WITH_DRAIN),
- LintId::of(methods::ITER_NTH),
- LintId::of(methods::ITER_OVEREAGER_CLONED),
- LintId::of(methods::MANUAL_STR_REPEAT),
- LintId::of(methods::OR_FUN_CALL),
- LintId::of(methods::SINGLE_CHAR_PATTERN),
- LintId::of(methods::UNNECESSARY_TO_OWNED),
- LintId::of(operators::CMP_OWNED),
- LintId::of(redundant_clone::REDUNDANT_CLONE),
- LintId::of(slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
- LintId::of(types::BOX_COLLECTION),
- LintId::of(types::REDUNDANT_ALLOCATION),
- LintId::of(vec::USELESS_VEC),
- LintId::of(vec_init_then_push::VEC_INIT_THEN_PUSH),
-])
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_restriction.rs b/src/tools/clippy/clippy_lints/src/lib.register_restriction.rs
deleted file mode 100644
index f62d57af5..000000000
--- a/src/tools/clippy/clippy_lints/src/lib.register_restriction.rs
+++ /dev/null
@@ -1,90 +0,0 @@
-// This file was generated by `cargo dev update_lints`.
-// Use that command to update this file and do not edit by hand.
-// Manual edits will be overwritten.
-
-store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
- LintId::of(as_conversions::AS_CONVERSIONS),
- LintId::of(asm_syntax::INLINE_ASM_X86_ATT_SYNTAX),
- LintId::of(asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX),
- LintId::of(assertions_on_result_states::ASSERTIONS_ON_RESULT_STATES),
- LintId::of(attrs::ALLOW_ATTRIBUTES_WITHOUT_REASON),
- LintId::of(casts::AS_UNDERSCORE),
- LintId::of(casts::FN_TO_NUMERIC_CAST_ANY),
- LintId::of(create_dir::CREATE_DIR),
- LintId::of(dbg_macro::DBG_MACRO),
- LintId::of(default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK),
- LintId::of(default_union_representation::DEFAULT_UNION_REPRESENTATION),
- LintId::of(disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS),
- LintId::of(else_if_without_else::ELSE_IF_WITHOUT_ELSE),
- LintId::of(empty_drop::EMPTY_DROP),
- LintId::of(empty_structs_with_brackets::EMPTY_STRUCTS_WITH_BRACKETS),
- LintId::of(exhaustive_items::EXHAUSTIVE_ENUMS),
- LintId::of(exhaustive_items::EXHAUSTIVE_STRUCTS),
- LintId::of(exit::EXIT),
- LintId::of(float_literal::LOSSY_FLOAT_LITERAL),
- LintId::of(format_push_string::FORMAT_PUSH_STRING),
- LintId::of(if_then_some_else_none::IF_THEN_SOME_ELSE_NONE),
- LintId::of(implicit_return::IMPLICIT_RETURN),
- LintId::of(indexing_slicing::INDEXING_SLICING),
- LintId::of(inherent_impl::MULTIPLE_INHERENT_IMPL),
- LintId::of(large_include_file::LARGE_INCLUDE_FILE),
- LintId::of(let_underscore::LET_UNDERSCORE_MUST_USE),
- LintId::of(literal_representation::DECIMAL_LITERAL_REPRESENTATION),
- LintId::of(matches::REST_PAT_IN_FULLY_BOUND_STRUCTS),
- LintId::of(matches::TRY_ERR),
- LintId::of(matches::WILDCARD_ENUM_MATCH_ARM),
- LintId::of(mem_forget::MEM_FORGET),
- LintId::of(methods::CLONE_ON_REF_PTR),
- LintId::of(methods::EXPECT_USED),
- LintId::of(methods::FILETYPE_IS_FILE),
- LintId::of(methods::GET_UNWRAP),
- LintId::of(methods::MAP_ERR_IGNORE),
- LintId::of(methods::UNWRAP_USED),
- LintId::of(methods::VERBOSE_FILE_READS),
- LintId::of(misc_early::SEPARATED_LITERAL_SUFFIX),
- LintId::of(misc_early::UNNEEDED_FIELD_PATTERN),
- LintId::of(misc_early::UNSEPARATED_LITERAL_SUFFIX),
- LintId::of(missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS),
- LintId::of(missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES),
- LintId::of(missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS),
- LintId::of(missing_trait_methods::MISSING_TRAIT_METHODS),
- LintId::of(mixed_read_write_in_expression::MIXED_READ_WRITE_IN_EXPRESSION),
- LintId::of(module_style::MOD_MODULE_FILES),
- LintId::of(module_style::SELF_NAMED_MODULE_FILES),
- LintId::of(operators::ARITHMETIC_SIDE_EFFECTS),
- LintId::of(operators::FLOAT_ARITHMETIC),
- LintId::of(operators::FLOAT_CMP_CONST),
- LintId::of(operators::INTEGER_ARITHMETIC),
- LintId::of(operators::INTEGER_DIVISION),
- LintId::of(operators::MODULO_ARITHMETIC),
- LintId::of(panic_in_result_fn::PANIC_IN_RESULT_FN),
- LintId::of(panic_unimplemented::PANIC),
- LintId::of(panic_unimplemented::TODO),
- LintId::of(panic_unimplemented::UNIMPLEMENTED),
- LintId::of(panic_unimplemented::UNREACHABLE),
- LintId::of(partial_pub_fields::PARTIAL_PUB_FIELDS),
- LintId::of(pattern_type_mismatch::PATTERN_TYPE_MISMATCH),
- LintId::of(pub_use::PUB_USE),
- LintId::of(redundant_slicing::DEREF_BY_SLICING),
- LintId::of(same_name_method::SAME_NAME_METHOD),
- LintId::of(shadow::SHADOW_REUSE),
- LintId::of(shadow::SHADOW_SAME),
- LintId::of(shadow::SHADOW_UNRELATED),
- LintId::of(single_char_lifetime_names::SINGLE_CHAR_LIFETIME_NAMES),
- LintId::of(std_instead_of_core::ALLOC_INSTEAD_OF_CORE),
- LintId::of(std_instead_of_core::STD_INSTEAD_OF_ALLOC),
- LintId::of(std_instead_of_core::STD_INSTEAD_OF_CORE),
- LintId::of(strings::STRING_ADD),
- LintId::of(strings::STRING_SLICE),
- LintId::of(strings::STRING_TO_STRING),
- LintId::of(strings::STR_TO_STRING),
- LintId::of(types::RC_BUFFER),
- LintId::of(types::RC_MUTEX),
- LintId::of(undocumented_unsafe_blocks::UNDOCUMENTED_UNSAFE_BLOCKS),
- LintId::of(unicode::NON_ASCII_LITERAL),
- LintId::of(unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS),
- LintId::of(unwrap_in_result::UNWRAP_IN_RESULT),
- LintId::of(write::PRINT_STDERR),
- LintId::of(write::PRINT_STDOUT),
- LintId::of(write::USE_DEBUG),
-])
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_style.rs b/src/tools/clippy/clippy_lints/src/lib.register_style.rs
deleted file mode 100644
index 3312f5648..000000000
--- a/src/tools/clippy/clippy_lints/src/lib.register_style.rs
+++ /dev/null
@@ -1,131 +0,0 @@
-// This file was generated by `cargo dev update_lints`.
-// Use that command to update this file and do not edit by hand.
-// Manual edits will be overwritten.
-
-store.register_group(true, "clippy::style", Some("clippy_style"), vec![
- LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS),
- LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS),
- LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON),
- LintId::of(bool_to_int_with_if::BOOL_TO_INT_WITH_IF),
- LintId::of(casts::FN_TO_NUMERIC_CAST),
- LintId::of(casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION),
- LintId::of(collapsible_if::COLLAPSIBLE_ELSE_IF),
- LintId::of(collapsible_if::COLLAPSIBLE_IF),
- LintId::of(comparison_chain::COMPARISON_CHAIN),
- LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT),
- LintId::of(default_instead_of_iter_empty::DEFAULT_INSTEAD_OF_ITER_EMPTY),
- LintId::of(dereference::NEEDLESS_BORROW),
- LintId::of(disallowed_macros::DISALLOWED_MACROS),
- LintId::of(disallowed_methods::DISALLOWED_METHODS),
- LintId::of(disallowed_names::DISALLOWED_NAMES),
- LintId::of(disallowed_types::DISALLOWED_TYPES),
- LintId::of(doc::MISSING_SAFETY_DOC),
- LintId::of(doc::NEEDLESS_DOCTEST_MAIN),
- LintId::of(enum_variants::ENUM_VARIANT_NAMES),
- LintId::of(enum_variants::MODULE_INCEPTION),
- LintId::of(eta_reduction::REDUNDANT_CLOSURE),
- LintId::of(float_literal::EXCESSIVE_PRECISION),
- LintId::of(from_over_into::FROM_OVER_INTO),
- LintId::of(from_str_radix_10::FROM_STR_RADIX_10),
- LintId::of(functions::DOUBLE_MUST_USE),
- LintId::of(functions::MUST_USE_UNIT),
- LintId::of(functions::RESULT_UNIT_ERR),
- LintId::of(implicit_saturating_add::IMPLICIT_SATURATING_ADD),
- LintId::of(implicit_saturating_sub::IMPLICIT_SATURATING_SUB),
- LintId::of(inherent_to_string::INHERENT_TO_STRING),
- LintId::of(init_numbered_fields::INIT_NUMBERED_FIELDS),
- LintId::of(len_zero::COMPARISON_TO_EMPTY),
- LintId::of(len_zero::LEN_WITHOUT_IS_EMPTY),
- LintId::of(len_zero::LEN_ZERO),
- LintId::of(literal_representation::INCONSISTENT_DIGIT_GROUPING),
- LintId::of(literal_representation::UNUSUAL_BYTE_GROUPINGS),
- LintId::of(loops::FOR_KV_MAP),
- LintId::of(loops::NEEDLESS_RANGE_LOOP),
- LintId::of(loops::SAME_ITEM_PUSH),
- LintId::of(loops::WHILE_LET_ON_ITERATOR),
- LintId::of(main_recursion::MAIN_RECURSION),
- LintId::of(manual_async_fn::MANUAL_ASYNC_FN),
- LintId::of(manual_bits::MANUAL_BITS),
- LintId::of(manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
- LintId::of(match_result_ok::MATCH_RESULT_OK),
- LintId::of(matches::COLLAPSIBLE_MATCH),
- LintId::of(matches::INFALLIBLE_DESTRUCTURING_MATCH),
- LintId::of(matches::MANUAL_MAP),
- LintId::of(matches::MATCH_LIKE_MATCHES_MACRO),
- LintId::of(matches::MATCH_OVERLAPPING_ARM),
- LintId::of(matches::MATCH_REF_PATS),
- LintId::of(matches::REDUNDANT_PATTERN_MATCHING),
- LintId::of(matches::SINGLE_MATCH),
- LintId::of(mem_replace::MEM_REPLACE_OPTION_WITH_NONE),
- LintId::of(mem_replace::MEM_REPLACE_WITH_DEFAULT),
- LintId::of(methods::BYTES_NTH),
- LintId::of(methods::CHARS_LAST_CMP),
- LintId::of(methods::CHARS_NEXT_CMP),
- LintId::of(methods::ERR_EXPECT),
- LintId::of(methods::GET_FIRST),
- LintId::of(methods::INTO_ITER_ON_REF),
- LintId::of(methods::IS_DIGIT_ASCII_RADIX),
- LintId::of(methods::ITER_CLONED_COLLECT),
- LintId::of(methods::ITER_NEXT_SLICE),
- LintId::of(methods::ITER_NTH_ZERO),
- LintId::of(methods::ITER_SKIP_NEXT),
- LintId::of(methods::MANUAL_SATURATING_ARITHMETIC),
- LintId::of(methods::MAP_CLONE),
- LintId::of(methods::MAP_COLLECT_RESULT_UNIT),
- LintId::of(methods::MUT_MUTEX_LOCK),
- LintId::of(methods::NEW_RET_NO_SELF),
- LintId::of(methods::OBFUSCATED_IF_ELSE),
- LintId::of(methods::OK_EXPECT),
- LintId::of(methods::OPTION_MAP_OR_NONE),
- LintId::of(methods::RESULT_MAP_OR_INTO_OPTION),
- LintId::of(methods::SHOULD_IMPLEMENT_TRAIT),
- LintId::of(methods::SINGLE_CHAR_ADD_STR),
- LintId::of(methods::STRING_EXTEND_CHARS),
- LintId::of(methods::UNNECESSARY_FOLD),
- LintId::of(methods::UNNECESSARY_LAZY_EVALUATIONS),
- LintId::of(methods::UNWRAP_OR_ELSE_DEFAULT),
- LintId::of(methods::WRONG_SELF_CONVENTION),
- LintId::of(misc::TOPLEVEL_REF_ARG),
- LintId::of(misc::ZERO_PTR),
- LintId::of(misc_early::BUILTIN_TYPE_SHADOW),
- LintId::of(misc_early::DOUBLE_NEG),
- LintId::of(misc_early::DUPLICATE_UNDERSCORE_ARGUMENT),
- LintId::of(misc_early::MIXED_CASE_HEX_LITERALS),
- LintId::of(misc_early::REDUNDANT_PATTERN),
- LintId::of(mut_reference::UNNECESSARY_MUT_PASSED),
- LintId::of(needless_late_init::NEEDLESS_LATE_INIT),
- LintId::of(needless_parens_on_range_literals::NEEDLESS_PARENS_ON_RANGE_LITERALS),
- LintId::of(neg_multiply::NEG_MULTIPLY),
- LintId::of(new_without_default::NEW_WITHOUT_DEFAULT),
- LintId::of(non_copy_const::BORROW_INTERIOR_MUTABLE_CONST),
- LintId::of(non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST),
- LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS),
- LintId::of(operators::ASSIGN_OP_PATTERN),
- LintId::of(operators::OP_REF),
- LintId::of(operators::PTR_EQ),
- LintId::of(partialeq_to_none::PARTIALEQ_TO_NONE),
- LintId::of(ptr::CMP_NULL),
- LintId::of(ptr::PTR_ARG),
- LintId::of(question_mark::QUESTION_MARK),
- LintId::of(ranges::MANUAL_RANGE_CONTAINS),
- LintId::of(redundant_field_names::REDUNDANT_FIELD_NAMES),
- LintId::of(redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES),
- LintId::of(returns::LET_AND_RETURN),
- LintId::of(returns::NEEDLESS_RETURN),
- LintId::of(self_named_constructors::SELF_NAMED_CONSTRUCTORS),
- LintId::of(single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
- LintId::of(strings::TRIM_SPLIT_WHITESPACE),
- LintId::of(tabs_in_doc_comments::TABS_IN_DOC_COMMENTS),
- LintId::of(to_digit_is_some::TO_DIGIT_IS_SOME),
- LintId::of(unit_types::LET_UNIT_VALUE),
- LintId::of(unnecessary_owned_empty_strings::UNNECESSARY_OWNED_EMPTY_STRINGS),
- LintId::of(unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME),
- LintId::of(unused_unit::UNUSED_UNIT),
- LintId::of(upper_case_acronyms::UPPER_CASE_ACRONYMS),
- LintId::of(write::PRINTLN_EMPTY_STRING),
- LintId::of(write::PRINT_LITERAL),
- LintId::of(write::PRINT_WITH_NEWLINE),
- LintId::of(write::WRITELN_EMPTY_STRING),
- LintId::of(write::WRITE_LITERAL),
- LintId::of(write::WRITE_WITH_NEWLINE),
-])
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs b/src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs
deleted file mode 100644
index b70c4bb73..000000000
--- a/src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs
+++ /dev/null
@@ -1,38 +0,0 @@
-// This file was generated by `cargo dev update_lints`.
-// Use that command to update this file and do not edit by hand.
-// Manual edits will be overwritten.
-
-store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec![
- LintId::of(almost_complete_letter_range::ALMOST_COMPLETE_LETTER_RANGE),
- LintId::of(attrs::BLANKET_CLIPPY_RESTRICTION_LINTS),
- LintId::of(await_holding_invalid::AWAIT_HOLDING_INVALID_TYPE),
- LintId::of(await_holding_invalid::AWAIT_HOLDING_LOCK),
- LintId::of(await_holding_invalid::AWAIT_HOLDING_REFCELL_REF),
- LintId::of(casts::CAST_ABS_TO_UNSIGNED),
- LintId::of(casts::CAST_ENUM_CONSTRUCTOR),
- LintId::of(casts::CAST_ENUM_TRUNCATION),
- LintId::of(casts::CAST_NAN_TO_INT),
- LintId::of(casts::CAST_SLICE_FROM_RAW_PARTS),
- LintId::of(crate_in_macro_def::CRATE_IN_MACRO_DEF),
- LintId::of(drop_forget_ref::DROP_NON_DROP),
- LintId::of(drop_forget_ref::FORGET_NON_DROP),
- LintId::of(duplicate_mod::DUPLICATE_MOD),
- LintId::of(format_impl::PRINT_IN_FORMAT_IMPL),
- LintId::of(formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING),
- LintId::of(formatting::SUSPICIOUS_ELSE_FORMATTING),
- LintId::of(formatting::SUSPICIOUS_UNARY_OP_FORMATTING),
- LintId::of(loops::EMPTY_LOOP),
- LintId::of(loops::MUT_RANGE_BOUND),
- LintId::of(methods::NO_EFFECT_REPLACE),
- LintId::of(methods::SUSPICIOUS_MAP),
- LintId::of(methods::SUSPICIOUS_TO_OWNED),
- LintId::of(multi_assignments::MULTI_ASSIGNMENTS),
- LintId::of(mut_key::MUTABLE_KEY_TYPE),
- LintId::of(octal_escapes::OCTAL_ESCAPES),
- LintId::of(operators::FLOAT_EQUALITY_WITHOUT_ABS),
- LintId::of(operators::MISREFACTORED_ASSIGN_OP),
- LintId::of(rc_clone_in_vec_init::RC_CLONE_IN_VEC_INIT),
- LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
- LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
- LintId::of(swap_ptr_to_ref::SWAP_PTR_TO_REF),
-])
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 1307096b2..7b17d8a15 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -26,14 +26,13 @@
extern crate rustc_arena;
extern crate rustc_ast;
extern crate rustc_ast_pretty;
-extern crate rustc_attr;
extern crate rustc_data_structures;
extern crate rustc_driver;
extern crate rustc_errors;
extern crate rustc_hir;
extern crate rustc_hir_analysis;
-extern crate rustc_hir_typeck;
extern crate rustc_hir_pretty;
+extern crate rustc_hir_typeck;
extern crate rustc_index;
extern crate rustc_infer;
extern crate rustc_lexer;
@@ -47,122 +46,23 @@ extern crate rustc_trait_selection;
#[macro_use]
extern crate clippy_utils;
+#[macro_use]
+extern crate declare_clippy_lint;
-use clippy_utils::parse_msrv;
+use std::io;
+use std::path::PathBuf;
+
+use clippy_utils::msrvs::Msrv;
use rustc_data_structures::fx::FxHashSet;
-use rustc_lint::LintId;
-use rustc_semver::RustcVersion;
+use rustc_lint::{Lint, LintId};
use rustc_session::Session;
-/// Macro used to declare a Clippy lint.
-///
-/// Every lint declaration consists of 4 parts:
-///
-/// 1. The documentation, which is used for the website
-/// 2. The `LINT_NAME`. See [lint naming][lint_naming] on lint naming conventions.
-/// 3. The `lint_level`, which is a mapping from *one* of our lint groups to `Allow`, `Warn` or
-/// `Deny`. The lint level here has nothing to do with what lint groups the lint is a part of.
-/// 4. The `description` that contains a short explanation on what's wrong with code where the
-/// lint is triggered.
-///
-/// Currently the categories `style`, `correctness`, `suspicious`, `complexity` and `perf` are
-/// enabled by default. As said in the README.md of this repository, if the lint level mapping
-/// changes, please update README.md.
-///
-/// # Example
-///
-/// ```
-/// #![feature(rustc_private)]
-/// extern crate rustc_session;
-/// use rustc_session::declare_tool_lint;
-/// use clippy_lints::declare_clippy_lint;
-///
-/// declare_clippy_lint! {
-/// /// ### What it does
-/// /// Checks for ... (describe what the lint matches).
-/// ///
-/// /// ### Why is this bad?
-/// /// Supply the reason for linting the code.
-/// ///
-/// /// ### Example
-/// /// ```rust
-/// /// Insert a short example of code that triggers the lint
-/// /// ```
-/// ///
-/// /// Use instead:
-/// /// ```rust
-/// /// Insert a short example of improved code that doesn't trigger the lint
-/// /// ```
-/// pub LINT_NAME,
-/// pedantic,
-/// "description"
-/// }
-/// ```
-/// [lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints
-#[macro_export]
-macro_rules! declare_clippy_lint {
- { $(#[$attr:meta])* pub $name:tt, style, $description:tt } => {
- declare_tool_lint! {
- $(#[$attr])* pub clippy::$name, Warn, $description, report_in_external_macro: true
- }
- };
- { $(#[$attr:meta])* pub $name:tt, correctness, $description:tt } => {
- declare_tool_lint! {
- $(#[$attr])* pub clippy::$name, Deny, $description, report_in_external_macro: true
- }
- };
- { $(#[$attr:meta])* pub $name:tt, suspicious, $description:tt } => {
- declare_tool_lint! {
- $(#[$attr])* pub clippy::$name, Warn, $description, report_in_external_macro: true
- }
- };
- { $(#[$attr:meta])* pub $name:tt, complexity, $description:tt } => {
- declare_tool_lint! {
- $(#[$attr])* pub clippy::$name, Warn, $description, report_in_external_macro: true
- }
- };
- { $(#[$attr:meta])* pub $name:tt, perf, $description:tt } => {
- declare_tool_lint! {
- $(#[$attr])* pub clippy::$name, Warn, $description, report_in_external_macro: true
- }
- };
- { $(#[$attr:meta])* pub $name:tt, pedantic, $description:tt } => {
- declare_tool_lint! {
- $(#[$attr])* pub clippy::$name, Allow, $description, report_in_external_macro: true
- }
- };
- { $(#[$attr:meta])* pub $name:tt, restriction, $description:tt } => {
- declare_tool_lint! {
- $(#[$attr])* pub clippy::$name, Allow, $description, report_in_external_macro: true
- }
- };
- { $(#[$attr:meta])* pub $name:tt, cargo, $description:tt } => {
- declare_tool_lint! {
- $(#[$attr])* pub clippy::$name, Allow, $description, report_in_external_macro: true
- }
- };
- { $(#[$attr:meta])* pub $name:tt, nursery, $description:tt } => {
- declare_tool_lint! {
- $(#[$attr])* pub clippy::$name, Allow, $description, report_in_external_macro: true
- }
- };
- { $(#[$attr:meta])* pub $name:tt, internal, $description:tt } => {
- declare_tool_lint! {
- $(#[$attr])* pub clippy::$name, Allow, $description, report_in_external_macro: true
- }
- };
- { $(#[$attr:meta])* pub $name:tt, internal_warn, $description:tt } => {
- declare_tool_lint! {
- $(#[$attr])* pub clippy::$name, Warn, $description, report_in_external_macro: true
- }
- };
-}
-
#[cfg(feature = "internal")]
pub mod deprecated_lints;
#[cfg_attr(feature = "internal", allow(clippy::missing_clippy_version_attribute))]
mod utils;
+mod declared_lints;
mod renamed_lints;
// begin lints modules, do not remove this comment, it’s used in `update_lints`
@@ -231,6 +131,7 @@ mod format_impl;
mod format_push_string;
mod formatting;
mod from_over_into;
+mod from_raw_with_void_ptr;
mod from_str_radix_10;
mod functions;
mod future_not_send;
@@ -249,6 +150,7 @@ mod inherent_impl;
mod inherent_to_string;
mod init_numbered_fields;
mod inline_fn_without_body;
+mod instant_subtraction;
mod int_plus_one;
mod invalid_upcast_comparisons;
mod invalid_utf8_in_unchecked;
@@ -270,7 +172,8 @@ mod manual_assert;
mod manual_async_fn;
mod manual_bits;
mod manual_clamp;
-mod manual_instant_elapsed;
+mod manual_is_ascii_check;
+mod manual_let_else;
mod manual_non_exhaustive;
mod manual_rem_euclid;
mod manual_retain;
@@ -365,6 +268,7 @@ mod strings;
mod strlen_on_c_strings;
mod suspicious_operation_groupings;
mod suspicious_trait_impl;
+mod suspicious_xor_used_as_pow;
mod swap;
mod swap_ptr_to_ref;
mod tabs_in_doc_comments;
@@ -404,8 +308,8 @@ mod zero_div_zero;
mod zero_sized_map_values;
// end lints modules, do not remove this comment, it’s used in `update_lints`
-pub use crate::utils::conf::Conf;
use crate::utils::conf::{format_error, TryConf};
+pub use crate::utils::conf::{lookup_conf_file, Conf};
/// Register all pre expansion lints
///
@@ -417,53 +321,15 @@ use crate::utils::conf::{format_error, TryConf};
/// Used in `./src/driver.rs`.
pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore, sess: &Session, conf: &Conf) {
// NOTE: Do not add any more pre-expansion passes. These should be removed eventually.
+ let msrv = Msrv::read(&conf.msrv, sess);
+ let msrv = move || msrv.clone();
- let msrv = conf.msrv.as_ref().and_then(|s| {
- parse_msrv(s, None, None).or_else(|| {
- sess.err(format!(
- "error reading Clippy's configuration file. `{s}` is not a valid Rust version"
- ));
- None
- })
- });
-
- store.register_pre_expansion_pass(move || Box::new(attrs::EarlyAttributes { msrv }));
-}
-
-fn read_msrv(conf: &Conf, sess: &Session) -> Option<RustcVersion> {
- let cargo_msrv = std::env::var("CARGO_PKG_RUST_VERSION")
- .ok()
- .and_then(|v| parse_msrv(&v, None, None));
- let clippy_msrv = conf.msrv.as_ref().and_then(|s| {
- parse_msrv(s, None, None).or_else(|| {
- sess.err(format!(
- "error reading Clippy's configuration file. `{s}` is not a valid Rust version"
- ));
- None
- })
- });
-
- if let Some(cargo_msrv) = cargo_msrv {
- if let Some(clippy_msrv) = clippy_msrv {
- // if both files have an msrv, let's compare them and emit a warning if they differ
- if clippy_msrv != cargo_msrv {
- sess.warn(format!(
- "the MSRV in `clippy.toml` and `Cargo.toml` differ; using `{clippy_msrv}` from `clippy.toml`"
- ));
- }
-
- Some(clippy_msrv)
- } else {
- Some(cargo_msrv)
- }
- } else {
- clippy_msrv
- }
+ store.register_pre_expansion_pass(move || Box::new(attrs::EarlyAttributes { msrv: msrv() }));
}
#[doc(hidden)]
-pub fn read_conf(sess: &Session) -> Conf {
- let file_name = match utils::conf::lookup_conf_file() {
+pub fn read_conf(sess: &Session, path: &io::Result<Option<PathBuf>>) -> Conf {
+ let file_name = match path {
Ok(Some(path)) => path,
Ok(None) => return Conf::default(),
Err(error) => {
@@ -473,7 +339,7 @@ pub fn read_conf(sess: &Session) -> Conf {
},
};
- let TryConf { conf, errors, warnings } = utils::conf::read(&file_name);
+ let TryConf { conf, errors, warnings } = utils::conf::read(file_name);
// all conf errors are non-fatal, we just use the default conf in case of error
for error in errors {
sess.err(format!(
@@ -495,31 +361,121 @@ pub fn read_conf(sess: &Session) -> Conf {
conf
}
+#[derive(Default)]
+struct RegistrationGroups {
+ all: Vec<LintId>,
+ cargo: Vec<LintId>,
+ complexity: Vec<LintId>,
+ correctness: Vec<LintId>,
+ nursery: Vec<LintId>,
+ pedantic: Vec<LintId>,
+ perf: Vec<LintId>,
+ restriction: Vec<LintId>,
+ style: Vec<LintId>,
+ suspicious: Vec<LintId>,
+ #[cfg(feature = "internal")]
+ internal: Vec<LintId>,
+}
+
+impl RegistrationGroups {
+ #[rustfmt::skip]
+ fn register(self, store: &mut rustc_lint::LintStore) {
+ store.register_group(true, "clippy::all", Some("clippy_all"), self.all);
+ store.register_group(true, "clippy::cargo", Some("clippy_cargo"), self.cargo);
+ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), self.complexity);
+ store.register_group(true, "clippy::correctness", Some("clippy_correctness"), self.correctness);
+ store.register_group(true, "clippy::nursery", Some("clippy_nursery"), self.nursery);
+ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), self.pedantic);
+ store.register_group(true, "clippy::perf", Some("clippy_perf"), self.perf);
+ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), self.restriction);
+ store.register_group(true, "clippy::style", Some("clippy_style"), self.style);
+ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), self.suspicious);
+ #[cfg(feature = "internal")]
+ store.register_group(true, "clippy::internal", Some("clippy_internal"), self.internal);
+ }
+}
+
+#[derive(Copy, Clone)]
+pub(crate) enum LintCategory {
+ Cargo,
+ Complexity,
+ Correctness,
+ Nursery,
+ Pedantic,
+ Perf,
+ Restriction,
+ Style,
+ Suspicious,
+ #[cfg(feature = "internal")]
+ Internal,
+}
+#[allow(clippy::enum_glob_use)]
+use LintCategory::*;
+
+impl LintCategory {
+ fn is_all(self) -> bool {
+ matches!(self, Correctness | Suspicious | Style | Complexity | Perf)
+ }
+
+ fn group(self, groups: &mut RegistrationGroups) -> &mut Vec<LintId> {
+ match self {
+ Cargo => &mut groups.cargo,
+ Complexity => &mut groups.complexity,
+ Correctness => &mut groups.correctness,
+ Nursery => &mut groups.nursery,
+ Pedantic => &mut groups.pedantic,
+ Perf => &mut groups.perf,
+ Restriction => &mut groups.restriction,
+ Style => &mut groups.style,
+ Suspicious => &mut groups.suspicious,
+ #[cfg(feature = "internal")]
+ Internal => &mut groups.internal,
+ }
+ }
+}
+
+pub(crate) struct LintInfo {
+ /// Double reference to maintain pointer equality
+ lint: &'static &'static Lint,
+ category: LintCategory,
+ explanation: &'static str,
+}
+
+pub fn explain(name: &str) {
+ let target = format!("clippy::{}", name.to_ascii_uppercase());
+ match declared_lints::LINTS.iter().find(|info| info.lint.name == target) {
+ Some(info) => print!("{}", info.explanation),
+ None => println!("unknown lint: {name}"),
+ }
+}
+
+fn register_categories(store: &mut rustc_lint::LintStore) {
+ let mut groups = RegistrationGroups::default();
+
+ for LintInfo { lint, category, .. } in declared_lints::LINTS {
+ if category.is_all() {
+ groups.all.push(LintId::of(lint));
+ }
+
+ category.group(&mut groups).push(LintId::of(lint));
+ }
+
+ let lints: Vec<&'static Lint> = declared_lints::LINTS.iter().map(|info| *info.lint).collect();
+
+ store.register_lints(&lints);
+ groups.register(store);
+}
+
/// Register all lints and lint groups with the rustc plugin registry
///
/// Used in `./src/driver.rs`.
#[expect(clippy::too_many_lines)]
pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &Conf) {
register_removed_non_tool_lints(store);
+ register_categories(store);
include!("lib.deprecated.rs");
- include!("lib.register_lints.rs");
- include!("lib.register_restriction.rs");
- include!("lib.register_pedantic.rs");
-
- #[cfg(feature = "internal")]
- include!("lib.register_internal.rs");
-
- include!("lib.register_all.rs");
- include!("lib.register_style.rs");
- include!("lib.register_complexity.rs");
- include!("lib.register_correctness.rs");
- include!("lib.register_suspicious.rs");
- include!("lib.register_perf.rs");
- include!("lib.register_cargo.rs");
- include!("lib.register_nursery.rs");
-
#[cfg(feature = "internal")]
{
if std::env::var("ENABLE_METADATA_COLLECTION").eq(&Ok("1".to_string())) {
@@ -600,41 +556,44 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|_| Box::new(non_octal_unix_permissions::NonOctalUnixPermissions));
store.register_early_pass(|| Box::new(unnecessary_self_imports::UnnecessarySelfImports));
- let msrv = read_msrv(conf, sess);
+ let msrv = Msrv::read(&conf.msrv, sess);
+ let msrv = move || msrv.clone();
let avoid_breaking_exported_api = conf.avoid_breaking_exported_api;
let allow_expect_in_tests = conf.allow_expect_in_tests;
let allow_unwrap_in_tests = conf.allow_unwrap_in_tests;
- store.register_late_pass(move |_| Box::new(approx_const::ApproxConstant::new(msrv)));
+ store.register_late_pass(move |_| Box::new(approx_const::ApproxConstant::new(msrv())));
store.register_late_pass(move |_| {
Box::new(methods::Methods::new(
avoid_breaking_exported_api,
- msrv,
+ msrv(),
allow_expect_in_tests,
allow_unwrap_in_tests,
))
});
- store.register_late_pass(move |_| Box::new(matches::Matches::new(msrv)));
- store.register_early_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustiveStruct::new(msrv)));
- store.register_late_pass(move |_| Box::new(manual_non_exhaustive::ManualNonExhaustiveEnum::new(msrv)));
- store.register_late_pass(move |_| Box::new(manual_strip::ManualStrip::new(msrv)));
- store.register_early_pass(move || Box::new(redundant_static_lifetimes::RedundantStaticLifetimes::new(msrv)));
- store.register_early_pass(move || Box::new(redundant_field_names::RedundantFieldNames::new(msrv)));
- store.register_late_pass(move |_| Box::new(checked_conversions::CheckedConversions::new(msrv)));
- store.register_late_pass(move |_| Box::new(mem_replace::MemReplace::new(msrv)));
- store.register_late_pass(move |_| Box::new(ranges::Ranges::new(msrv)));
- store.register_late_pass(move |_| Box::new(from_over_into::FromOverInto::new(msrv)));
- store.register_late_pass(move |_| Box::new(use_self::UseSelf::new(msrv)));
- store.register_late_pass(move |_| Box::new(missing_const_for_fn::MissingConstForFn::new(msrv)));
+ store.register_late_pass(move |_| Box::new(matches::Matches::new(msrv())));
+ let matches_for_let_else = conf.matches_for_let_else;
+ store.register_late_pass(move |_| Box::new(manual_let_else::ManualLetElse::new(msrv(), matches_for_let_else)));
+ store.register_early_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustiveStruct::new(msrv())));
+ store.register_late_pass(move |_| Box::new(manual_non_exhaustive::ManualNonExhaustiveEnum::new(msrv())));
+ store.register_late_pass(move |_| Box::new(manual_strip::ManualStrip::new(msrv())));
+ store.register_early_pass(move || Box::new(redundant_static_lifetimes::RedundantStaticLifetimes::new(msrv())));
+ store.register_early_pass(move || Box::new(redundant_field_names::RedundantFieldNames::new(msrv())));
+ store.register_late_pass(move |_| Box::new(checked_conversions::CheckedConversions::new(msrv())));
+ store.register_late_pass(move |_| Box::new(mem_replace::MemReplace::new(msrv())));
+ store.register_late_pass(move |_| Box::new(ranges::Ranges::new(msrv())));
+ store.register_late_pass(move |_| Box::new(from_over_into::FromOverInto::new(msrv())));
+ store.register_late_pass(move |_| Box::new(use_self::UseSelf::new(msrv())));
+ store.register_late_pass(move |_| Box::new(missing_const_for_fn::MissingConstForFn::new(msrv())));
store.register_late_pass(move |_| Box::new(needless_question_mark::NeedlessQuestionMark));
- store.register_late_pass(move |_| Box::new(casts::Casts::new(msrv)));
- store.register_early_pass(move || Box::new(unnested_or_patterns::UnnestedOrPatterns::new(msrv)));
+ store.register_late_pass(move |_| Box::new(casts::Casts::new(msrv())));
+ store.register_early_pass(move || Box::new(unnested_or_patterns::UnnestedOrPatterns::new(msrv())));
store.register_late_pass(|_| Box::new(size_of_in_element_count::SizeOfInElementCount));
store.register_late_pass(|_| Box::new(same_name_method::SameNameMethod));
let max_suggested_slice_pattern_length = conf.max_suggested_slice_pattern_length;
store.register_late_pass(move |_| {
Box::new(index_refutable_slice::IndexRefutableSlice::new(
max_suggested_slice_pattern_length,
- msrv,
+ msrv(),
))
});
store.register_late_pass(|_| Box::<shadow::Shadow>::default());
@@ -651,7 +610,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|_| Box::new(borrow_deref_ref::BorrowDerefRef));
store.register_late_pass(|_| Box::new(no_effect::NoEffect));
store.register_late_pass(|_| Box::new(temporary_assignment::TemporaryAssignment));
- store.register_late_pass(move |_| Box::new(transmute::Transmute::new(msrv)));
+ store.register_late_pass(move |_| Box::new(transmute::Transmute::new(msrv())));
let cognitive_complexity_threshold = conf.cognitive_complexity_threshold;
store.register_late_pass(move |_| {
Box::new(cognitive_complexity::CognitiveComplexity::new(
@@ -735,7 +694,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
let max_trait_bounds = conf.max_trait_bounds;
store.register_late_pass(move |_| Box::new(trait_bounds::TraitBounds::new(max_trait_bounds)));
store.register_late_pass(|_| Box::new(comparison_chain::ComparisonChain));
- store.register_late_pass(|_| Box::new(mut_key::MutableKeyType));
+ let ignore_interior_mutability = conf.ignore_interior_mutability.clone();
+ store.register_late_pass(move |_| Box::new(mut_key::MutableKeyType::new(ignore_interior_mutability.clone())));
store.register_early_pass(|| Box::new(reference::DerefAddrOf));
store.register_early_pass(|| Box::new(double_parens::DoubleParens));
store.register_late_pass(|_| Box::new(format_impl::FormatImpl::new()));
@@ -794,10 +754,10 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|_| Box::new(floating_point_arithmetic::FloatingPointArithmetic));
store.register_early_pass(|| Box::new(as_conversions::AsConversions));
store.register_late_pass(|_| Box::new(let_underscore::LetUnderscore));
- store.register_early_pass(|| Box::new(single_component_path_imports::SingleComponentPathImports));
+ store.register_early_pass(|| Box::<single_component_path_imports::SingleComponentPathImports>::default());
let max_fn_params_bools = conf.max_fn_params_bools;
let max_struct_bools = conf.max_struct_bools;
- store.register_early_pass(move || {
+ store.register_late_pass(move |_| {
Box::new(excessive_bools::ExcessiveBools::new(
max_struct_bools,
max_fn_params_bools,
@@ -808,7 +768,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(move |_| Box::new(wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports)));
store.register_late_pass(|_| Box::<redundant_pub_crate::RedundantPubCrate>::default());
store.register_late_pass(|_| Box::new(unnamed_address::UnnamedAddress));
- store.register_late_pass(move |_| Box::new(dereference::Dereferencing::new(msrv)));
+ store.register_late_pass(move |_| Box::new(dereference::Dereferencing::new(msrv())));
store.register_late_pass(|_| Box::new(option_if_let_else::OptionIfLetElse));
store.register_late_pass(|_| Box::new(future_not_send::FutureNotSend));
store.register_late_pass(|_| Box::new(if_let_mutex::IfLetMutex));
@@ -842,7 +802,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|_| Box::<vec_init_then_push::VecInitThenPush>::default());
store.register_late_pass(|_| Box::new(redundant_slicing::RedundantSlicing));
store.register_late_pass(|_| Box::new(from_str_radix_10::FromStrRadix10));
- store.register_late_pass(move |_| Box::new(if_then_some_else_none::IfThenSomeElseNone::new(msrv)));
+ store.register_late_pass(move |_| Box::new(if_then_some_else_none::IfThenSomeElseNone::new(msrv())));
store.register_late_pass(|_| Box::new(bool_assert_comparison::BoolAssertComparison));
store.register_early_pass(move || Box::new(module_style::ModStyle));
store.register_late_pass(|_| Box::new(unused_async::UnusedAsync));
@@ -867,25 +827,27 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
))
});
store.register_late_pass(move |_| Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks));
- store.register_late_pass(move |_| Box::new(format_args::FormatArgs::new(msrv)));
+ let allow_mixed_uninlined = conf.allow_mixed_uninlined_format_args;
+ store.register_late_pass(move |_| Box::new(format_args::FormatArgs::new(msrv(), allow_mixed_uninlined)));
store.register_late_pass(|_| Box::new(trailing_empty_array::TrailingEmptyArray));
store.register_early_pass(|| Box::new(octal_escapes::OctalEscapes));
store.register_late_pass(|_| Box::new(needless_late_init::NeedlessLateInit));
store.register_late_pass(|_| Box::new(return_self_not_must_use::ReturnSelfNotMustUse));
store.register_late_pass(|_| Box::new(init_numbered_fields::NumberedFields));
store.register_early_pass(|| Box::new(single_char_lifetime_names::SingleCharLifetimeNames));
- store.register_late_pass(move |_| Box::new(manual_bits::ManualBits::new(msrv)));
+ store.register_late_pass(move |_| Box::new(manual_bits::ManualBits::new(msrv())));
store.register_late_pass(|_| Box::new(default_union_representation::DefaultUnionRepresentation));
store.register_late_pass(|_| Box::<only_used_in_recursion::OnlyUsedInRecursion>::default());
let allow_dbg_in_tests = conf.allow_dbg_in_tests;
store.register_late_pass(move |_| Box::new(dbg_macro::DbgMacro::new(allow_dbg_in_tests)));
+ let allow_print_in_tests = conf.allow_print_in_tests;
+ store.register_late_pass(move |_| Box::new(write::Write::new(allow_print_in_tests)));
let cargo_ignore_publish = conf.cargo_ignore_publish;
store.register_late_pass(move |_| {
Box::new(cargo::Cargo {
ignore_publish: cargo_ignore_publish,
})
});
- store.register_late_pass(|_| Box::<write::Write>::default());
store.register_early_pass(|| Box::new(crate_in_macro_def::CrateInMacroDef));
store.register_early_pass(|| Box::new(empty_structs_with_brackets::EmptyStructsWithBrackets));
store.register_late_pass(|_| Box::new(unnecessary_owned_empty_strings::UnnecessaryOwnedEmptyStrings));
@@ -897,20 +859,20 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|_| Box::new(rc_clone_in_vec_init::RcCloneInVecInit));
store.register_early_pass(|| Box::<duplicate_mod::DuplicateMod>::default());
store.register_early_pass(|| Box::new(unused_rounding::UnusedRounding));
- store.register_early_pass(move || Box::new(almost_complete_letter_range::AlmostCompleteLetterRange::new(msrv)));
+ store.register_early_pass(move || Box::new(almost_complete_letter_range::AlmostCompleteLetterRange::new(msrv())));
store.register_late_pass(|_| Box::new(swap_ptr_to_ref::SwapPtrToRef));
store.register_late_pass(|_| Box::new(mismatching_type_param_order::TypeParamMismatch));
store.register_late_pass(|_| Box::new(read_zero_byte_vec::ReadZeroByteVec));
store.register_late_pass(|_| Box::new(default_instead_of_iter_empty::DefaultIterEmpty));
- store.register_late_pass(move |_| Box::new(manual_rem_euclid::ManualRemEuclid::new(msrv)));
- store.register_late_pass(move |_| Box::new(manual_retain::ManualRetain::new(msrv)));
+ store.register_late_pass(move |_| Box::new(manual_rem_euclid::ManualRemEuclid::new(msrv())));
+ store.register_late_pass(move |_| Box::new(manual_retain::ManualRetain::new(msrv())));
let verbose_bit_mask_threshold = conf.verbose_bit_mask_threshold;
store.register_late_pass(move |_| Box::new(operators::Operators::new(verbose_bit_mask_threshold)));
store.register_late_pass(|_| Box::new(invalid_utf8_in_unchecked::InvalidUtf8InUnchecked));
store.register_late_pass(|_| Box::<std_instead_of_core::StdReexports>::default());
- store.register_late_pass(|_| Box::new(manual_instant_elapsed::ManualInstantElapsed));
+ store.register_late_pass(move |_| Box::new(instant_subtraction::InstantSubtraction::new(msrv())));
store.register_late_pass(|_| Box::new(partialeq_to_none::PartialeqToNone));
- store.register_late_pass(move |_| Box::new(manual_clamp::ManualClamp::new(msrv)));
+ store.register_late_pass(move |_| Box::new(manual_clamp::ManualClamp::new(msrv())));
store.register_late_pass(|_| Box::new(manual_string_new::ManualStringNew));
store.register_late_pass(|_| Box::new(unused_peekable::UnusedPeekable));
store.register_early_pass(|| Box::new(multi_assignments::MultiAssignments));
@@ -919,6 +881,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|_| Box::new(implicit_saturating_add::ImplicitSaturatingAdd));
store.register_early_pass(|| Box::new(partial_pub_fields::PartialPubFields));
store.register_late_pass(|_| Box::new(missing_trait_methods::MissingTraitMethods));
+ store.register_late_pass(|_| Box::new(from_raw_with_void_ptr::FromRawWithVoidPtr));
+ store.register_late_pass(|_| Box::new(suspicious_xor_used_as_pow::ConfusingXorAndPow));
+ store.register_late_pass(move |_| Box::new(manual_is_ascii_check::ManualIsAsciiCheck::new(msrv())));
// 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 3bf2d7e4e..7cf1a6b80 100644
--- a/src/tools/clippy/clippy_lints/src/lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs
@@ -1,15 +1,16 @@
-use clippy_utils::diagnostics::span_lint;
+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_hir::intravisit::nested_filter::{self as hir_nested_filter, NestedFilter};
use rustc_hir::intravisit::{
- walk_fn_decl, walk_generic_param, walk_generics, walk_impl_item_ref, walk_item, walk_param_bound,
+ walk_fn_decl, walk_generic_arg, 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, LangItem, Lifetime, LifetimeName, ParamName, PolyTraitRef, PredicateOrigin, TraitFn,
+ ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, LifetimeParamKind, PolyTraitRef, PredicateOrigin, TraitFn,
TraitItem, TraitItemKind, Ty, TyKind, WherePredicate,
};
use rustc_lint::{LateContext, LateLintPass};
@@ -151,6 +152,7 @@ fn check_fn_inner<'tcx>(
.params
.iter()
.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 pred.origin == PredicateOrigin::WhereClause {
@@ -178,7 +180,7 @@ fn check_fn_inner<'tcx>(
_ => None,
});
for bound in lifetimes {
- if bound.name != LifetimeName::Static && !bound.is_elided() {
+ if !bound.is_static() && !bound.is_elided() {
return;
}
}
@@ -187,15 +189,30 @@ fn check_fn_inner<'tcx>(
}
}
}
- if could_use_elision(cx, decl, body, trait_sig, generics.params) {
- span_lint(
+
+ if let Some(elidable_lts) = could_use_elision(cx, decl, body, trait_sig, generics.params) {
+ 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())
+ .map(|ident| ident.to_string())
+ .collect::<Vec<_>>()
+ .join(", ");
+
+ span_lint_and_then(
cx,
NEEDLESS_LIFETIMES,
span.with_hi(decl.output.span().hi()),
- "explicit lifetimes given in parameter types where they could be elided \
- (or replaced with `'_` if needed by type declaration)",
+ &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 report_extra_lifetimes {
self::report_extra_lifetimes(cx, decl, generics);
}
@@ -226,7 +243,7 @@ fn could_use_elision<'tcx>(
body: Option<BodyId>,
trait_sig: Option<&[Ident]>,
named_generics: &'tcx [GenericParam<'_>],
-) -> bool {
+) -> Option<Vec<(LocalDefId, Option<Span>)>> {
// 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
@@ -253,7 +270,7 @@ fn could_use_elision<'tcx>(
}
if input_visitor.abort() || output_visitor.abort() {
- return false;
+ return None;
}
let input_lts = input_visitor.lts;
@@ -261,7 +278,7 @@ fn could_use_elision<'tcx>(
if let Some(trait_sig) = trait_sig {
if explicit_self_type(cx, func, trait_sig.first().copied()) {
- return false;
+ return None;
}
}
@@ -270,7 +287,7 @@ fn could_use_elision<'tcx>(
let first_ident = body.params.first().and_then(|param| param.pat.simple_ident());
if explicit_self_type(cx, func, first_ident) {
- return false;
+ return None;
}
let mut checker = BodyLifetimeChecker {
@@ -278,14 +295,14 @@ fn could_use_elision<'tcx>(
};
checker.visit_expr(body.value);
if checker.lifetimes_used_in_body {
- return false;
+ return None;
}
}
// check for lifetimes from higher scopes
for lt in input_lts.iter().chain(output_lts.iter()) {
if !allowed_lts.contains(lt) {
- return false;
+ return None;
}
}
@@ -301,48 +318,45 @@ fn could_use_elision<'tcx>(
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 false;
+ 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 false;
+ return None;
}
}
}
}
- // no input lifetimes? easy case!
- if input_lts.is_empty() {
- false
- } else if output_lts.is_empty() {
- // no output lifetimes, check distinctness of input lifetimes
+ // A lifetime can be newly elided if:
+ // - It occurs only once among the inputs.
+ // - If there are multiple input lifetimes, then the newly elided lifetime does not occur among the
+ // outputs (because eliding such an lifetime would create an ambiguity).
+ 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(),
+ ))
+ } else {
+ None
+ }
+ })
+ .collect::<Vec<_>>();
- // only unnamed and static, ok
- let unnamed_and_static = input_lts.iter().all(|lt| *lt == RefLt::Unnamed || *lt == RefLt::Static);
- if unnamed_and_static {
- return false;
- }
- // we have no output reference, so we only need all distinct lifetimes
- input_lts.len() == unique_lifetimes(&input_lts)
+ if elidable_lts.is_empty() {
+ None
} else {
- // we have output references, so we need one input reference,
- // and all output lifetimes must be the same
- if unique_lifetimes(&output_lts) > 1 {
- return false;
- }
- if input_lts.len() == 1 {
- match (&input_lts[0], &output_lts[0]) {
- (&RefLt::Named(n1), &RefLt::Named(n2)) if n1 == n2 => true,
- (&RefLt::Named(_), &RefLt::Unnamed) => true,
- _ => false, /* already elided, different named lifetimes
- * or something static going on */
- }
- } else {
- false
- }
+ Some(elidable_lts)
}
}
@@ -358,18 +372,31 @@ fn allowed_lts_from(tcx: TyCtxt<'_>, named_generics: &[GenericParam<'_>]) -> FxH
allowed_lts
}
-/// Number of unique lifetimes in the given vector.
+/// Number of times each named lifetime occurs in the given slice. Returns a vector to preserve
+/// relative order.
#[must_use]
-fn unique_lifetimes(lts: &[RefLt]) -> usize {
- lts.iter().collect::<FxHashSet<_>>().len()
+fn named_lifetime_occurrences(lts: &[RefLt]) -> Vec<(LocalDefId, usize)> {
+ let mut occurrences = Vec::new();
+ for lt in lts {
+ if let &RefLt::Named(curr_def_id) = lt {
+ if let Some(pair) = occurrences
+ .iter_mut()
+ .find(|(prev_def_id, _)| *prev_def_id == curr_def_id)
+ {
+ pair.1 += 1;
+ } else {
+ occurrences.push((curr_def_id, 1));
+ }
+ }
+ }
+ occurrences
}
-const CLOSURE_TRAIT_BOUNDS: [LangItem; 3] = [LangItem::Fn, LangItem::FnMut, LangItem::FnOnce];
-
/// 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>,
unelided_trait_object_lifetime: bool,
}
@@ -379,6 +406,7 @@ 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,
}
@@ -386,17 +414,13 @@ impl<'a, 'tcx> RefVisitor<'a, 'tcx> {
fn record(&mut self, lifetime: &Option<Lifetime>) {
if let Some(ref lt) = *lifetime {
- if lt.name == LifetimeName::Static {
+ if lt.is_static() {
self.lts.push(RefLt::Static);
- } else if let LifetimeName::Param(_, ParamName::Fresh) = lt.name {
+ } else if lt.is_anonymous() {
// Fresh lifetimes generated should be ignored.
self.lts.push(RefLt::Unnamed);
- } else if lt.is_elided() {
- self.lts.push(RefLt::Unnamed);
- } else if let LifetimeName::Param(def_id, _) = lt.name {
+ } else if let LifetimeName::Param(def_id) = lt.res {
self.lts.push(RefLt::Named(def_id));
- } else {
- self.lts.push(RefLt::Unnamed);
}
} else {
self.lts.push(RefLt::Unnamed);
@@ -424,12 +448,8 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> {
fn visit_poly_trait_ref(&mut self, poly_tref: &'tcx PolyTraitRef<'tcx>) {
let trait_ref = &poly_tref.trait_ref;
- if CLOSURE_TRAIT_BOUNDS.iter().any(|&item| {
- self.cx
- .tcx
- .lang_items()
- .require(item)
- .map_or(false, |id| Some(id) == trait_ref.trait_def_id())
+ if let Some(id) = trait_ref.trait_def_id() && lang_items::FN_TRAITS.iter().any(|&item| {
+ self.cx.tcx.lang_items().get(item) == Some(id)
}) {
let mut sub_visitor = RefVisitor::new(self.cx);
sub_visitor.visit_trait_ref(trait_ref);
@@ -448,7 +468,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.name {
+ GenericArg::Lifetime(l) => Some(if let LifetimeName::Param(def_id) = l.res {
RefLt::Named(def_id)
} else {
RefLt::Unnamed
@@ -461,7 +481,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> {
sub_visitor.visit_fn_decl(decl);
self.nested_elision_site_lts.append(&mut sub_visitor.all_lts());
},
- TyKind::TraitObject(bounds, ref lt, _) => {
+ TyKind::TraitObject(bounds, lt, _) => {
if !lt.is_elided() {
self.unelided_trait_object_lifetime = true;
}
@@ -472,6 +492,13 @@ 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
@@ -537,7 +564,7 @@ where
// for lifetimes as parameters of generics
fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) {
- self.map.remove(&lifetime.name.ident().name);
+ self.map.remove(&lifetime.ident.name);
}
fn visit_generic_param(&mut self, param: &'tcx GenericParam<'_>) {
@@ -561,7 +588,9 @@ fn report_extra_lifetimes<'tcx>(cx: &LateContext<'tcx>, func: &'tcx FnDecl<'_>,
.params
.iter()
.filter_map(|par| match par.kind {
- GenericParamKind::Lifetime { .. } => Some((par.name.ident().name, par.span)),
+ GenericParamKind::Lifetime {
+ kind: LifetimeParamKind::Explicit,
+ } => Some((par.name.ident().name, par.span)),
_ => None,
})
.collect();
@@ -586,7 +615,9 @@ fn report_extra_impl_lifetimes<'tcx>(cx: &LateContext<'tcx>, impl_: &'tcx Impl<'
.params
.iter()
.filter_map(|par| match par.kind {
- GenericParamKind::Lifetime { .. } => Some((par.name.ident().name, par.span)),
+ GenericParamKind::Lifetime {
+ kind: LifetimeParamKind::Explicit,
+ } => Some((par.name.ident().name, par.span)),
_ => None,
})
.collect();
@@ -613,7 +644,7 @@ struct BodyLifetimeChecker {
impl<'tcx> Visitor<'tcx> for BodyLifetimeChecker {
// for lifetimes as parameters of generics
fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) {
- if lifetime.name.ident().name != kw::UnderscoreLifetime && lifetime.name.ident().name != kw::StaticLifetime {
+ if !lifetime.is_anonymous() && lifetime.ident.name != kw::StaticLifetime {
self.lifetimes_used_in_body = true;
}
}
diff --git a/src/tools/clippy/clippy_lints/src/literal_representation.rs b/src/tools/clippy/clippy_lints/src/literal_representation.rs
index 25f19b9c6..3a7b7835c 100644
--- a/src/tools/clippy/clippy_lints/src/literal_representation.rs
+++ b/src/tools/clippy/clippy_lints/src/literal_representation.rs
@@ -5,11 +5,13 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::numeric_literal::{NumericLiteral, Radix};
use clippy_utils::source::snippet_opt;
use if_chain::if_chain;
-use rustc_ast::ast::{Expr, ExprKind, Lit, LitKind};
+use rustc_ast::ast::{Expr, ExprKind, LitKind};
+use rustc_ast::token;
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::Span;
use std::iter;
declare_clippy_lint! {
@@ -236,8 +238,8 @@ impl EarlyLintPass for LiteralDigitGrouping {
return;
}
- if let ExprKind::Lit(ref lit) = expr.kind {
- self.check_lit(cx, lit);
+ if let ExprKind::Lit(lit) = expr.kind {
+ self.check_lit(cx, lit, expr.span);
}
}
}
@@ -252,12 +254,13 @@ impl LiteralDigitGrouping {
}
}
- fn check_lit(self, cx: &EarlyContext<'_>, lit: &Lit) {
+ fn check_lit(self, cx: &EarlyContext<'_>, lit: token::Lit, span: Span) {
if_chain! {
- if let Some(src) = snippet_opt(cx, lit.span);
- if let Some(mut num_lit) = NumericLiteral::from_lit(&src, lit);
+ if let Some(src) = snippet_opt(cx, span);
+ if let Ok(lit_kind) = LitKind::from_token_lit(lit);
+ if let Some(mut num_lit) = NumericLiteral::from_lit_kind(&src, &lit_kind);
then {
- if !Self::check_for_mistyped_suffix(cx, lit.span, &mut num_lit) {
+ if !Self::check_for_mistyped_suffix(cx, span, &mut num_lit) {
return;
}
@@ -293,14 +296,14 @@ impl LiteralDigitGrouping {
| WarningType::InconsistentDigitGrouping
| WarningType::UnusualByteGroupings
| WarningType::LargeDigitGroups => {
- !lit.span.from_expansion()
+ !span.from_expansion()
}
WarningType::DecimalRepresentation | WarningType::MistypedLiteralSuffix => {
true
}
};
if should_warn {
- warning_type.display(num_lit.format(), cx, lit.span);
+ warning_type.display(num_lit.format(), cx, span);
}
}
}
@@ -458,8 +461,8 @@ impl EarlyLintPass for DecimalLiteralRepresentation {
return;
}
- if let ExprKind::Lit(ref lit) = expr.kind {
- self.check_lit(cx, lit);
+ if let ExprKind::Lit(lit) = expr.kind {
+ self.check_lit(cx, lit, expr.span);
}
}
}
@@ -469,19 +472,20 @@ impl DecimalLiteralRepresentation {
pub fn new(threshold: u64) -> Self {
Self { threshold }
}
- fn check_lit(self, cx: &EarlyContext<'_>, lit: &Lit) {
+ fn check_lit(self, cx: &EarlyContext<'_>, lit: token::Lit, span: Span) {
// Lint integral literals.
if_chain! {
- if let LitKind::Int(val, _) = lit.kind;
- if let Some(src) = snippet_opt(cx, lit.span);
- if let Some(num_lit) = NumericLiteral::from_lit(&src, lit);
+ if let Ok(lit_kind) = LitKind::from_token_lit(lit);
+ if let LitKind::Int(val, _) = lit_kind;
+ if let Some(src) = snippet_opt(cx, span);
+ if let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit_kind);
if num_lit.radix == Radix::Decimal;
if val >= u128::from(self.threshold);
then {
let hex = format!("{val:#X}");
let num_lit = NumericLiteral::new(&hex, num_lit.suffix, false);
let _ = Self::do_lint(num_lit.integer).map_err(|warning_type| {
- warning_type.display(num_lit.format(), cx, lit.span);
+ warning_type.display(num_lit.format(), cx, span);
});
}
}
diff --git a/src/tools/clippy/clippy_lints/src/loops/mod.rs b/src/tools/clippy/clippy_lints/src/loops/mod.rs
index bcf278d9c..8e52cac43 100644
--- a/src/tools/clippy/clippy_lints/src/loops/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/mod.rs
@@ -9,7 +9,6 @@ mod manual_flatten;
mod manual_memcpy;
mod missing_spin_loop;
mod mut_range_bound;
-mod needless_collect;
mod needless_range_loop;
mod never_loop;
mod same_item_push;
@@ -207,28 +206,6 @@ declare_clippy_lint! {
declare_clippy_lint! {
/// ### What it does
- /// Checks for functions collecting an iterator when collect
- /// is not needed.
- ///
- /// ### Why is this bad?
- /// `collect` causes the allocation of a new data structure,
- /// when this allocation may not be needed.
- ///
- /// ### Example
- /// ```rust
- /// # let iterator = vec![1].into_iter();
- /// let len = iterator.clone().collect::<Vec<_>>().len();
- /// // should be
- /// let len = iterator.count();
- /// ```
- #[clippy::version = "1.30.0"]
- pub NEEDLESS_COLLECT,
- perf,
- "collecting an iterator when collect is not needed"
-}
-
-declare_clippy_lint! {
- /// ### What it does
/// Checks `for` loops over slices with an explicit counter
/// and suggests the use of `.enumerate()`.
///
@@ -605,7 +582,6 @@ declare_lint_pass!(Loops => [
EXPLICIT_INTO_ITER_LOOP,
ITER_NEXT_LOOP,
WHILE_LET_LOOP,
- NEEDLESS_COLLECT,
EXPLICIT_COUNTER_LOOP,
EMPTY_LOOP,
WHILE_LET_ON_ITERATOR,
@@ -667,8 +643,6 @@ impl<'tcx> LateLintPass<'tcx> for Loops {
while_immutable_condition::check(cx, condition, body);
missing_spin_loop::check(cx, condition, body);
}
-
- needless_collect::check(expr, cx);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
index 91b321c44..4dae93f60 100644
--- a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
@@ -52,8 +52,8 @@ fn check_for_mutability(cx: &LateContext<'_>, bound: &Expr<'_>) -> Option<HirId>
None
}
-fn check_for_mutation<'tcx>(
- cx: &LateContext<'tcx>,
+fn check_for_mutation(
+ cx: &LateContext<'_>,
body: &Expr<'_>,
bound_id_start: Option<HirId>,
bound_id_end: Option<HirId>,
@@ -113,13 +113,7 @@ impl<'tcx> Delegate<'tcx> for MutatePairDelegate<'_, 'tcx> {
}
}
- fn fake_read(
- &mut self,
- _: &rustc_hir_typeck::expr_use_visitor::PlaceWithHirId<'tcx>,
- _: FakeReadCause,
- _: HirId,
- ) {
- }
+ fn fake_read(&mut self, _: &rustc_hir_typeck::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
}
impl MutatePairDelegate<'_, '_> {
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 16b00ad66..14f161f51 100644
--- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
@@ -4,7 +4,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::higher::ForLoop;
use clippy_utils::source::snippet;
use rustc_errors::Applicability;
-use rustc_hir::{Block, Expr, ExprKind, HirId, InlineAsmOperand, Pat, Stmt, StmtKind};
+use rustc_hir::{Block, Destination, Expr, ExprKind, HirId, InlineAsmOperand, Pat, Stmt, StmtKind};
use rustc_lint::LateContext;
use rustc_span::Span;
use std::iter::{once, Iterator};
@@ -16,7 +16,7 @@ pub(super) fn check(
span: Span,
for_loop: Option<&ForLoop<'_>>,
) {
- match never_loop_block(block, loop_id) {
+ match never_loop_block(block, &mut Vec::new(), loop_id) {
NeverLoopResult::AlwaysBreak => {
span_lint_and_then(cx, NEVER_LOOP, span, "this loop never actually loops", |diag| {
if let Some(ForLoop {
@@ -92,35 +92,34 @@ fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult) -> NeverLoopResult
}
}
-fn never_loop_block(block: &Block<'_>, main_loop_id: HirId) -> NeverLoopResult {
- let mut iter = block
+fn never_loop_block(block: &Block<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: HirId) -> NeverLoopResult {
+ let iter = block
.stmts
.iter()
.filter_map(stmt_to_expr)
.chain(block.expr.map(|expr| (expr, None)));
- never_loop_expr_seq(&mut iter, main_loop_id)
-}
-fn never_loop_expr_seq<'a, T: Iterator<Item = (&'a Expr<'a>, Option<&'a Block<'a>>)>>(
- es: &mut T,
- main_loop_id: HirId,
-) -> NeverLoopResult {
- es.map(|(e, els)| {
- let e = never_loop_expr(e, main_loop_id);
- els.map_or(e, |els| combine_branches(e, never_loop_block(els, main_loop_id)))
+ iter.map(|(e, els)| {
+ 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))
+ })
})
.fold(NeverLoopResult::Otherwise, combine_seq)
}
fn stmt_to_expr<'tcx>(stmt: &Stmt<'tcx>) -> Option<(&'tcx Expr<'tcx>, Option<&'tcx Block<'tcx>>)> {
match stmt.kind {
- StmtKind::Semi(e, ..) | StmtKind::Expr(e, ..) => Some((e, None)),
+ StmtKind::Semi(e) | StmtKind::Expr(e) => Some((e, None)),
+ // add the let...else expression (if present)
StmtKind::Local(local) => local.init.map(|init| (init, local.els)),
StmtKind::Item(..) => None,
}
}
-fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
+#[allow(clippy::too_many_lines)]
+fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: HirId) -> NeverLoopResult {
match expr.kind {
ExprKind::Box(e)
| ExprKind::Unary(_, e)
@@ -129,47 +128,56 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
| ExprKind::Field(e, _)
| ExprKind::AddrOf(_, _, e)
| ExprKind::Repeat(e, _)
- | ExprKind::DropTemps(e) => never_loop_expr(e, main_loop_id),
- ExprKind::Let(let_expr) => never_loop_expr(let_expr.init, main_loop_id),
- ExprKind::Array(es) | ExprKind::Tup(es) => never_loop_expr_all(&mut es.iter(), main_loop_id),
- ExprKind::MethodCall(_, receiver, es, _) => {
- never_loop_expr_all(&mut std::iter::once(receiver).chain(es.iter()), main_loop_id)
- },
+ | ExprKind::DropTemps(e) => never_loop_expr(e, ignore_ids, main_loop_id),
+ ExprKind::Let(let_expr) => never_loop_expr(let_expr.init, ignore_ids, main_loop_id),
+ ExprKind::Array(es) | ExprKind::Tup(es) => never_loop_expr_all(&mut es.iter(), ignore_ids, main_loop_id),
+ ExprKind::MethodCall(_, receiver, es, _) => never_loop_expr_all(
+ &mut std::iter::once(receiver).chain(es.iter()),
+ ignore_ids,
+ main_loop_id,
+ ),
ExprKind::Struct(_, fields, base) => {
- let fields = never_loop_expr_all(&mut fields.iter().map(|f| f.expr), main_loop_id);
+ 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, main_loop_id))
+ combine_both(fields, never_loop_expr(base, ignore_ids, main_loop_id))
} else {
fields
}
},
- ExprKind::Call(e, es) => never_loop_expr_all(&mut once(e).chain(es.iter()), main_loop_id),
+ ExprKind::Call(e, es) => never_loop_expr_all(&mut once(e).chain(es.iter()), ignore_ids, main_loop_id),
ExprKind::Binary(_, e1, e2)
| ExprKind::Assign(e1, e2, _)
| ExprKind::AssignOp(_, e1, e2)
- | ExprKind::Index(e1, e2) => never_loop_expr_all(&mut [e1, e2].iter().copied(), main_loop_id),
+ | ExprKind::Index(e1, e2) => never_loop_expr_all(&mut [e1, e2].iter().copied(), ignore_ids, main_loop_id),
ExprKind::Loop(b, _, _, _) => {
// Break can come from the inner loop so remove them.
- absorb_break(never_loop_block(b, main_loop_id))
+ absorb_break(never_loop_block(b, ignore_ids, main_loop_id))
},
ExprKind::If(e, e2, e3) => {
- let e1 = never_loop_expr(e, main_loop_id);
- let e2 = never_loop_expr(e2, main_loop_id);
- let e3 = e3
- .as_ref()
- .map_or(NeverLoopResult::Otherwise, |e| never_loop_expr(e, main_loop_id));
+ let e1 = never_loop_expr(e, ignore_ids, main_loop_id);
+ let e2 = never_loop_expr(e2, ignore_ids, main_loop_id);
+ 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))
},
ExprKind::Match(e, arms, _) => {
- let e = never_loop_expr(e, main_loop_id);
+ let e = never_loop_expr(e, ignore_ids, main_loop_id);
if arms.is_empty() {
e
} else {
- let arms = never_loop_expr_branch(&mut arms.iter().map(|a| a.body), main_loop_id);
+ let arms = never_loop_expr_branch(&mut arms.iter().map(|a| a.body), ignore_ids, main_loop_id);
combine_seq(e, arms)
}
},
- ExprKind::Block(b, _) => never_loop_block(b, main_loop_id),
+ ExprKind::Block(b, l) => {
+ if l.is_some() {
+ ignore_ids.push(b.hir_id);
+ }
+ let ret = never_loop_block(b, ignore_ids, main_loop_id);
+ ignore_ids.pop();
+ ret
+ },
ExprKind::Continue(d) => {
let id = d
.target_id
@@ -180,20 +188,32 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
NeverLoopResult::AlwaysBreak
}
},
+ // 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)
+ }),
ExprKind::Break(_, e) | ExprKind::Ret(e) => e.as_ref().map_or(NeverLoopResult::AlwaysBreak, |e| {
- combine_seq(never_loop_expr(e, main_loop_id), NeverLoopResult::AlwaysBreak)
+ combine_seq(
+ never_loop_expr(e, ignore_ids, main_loop_id),
+ NeverLoopResult::AlwaysBreak,
+ )
}),
ExprKind::InlineAsm(asm) => asm
.operands
.iter()
.map(|(o, _)| match o {
InlineAsmOperand::In { expr, .. } | InlineAsmOperand::InOut { expr, .. } => {
- never_loop_expr(expr, main_loop_id)
+ never_loop_expr(expr, ignore_ids, main_loop_id)
},
- InlineAsmOperand::Out { expr, .. } => never_loop_expr_all(&mut expr.iter().copied(), main_loop_id),
- InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => {
- never_loop_expr_all(&mut once(*in_expr).chain(out_expr.iter().copied()), main_loop_id)
+ InlineAsmOperand::Out { expr, .. } => {
+ never_loop_expr_all(&mut expr.iter().copied(), ignore_ids, main_loop_id)
},
+ InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => never_loop_expr_all(
+ &mut once(*in_expr).chain(out_expr.iter().copied()),
+ ignore_ids,
+ main_loop_id,
+ ),
InlineAsmOperand::Const { .. }
| InlineAsmOperand::SymFn { .. }
| InlineAsmOperand::SymStatic { .. } => NeverLoopResult::Otherwise,
@@ -208,13 +228,21 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
}
}
-fn never_loop_expr_all<'a, T: Iterator<Item = &'a Expr<'a>>>(es: &mut T, main_loop_id: HirId) -> NeverLoopResult {
- es.map(|e| never_loop_expr(e, main_loop_id))
+fn never_loop_expr_all<'a, T: Iterator<Item = &'a Expr<'a>>>(
+ es: &mut T,
+ ignore_ids: &mut Vec<HirId>,
+ main_loop_id: HirId,
+) -> NeverLoopResult {
+ es.map(|e| never_loop_expr(e, ignore_ids, main_loop_id))
.fold(NeverLoopResult::Otherwise, combine_both)
}
-fn never_loop_expr_branch<'a, T: Iterator<Item = &'a Expr<'a>>>(e: &mut T, main_loop_id: HirId) -> NeverLoopResult {
- e.map(|e| never_loop_expr(e, main_loop_id))
+fn never_loop_expr_branch<'a, T: Iterator<Item = &'a Expr<'a>>>(
+ e: &mut T,
+ 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)
}
diff --git a/src/tools/clippy/clippy_lints/src/macro_use.rs b/src/tools/clippy/clippy_lints/src/macro_use.rs
index 594f6af76..e2e6a87a3 100644
--- a/src/tools/clippy/clippy_lints/src/macro_use.rs
+++ b/src/tools/clippy/clippy_lints/src/macro_use.rs
@@ -94,7 +94,10 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports {
let hir_id = item.hir_id();
let attrs = cx.tcx.hir().attrs(hir_id);
if let Some(mac_attr) = attrs.iter().find(|attr| attr.has_name(sym::macro_use));
- if let Res::Def(DefKind::Mod, id) = path.res;
+ if let Some(id) = path.res.iter().find_map(|res| match res {
+ Res::Def(DefKind::Mod, id) => Some(id),
+ _ => None,
+ });
if !id.is_local();
then {
for kid in cx.tcx.module_children(id).iter() {
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 090f9f8ff..075ecbe7e 100644
--- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
@@ -6,7 +6,7 @@ use rustc_errors::Applicability;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{
AsyncGeneratorKind, Block, Body, Closure, Expr, ExprKind, FnDecl, FnRetTy, GeneratorKind, GenericArg, GenericBound,
- HirId, IsAsync, ItemKind, LifetimeName, Term, TraitRef, Ty, TyKind, TypeBindingKind,
+ HirId, ItemKind, LifetimeName, Term, TraitRef, Ty, TyKind, TypeBindingKind,
};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -49,7 +49,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn {
) {
if_chain! {
if let Some(header) = kind.header();
- if header.asyncness == IsAsync::NotAsync;
+ if !header.asyncness.is_async();
// Check that this function returns `impl Future`
if let FnRetTy::Return(ret_ty) = decl.output;
if let Some((trait_ref, output_lifetimes)) = future_trait_ref(cx, ret_ty);
@@ -118,7 +118,7 @@ fn future_trait_ref<'tcx>(
.iter()
.filter_map(|bound| {
if let GenericArg::Lifetime(lt) = bound {
- Some(lt.name)
+ Some(lt.res)
} else {
None
}
@@ -153,7 +153,7 @@ fn captures_all_lifetimes(inputs: &[Ty<'_>], output_lifetimes: &[LifetimeName])
.iter()
.filter_map(|ty| {
if let TyKind::Rptr(lt, _) = ty.kind {
- Some(lt.name)
+ Some(lt.res)
} else {
None
}
@@ -177,7 +177,7 @@ fn desugared_async_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>)
if let Some(args) = cx
.tcx
.lang_items()
- .from_generator_fn()
+ .identity_future_fn()
.and_then(|def_id| match_function_call_with_def_id(cx, block_expr, def_id));
if args.len() == 1;
if let Expr {
diff --git a/src/tools/clippy/clippy_lints/src/manual_bits.rs b/src/tools/clippy/clippy_lints/src/manual_bits.rs
index 6655c92b1..462d73cf0 100644
--- a/src/tools/clippy/clippy_lints/src/manual_bits.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_bits.rs
@@ -1,12 +1,12 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::get_parent_expr;
+use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{get_parent_expr, meets_msrv, msrvs};
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind, GenericArg, QPath};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, Ty};
-use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::sym;
@@ -34,12 +34,12 @@ declare_clippy_lint! {
#[derive(Clone)]
pub struct ManualBits {
- msrv: Option<RustcVersion>,
+ msrv: Msrv,
}
impl ManualBits {
#[must_use]
- pub fn new(msrv: Option<RustcVersion>) -> Self {
+ pub fn new(msrv: Msrv) -> Self {
Self { msrv }
}
}
@@ -48,7 +48,7 @@ impl_lint_pass!(ManualBits => [MANUAL_BITS]);
impl<'tcx> LateLintPass<'tcx> for ManualBits {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- if !meets_msrv(self.msrv, msrvs::MANUAL_BITS) {
+ if !self.msrv.meets(msrvs::MANUAL_BITS) {
return;
}
diff --git a/src/tools/clippy/clippy_lints/src/manual_clamp.rs b/src/tools/clippy/clippy_lints/src/manual_clamp.rs
index 02dc8755d..f239736d3 100644
--- a/src/tools/clippy/clippy_lints/src/manual_clamp.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_clamp.rs
@@ -1,28 +1,25 @@
+use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
+use clippy_utils::higher::If;
+use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::sugg::Sugg;
+use clippy_utils::ty::implements_trait;
+use clippy_utils::visitors::is_const_evaluatable;
+use clippy_utils::MaybePath;
+use clippy_utils::{
+ eq_expr_value, is_diag_trait_item, is_trait_method, path_res, path_to_local_id, peel_blocks, peel_blocks_with_stmt,
+};
use itertools::Itertools;
+use rustc_errors::Applicability;
use rustc_errors::Diagnostic;
use rustc_hir::{
def::Res, Arm, BinOpKind, Block, Expr, ExprKind, Guard, HirId, PatKind, PathSegment, PrimTy, QPath, StmtKind,
};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::Ty;
-use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{symbol::sym, Span};
use std::ops::Deref;
-use clippy_utils::{
- diagnostics::{span_lint_and_then, span_lint_hir_and_then},
- eq_expr_value,
- higher::If,
- is_diag_trait_item, is_trait_method, meets_msrv, msrvs, path_res, path_to_local_id, peel_blocks,
- peel_blocks_with_stmt,
- sugg::Sugg,
- ty::implements_trait,
- visitors::is_const_evaluatable,
- MaybePath,
-};
-use rustc_errors::Applicability;
-
declare_clippy_lint! {
/// ### What it does
/// Identifies good opportunities for a clamp function from std or core, and suggests using it.
@@ -38,6 +35,9 @@ declare_clippy_lint! {
/// Some may consider panicking in these situations to be desirable, but it also may
/// introduce panicking where there wasn't any before.
///
+ /// See also [the discussion in the
+ /// PR](https://github.com/rust-lang/rust-clippy/pull/9484#issuecomment-1278922613).
+ ///
/// ### Examples
/// ```rust
/// # let (input, min, max) = (0, -2, 1);
@@ -81,17 +81,17 @@ declare_clippy_lint! {
/// ```
#[clippy::version = "1.66.0"]
pub MANUAL_CLAMP,
- complexity,
+ nursery,
"using a clamp pattern instead of the clamp function"
}
impl_lint_pass!(ManualClamp => [MANUAL_CLAMP]);
pub struct ManualClamp {
- msrv: Option<RustcVersion>,
+ msrv: Msrv,
}
impl ManualClamp {
- pub fn new(msrv: Option<RustcVersion>) -> Self {
+ pub fn new(msrv: Msrv) -> Self {
Self { msrv }
}
}
@@ -114,7 +114,7 @@ struct InputMinMax<'tcx> {
impl<'tcx> LateLintPass<'tcx> for ManualClamp {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
- if !meets_msrv(self.msrv, msrvs::CLAMP) {
+ if !self.msrv.meets(msrvs::CLAMP) {
return;
}
if !expr.span.from_expansion() {
@@ -130,7 +130,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualClamp {
}
fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) {
- if !meets_msrv(self.msrv, msrvs::CLAMP) {
+ if !self.msrv.meets(msrvs::CLAMP) {
return;
}
for suggestion in is_two_if_pattern(cx, block) {
diff --git a/src/tools/clippy/clippy_lints/src/manual_instant_elapsed.rs b/src/tools/clippy/clippy_lints/src/manual_instant_elapsed.rs
deleted file mode 100644
index 331cda1db..000000000
--- a/src/tools/clippy/clippy_lints/src/manual_instant_elapsed.rs
+++ /dev/null
@@ -1,69 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use rustc_errors::Applicability;
-use rustc_hir::{BinOpKind, Expr, ExprKind};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::source_map::Spanned;
-
-declare_clippy_lint! {
- /// ### What it does
- /// Lints subtraction between `Instant::now()` and another `Instant`.
- ///
- /// ### Why is this bad?
- /// It is easy to accidentally write `prev_instant - Instant::now()`, which will always be 0ns
- /// as `Instant` subtraction saturates.
- ///
- /// `prev_instant.elapsed()` also more clearly signals intention.
- ///
- /// ### Example
- /// ```rust
- /// use std::time::Instant;
- /// let prev_instant = Instant::now();
- /// let duration = Instant::now() - prev_instant;
- /// ```
- /// Use instead:
- /// ```rust
- /// use std::time::Instant;
- /// let prev_instant = Instant::now();
- /// let duration = prev_instant.elapsed();
- /// ```
- #[clippy::version = "1.64.0"]
- pub MANUAL_INSTANT_ELAPSED,
- pedantic,
- "subtraction between `Instant::now()` and previous `Instant`"
-}
-
-declare_lint_pass!(ManualInstantElapsed => [MANUAL_INSTANT_ELAPSED]);
-
-impl LateLintPass<'_> for ManualInstantElapsed {
- fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
- if let ExprKind::Binary(Spanned {node: BinOpKind::Sub, ..}, lhs, rhs) = expr.kind
- && check_instant_now_call(cx, lhs)
- && let ty_resolved = cx.typeck_results().expr_ty(rhs)
- && let rustc_middle::ty::Adt(def, _) = ty_resolved.kind()
- && clippy_utils::match_def_path(cx, def.did(), &clippy_utils::paths::INSTANT)
- && let Some(sugg) = clippy_utils::sugg::Sugg::hir_opt(cx, rhs)
- {
- span_lint_and_sugg(
- cx,
- MANUAL_INSTANT_ELAPSED,
- expr.span,
- "manual implementation of `Instant::elapsed`",
- "try",
- format!("{}.elapsed()", sugg.maybe_par()),
- Applicability::MachineApplicable,
- );
- }
- }
-}
-
-fn check_instant_now_call(cx: &LateContext<'_>, expr_block: &'_ Expr<'_>) -> bool {
- if let ExprKind::Call(fn_expr, []) = expr_block.kind
- && let Some(fn_id) = clippy_utils::path_def_id(cx, fn_expr)
- && clippy_utils::match_def_path(cx, fn_id, &clippy_utils::paths::INSTANT_NOW)
- {
- true
- } else {
- false
- }
-}
diff --git a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
new file mode 100644
index 000000000..5ab049d8d
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
@@ -0,0 +1,155 @@
+use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::{diagnostics::span_lint_and_sugg, in_constant, macros::root_macro_call, source::snippet};
+use rustc_ast::LitKind::{Byte, Char};
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind, PatKind, RangeEnd};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::{def_id::DefId, sym};
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Suggests to use dedicated built-in methods,
+ /// `is_ascii_(lowercase|uppercase|digit)` for checking on corresponding ascii range
+ ///
+ /// ### Why is this bad?
+ /// Using the built-in functions is more readable and makes it
+ /// clear that it's not a specific subset of characters, but all
+ /// ASCII (lowercase|uppercase|digit) characters.
+ /// ### Example
+ /// ```rust
+ /// fn main() {
+ /// assert!(matches!('x', 'a'..='z'));
+ /// assert!(matches!(b'X', b'A'..=b'Z'));
+ /// assert!(matches!('2', '0'..='9'));
+ /// assert!(matches!('x', 'A'..='Z' | 'a'..='z'));
+ /// }
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// fn main() {
+ /// assert!('x'.is_ascii_lowercase());
+ /// assert!(b'X'.is_ascii_uppercase());
+ /// assert!('2'.is_ascii_digit());
+ /// assert!('x'.is_ascii_alphabetic());
+ /// }
+ /// ```
+ #[clippy::version = "1.66.0"]
+ pub MANUAL_IS_ASCII_CHECK,
+ style,
+ "use dedicated method to check ascii range"
+}
+impl_lint_pass!(ManualIsAsciiCheck => [MANUAL_IS_ASCII_CHECK]);
+
+pub struct ManualIsAsciiCheck {
+ msrv: Msrv,
+}
+
+impl ManualIsAsciiCheck {
+ #[must_use]
+ pub fn new(msrv: Msrv) -> Self {
+ Self { msrv }
+ }
+}
+
+#[derive(Debug, PartialEq)]
+enum CharRange {
+ /// 'a'..='z' | b'a'..=b'z'
+ LowerChar,
+ /// 'A'..='Z' | b'A'..=b'Z'
+ UpperChar,
+ /// AsciiLower | AsciiUpper
+ FullChar,
+ /// '0..=9'
+ Digit,
+ Otherwise,
+}
+
+impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+ if !self.msrv.meets(msrvs::IS_ASCII_DIGIT) {
+ return;
+ }
+
+ if in_constant(cx, expr.hir_id) && !self.msrv.meets(msrvs::IS_ASCII_DIGIT_CONST) {
+ return;
+ }
+
+ let Some(macro_call) = root_macro_call(expr.span) else { return };
+
+ if is_matches_macro(cx, macro_call.def_id) {
+ if let ExprKind::Match(recv, [arm, ..], _) = expr.kind {
+ let range = check_pat(&arm.pat.kind);
+
+ if let Some(sugg) = match range {
+ CharRange::UpperChar => Some("is_ascii_uppercase"),
+ CharRange::LowerChar => Some("is_ascii_lowercase"),
+ CharRange::FullChar => Some("is_ascii_alphabetic"),
+ CharRange::Digit => Some("is_ascii_digit"),
+ CharRange::Otherwise => None,
+ } {
+ let default_snip = "..";
+ // `snippet_with_applicability` may set applicability to `MaybeIncorrect` for
+ // macro span, so we check applicability manually by comparing `recv` is not default.
+ let recv = snippet(cx, recv.span, default_snip);
+
+ let applicability = if recv == default_snip {
+ Applicability::HasPlaceholders
+ } else {
+ Applicability::MachineApplicable
+ };
+
+ span_lint_and_sugg(
+ cx,
+ MANUAL_IS_ASCII_CHECK,
+ macro_call.span,
+ "manual check for common ascii range",
+ "try",
+ format!("{recv}.{sugg}()"),
+ applicability,
+ );
+ }
+ }
+ }
+ }
+
+ extract_msrv_attr!(LateContext);
+}
+
+fn check_pat(pat_kind: &PatKind<'_>) -> CharRange {
+ match pat_kind {
+ PatKind::Or(pats) => {
+ let ranges = pats.iter().map(|p| check_pat(&p.kind)).collect::<Vec<_>>();
+
+ if ranges.len() == 2 && ranges.contains(&CharRange::UpperChar) && ranges.contains(&CharRange::LowerChar) {
+ CharRange::FullChar
+ } else {
+ CharRange::Otherwise
+ }
+ },
+ PatKind::Range(Some(start), Some(end), kind) if *kind == RangeEnd::Included => check_range(start, end),
+ _ => CharRange::Otherwise,
+ }
+}
+
+fn check_range(start: &Expr<'_>, end: &Expr<'_>) -> CharRange {
+ if let ExprKind::Lit(start_lit) = &start.kind
+ && let ExprKind::Lit(end_lit) = &end.kind {
+ match (&start_lit.node, &end_lit.node) {
+ (Char('a'), Char('z')) | (Byte(b'a'), Byte(b'z')) => CharRange::LowerChar,
+ (Char('A'), Char('Z')) | (Byte(b'A'), Byte(b'Z')) => CharRange::UpperChar,
+ (Char('0'), Char('9')) | (Byte(b'0'), Byte(b'9')) => CharRange::Digit,
+ _ => CharRange::Otherwise,
+ }
+ } else {
+ CharRange::Otherwise
+ }
+}
+
+fn is_matches_macro(cx: &LateContext<'_>, macro_def_id: DefId) -> bool {
+ if let Some(name) = cx.tcx.get_diagnostic_name(macro_def_id) {
+ return sym::matches_macro == name;
+ }
+
+ false
+}
diff --git a/src/tools/clippy/clippy_lints/src/manual_let_else.rs b/src/tools/clippy/clippy_lints/src/manual_let_else.rs
new file mode 100644
index 000000000..874d36ca9
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/manual_let_else.rs
@@ -0,0 +1,295 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::higher::IfLetOrMatch;
+use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::peel_blocks;
+use clippy_utils::source::snippet_with_context;
+use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::visitors::{for_each_expr, Descend};
+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_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::lint::in_external_macro;
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::symbol::sym;
+use rustc_span::Span;
+use serde::Deserialize;
+use std::ops::ControlFlow;
+
+declare_clippy_lint! {
+ /// ### What it does
+ ///
+ /// Warn of cases where `let...else` could be used
+ ///
+ /// ### Why is this bad?
+ ///
+ /// `let...else` provides a standard construct for this pattern
+ /// that people can easily recognize. It's also more compact.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// # let w = Some(0);
+ /// let v = if let Some(v) = w { v } else { return };
+ /// ```
+ ///
+ /// Could be written:
+ ///
+ /// ```rust
+ /// # #![feature(let_else)]
+ /// # fn main () {
+ /// # let w = Some(0);
+ /// let Some(v) = w else { return };
+ /// # }
+ /// ```
+ #[clippy::version = "1.67.0"]
+ pub MANUAL_LET_ELSE,
+ pedantic,
+ "manual implementation of a let...else statement"
+}
+
+pub struct ManualLetElse {
+ msrv: Msrv,
+ matches_behaviour: MatchLintBehaviour,
+}
+
+impl ManualLetElse {
+ #[must_use]
+ pub fn new(msrv: Msrv, matches_behaviour: MatchLintBehaviour) -> Self {
+ Self {
+ msrv,
+ matches_behaviour,
+ }
+ }
+}
+
+impl_lint_pass!(ManualLetElse => [MANUAL_LET_ELSE]);
+
+impl<'tcx> LateLintPass<'tcx> for ManualLetElse {
+ fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &'tcx Stmt<'tcx>) {
+ let if_let_or_match = if_chain! {
+ if self.msrv.meets(msrvs::LET_ELSE);
+ if !in_external_macro(cx.sess(), stmt.span);
+ if let StmtKind::Local(local) = stmt.kind;
+ if let Some(init) = local.init;
+ if local.els.is_none();
+ if local.ty.is_none();
+ if init.span.ctxt() == stmt.span.ctxt();
+ if let Some(if_let_or_match) = IfLetOrMatch::parse(cx, init);
+ then {
+ if_let_or_match
+ } else {
+ return;
+ }
+ };
+
+ match if_let_or_match {
+ IfLetOrMatch::IfLet(if_let_expr, let_pat, if_then, if_else) => if_chain! {
+ if expr_is_simple_identity(let_pat, if_then);
+ if let Some(if_else) = if_else;
+ if expr_diverges(cx, if_else);
+ then {
+ emit_manual_let_else(cx, stmt.span, if_let_expr, let_pat, if_else);
+ }
+ },
+ IfLetOrMatch::Match(match_expr, arms, source) => {
+ if self.matches_behaviour == MatchLintBehaviour::Never {
+ return;
+ }
+ if source != MatchSource::Normal {
+ return;
+ }
+ // Any other number than two arms doesn't (neccessarily)
+ // have a trivial mapping to let else.
+ if arms.len() != 2 {
+ return;
+ }
+ // Guards don't give us an easy mapping either
+ if arms.iter().any(|arm| arm.guard.is_some()) {
+ return;
+ }
+ let check_types = self.matches_behaviour == MatchLintBehaviour::WellKnownTypes;
+ let diverging_arm_opt = arms
+ .iter()
+ .enumerate()
+ .find(|(_, arm)| expr_diverges(cx, arm.body) && pat_allowed_for_else(cx, arm.pat, check_types));
+ let Some((idx, diverging_arm)) = diverging_arm_opt else { return; };
+ let pat_arm = &arms[1 - idx];
+ if !expr_is_simple_identity(pat_arm.pat, pat_arm.body) {
+ return;
+ }
+
+ emit_manual_let_else(cx, stmt.span, match_expr, pat_arm.pat, diverging_arm.body);
+ },
+ }
+ }
+
+ extract_msrv_attr!(LateContext);
+}
+
+fn emit_manual_let_else(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, pat: &Pat<'_>, else_body: &Expr<'_>) {
+ span_lint_and_then(
+ cx,
+ MANUAL_LET_ELSE,
+ span,
+ "this could be rewritten as `let...else`",
+ |diag| {
+ // This is far from perfect, for example there needs to be:
+ // * mut additions for the bindings
+ // * renamings of the bindings
+ // * unused binding collision detection with existing ones
+ // * putting patterns with at the top level | inside ()
+ // for this to be machine applicable.
+ let mut app = Applicability::HasPlaceholders;
+ let (sn_pat, _) = snippet_with_context(cx, pat.span, span.ctxt(), "", &mut app);
+ let (sn_expr, _) = snippet_with_context(cx, expr.span, span.ctxt(), "", &mut app);
+ let (sn_else, _) = snippet_with_context(cx, else_body.span, span.ctxt(), "", &mut app);
+
+ let else_bl = if matches!(else_body.kind, ExprKind::Block(..)) {
+ sn_else.into_owned()
+ } else {
+ format!("{{ {sn_else} }}")
+ };
+ let sugg = format!("let {sn_pat} = {sn_expr} else {else_bl};");
+ diag.span_suggestion(span, "consider writing", sugg, app);
+ },
+ );
+}
+
+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
+ }
+ // 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(());
+ }
+ 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)
+ },
+
+ // 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),
+ }
+ })
+ .is_some()
+}
+
+fn pat_allowed_for_else(cx: &LateContext<'_>, pat: &'_ Pat<'_>, check_types: bool) -> bool {
+ // Check whether the pattern contains any bindings, as the
+ // binding might potentially be used in the body.
+ // TODO: only look for *used* bindings.
+ let mut has_bindings = false;
+ pat.each_binding_or_first(&mut |_, _, _, _| has_bindings = true);
+ if has_bindings {
+ return false;
+ }
+
+ // If we shouldn't check the types, exit early.
+ if !check_types {
+ return true;
+ }
+
+ // Check whether any possibly "unknown" patterns are included,
+ // because users might not know which values some enum has.
+ // Well-known enums are excepted, as we assume people know them.
+ // We do a deep check, to be able to disallow Err(En::Foo(_))
+ // for usage of the En::Foo variant, as we disallow En::Foo(_),
+ // but we allow Err(_).
+ let typeck_results = cx.typeck_results();
+ let mut has_disallowed = false;
+ pat.walk_always(|pat| {
+ // Only do the check if the type is "spelled out" in the pattern
+ if !matches!(
+ pat.kind,
+ PatKind::Struct(..) | PatKind::TupleStruct(..) | PatKind::Path(..)
+ ) {
+ return;
+ };
+ let ty = typeck_results.pat_ty(pat);
+ // Option and Result are allowed, everything else isn't.
+ if !(is_type_diagnostic_item(cx, ty, sym::Option) || is_type_diagnostic_item(cx, ty, sym::Result)) {
+ has_disallowed = true;
+ }
+ });
+ !has_disallowed
+}
+
+/// Checks if the passed block is a simple identity referring to bindings created by the pattern
+fn expr_is_simple_identity(pat: &'_ Pat<'_>, expr: &'_ Expr<'_>) -> bool {
+ // We support patterns with multiple bindings and tuples, like:
+ // let ... = if let (Some(foo), bar) = g() { (foo, bar) } else { ... }
+ let peeled = peel_blocks(expr);
+ let paths = match peeled.kind {
+ ExprKind::Tup(exprs) | ExprKind::Array(exprs) => exprs,
+ ExprKind::Path(_) => std::slice::from_ref(peeled),
+ _ => return false,
+ };
+ let mut pat_bindings = FxHashSet::default();
+ pat.each_binding_or_first(&mut |_ann, _hir_id, _sp, ident| {
+ pat_bindings.insert(ident);
+ });
+ if pat_bindings.len() < paths.len() {
+ return false;
+ }
+ for path in paths {
+ if_chain! {
+ if let ExprKind::Path(QPath::Resolved(_ty, path)) = path.kind;
+ if let [path_seg] = path.segments;
+ then {
+ if !pat_bindings.remove(&path_seg.ident) {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+ }
+ true
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize)]
+pub enum MatchLintBehaviour {
+ AllTypes,
+ WellKnownTypes,
+ Never,
+}
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 6806c1466..bca193be9 100644
--- a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
@@ -1,6 +1,7 @@
use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
+use clippy_utils::is_doc_hidden;
+use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_opt;
-use clippy_utils::{is_doc_hidden, meets_msrv, msrvs};
use rustc_ast::ast::{self, VisibilityKind};
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
@@ -8,7 +9,6 @@ use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
use rustc_hir::{self as hir, Expr, ExprKind, QPath};
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
use rustc_middle::ty::DefIdTree;
-use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::def_id::{DefId, LocalDefId};
use rustc_span::{sym, Span};
@@ -63,12 +63,12 @@ declare_clippy_lint! {
#[expect(clippy::module_name_repetitions)]
pub struct ManualNonExhaustiveStruct {
- msrv: Option<RustcVersion>,
+ msrv: Msrv,
}
impl ManualNonExhaustiveStruct {
#[must_use]
- pub fn new(msrv: Option<RustcVersion>) -> Self {
+ pub fn new(msrv: Msrv) -> Self {
Self { msrv }
}
}
@@ -77,14 +77,14 @@ impl_lint_pass!(ManualNonExhaustiveStruct => [MANUAL_NON_EXHAUSTIVE]);
#[expect(clippy::module_name_repetitions)]
pub struct ManualNonExhaustiveEnum {
- msrv: Option<RustcVersion>,
+ msrv: Msrv,
constructed_enum_variants: FxHashSet<(DefId, DefId)>,
potential_enums: Vec<(LocalDefId, LocalDefId, Span, Span)>,
}
impl ManualNonExhaustiveEnum {
#[must_use]
- pub fn new(msrv: Option<RustcVersion>) -> Self {
+ pub fn new(msrv: Msrv) -> Self {
Self {
msrv,
constructed_enum_variants: FxHashSet::default(),
@@ -97,7 +97,7 @@ impl_lint_pass!(ManualNonExhaustiveEnum => [MANUAL_NON_EXHAUSTIVE]);
impl EarlyLintPass for ManualNonExhaustiveStruct {
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
- if !meets_msrv(self.msrv, msrvs::NON_EXHAUSTIVE) {
+ if !self.msrv.meets(msrvs::NON_EXHAUSTIVE) {
return;
}
@@ -149,7 +149,7 @@ impl EarlyLintPass for ManualNonExhaustiveStruct {
impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
- if !meets_msrv(self.msrv, msrvs::NON_EXHAUSTIVE) {
+ if !self.msrv.meets(msrvs::NON_EXHAUSTIVE) {
return;
}
@@ -157,10 +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.id);
- (matches!(v.data, hir::VariantData::Unit(_))
+ let id = cx.tcx.hir().local_def_id(v.hir_id);
+ (matches!(v.data, hir::VariantData::Unit(..))
&& v.ident.as_str().starts_with('_')
- && is_doc_hidden(cx.tcx.hir().attrs(v.id)))
+ && is_doc_hidden(cx.tcx.hir().attrs(v.hir_id)))
.then_some((id, v.span))
});
if let Some((id, span)) = iter.next()
diff --git a/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
index 6f25a2ed8..8d447c371 100644
--- a/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
@@ -1,12 +1,12 @@
use clippy_utils::consts::{constant_full_int, FullInt};
use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{in_constant, meets_msrv, msrvs, path_to_local};
+use clippy_utils::{in_constant, path_to_local};
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind, Node, TyKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass};
declare_clippy_lint! {
@@ -34,12 +34,12 @@ declare_clippy_lint! {
}
pub struct ManualRemEuclid {
- msrv: Option<RustcVersion>,
+ msrv: Msrv,
}
impl ManualRemEuclid {
#[must_use]
- pub fn new(msrv: Option<RustcVersion>) -> Self {
+ pub fn new(msrv: Msrv) -> Self {
Self { msrv }
}
}
@@ -48,11 +48,11 @@ impl_lint_pass!(ManualRemEuclid => [MANUAL_REM_EUCLID]);
impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- if !meets_msrv(self.msrv, msrvs::REM_EUCLID) {
+ if !self.msrv.meets(msrvs::REM_EUCLID) {
return;
}
- if in_constant(cx, expr.hir_id) && !meets_msrv(self.msrv, msrvs::REM_EUCLID_CONST) {
+ if in_constant(cx, expr.hir_id) && !self.msrv.meets(msrvs::REM_EUCLID_CONST) {
return;
}
diff --git a/src/tools/clippy/clippy_lints/src/manual_retain.rs b/src/tools/clippy/clippy_lints/src/manual_retain.rs
index 3181bc86d..c1e6c8248 100644
--- a/src/tools/clippy/clippy_lints/src/manual_retain.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_retain.rs
@@ -1,8 +1,8 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
use clippy_utils::{get_parent_expr, match_def_path, paths, SpanlessEq};
-use clippy_utils::{meets_msrv, msrvs};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
@@ -50,12 +50,12 @@ declare_clippy_lint! {
}
pub struct ManualRetain {
- msrv: Option<RustcVersion>,
+ msrv: Msrv,
}
impl ManualRetain {
#[must_use]
- pub fn new(msrv: Option<RustcVersion>) -> Self {
+ pub fn new(msrv: Msrv) -> Self {
Self { msrv }
}
}
@@ -71,9 +71,9 @@ impl<'tcx> LateLintPass<'tcx> for ManualRetain {
&& let hir::ExprKind::MethodCall(_, target_expr, [], _) = &collect_expr.kind
&& let Some(collect_def_id) = cx.typeck_results().type_dependent_def_id(collect_expr.hir_id)
&& match_def_path(cx, collect_def_id, &paths::CORE_ITER_COLLECT) {
- check_into_iter(cx, parent_expr, left_expr, target_expr, self.msrv);
- check_iter(cx, parent_expr, left_expr, target_expr, self.msrv);
- check_to_owned(cx, parent_expr, left_expr, target_expr, self.msrv);
+ check_into_iter(cx, parent_expr, left_expr, target_expr, &self.msrv);
+ check_iter(cx, parent_expr, left_expr, target_expr, &self.msrv);
+ check_to_owned(cx, parent_expr, left_expr, target_expr, &self.msrv);
}
}
@@ -85,14 +85,14 @@ fn check_into_iter(
parent_expr: &hir::Expr<'_>,
left_expr: &hir::Expr<'_>,
target_expr: &hir::Expr<'_>,
- msrv: Option<RustcVersion>,
+ msrv: &Msrv,
) {
if let hir::ExprKind::MethodCall(_, into_iter_expr, [_], _) = &target_expr.kind
&& let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id)
&& match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER)
&& let hir::ExprKind::MethodCall(_, struct_expr, [], _) = &into_iter_expr.kind
&& let Some(into_iter_def_id) = cx.typeck_results().type_dependent_def_id(into_iter_expr.hir_id)
- && cx.tcx.lang_items().require(hir::LangItem::IntoIterIntoIter).ok() == Some(into_iter_def_id)
+ && Some(into_iter_def_id) == cx.tcx.lang_items().into_iter_fn()
&& match_acceptable_type(cx, left_expr, msrv)
&& SpanlessEq::new(cx).eq_expr(left_expr, struct_expr) {
suggest(cx, parent_expr, left_expr, target_expr);
@@ -104,7 +104,7 @@ fn check_iter(
parent_expr: &hir::Expr<'_>,
left_expr: &hir::Expr<'_>,
target_expr: &hir::Expr<'_>,
- msrv: Option<RustcVersion>,
+ msrv: &Msrv,
) {
if let hir::ExprKind::MethodCall(_, filter_expr, [], _) = &target_expr.kind
&& let Some(copied_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id)
@@ -127,9 +127,9 @@ fn check_to_owned(
parent_expr: &hir::Expr<'_>,
left_expr: &hir::Expr<'_>,
target_expr: &hir::Expr<'_>,
- msrv: Option<RustcVersion>,
+ msrv: &Msrv,
) {
- if meets_msrv(msrv, msrvs::STRING_RETAIN)
+ if msrv.meets(msrvs::STRING_RETAIN)
&& let hir::ExprKind::MethodCall(_, filter_expr, [], _) = &target_expr.kind
&& let Some(to_owned_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id)
&& match_def_path(cx, to_owned_def_id, &paths::TO_OWNED_METHOD)
@@ -140,7 +140,7 @@ fn check_to_owned(
&& let Some(chars_expr_def_id) = cx.typeck_results().type_dependent_def_id(chars_expr.hir_id)
&& match_def_path(cx, chars_expr_def_id, &paths::STR_CHARS)
&& let ty = cx.typeck_results().expr_ty(str_expr).peel_refs()
- && is_type_diagnostic_item(cx, ty, sym::String)
+ && is_type_lang_item(cx, ty, hir::LangItem::String)
&& SpanlessEq::new(cx).eq_expr(left_expr, str_expr) {
suggest(cx, parent_expr, left_expr, filter_expr);
}
@@ -215,10 +215,10 @@ fn match_acceptable_def_path(cx: &LateContext<'_>, collect_def_id: DefId) -> boo
.any(|&method| match_def_path(cx, collect_def_id, method))
}
-fn match_acceptable_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>, msrv: Option<RustcVersion>) -> bool {
+fn match_acceptable_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>, msrv: &Msrv) -> bool {
let expr_ty = cx.typeck_results().expr_ty(expr).peel_refs();
ACCEPTABLE_TYPES.iter().any(|(ty, acceptable_msrv)| {
is_type_diagnostic_item(cx, expr_ty, *ty)
- && acceptable_msrv.map_or(true, |acceptable_msrv| meets_msrv(msrv, acceptable_msrv))
+ && acceptable_msrv.map_or(true, |acceptable_msrv| msrv.meets(acceptable_msrv))
})
}
diff --git a/src/tools/clippy/clippy_lints/src/manual_string_new.rs b/src/tools/clippy/clippy_lints/src/manual_string_new.rs
index 6acfb2ae3..c20d7959f 100644
--- a/src/tools/clippy/clippy_lints/src/manual_string_new.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_string_new.rs
@@ -44,7 +44,7 @@ impl LateLintPass<'_> for ManualStringNew {
let ty = cx.typeck_results().expr_ty(expr);
match ty.kind() {
ty::Adt(adt_def, _) if adt_def.is_struct() => {
- if !cx.tcx.is_diagnostic_item(sym::String, adt_def.did()) {
+ if cx.tcx.lang_items().string() != Some(adt_def.did()) {
return;
}
},
diff --git a/src/tools/clippy/clippy_lints/src/manual_strip.rs b/src/tools/clippy/clippy_lints/src/manual_strip.rs
index 0976940af..de166b976 100644
--- a/src/tools/clippy/clippy_lints/src/manual_strip.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs
@@ -1,8 +1,9 @@
use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
+use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet;
use clippy_utils::usage::mutated_variables;
-use clippy_utils::{eq_expr_value, higher, match_def_path, meets_msrv, msrvs, paths};
+use clippy_utils::{eq_expr_value, higher, match_def_path, paths};
use if_chain::if_chain;
use rustc_ast::ast::LitKind;
use rustc_hir::def::Res;
@@ -11,7 +12,6 @@ use rustc_hir::BinOpKind;
use rustc_hir::{BorrowKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
-use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Spanned;
use rustc_span::Span;
@@ -48,12 +48,12 @@ declare_clippy_lint! {
}
pub struct ManualStrip {
- msrv: Option<RustcVersion>,
+ msrv: Msrv,
}
impl ManualStrip {
#[must_use]
- pub fn new(msrv: Option<RustcVersion>) -> Self {
+ pub fn new(msrv: Msrv) -> Self {
Self { msrv }
}
}
@@ -68,7 +68,7 @@ enum StripKind {
impl<'tcx> LateLintPass<'tcx> for ManualStrip {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- if !meets_msrv(self.msrv, msrvs::STR_STRIP_PREFIX) {
+ if !self.msrv.meets(msrvs::STR_STRIP_PREFIX) {
return;
}
diff --git a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
index 32da37a86..59195d1ae 100644
--- a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
@@ -119,7 +119,7 @@ fn is_unit_expression(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
/// semicolons, which causes problems when generating a suggestion. Given an
/// expression that evaluates to '()' or '!', recursively remove useless braces
/// and semi-colons until is suitable for including in the suggestion template
-fn reduce_unit_expression<'a>(cx: &LateContext<'_>, expr: &'a hir::Expr<'_>) -> Option<Span> {
+fn reduce_unit_expression(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Span> {
if !is_unit_expression(cx, expr) {
return None;
}
diff --git a/src/tools/clippy/clippy_lints/src/matches/infallible_destructuring_match.rs b/src/tools/clippy/clippy_lints/src/matches/infallible_destructuring_match.rs
index 2472acb6f..d18c92cab 100644
--- a/src/tools/clippy/clippy_lints/src/matches/infallible_destructuring_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/infallible_destructuring_match.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::{path_to_local_id, peel_blocks, strip_pat_refs};
use rustc_errors::Applicability;
-use rustc_hir::{ExprKind, Local, MatchSource, PatKind, QPath};
+use rustc_hir::{ByRef, ExprKind, Local, MatchSource, PatKind, QPath};
use rustc_lint::LateContext;
use super::INFALLIBLE_DESTRUCTURING_MATCH;
@@ -16,7 +16,7 @@ pub(crate) fn check(cx: &LateContext<'_>, local: &Local<'_>) -> bool {
if let PatKind::TupleStruct(
QPath::Resolved(None, variant_name), args, _) = arms[0].pat.kind;
if args.len() == 1;
- if let PatKind::Binding(_, arg, ..) = strip_pat_refs(&args[0]).kind;
+ if let PatKind::Binding(binding, arg, ..) = strip_pat_refs(&args[0]).kind;
let body = peel_blocks(arms[0].body);
if path_to_local_id(body, arg);
@@ -30,8 +30,9 @@ pub(crate) fn check(cx: &LateContext<'_>, local: &Local<'_>) -> bool {
Consider using `let`",
"try this",
format!(
- "let {}({}) = {};",
+ "let {}({}{}) = {};",
snippet_with_applicability(cx, variant_name.span, "..", &mut applicability),
+ if binding.0 == ByRef::Yes { "ref " } else { "" },
snippet_with_applicability(cx, local.pat.span, "..", &mut applicability),
snippet_with_applicability(cx, target.span, "..", &mut applicability),
),
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs b/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs
index 66ba1f6f9..d521a529e 100644
--- a/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs
@@ -62,7 +62,7 @@ fn peels_blocks_incl_unsafe<'a>(expr: &'a Expr<'a>) -> &'a Expr<'a> {
// <expr>
// }
// Returns true if <expr> resolves to `Some(x)`, `false` otherwise
-fn is_some_expr<'tcx>(cx: &LateContext<'_>, target: HirId, ctxt: SyntaxContext, expr: &'tcx Expr<'_>) -> bool {
+fn is_some_expr(cx: &LateContext<'_>, target: HirId, ctxt: SyntaxContext, expr: &Expr<'_>) -> bool {
if let Some(inner_expr) = peels_blocks_incl_unsafe_opt(expr) {
// there can be not statements in the block as they would be removed when switching to `.filter`
if let ExprKind::Call(callee, [arg]) = inner_expr.kind {
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs b/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs
index 6647322ca..675a85ae5 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs
@@ -1,13 +1,13 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::ty::is_type_lang_item;
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::intravisit::{walk_expr, Visitor};
-use rustc_hir::{Arm, Expr, ExprKind, PatKind};
+use rustc_hir::{Arm, Expr, ExprKind, LangItem, PatKind};
use rustc_lint::LateContext;
use rustc_middle::ty;
use rustc_span::symbol::Symbol;
-use rustc_span::{sym, Span};
+use rustc_span::Span;
use super::MATCH_STR_CASE_MISMATCH;
@@ -59,7 +59,7 @@ impl<'a, 'tcx> MatchExprVisitor<'a, 'tcx> {
if let Some(case_method) = get_case_method(segment_ident) {
let ty = self.cx.typeck_results().expr_ty(receiver).peel_refs();
- if is_type_diagnostic_item(self.cx, ty, sym::String) || ty.kind() == &ty::Str {
+ if is_type_lang_item(self.cx, ty, LangItem::String) || ty.kind() == &ty::Str {
self.case_method = Some(case_method);
return true;
}
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 6f8d766ae..7f8d12483 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
@@ -65,14 +65,14 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
_ => return,
};
if arm.guard.is_none() {
- missing_variants.retain(|e| e.ctor_def_id != Some(id));
+ missing_variants.retain(|e| e.ctor_def_id() != Some(id));
}
path
},
PatKind::TupleStruct(path, patterns, ..) => {
if let Some(id) = cx.qpath_res(path, pat.hir_id).opt_def_id() {
if arm.guard.is_none() && patterns.iter().all(|p| !is_refutable(cx, p)) {
- missing_variants.retain(|e| e.ctor_def_id != Some(id));
+ missing_variants.retain(|e| e.ctor_def_id() != Some(id));
}
}
path
@@ -122,11 +122,11 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
s
},
variant.name,
- match variant.ctor_kind {
- CtorKind::Fn if variant.fields.len() == 1 => "(_)",
- CtorKind::Fn => "(..)",
- CtorKind::Const => "",
- CtorKind::Fictive => "{ .. }",
+ match variant.ctor_kind() {
+ Some(CtorKind::Fn) if variant.fields.len() == 1 => "(_)",
+ Some(CtorKind::Fn) => "(..)",
+ Some(CtorKind::Const) => "",
+ None => "{ .. }",
}
)
};
diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs
index 7d8171ead..7b15a307f 100644
--- a/src/tools/clippy/clippy_lints/src/matches/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs
@@ -23,13 +23,13 @@ mod single_match;
mod try_err;
mod wild_in_or_pats;
+use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::{snippet_opt, walk_span_to_context};
-use clippy_utils::{higher, in_constant, is_span_match, meets_msrv, msrvs};
+use clippy_utils::{higher, in_constant, is_span_match};
use rustc_hir::{Arm, Expr, ExprKind, Local, MatchSource, Pat};
use rustc_lexer::{tokenize, TokenKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{Span, SpanData, SyntaxContext};
@@ -930,13 +930,13 @@ declare_clippy_lint! {
#[derive(Default)]
pub struct Matches {
- msrv: Option<RustcVersion>,
+ msrv: Msrv,
infallible_destructuring_match_linted: bool,
}
impl Matches {
#[must_use]
- pub fn new(msrv: Option<RustcVersion>) -> Self {
+ pub fn new(msrv: Msrv) -> Self {
Self {
msrv,
..Matches::default()
@@ -1000,9 +1000,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
if !from_expansion && !contains_cfg_arm(cx, expr, ex, arms) {
if source == MatchSource::Normal {
- if !(meets_msrv(self.msrv, msrvs::MATCHES_MACRO)
- && match_like_matches::check_match(cx, expr, ex, arms))
- {
+ if !(self.msrv.meets(msrvs::MATCHES_MACRO) && match_like_matches::check_match(cx, expr, ex, arms)) {
match_same_arms::check(cx, arms);
}
@@ -1034,7 +1032,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
collapsible_match::check_if_let(cx, if_let.let_pat, if_let.if_then, if_let.if_else);
if !from_expansion {
if let Some(else_expr) = if_let.if_else {
- if meets_msrv(self.msrv, msrvs::MATCHES_MACRO) {
+ if self.msrv.meets(msrvs::MATCHES_MACRO) {
match_like_matches::check_if_let(
cx,
expr,
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 85269e533..f587c69f7 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
@@ -83,8 +83,8 @@ fn set_diagnostic<'tcx>(diag: &mut Diagnostic, cx: &LateContext<'tcx>, expr: &'t
/// If the expression is an `ExprKind::Match`, check if the scrutinee has a significant drop that
/// may have a surprising lifetime.
-fn has_significant_drop_in_scrutinee<'tcx, 'a>(
- cx: &'a LateContext<'tcx>,
+fn has_significant_drop_in_scrutinee<'tcx>(
+ cx: &LateContext<'tcx>,
scrutinee: &'tcx Expr<'tcx>,
source: MatchSource,
) -> Option<(Vec<FoundSigDrop>, &'static str)> {
@@ -226,7 +226,7 @@ impl<'a, 'tcx> SigDropHelper<'a, 'tcx> {
/// This will try to set the current suggestion (so it can be moved into the suggestions vec
/// later). If `allow_move_and_clone` is false, the suggestion *won't* be set -- this gives us
/// an opportunity to look for another type in the chain that will be trivially copyable.
- /// However, if we are at the the end of the chain, we want to accept whatever is there. (The
+ /// However, if we are at the end of the chain, we want to accept whatever is there. (The
/// suggestion won't actually be output, but the diagnostic message will be output, so the user
/// can determine the best way to handle the lint.)
fn try_setting_current_suggestion(&mut self, expr: &'tcx Expr<'_>, allow_move_and_clone: bool) {
@@ -377,7 +377,7 @@ impl<'a, 'tcx> ArmSigDropHelper<'a, 'tcx> {
}
}
-fn has_significant_drop_in_arms<'tcx, 'a>(cx: &'a LateContext<'tcx>, arms: &'tcx [Arm<'_>]) -> FxHashSet<Span> {
+fn has_significant_drop_in_arms<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) -> FxHashSet<Span> {
let mut helper = ArmSigDropHelper::new(cx);
for arm in arms {
helper.visit_expr(arm.body);
diff --git a/src/tools/clippy/clippy_lints/src/matches/single_match.rs b/src/tools/clippy/clippy_lints/src/matches/single_match.rs
index e5a15b2e1..19b49c44d 100644
--- a/src/tools/clippy/clippy_lints/src/matches/single_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/single_match.rs
@@ -153,7 +153,7 @@ fn pat_in_candidate_enum<'a>(cx: &LateContext<'a>, ty: Ty<'a>, pat: &Pat<'_>) ->
}
/// Returns `true` if the given type is an enum we know won't be expanded in the future
-fn in_candidate_enum<'a>(cx: &LateContext<'a>, ty: Ty<'_>) -> bool {
+fn in_candidate_enum(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
// list of candidate `Enum`s we know will never get any more members
let candidates = [sym::Cow, sym::Option, sym::Result];
diff --git a/src/tools/clippy/clippy_lints/src/matches/try_err.rs b/src/tools/clippy/clippy_lints/src/matches/try_err.rs
index c6cba81d8..704c34c32 100644
--- a/src/tools/clippy/clippy_lints/src/matches/try_err.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/try_err.rs
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{get_parent_expr, is_res_lang_ctor, match_def_path, path_res, paths};
+use clippy_utils::{get_parent_expr, is_res_lang_ctor, path_res};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::LangItem::ResultErr;
@@ -107,7 +107,7 @@ fn result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'t
fn poll_result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
if_chain! {
if let ty::Adt(def, subst) = ty.kind();
- if match_def_path(cx, def.did(), &paths::POLL);
+ if cx.tcx.lang_items().get(LangItem::Poll) == Some(def.did());
let ready_ty = subst.type_at(0);
if let ty::Adt(ready_def, ready_subst) = ready_ty.kind();
@@ -124,7 +124,7 @@ fn poll_result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<
fn poll_option_result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
if_chain! {
if let ty::Adt(def, subst) = ty.kind();
- if match_def_path(cx, def.did(), &paths::POLL);
+ if cx.tcx.lang_items().get(LangItem::Poll) == Some(def.did());
let ready_ty = subst.type_at(0);
if let ty::Adt(ready_def, ready_subst) = ready_ty.kind();
diff --git a/src/tools/clippy/clippy_lints/src/mem_replace.rs b/src/tools/clippy/clippy_lints/src/mem_replace.rs
index 0c4d9f100..35024ec12 100644
--- a/src/tools/clippy/clippy_lints/src/mem_replace.rs
+++ b/src/tools/clippy/clippy_lints/src/mem_replace.rs
@@ -1,14 +1,14 @@
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::{snippet, snippet_with_applicability};
use clippy_utils::ty::is_non_aggregate_primitive_type;
-use clippy_utils::{is_default_equivalent, is_res_lang_ctor, meets_msrv, msrvs, path_res};
+use clippy_utils::{is_default_equivalent, is_res_lang_ctor, path_res};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::LangItem::OptionNone;
use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, QPath};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::lint::in_external_macro;
-use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Span;
use rustc_span::symbol::sym;
@@ -227,12 +227,12 @@ fn check_replace_with_default(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<
}
pub struct MemReplace {
- msrv: Option<RustcVersion>,
+ msrv: Msrv,
}
impl MemReplace {
#[must_use]
- pub fn new(msrv: Option<RustcVersion>) -> Self {
+ pub fn new(msrv: Msrv) -> Self {
Self { msrv }
}
}
@@ -248,7 +248,7 @@ impl<'tcx> LateLintPass<'tcx> for MemReplace {
then {
check_replace_option_with_none(cx, src, dest, expr.span);
check_replace_with_uninit(cx, src, dest, expr.span);
- if meets_msrv(self.msrv, msrvs::MEM_TAKE) {
+ if self.msrv.meets(msrvs::MEM_TAKE) {
check_replace_with_default(cx, src, dest, expr.span);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs b/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
index cc26b0f7f..4720a6e68 100644
--- a/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
@@ -41,7 +41,7 @@ pub(crate) trait BindInsteadOfMap {
const GOOD_METHOD_NAME: &'static str;
fn no_op_msg(cx: &LateContext<'_>) -> Option<String> {
- let variant_id = cx.tcx.lang_items().require(Self::VARIANT_LANG_ITEM).ok()?;
+ let variant_id = cx.tcx.lang_items().get(Self::VARIANT_LANG_ITEM)?;
let item_id = cx.tcx.parent(variant_id);
Some(format!(
"using `{}.{}({})`, which is a no-op",
@@ -52,7 +52,7 @@ pub(crate) trait BindInsteadOfMap {
}
fn lint_msg(cx: &LateContext<'_>) -> Option<String> {
- let variant_id = cx.tcx.lang_items().require(Self::VARIANT_LANG_ITEM).ok()?;
+ let variant_id = cx.tcx.lang_items().get(Self::VARIANT_LANG_ITEM)?;
let item_id = cx.tcx.parent(variant_id);
Some(format!(
"using `{}.{}(|x| {}(y))`, which is more succinctly expressed as `{}(|x| y)`",
@@ -144,7 +144,7 @@ pub(crate) trait BindInsteadOfMap {
fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) -> bool {
if_chain! {
if let Some(adt) = cx.typeck_results().expr_ty(recv).ty_adt_def();
- if let Ok(vid) = cx.tcx.lang_items().require(Self::VARIANT_LANG_ITEM);
+ if let Some(vid) = cx.tcx.lang_items().get(Self::VARIANT_LANG_ITEM);
if adt.did() == cx.tcx.parent(vid);
then {} else { return false; }
}
@@ -181,7 +181,7 @@ pub(crate) trait BindInsteadOfMap {
fn is_variant(cx: &LateContext<'_>, res: Res) -> bool {
if let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Fn), id) = res {
- if let Ok(variant_id) = cx.tcx.lang_items().require(Self::VARIANT_LANG_ITEM) {
+ if let Some(variant_id) = cx.tcx.lang_items().get(Self::VARIANT_LANG_ITEM) {
return cx.tcx.parent(id) == variant_id;
}
}
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 fcfc25b52..89aaad359 100644
--- a/src/tools/clippy/clippy_lints/src/methods/bytes_count_to_len.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/bytes_count_to_len.rs
@@ -1,11 +1,10 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::ty::is_type_lang_item;
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
-use rustc_span::sym;
use super::BYTES_COUNT_TO_LEN;
@@ -20,7 +19,7 @@ pub(super) fn check<'tcx>(
if let Some(impl_id) = cx.tcx.impl_of_method(bytes_id);
if cx.tcx.type_of(impl_id).is_str();
let ty = cx.typeck_results().expr_ty(bytes_recv).peel_refs();
- if ty.is_str() || is_type_diagnostic_item(cx, ty, sym::String);
+ if ty.is_str() || is_type_lang_item(cx, ty, hir::LangItem::String);
then {
let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg(
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 2e96346be..d512cc4ee 100644
--- a/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs
@@ -1,10 +1,9 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::ty::is_type_lang_item;
use rustc_errors::Applicability;
-use rustc_hir::Expr;
+use rustc_hir::{Expr, LangItem};
use rustc_lint::LateContext;
-use rustc_span::sym;
use super::BYTES_NTH;
@@ -12,7 +11,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E
let ty = cx.typeck_results().expr_ty(recv).peel_refs();
let caller_type = if ty.is_str() {
"str"
- } else if is_type_diagnostic_item(cx, ty, sym::String) {
+ } else if is_type_lang_item(cx, ty, LangItem::String) {
"String"
} else {
return;
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 b3c2c7c9a..d226c0bba 100644
--- a/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs
@@ -1,10 +1,10 @@
use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::ty::is_type_lang_item;
use if_chain::if_chain;
use rustc_ast::ast::LitKind;
-use rustc_hir::{Expr, ExprKind};
+use rustc_hir::{Expr, ExprKind, LangItem};
use rustc_lint::LateContext;
-use rustc_span::{source_map::Spanned, symbol::sym, Span};
+use rustc_span::{source_map::Spanned, Span};
use super::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS;
@@ -26,7 +26,7 @@ pub(super) fn check<'tcx>(
if ext_str.chars().skip(1).all(|c| c.is_uppercase() || c.is_ascii_digit())
|| ext_str.chars().skip(1).all(|c| c.is_lowercase() || c.is_ascii_digit());
let recv_ty = cx.typeck_results().expr_ty(recv).peel_refs();
- if recv_ty.is_str() || is_type_diagnostic_item(cx, recv_ty, sym::String);
+ if recv_ty.is_str() || is_type_lang_item(cx, recv_ty, LangItem::String);
then {
span_lint_and_help(
cx,
diff --git a/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs
index 7e8087606..27a05337a 100644
--- a/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs
@@ -9,8 +9,8 @@ use rustc_lint::LateContext;
use rustc_lint::Lint;
/// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints with `unwrap()`.
-pub(super) fn check<'tcx>(
- cx: &LateContext<'tcx>,
+pub(super) fn check(
+ cx: &LateContext<'_>,
info: &crate::methods::BinaryExprInfo<'_>,
chain_methods: &[&str],
lint: &'static Lint,
diff --git a/src/tools/clippy/clippy_lints/src/methods/chars_last_cmp.rs b/src/tools/clippy/clippy_lints/src/methods/chars_last_cmp.rs
index 07bbc5ca1..2efff4c3c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/chars_last_cmp.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/chars_last_cmp.rs
@@ -4,7 +4,7 @@ use rustc_lint::LateContext;
use super::CHARS_LAST_CMP;
/// Checks for the `CHARS_LAST_CMP` lint.
-pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, info: &crate::methods::BinaryExprInfo<'_>) -> bool {
+pub(super) fn check(cx: &LateContext<'_>, info: &crate::methods::BinaryExprInfo<'_>) -> bool {
if chars_cmp::check(cx, info, &["chars", "last"], CHARS_LAST_CMP, "ends_with") {
true
} else {
diff --git a/src/tools/clippy/clippy_lints/src/methods/chars_last_cmp_with_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/chars_last_cmp_with_unwrap.rs
index c29ee0ec8..5b8713f7d 100644
--- a/src/tools/clippy/clippy_lints/src/methods/chars_last_cmp_with_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/chars_last_cmp_with_unwrap.rs
@@ -4,7 +4,7 @@ use rustc_lint::LateContext;
use super::CHARS_LAST_CMP;
/// Checks for the `CHARS_LAST_CMP` lint with `unwrap()`.
-pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, info: &crate::methods::BinaryExprInfo<'_>) -> bool {
+pub(super) fn check(cx: &LateContext<'_>, info: &crate::methods::BinaryExprInfo<'_>) -> bool {
if chars_cmp_with_unwrap::check(cx, info, &["chars", "last", "unwrap"], CHARS_LAST_CMP, "ends_with") {
true
} else {
diff --git a/src/tools/clippy/clippy_lints/src/methods/chars_next_cmp.rs b/src/tools/clippy/clippy_lints/src/methods/chars_next_cmp.rs
index a6701d883..b631fecab 100644
--- a/src/tools/clippy/clippy_lints/src/methods/chars_next_cmp.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/chars_next_cmp.rs
@@ -3,6 +3,6 @@ use rustc_lint::LateContext;
use super::CHARS_NEXT_CMP;
/// Checks for the `CHARS_NEXT_CMP` lint.
-pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, info: &crate::methods::BinaryExprInfo<'_>) -> bool {
+pub(super) fn check(cx: &LateContext<'_>, info: &crate::methods::BinaryExprInfo<'_>) -> bool {
crate::methods::chars_cmp::check(cx, info, &["chars", "next"], CHARS_NEXT_CMP, "starts_with")
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/chars_next_cmp_with_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/chars_next_cmp_with_unwrap.rs
index 28ede28e9..caf21d3ff 100644
--- a/src/tools/clippy/clippy_lints/src/methods/chars_next_cmp_with_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/chars_next_cmp_with_unwrap.rs
@@ -3,6 +3,6 @@ use rustc_lint::LateContext;
use super::CHARS_NEXT_CMP;
/// Checks for the `CHARS_NEXT_CMP` lint with `unwrap()`.
-pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, info: &crate::methods::BinaryExprInfo<'_>) -> bool {
+pub(super) fn check(cx: &LateContext<'_>, info: &crate::methods::BinaryExprInfo<'_>) -> bool {
crate::methods::chars_cmp_with_unwrap::check(cx, info, &["chars", "next", "unwrap"], CHARS_NEXT_CMP, "starts_with")
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs b/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs
index e9aeab2d5..4e6ec61f6 100644
--- a/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs
@@ -1,25 +1,25 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::is_trait_method;
+use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::ty::{get_iterator_item_ty, is_copy};
-use clippy_utils::{is_trait_method, meets_msrv, msrvs};
use rustc_errors::Applicability;
use rustc_hir::Expr;
use rustc_lint::LateContext;
use rustc_middle::ty;
-use rustc_semver::RustcVersion;
use rustc_span::{sym, Span};
use super::CLONED_INSTEAD_OF_COPIED;
-pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, msrv: Option<RustcVersion>) {
+pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, msrv: &Msrv) {
let recv_ty = cx.typeck_results().expr_ty_adjusted(recv);
let inner_ty = match recv_ty.kind() {
// `Option<T>` -> `T`
ty::Adt(adt, subst)
- if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) && meets_msrv(msrv, msrvs::OPTION_COPIED) =>
+ if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) && msrv.meets(msrvs::OPTION_COPIED) =>
{
subst.type_at(0)
},
- _ if is_trait_method(cx, expr, sym::Iterator) && meets_msrv(msrv, msrvs::ITERATOR_COPIED) => {
+ _ if is_trait_method(cx, expr, sym::Iterator) && msrv.meets(msrvs::ITERATOR_COPIED) => {
match get_iterator_item_ty(cx, recv_ty) {
// <T as Iterator>::Item
Some(ty) => ty,
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 501646863..ac61b4377 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
@@ -23,7 +23,7 @@ pub(super) fn check<'tcx>(
// If the parent node's `to` argument is the same as the `to` argument
// of the last replace call in the current chain, don't lint as it was already linted
if let Some(parent) = get_parent_expr(cx, expr)
- && let Some(("replace", _, [current_from, current_to], _)) = method_call(parent)
+ && let Some(("replace", _, [current_from, current_to], _, _)) = method_call(parent)
&& eq_expr_value(cx, to, current_to)
&& from_kind == cx.typeck_results().expr_ty(current_from).peel_refs().kind()
{
@@ -48,7 +48,7 @@ fn collect_replace_calls<'tcx>(
let mut from_args = VecDeque::new();
let _: Option<()> = for_each_expr(expr, |e| {
- if let Some(("replace", _, [from, to], _)) = method_call(e) {
+ if let Some(("replace", _, [from, to], _, _)) = method_call(e) {
if eq_expr_value(cx, to_arg, to) && cx.typeck_results().expr_ty(from).peel_refs().is_char() {
methods.push_front(e);
from_args.push_front(from);
@@ -78,7 +78,7 @@ fn check_consecutive_replace_calls<'tcx>(
.collect();
let app = Applicability::MachineApplicable;
let earliest_replace_call = replace_methods.methods.front().unwrap();
- if let Some((_, _, [..], span_lo)) = method_call(earliest_replace_call) {
+ if let Some((_, _, [..], span_lo, _)) = method_call(earliest_replace_call) {
span_lint_and_sugg(
cx,
COLLAPSIBLE_STR_REPLACE,
diff --git a/src/tools/clippy/clippy_lints/src/methods/err_expect.rs b/src/tools/clippy/clippy_lints/src/methods/err_expect.rs
index 720d9a68c..ae03da0d3 100644
--- a/src/tools/clippy/clippy_lints/src/methods/err_expect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/err_expect.rs
@@ -1,27 +1,27 @@
use super::ERR_EXPECT;
use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::ty::has_debug_impl;
-use clippy_utils::{meets_msrv, msrvs, ty::is_type_diagnostic_item};
+use clippy_utils::ty::is_type_diagnostic_item;
use rustc_errors::Applicability;
use rustc_lint::LateContext;
use rustc_middle::ty;
use rustc_middle::ty::Ty;
-use rustc_semver::RustcVersion;
use rustc_span::{sym, Span};
pub(super) fn check(
cx: &LateContext<'_>,
_expr: &rustc_hir::Expr<'_>,
recv: &rustc_hir::Expr<'_>,
- msrv: Option<RustcVersion>,
expect_span: Span,
err_span: Span,
+ msrv: &Msrv,
) {
if_chain! {
if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result);
// Test the version to make sure the lint can be showed (expect_err has been
// introduced in rust 1.17.0 : https://github.com/rust-lang/rust/pull/38982)
- if meets_msrv(msrv, msrvs::EXPECT_ERR);
+ if msrv.meets(msrvs::EXPECT_ERR);
// Grabs the `Result<T, E>` type
let result_type = cx.typeck_results().expr_ty(recv);
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 d0cf411df..a9189b31c 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
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::macros::{root_macro_call_first_node, FormatArgsExpn};
use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
@@ -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_diagnostic_item(cx, base_type, sym::String)
+ *base_type.kind() == ty::Str || is_type_lang_item(cx, base_type, hir::LangItem::String)
} {
receiver
} else {
@@ -50,7 +50,7 @@ pub(super) fn check<'tcx>(
// converted to string.
fn requires_to_string(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool {
let arg_ty = cx.typeck_results().expr_ty(arg);
- if is_type_diagnostic_item(cx, arg_ty, sym::String) {
+ if is_type_lang_item(cx, arg_ty, hir::LangItem::String) {
return false;
}
if let ty::Ref(_, ty, ..) = arg_ty.kind() {
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 d59fefa1d..cce8f797e 100644
--- a/src/tools/clippy/clippy_lints/src/methods/expect_used.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/expect_used.rs
@@ -1,5 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::is_in_test_function;
+use clippy_utils::is_in_cfg_test;
use clippy_utils::ty::is_type_diagnostic_item;
use rustc_hir as hir;
use rustc_lint::LateContext;
@@ -18,16 +18,16 @@ pub(super) fn check(
let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs();
let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) && !is_err {
- Some((EXPECT_USED, "an Option", "None", ""))
+ Some((EXPECT_USED, "an `Option`", "None", ""))
} else if is_type_diagnostic_item(cx, obj_ty, sym::Result) {
- Some((EXPECT_USED, "a Result", if is_err { "Ok" } else { "Err" }, "an "))
+ Some((EXPECT_USED, "a `Result`", if is_err { "Ok" } else { "Err" }, "an "))
} else {
None
};
let method = if is_err { "expect_err" } else { "expect" };
- if allow_expect_in_tests && is_in_test_function(cx.tcx, expr.hir_id) {
+ if allow_expect_in_tests && is_in_cfg_test(cx.tcx, expr.hir_id) {
return;
}
@@ -36,7 +36,7 @@ pub(super) fn check(
cx,
lint,
expr.span,
- &format!("used `{method}()` on `{kind}` value"),
+ &format!("used `{method}()` on {kind} value"),
None,
&format!("if this value is {none_prefix}`{none_value}`, it will panic"),
);
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
index 9719b2f1c..f888c58a7 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
@@ -17,7 +17,7 @@ use super::MANUAL_FILTER_MAP;
use super::MANUAL_FIND_MAP;
use super::OPTION_FILTER_MAP;
-fn is_method<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Symbol) -> bool {
+fn is_method(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol) -> bool {
match &expr.kind {
hir::ExprKind::Path(QPath::TypeRelative(_, mname)) => mname.ident.name == method_name,
hir::ExprKind::Path(QPath::Resolved(_, segments)) => {
@@ -46,7 +46,7 @@ fn is_method<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Sy
}
}
-fn is_option_filter_map<'tcx>(cx: &LateContext<'tcx>, filter_arg: &hir::Expr<'_>, map_arg: &hir::Expr<'_>) -> bool {
+fn is_option_filter_map(cx: &LateContext<'_>, filter_arg: &hir::Expr<'_>, map_arg: &hir::Expr<'_>) -> bool {
is_method(cx, map_arg, sym::unwrap) && is_method(cx, filter_arg, sym!(is_some))
}
@@ -66,8 +66,8 @@ fn is_filter_some_map_unwrap(
/// lint use of `filter().map()` or `find().map()` for `Iterators`
#[allow(clippy::too_many_arguments)]
-pub(super) fn check<'tcx>(
- cx: &LateContext<'tcx>,
+pub(super) fn check(
+ cx: &LateContext<'_>,
expr: &hir::Expr<'_>,
filter_recv: &hir::Expr<'_>,
filter_arg: &hir::Expr<'_>,
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs
index ddf8a1f09..175e04f8a 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs
@@ -1,10 +1,10 @@
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
+use clippy_utils::is_trait_method;
+use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet;
-use clippy_utils::{is_trait_method, meets_msrv, msrvs};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
-use rustc_semver::RustcVersion;
use rustc_span::sym;
use super::FILTER_MAP_NEXT;
@@ -14,10 +14,10 @@ pub(super) fn check<'tcx>(
expr: &'tcx hir::Expr<'_>,
recv: &'tcx hir::Expr<'_>,
arg: &'tcx hir::Expr<'_>,
- msrv: Option<RustcVersion>,
+ msrv: &Msrv,
) {
if is_trait_method(cx, expr, sym::Iterator) {
- if !meets_msrv(msrv, msrvs::ITERATOR_FIND_MAP) {
+ if !msrv.meets(msrvs::ITERATOR_FIND_MAP) {
return;
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs b/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs
index ede3b8bb7..d8c821bc9 100644
--- a/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs
@@ -1,19 +1,19 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::{is_type_diagnostic_item, walk_ptrs_ty_depth};
+use clippy_utils::ty::{is_type_lang_item, walk_ptrs_ty_depth};
use clippy_utils::{match_def_path, paths};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_middle::ty::{self, Ty};
-use rustc_span::symbol::{sym, Symbol};
+use rustc_span::symbol::{Symbol, sym};
use super::INEFFICIENT_TO_STRING;
/// Checks for the `INEFFICIENT_TO_STRING` lint
-pub fn check<'tcx>(
- cx: &LateContext<'tcx>,
+pub fn check(
+ cx: &LateContext<'_>,
expr: &hir::Expr<'_>,
method_name: Symbol,
receiver: &hir::Expr<'_>,
@@ -60,7 +60,7 @@ fn specializes_tostring(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
return true;
}
- if is_type_diagnostic_item(cx, ty, sym::String) {
+ if is_type_lang_item(cx, ty, hir::LangItem::String) {
return true;
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs b/src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs
index 304024e80..301aff5ae 100644
--- a/src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs
@@ -1,23 +1,22 @@
//! Lint for `c.is_digit(10)`
use super::IS_DIGIT_ASCII_RADIX;
+use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::{
- consts::constant_full_int, consts::FullInt, diagnostics::span_lint_and_sugg, meets_msrv, msrvs,
- source::snippet_with_applicability,
+ consts::constant_full_int, consts::FullInt, diagnostics::span_lint_and_sugg, source::snippet_with_applicability,
};
use rustc_errors::Applicability;
use rustc_hir::Expr;
use rustc_lint::LateContext;
-use rustc_semver::RustcVersion;
pub(super) fn check<'tcx>(
cx: &LateContext<'tcx>,
expr: &'tcx Expr<'_>,
self_arg: &'tcx Expr<'_>,
radix: &'tcx Expr<'_>,
- msrv: Option<RustcVersion>,
+ msrv: &Msrv,
) {
- if !meets_msrv(msrv, msrvs::IS_ASCII_DIGIT) {
+ if !msrv.meets(msrvs::IS_ASCII_DIGIT) {
return;
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs b/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs
index 68d906c3e..c830958d5 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs
@@ -10,7 +10,7 @@ use rustc_span::sym;
use super::ITER_NTH_ZERO;
-pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) {
if_chain! {
if is_trait_method(cx, expr, sym::Iterator);
if let Some((Constant::Int(0), _)) = constant(cx, cx.typeck_results(), arg);
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs b/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs
index 4f73b3ec4..70abe4891 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs
@@ -25,7 +25,7 @@ impl IterType {
}
}
-pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, method_name: &str, recv: &Expr<'_>) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: &str, recv: &Expr<'_>) {
let item = match recv.kind {
ExprKind::Array([]) => None,
ExprKind::Array([e]) => Some(e),
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
index 06a39c599..b4210d875 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
@@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet_opt;
-use clippy_utils::ty::{get_associated_type, implements_trait, is_copy};
+use clippy_utils::ty::{implements_trait, is_copy};
use rustc_errors::Applicability;
use rustc_hir::Expr;
use rustc_lint::LateContext;
@@ -25,7 +25,7 @@ pub(super) fn check<'tcx>(
&& let Some(method_id) = typeck.type_dependent_def_id(cloned_call.hir_id)
&& cx.tcx.trait_of_item(method_id) == Some(iter_id)
&& let cloned_recv_ty = typeck.expr_ty_adjusted(cloned_recv)
- && let Some(iter_assoc_ty) = get_associated_type(cx, cloned_recv_ty, iter_id, "Item")
+ && let Some(iter_assoc_ty) = cx.get_associated_type(cloned_recv_ty, iter_id, "Item")
&& matches!(*iter_assoc_ty.kind(), ty::Ref(_, ty, _) if !is_copy(cx, ty))
{
if needs_into_iter
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs
index b80541b86..a7284c644 100644
--- a/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs
@@ -67,7 +67,7 @@ enum MinMax {
Max,
}
-fn is_min_or_max<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) -> Option<MinMax> {
+fn is_min_or_max(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<MinMax> {
// `T::max_value()` `T::min_value()` inherent methods
if_chain! {
if let hir::ExprKind::Call(func, args) = &expr.kind;
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs b/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs
index 8b6b8f1bf..a08f72540 100644
--- a/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs
@@ -36,14 +36,14 @@ fn parse_repeat_arg(cx: &LateContext<'_>, e: &Expr<'_>) -> Option<RepeatKind> {
}
} else {
let ty = cx.typeck_results().expr_ty(e);
- if is_type_diagnostic_item(cx, ty, sym::String)
+ if is_type_lang_item(cx, ty, LangItem::String)
|| (is_type_lang_item(cx, ty, LangItem::OwnedBox) && get_ty_param(ty).map_or(false, Ty::is_str))
|| (is_type_diagnostic_item(cx, ty, sym::Cow) && get_ty_param(ty).map_or(false, Ty::is_str))
{
Some(RepeatKind::String)
} else {
let ty = ty.peel_refs();
- (ty.is_str() || is_type_diagnostic_item(cx, ty, sym::String)).then_some(RepeatKind::String)
+ (ty.is_str() || is_type_lang_item(cx, ty, LangItem::String)).then_some(RepeatKind::String)
}
}
}
@@ -58,11 +58,9 @@ pub(super) fn check(
if_chain! {
if let ExprKind::Call(repeat_fn, [repeat_arg]) = take_self_arg.kind;
if is_path_diagnostic_item(cx, repeat_fn, sym::iter_repeat);
- if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(collect_expr), sym::String);
- if let Some(collect_id) = cx.typeck_results().type_dependent_def_id(collect_expr.hir_id);
+ if is_type_lang_item(cx, cx.typeck_results().expr_ty(collect_expr), LangItem::String);
if let Some(take_id) = cx.typeck_results().type_dependent_def_id(take_expr.hir_id);
if let Some(iter_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator);
- if cx.tcx.trait_of_item(collect_id) == Some(iter_trait_id);
if cx.tcx.trait_of_item(take_id) == Some(iter_trait_id);
if let Some(repeat_kind) = parse_repeat_arg(cx, repeat_arg);
let ctxt = collect_expr.span.ctxt();
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 7ce14ec08..52cc1e046 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs
@@ -1,7 +1,8 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::{is_copy, is_type_diagnostic_item};
-use clippy_utils::{is_diag_trait_item, meets_msrv, msrvs, peel_blocks};
+use clippy_utils::{is_diag_trait_item, peel_blocks};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
@@ -9,19 +10,12 @@ use rustc_lint::LateContext;
use rustc_middle::mir::Mutability;
use rustc_middle::ty;
use rustc_middle::ty::adjustment::Adjust;
-use rustc_semver::RustcVersion;
use rustc_span::symbol::Ident;
use rustc_span::{sym, Span};
use super::MAP_CLONE;
-pub(super) fn check<'tcx>(
- cx: &LateContext<'_>,
- e: &hir::Expr<'_>,
- recv: &hir::Expr<'_>,
- arg: &'tcx hir::Expr<'_>,
- msrv: Option<RustcVersion>,
-) {
+pub(super) fn check(cx: &LateContext<'_>, e: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>, msrv: &Msrv) {
if_chain! {
if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id);
if cx.tcx.impl_of_method(method_id)
@@ -97,10 +91,10 @@ fn lint_needless_cloning(cx: &LateContext<'_>, root: Span, receiver: Span) {
);
}
-fn lint_explicit_closure(cx: &LateContext<'_>, replace: Span, root: Span, is_copy: bool, msrv: Option<RustcVersion>) {
+fn lint_explicit_closure(cx: &LateContext<'_>, replace: Span, root: Span, is_copy: bool, msrv: &Msrv) {
let mut applicability = Applicability::MachineApplicable;
- let (message, sugg_method) = if is_copy && meets_msrv(msrv, msrvs::ITERATOR_COPIED) {
+ let (message, sugg_method) = if is_copy && msrv.meets(msrvs::ITERATOR_COPIED) {
("you are using an explicit closure for copying elements", "copied")
} else {
("you are using an explicit closure for cloning elements", "cloned")
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_collect_result_unit.rs b/src/tools/clippy/clippy_lints/src/methods/map_collect_result_unit.rs
index d420f144e..a0300d278 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_collect_result_unit.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_collect_result_unit.rs
@@ -1,5 +1,4 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::is_trait_method;
use clippy_utils::source::snippet;
use clippy_utils::ty::is_type_diagnostic_item;
use if_chain::if_chain;
@@ -11,18 +10,10 @@ use rustc_span::symbol::sym;
use super::MAP_COLLECT_RESULT_UNIT;
-pub(super) fn check(
- cx: &LateContext<'_>,
- expr: &hir::Expr<'_>,
- iter: &hir::Expr<'_>,
- map_fn: &hir::Expr<'_>,
- collect_recv: &hir::Expr<'_>,
-) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, iter: &hir::Expr<'_>, map_fn: &hir::Expr<'_>) {
+ // return of collect `Result<(),_>`
+ let collect_ret_ty = cx.typeck_results().expr_ty(expr);
if_chain! {
- // called on Iterator
- if is_trait_method(cx, collect_recv, sym::Iterator);
- // return of collect `Result<(),_>`
- let collect_ret_ty = cx.typeck_results().expr_ty(expr);
if is_type_diagnostic_item(cx, collect_ret_ty, sym::Result);
if let ty::Adt(_, substs) = collect_ret_ty.kind();
if let Some(result_t) = substs.types().next();
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 1fb661714..b773b3e42 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
@@ -6,7 +6,7 @@ use rustc_span::sym;
use super::MAP_ERR_IGNORE;
-pub(super) fn check<'tcx>(cx: &LateContext<'_>, e: &Expr<'_>, arg: &'tcx Expr<'_>) {
+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)
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs
index 74fdead21..3122f72ee 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs
@@ -1,12 +1,11 @@
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
+use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::usage::mutated_variables;
-use clippy_utils::{meets_msrv, msrvs};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
-use rustc_semver::RustcVersion;
use rustc_span::symbol::sym;
use super::MAP_UNWRAP_OR;
@@ -19,13 +18,13 @@ pub(super) fn check<'tcx>(
recv: &'tcx hir::Expr<'_>,
map_arg: &'tcx hir::Expr<'_>,
unwrap_arg: &'tcx hir::Expr<'_>,
- msrv: Option<RustcVersion>,
+ msrv: &Msrv,
) -> bool {
// lint if the caller of `map()` is an `Option`
let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Option);
let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result);
- if is_result && !meets_msrv(msrv, msrvs::RESULT_MAP_OR_ELSE) {
+ if is_result && !msrv.meets(msrvs::RESULT_MAP_OR_ELSE) {
return false;
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index 8a76ba0b0..d2913680c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -54,6 +54,7 @@ mod map_flatten;
mod map_identity;
mod map_unwrap_or;
mod mut_mutex_lock;
+mod needless_collect;
mod needless_option_as_deref;
mod needless_option_take;
mod no_effect_replace;
@@ -69,6 +70,8 @@ mod path_buf_push_overwrite;
mod range_zip_with_len;
mod repeat_once;
mod search_is_some;
+mod seek_from_current;
+mod seek_to_start_instead_of_rewind;
mod single_char_add_str;
mod single_char_insert_string;
mod single_char_pattern;
@@ -101,17 +104,16 @@ mod zst_offset;
use bind_instead_of_map::BindInsteadOfMap;
use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
-use clippy_utils::ty::{contains_adt_constructor, implements_trait, is_copy, is_type_diagnostic_item};
-use clippy_utils::{contains_return, is_trait_method, iter_input_pats, meets_msrv, msrvs, return_ty};
+use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::ty::{contains_ty_adt_constructor_opaque, implements_trait, is_copy, is_type_diagnostic_item};
+use clippy_utils::{contains_return, is_bool, is_trait_method, iter_input_pats, return_ty};
use if_chain::if_chain;
use rustc_hir as hir;
-use rustc_hir::def::Res;
-use rustc_hir::{Expr, ExprKind, PrimTy, QPath, TraitItem, TraitItemKind};
+use rustc_hir::{Expr, ExprKind, TraitItem, TraitItemKind};
use rustc_hir_analysis::hir_ty_to_ty;
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::{self, TraitRef, Ty};
-use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{sym, Span};
@@ -156,9 +158,9 @@ declare_clippy_lint! {
/// ```
/// Use instead:
/// ```rust
- /// let hello = "hesuo worpd".replace(&['s', 'u', 'p'], "l");
+ /// let hello = "hesuo worpd".replace(['s', 'u', 'p'], "l");
/// ```
- #[clippy::version = "1.64.0"]
+ #[clippy::version = "1.65.0"]
pub COLLAPSIBLE_STR_REPLACE,
perf,
"collapse consecutive calls to str::replace (2 or more) into a single call"
@@ -829,32 +831,30 @@ declare_clippy_lint! {
/// etc. instead.
///
/// ### Why is this bad?
- /// The function will always be called and potentially
- /// allocate an object acting as the default.
+ /// The function will always be called. This is only bad if it allocates or
+ /// does some non-trivial amount of work.
///
/// ### Known problems
- /// If the function has side-effects, not calling it will
- /// change the semantic of the program, but you shouldn't rely on that anyway.
+ /// If the function has side-effects, not calling it will change the
+ /// semantic of the program, but you shouldn't rely on that.
+ ///
+ /// The lint also cannot figure out whether the function you call is
+ /// actually expensive to call or not.
///
/// ### Example
/// ```rust
/// # let foo = Some(String::new());
- /// foo.unwrap_or(String::new());
+ /// foo.unwrap_or(String::from("empty"));
/// ```
///
/// Use instead:
/// ```rust
/// # let foo = Some(String::new());
- /// foo.unwrap_or_else(String::new);
- ///
- /// // or
- ///
- /// # let foo = Some(String::new());
- /// foo.unwrap_or_default();
+ /// foo.unwrap_or_else(|| String::from("empty"));
/// ```
#[clippy::version = "pre 1.29.0"]
pub OR_FUN_CALL,
- perf,
+ nursery,
"using any `*or` method with a function call, which suggests `*or_else`"
}
@@ -1728,7 +1728,7 @@ declare_clippy_lint! {
declare_clippy_lint! {
/// ### What it does
- /// Checks for usage of `_.as_ref().map(Deref::deref)` or it's aliases (such as String::as_str).
+ /// Checks for usage of `_.as_ref().map(Deref::deref)` or its aliases (such as String::as_str).
///
/// ### Why is this bad?
/// Readability, this can be written more concisely as
@@ -2094,8 +2094,7 @@ declare_clippy_lint! {
/// let s = "Hello world!";
/// let cow = Cow::Borrowed(s);
///
- /// let data = cow.into_owned();
- /// assert!(matches!(data, String))
+ /// let _data: String = cow.into_owned();
/// ```
#[clippy::version = "1.65.0"]
pub SUSPICIOUS_TO_OWNED,
@@ -2426,7 +2425,7 @@ declare_clippy_lint! {
/// ### Known problems
///
/// The type of the resulting iterator might become incompatible with its usage
- #[clippy::version = "1.64.0"]
+ #[clippy::version = "1.65.0"]
pub ITER_ON_SINGLE_ITEMS,
nursery,
"Iterator for array of length 1"
@@ -2458,7 +2457,7 @@ declare_clippy_lint! {
/// ### Known problems
///
/// The type of the resulting iterator might become incompatible with its usage
- #[clippy::version = "1.64.0"]
+ #[clippy::version = "1.65.0"]
pub ITER_ON_EMPTY_COLLECTIONS,
nursery,
"Iterator for empty array"
@@ -3066,9 +3065,105 @@ declare_clippy_lint! {
"iterating on map using `iter` when `keys` or `values` would do"
}
+declare_clippy_lint! {
+ /// ### What it does
+ ///
+ /// Checks an argument of `seek` method of `Seek` trait
+ /// and if it start seek from `SeekFrom::Current(0)`, suggests `stream_position` instead.
+ ///
+ /// ### Why is this bad?
+ ///
+ /// Readability. Use dedicated method.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,no_run
+ /// use std::fs::File;
+ /// use std::io::{self, Write, Seek, SeekFrom};
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let mut f = File::create("foo.txt")?;
+ /// f.write_all(b"Hello")?;
+ /// eprintln!("Written {} bytes", f.seek(SeekFrom::Current(0))?);
+ ///
+ /// Ok(())
+ /// }
+ /// ```
+ /// Use instead:
+ /// ```rust,no_run
+ /// use std::fs::File;
+ /// use std::io::{self, Write, Seek, SeekFrom};
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let mut f = File::create("foo.txt")?;
+ /// f.write_all(b"Hello")?;
+ /// eprintln!("Written {} bytes", f.stream_position()?);
+ ///
+ /// Ok(())
+ /// }
+ /// ```
+ #[clippy::version = "1.66.0"]
+ pub SEEK_FROM_CURRENT,
+ complexity,
+ "use dedicated method for seek from current position"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ ///
+ /// Checks for jumps to the start of a stream that implements `Seek`
+ /// and uses the `seek` method providing `Start` as parameter.
+ ///
+ /// ### Why is this bad?
+ ///
+ /// Readability. There is a specific method that was implemented for
+ /// this exact scenario.
+ ///
+ /// ### Example
+ /// ```rust
+ /// # use std::io;
+ /// fn foo<T: io::Seek>(t: &mut T) {
+ /// t.seek(io::SeekFrom::Start(0));
+ /// }
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// # use std::io;
+ /// fn foo<T: io::Seek>(t: &mut T) {
+ /// t.rewind();
+ /// }
+ /// ```
+ #[clippy::version = "1.66.0"]
+ pub SEEK_TO_START_INSTEAD_OF_REWIND,
+ complexity,
+ "jumping to the start of stream using `seek` method"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for functions collecting an iterator when collect
+ /// is not needed.
+ ///
+ /// ### Why is this bad?
+ /// `collect` causes the allocation of a new data structure,
+ /// when this allocation may not be needed.
+ ///
+ /// ### Example
+ /// ```rust
+ /// # let iterator = vec![1].into_iter();
+ /// let len = iterator.clone().collect::<Vec<_>>().len();
+ /// // should be
+ /// let len = iterator.count();
+ /// ```
+ #[clippy::version = "1.30.0"]
+ pub NEEDLESS_COLLECT,
+ nursery,
+ "collecting an iterator when collect is not needed"
+}
+
pub struct Methods {
avoid_breaking_exported_api: bool,
- msrv: Option<RustcVersion>,
+ msrv: Msrv,
allow_expect_in_tests: bool,
allow_unwrap_in_tests: bool,
}
@@ -3077,7 +3172,7 @@ impl Methods {
#[must_use]
pub fn new(
avoid_breaking_exported_api: bool,
- msrv: Option<RustcVersion>,
+ msrv: Msrv,
allow_expect_in_tests: bool,
allow_unwrap_in_tests: bool,
) -> Self {
@@ -3190,16 +3285,19 @@ impl_lint_pass!(Methods => [
VEC_RESIZE_TO_ZERO,
VERBOSE_FILE_READS,
ITER_KV_MAP,
+ SEEK_FROM_CURRENT,
+ SEEK_TO_START_INSTEAD_OF_REWIND,
+ NEEDLESS_COLLECT,
]);
/// Extracts a method call name, args, and `Span` of the method name.
fn method_call<'tcx>(
recv: &'tcx hir::Expr<'tcx>,
-) -> Option<(&'tcx str, &'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>], Span)> {
- if let ExprKind::MethodCall(path, receiver, args, _) = recv.kind {
+) -> Option<(&'tcx str, &'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>], Span, Span)> {
+ if let ExprKind::MethodCall(path, receiver, args, call_span) = recv.kind {
if !args.iter().any(|e| e.span.from_expansion()) && !receiver.span.from_expansion() {
let name = path.ident.name.as_str();
- return Some((name, receiver, args, path.ident.span));
+ return Some((name, receiver, args, path.ident.span, call_span));
}
}
None
@@ -3227,7 +3325,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
single_char_add_str::check(cx, expr, receiver, args);
into_iter_on_ref::check(cx, expr, method_span, method_call.ident.name, receiver);
single_char_pattern::check(cx, expr, method_call.ident.name, receiver, args);
- unnecessary_to_owned::check(cx, expr, method_call.ident.name, receiver, args, self.msrv);
+ unnecessary_to_owned::check(cx, expr, method_call.ident.name, receiver, args, &self.msrv);
},
hir::ExprKind::Binary(op, lhs, rhs) if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => {
let mut info = BinaryExprInfo {
@@ -3316,36 +3414,10 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
if let hir::ImplItemKind::Fn(_, _) = impl_item.kind {
let ret_ty = return_ty(cx, impl_item.hir_id());
- // walk the return type and check for Self (this does not check associated types)
- if let Some(self_adt) = self_ty.ty_adt_def() {
- if contains_adt_constructor(ret_ty, self_adt) {
- return;
- }
- } else if ret_ty.contains(self_ty) {
+ if contains_ty_adt_constructor_opaque(cx, ret_ty, self_ty) {
return;
}
- // if return type is impl trait, check the associated types
- if let ty::Opaque(def_id, _) = *ret_ty.kind() {
- // one of the associated types must be Self
- for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) {
- if let ty::PredicateKind::Projection(projection_predicate) = predicate.kind().skip_binder() {
- let assoc_ty = match projection_predicate.term.unpack() {
- ty::TermKind::Ty(ty) => ty,
- ty::TermKind::Const(_c) => continue,
- };
- // walk the associated type and check for Self
- if let Some(self_adt) = self_ty.ty_adt_def() {
- if contains_adt_constructor(assoc_ty, self_adt) {
- return;
- }
- } else if assoc_ty.contains(self_ty) {
- return;
- }
- }
- }
- }
-
if name == "new" && ret_ty != self_ty {
span_lint(
cx,
@@ -3411,7 +3483,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
impl Methods {
#[allow(clippy::too_many_lines)]
fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- if let Some((name, recv, args, span)) = method_call(expr) {
+ if let Some((name, recv, args, span, call_span)) = method_call(expr) {
match (name, args) {
("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [_arg]) => {
zst_offset::check(cx, expr, recv);
@@ -3429,29 +3501,32 @@ impl Methods {
("as_mut", []) => useless_asref::check(cx, expr, "as_mut", recv),
("as_ref", []) => useless_asref::check(cx, expr, "as_ref", recv),
("assume_init", []) => uninit_assumed_init::check(cx, expr, recv),
- ("cloned", []) => cloned_instead_of_copied::check(cx, expr, recv, span, self.msrv),
- ("collect", []) => match method_call(recv) {
- Some((name @ ("cloned" | "copied"), recv2, [], _)) => {
- iter_cloned_collect::check(cx, name, expr, recv2);
- },
- Some(("map", m_recv, [m_arg], _)) => {
- map_collect_result_unit::check(cx, expr, m_recv, m_arg, recv);
- },
- Some(("take", take_self_arg, [take_arg], _)) => {
- if meets_msrv(self.msrv, msrvs::STR_REPEAT) {
- manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg);
- }
- },
- _ => {},
+ ("cloned", []) => cloned_instead_of_copied::check(cx, expr, recv, span, &self.msrv),
+ ("collect", []) if is_trait_method(cx, expr, sym::Iterator) => {
+ needless_collect::check(cx, span, expr, recv, call_span);
+ match method_call(recv) {
+ Some((name @ ("cloned" | "copied"), recv2, [], _, _)) => {
+ iter_cloned_collect::check(cx, name, expr, recv2);
+ },
+ Some(("map", m_recv, [m_arg], _, _)) => {
+ map_collect_result_unit::check(cx, expr, m_recv, m_arg);
+ },
+ Some(("take", take_self_arg, [take_arg], _, _)) => {
+ if self.msrv.meets(msrvs::STR_REPEAT) {
+ manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg);
+ }
+ },
+ _ => {},
+ }
},
("count", []) if is_trait_method(cx, expr, sym::Iterator) => match method_call(recv) {
- Some(("cloned", recv2, [], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, true, false),
- Some((name2 @ ("into_iter" | "iter" | "iter_mut"), recv2, [], _)) => {
+ Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, true, false),
+ Some((name2 @ ("into_iter" | "iter" | "iter_mut"), recv2, [], _, _)) => {
iter_count::check(cx, expr, recv2, name2);
},
- Some(("map", _, [arg], _)) => suspicious_map::check(cx, expr, recv, arg),
- Some(("filter", recv2, [arg], _)) => bytecount::check(cx, expr, recv2, arg),
- Some(("bytes", recv2, [], _)) => bytes_count_to_len::check(cx, expr, recv, recv2),
+ Some(("map", _, [arg], _, _)) => suspicious_map::check(cx, expr, recv, arg),
+ Some(("filter", recv2, [arg], _, _)) => bytecount::check(cx, expr, recv2, arg),
+ Some(("bytes", recv2, [], _, _)) => bytes_count_to_len::check(cx, expr, recv, recv2),
_ => {},
},
("drain", [arg]) => {
@@ -3463,8 +3538,8 @@ impl Methods {
}
},
("expect", [_]) => match method_call(recv) {
- Some(("ok", recv, [], _)) => ok_expect::check(cx, expr, recv),
- Some(("err", recv, [], err_span)) => err_expect::check(cx, expr, recv, self.msrv, span, err_span),
+ Some(("ok", recv, [], _, _)) => ok_expect::check(cx, expr, recv),
+ Some(("err", recv, [], err_span, _)) => err_expect::check(cx, expr, recv, span, err_span, &self.msrv),
_ => expect_used::check(cx, expr, recv, false, self.allow_expect_in_tests),
},
("expect_err", [_]) => expect_used::check(cx, expr, recv, true, self.allow_expect_in_tests),
@@ -3484,13 +3559,13 @@ impl Methods {
flat_map_option::check(cx, expr, arg, span);
},
("flatten", []) => match method_call(recv) {
- Some(("map", recv, [map_arg], map_span)) => map_flatten::check(cx, expr, recv, map_arg, map_span),
- Some(("cloned", recv2, [], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, true),
+ Some(("map", recv, [map_arg], map_span, _)) => map_flatten::check(cx, expr, recv, map_arg, map_span),
+ Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, true),
_ => {},
},
("fold", [init, acc]) => unnecessary_fold::check(cx, expr, init, acc, span),
("for_each", [_]) => {
- if let Some(("inspect", _, [_], span2)) = method_call(recv) {
+ if let Some(("inspect", _, [_], span2, _)) = method_call(recv) {
inspect_for_each::check(cx, expr, span2);
}
},
@@ -3503,19 +3578,19 @@ impl Methods {
unit_hash::check(cx, expr, recv, arg);
},
("is_file", []) => filetype_is_file::check(cx, expr, recv),
- ("is_digit", [radix]) => is_digit_ascii_radix::check(cx, expr, recv, radix, self.msrv),
+ ("is_digit", [radix]) => is_digit_ascii_radix::check(cx, expr, recv, radix, &self.msrv),
("is_none", []) => check_is_some_is_none(cx, expr, recv, false),
("is_some", []) => check_is_some_is_none(cx, expr, recv, true),
("iter" | "iter_mut" | "into_iter", []) => {
iter_on_single_or_empty_collections::check(cx, expr, name, recv);
},
("join", [join_arg]) => {
- if let Some(("collect", _, _, span)) = method_call(recv) {
+ if let Some(("collect", _, _, span, _)) = method_call(recv) {
unnecessary_join::check(cx, expr, recv, join_arg, span);
}
},
("last", []) | ("skip", [_]) => {
- if let Some((name2, recv2, args2, _span2)) = method_call(recv) {
+ if let Some((name2, recv2, args2, _span2, _)) = method_call(recv) {
if let ("cloned", []) = (name2, args2) {
iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
}
@@ -3526,17 +3601,17 @@ impl Methods {
},
(name @ ("map" | "map_err"), [m_arg]) => {
if name == "map" {
- map_clone::check(cx, expr, recv, m_arg, self.msrv);
- if let Some((map_name @ ("iter" | "into_iter"), recv2, _, _)) = method_call(recv) {
+ map_clone::check(cx, expr, recv, m_arg, &self.msrv);
+ if let Some((map_name @ ("iter" | "into_iter"), recv2, _, _, _)) = method_call(recv) {
iter_kv_map::check(cx, map_name, expr, recv2, m_arg);
}
} else {
map_err_ignore::check(cx, expr, m_arg);
}
- if let Some((name, recv2, args, span2)) = method_call(recv) {
+ if let Some((name, recv2, args, span2,_)) = method_call(recv) {
match (name, args) {
- ("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, self.msrv),
- ("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, self.msrv),
+ ("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, &self.msrv),
+ ("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, &self.msrv),
("filter", [f_arg]) => {
filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, false);
},
@@ -3553,11 +3628,11 @@ impl Methods {
manual_ok_or::check(cx, expr, recv, def, map);
},
("next", []) => {
- if let Some((name2, recv2, args2, _)) = method_call(recv) {
+ if let Some((name2, recv2, args2, _, _)) = method_call(recv) {
match (name2, args2) {
("cloned", []) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false),
("filter", [arg]) => filter_next::check(cx, expr, recv2, arg),
- ("filter_map", [arg]) => filter_map_next::check(cx, expr, recv2, arg, self.msrv),
+ ("filter_map", [arg]) => filter_map_next::check(cx, expr, recv2, arg, &self.msrv),
("iter", []) => iter_next_slice::check(cx, expr, recv2),
("skip", [arg]) => iter_skip_next::check(cx, expr, recv2, arg),
("skip_while", [_]) => skip_while_next::check(cx, expr),
@@ -3566,10 +3641,10 @@ impl Methods {
}
},
("nth", [n_arg]) => match method_call(recv) {
- Some(("bytes", recv2, [], _)) => bytes_nth::check(cx, expr, recv2, n_arg),
- Some(("cloned", recv2, [], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false),
- Some(("iter", recv2, [], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, false),
- Some(("iter_mut", recv2, [], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, true),
+ Some(("bytes", recv2, [], _, _)) => bytes_nth::check(cx, expr, recv2, n_arg),
+ Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false),
+ Some(("iter", recv2, [], _, _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, false),
+ Some(("iter_mut", recv2, [], _, _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, true),
_ => iter_nth_zero::check(cx, expr, recv, n_arg),
},
("ok_or_else", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or"),
@@ -3604,6 +3679,14 @@ impl Methods {
("resize", [count_arg, default_arg]) => {
vec_resize_to_zero::check(cx, expr, count_arg, default_arg, span);
},
+ ("seek", [arg]) => {
+ if self.msrv.meets(msrvs::SEEK_FROM_CURRENT) {
+ seek_from_current::check(cx, expr, recv, arg);
+ }
+ if self.msrv.meets(msrvs::SEEK_REWIND) {
+ seek_to_start_instead_of_rewind::check(cx, expr, recv, arg, span);
+ }
+ },
("sort", []) => {
stable_sort_primitive::check(cx, expr, recv);
},
@@ -3616,7 +3699,7 @@ impl Methods {
("splitn" | "rsplitn", [count_arg, pat_arg]) => {
if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg) {
suspicious_splitn::check(cx, name, expr, recv, count);
- str_splitn::check(cx, name, expr, recv, pat_arg, count, self.msrv);
+ str_splitn::check(cx, name, expr, recv, pat_arg, count, &self.msrv);
}
},
("splitn_mut" | "rsplitn_mut", [count_arg, _]) => {
@@ -3626,7 +3709,7 @@ impl Methods {
},
("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg),
("take", [_arg]) => {
- if let Some((name2, recv2, args2, _span2)) = method_call(recv) {
+ if let Some((name2, recv2, args2, _span2, _)) = method_call(recv) {
if let ("cloned", []) = (name2, args2) {
iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
}
@@ -3634,7 +3717,7 @@ impl Methods {
},
("take", []) => needless_option_take::check(cx, expr, recv),
("then", [arg]) => {
- if !meets_msrv(self.msrv, msrvs::BOOL_THEN_SOME) {
+ if !self.msrv.meets(msrvs::BOOL_THEN_SOME) {
return;
}
unnecessary_lazy_eval::check(cx, expr, recv, arg, "then_some");
@@ -3649,13 +3732,13 @@ impl Methods {
},
("unwrap", []) => {
match method_call(recv) {
- Some(("get", recv, [get_arg], _)) => {
+ Some(("get", recv, [get_arg], _, _)) => {
get_unwrap::check(cx, expr, recv, get_arg, false);
},
- Some(("get_mut", recv, [get_arg], _)) => {
+ Some(("get_mut", recv, [get_arg], _, _)) => {
get_unwrap::check(cx, expr, recv, get_arg, true);
},
- Some(("or", recv, [or_arg], or_span)) => {
+ Some(("or", recv, [or_arg], or_span, _)) => {
or_then_unwrap::check(cx, expr, recv, or_arg, or_span);
},
_ => {},
@@ -3664,20 +3747,20 @@ impl Methods {
},
("unwrap_err", []) => unwrap_used::check(cx, expr, recv, true, self.allow_unwrap_in_tests),
("unwrap_or", [u_arg]) => match method_call(recv) {
- Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), lhs, [rhs], _)) => {
+ Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), lhs, [rhs], _, _)) => {
manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]);
},
- Some(("map", m_recv, [m_arg], span)) => {
+ Some(("map", m_recv, [m_arg], span, _)) => {
option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span);
},
- Some(("then_some", t_recv, [t_arg], _)) => {
+ Some(("then_some", t_recv, [t_arg], _, _)) => {
obfuscated_if_else::check(cx, expr, t_recv, t_arg, u_arg);
},
_ => {},
},
("unwrap_or_else", [u_arg]) => match method_call(recv) {
- Some(("map", recv, [map_arg], _))
- if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, self.msrv) => {},
+ Some(("map", recv, [map_arg], _, _))
+ if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, &self.msrv) => {},
_ => {
unwrap_or_else_default::check(cx, expr, recv, u_arg);
unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or");
@@ -3697,7 +3780,7 @@ impl Methods {
}
fn check_is_some_is_none(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, is_some: bool) {
- if let Some((name @ ("find" | "position" | "rposition"), f_recv, [arg], span)) = method_call(recv) {
+ if let Some((name @ ("find" | "position" | "rposition"), f_recv, [arg], span, _)) = method_call(recv) {
search_is_some::check(cx, expr, name, is_some, f_recv, arg, recv, span);
}
}
@@ -3906,14 +3989,6 @@ impl OutType {
}
}
-fn is_bool(ty: &hir::Ty<'_>) -> bool {
- if let hir::TyKind::Path(QPath::Resolved(_, path)) = ty.kind {
- matches!(path.res, Res::PrimTy(PrimTy::Bool))
- } else {
- false
- }
-}
-
fn fn_header_equals(expected: hir::FnHeader, actual: hir::FnHeader) -> bool {
expected.constness == actual.constness
&& expected.unsafety == actual.unsafety
diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
index 66f9e2859..b088e642e 100644
--- a/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
@@ -3,94 +3,99 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
use clippy_utils::higher;
use clippy_utils::source::{snippet, snippet_with_applicability};
use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{can_move_expr_to_closure, is_trait_method, path_to_local, path_to_local_id, CaptureKind};
-use if_chain::if_chain;
+use clippy_utils::ty::{is_type_diagnostic_item, make_normalized_projection, make_projection};
+use clippy_utils::{
+ can_move_expr_to_closure, get_enclosing_block, get_parent_node, is_trait_method, path_to_local, path_to_local_id,
+ CaptureKind,
+};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{Applicability, MultiSpan};
use rustc_hir::intravisit::{walk_block, walk_expr, Visitor};
-use rustc_hir::{Block, Expr, ExprKind, HirId, HirIdSet, Local, Mutability, Node, PatKind, Stmt, StmtKind};
+use rustc_hir::{
+ BindingAnnotation, Block, Expr, ExprKind, HirId, HirIdSet, Local, Mutability, Node, PatKind, Stmt, StmtKind,
+};
use rustc_lint::LateContext;
use rustc_middle::hir::nested_filter;
-use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::{self, Ty};
-use rustc_span::sym;
-use rustc_span::Span;
+use rustc_middle::ty::{self, AssocKind, EarlyBinder, GenericArg, GenericArgKind, Ty};
+use rustc_span::symbol::Ident;
+use rustc_span::{sym, Span, Symbol};
const NEEDLESS_COLLECT_MSG: &str = "avoid using `collect()` when not needed";
-pub(super) fn check<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
- check_needless_collect_direct_usage(expr, cx);
- check_needless_collect_indirect_usage(expr, cx);
-}
-fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
- if_chain! {
- if let ExprKind::MethodCall(method, receiver, args, _) = expr.kind;
- if let ExprKind::MethodCall(chain_method, ..) = receiver.kind;
- if chain_method.ident.name == sym!(collect) && is_trait_method(cx, receiver, sym::Iterator);
- then {
- let ty = cx.typeck_results().expr_ty(receiver);
- let mut applicability = Applicability::MaybeIncorrect;
- let is_empty_sugg = "next().is_none()".to_string();
- let method_name = method.ident.name.as_str();
- let sugg = if is_type_diagnostic_item(cx, ty, sym::Vec) ||
- is_type_diagnostic_item(cx, ty, sym::VecDeque) ||
- is_type_diagnostic_item(cx, ty, sym::LinkedList) ||
- is_type_diagnostic_item(cx, ty, sym::BinaryHeap) {
- match method_name {
- "len" => "count()".to_string(),
- "is_empty" => is_empty_sugg,
- "contains" => {
- let contains_arg = snippet_with_applicability(cx, args[0].span, "??", &mut applicability);
- let (arg, pred) = contains_arg
- .strip_prefix('&')
- .map_or(("&x", &*contains_arg), |s| ("x", s));
- format!("any(|{arg}| x == {pred})")
- }
- _ => return,
- }
- }
- else if is_type_diagnostic_item(cx, ty, sym::BTreeMap) ||
- is_type_diagnostic_item(cx, ty, sym::HashMap) {
- match method_name {
- "is_empty" => is_empty_sugg,
- _ => return,
- }
- }
- else {
- return;
- };
- span_lint_and_sugg(
- cx,
- NEEDLESS_COLLECT,
- chain_method.ident.span.with_hi(expr.span.hi()),
- NEEDLESS_COLLECT_MSG,
- "replace with",
- sugg,
- applicability,
- );
- }
- }
-}
+pub(super) fn check<'tcx>(
+ cx: &LateContext<'tcx>,
+ name_span: Span,
+ collect_expr: &'tcx Expr<'_>,
+ iter_expr: &'tcx Expr<'tcx>,
+ call_span: Span,
+) {
+ if let Some(parent) = get_parent_node(cx.tcx, collect_expr.hir_id) {
+ match parent {
+ Node::Expr(parent) => {
+ if let ExprKind::MethodCall(name, _, args @ ([] | [_]), _) = parent.kind {
+ let mut app = Applicability::MachineApplicable;
+ let name = name.ident.as_str();
+ let collect_ty = cx.typeck_results().expr_ty(collect_expr);
-fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
- if let ExprKind::Block(block, _) = expr.kind {
- for stmt in block.stmts {
- if_chain! {
- if let StmtKind::Local(local) = stmt.kind;
- if let PatKind::Binding(_, id, ..) = local.pat.kind;
- if let Some(init_expr) = local.init;
- if let ExprKind::MethodCall(method_name, iter_source, [], ..) = init_expr.kind;
- if method_name.ident.name == sym!(collect) && is_trait_method(cx, init_expr, sym::Iterator);
- let ty = cx.typeck_results().expr_ty(init_expr);
- if is_type_diagnostic_item(cx, ty, sym::Vec) ||
- is_type_diagnostic_item(cx, ty, sym::VecDeque) ||
- is_type_diagnostic_item(cx, ty, sym::BinaryHeap) ||
- is_type_diagnostic_item(cx, ty, sym::LinkedList);
- let iter_ty = cx.typeck_results().expr_ty(iter_source);
- if let Some(iter_calls) = detect_iter_and_into_iters(block, id, cx, get_captured_ids(cx, iter_ty));
- if let [iter_call] = &*iter_calls;
- then {
+ let sugg: String = match name {
+ "len" => {
+ if let Some(adt) = collect_ty.ty_adt_def()
+ && matches!(
+ cx.tcx.get_diagnostic_name(adt.did()),
+ Some(sym::Vec | sym::VecDeque | sym::LinkedList | sym::BinaryHeap)
+ )
+ {
+ "count()".into()
+ } else {
+ return;
+ }
+ },
+ "is_empty"
+ if is_is_empty_sig(cx, parent.hir_id)
+ && iterates_same_ty(cx, cx.typeck_results().expr_ty(iter_expr), collect_ty) =>
+ {
+ "next().is_none()".into()
+ },
+ "contains" => {
+ if is_contains_sig(cx, parent.hir_id, iter_expr)
+ && let Some(arg) = args.first()
+ {
+ let (span, prefix) = if let ExprKind::AddrOf(_, _, arg) = arg.kind {
+ (arg.span, "")
+ } else {
+ (arg.span, "*")
+ };
+ let snip = snippet_with_applicability(cx, span, "??", &mut app);
+ format!("any(|x| x == {prefix}{snip})")
+ } else {
+ return;
+ }
+ },
+ _ => return,
+ };
+
+ span_lint_and_sugg(
+ cx,
+ NEEDLESS_COLLECT,
+ call_span.with_hi(parent.span.hi()),
+ NEEDLESS_COLLECT_MSG,
+ "replace with",
+ sugg,
+ app,
+ );
+ }
+ },
+ Node::Local(l) => {
+ if let PatKind::Binding(BindingAnnotation::NONE | BindingAnnotation::MUT, id, _, None)
+ = l.pat.kind
+ && let ty = cx.typeck_results().expr_ty(collect_expr)
+ && [sym::Vec, sym::VecDeque, sym::BinaryHeap, sym::LinkedList].into_iter()
+ .any(|item| is_type_diagnostic_item(cx, ty, item))
+ && let iter_ty = cx.typeck_results().expr_ty(iter_expr)
+ && let Some(block) = get_enclosing_block(cx, l.hir_id)
+ && let Some(iter_calls) = detect_iter_and_into_iters(block, id, cx, get_captured_ids(cx, iter_ty))
+ && let [iter_call] = &*iter_calls
+ {
let mut used_count_visitor = UsedCountVisitor {
cx,
id,
@@ -102,20 +107,20 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo
}
// Suggest replacing iter_call with iter_replacement, and removing stmt
- let mut span = MultiSpan::from_span(method_name.ident.span);
+ let mut span = MultiSpan::from_span(name_span);
span.push_span_label(iter_call.span, "the iterator could be used here instead");
span_lint_hir_and_then(
cx,
super::NEEDLESS_COLLECT,
- init_expr.hir_id,
+ collect_expr.hir_id,
span,
NEEDLESS_COLLECT_MSG,
|diag| {
- let iter_replacement = format!("{}{}", Sugg::hir(cx, iter_source, ".."), iter_call.get_iter_method(cx));
+ let iter_replacement = format!("{}{}", Sugg::hir(cx, iter_expr, ".."), iter_call.get_iter_method(cx));
diag.multipart_suggestion(
iter_call.get_suggestion_text(),
vec![
- (stmt.span, String::new()),
+ (l.span, String::new()),
(iter_call.span, iter_replacement)
],
Applicability::MaybeIncorrect,
@@ -123,11 +128,61 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo
},
);
}
- }
+ },
+ _ => (),
}
}
}
+/// 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();
+ sig.inputs().len() == 1 && sig.output().is_bool()
+ })
+}
+
+/// Checks if `<iter_ty as Iterator>::Item` is the same as `<collect_ty as IntoIter>::Item`
+fn iterates_same_ty<'tcx>(cx: &LateContext<'tcx>, iter_ty: Ty<'tcx>, collect_ty: Ty<'tcx>) -> bool {
+ let item = Symbol::intern("Item");
+ if let Some(iter_trait) = cx.tcx.get_diagnostic_item(sym::Iterator)
+ && let Some(into_iter_trait) = cx.tcx.get_diagnostic_item(sym::IntoIterator)
+ && let Some(iter_item_ty) = make_normalized_projection(cx.tcx, cx.param_env, iter_trait, item, [iter_ty])
+ && let Some(into_iter_item_proj) = make_projection(cx.tcx, into_iter_trait, item, [collect_ty])
+ && let Ok(into_iter_item_ty) = cx.tcx.try_normalize_erasing_regions(
+ cx.param_env,
+ cx.tcx.mk_projection(into_iter_item_proj.item_def_id, into_iter_item_proj.substs)
+ )
+ {
+ iter_item_ty == into_iter_item_ty
+ } else {
+ false
+ }
+}
+
+/// Checks if the given method call matches the expected signature of
+/// `([&[mut]] self, &<iter_ty as Iterator>::Item) -> bool`
+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)
+ && sig.skip_binder().output().is_bool()
+ && let [_, search_ty] = *sig.skip_binder().inputs()
+ && let ty::Ref(_, search_ty, Mutability::Not) = *cx.tcx.erase_late_bound_regions(sig.rebind(search_ty)).kind()
+ && let Some(iter_trait) = cx.tcx.get_diagnostic_item(sym::Iterator)
+ && let Some(iter_item) = cx.tcx
+ .associated_items(iter_trait)
+ .find_by_name_and_kind(cx.tcx, 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 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)
+ {
+ item_ty == EarlyBinder(search_ty).subst(cx.tcx, cx.typeck_results().node_substs(call_id))
+ } else {
+ false
+ }
+}
+
struct IterFunction {
func: IterFunctionKind,
span: Span,
diff --git a/src/tools/clippy/clippy_lints/src/methods/no_effect_replace.rs b/src/tools/clippy/clippy_lints/src/methods/no_effect_replace.rs
index a76341855..01655e860 100644
--- a/src/tools/clippy/clippy_lints/src/methods/no_effect_replace.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/no_effect_replace.rs
@@ -1,11 +1,10 @@
use clippy_utils::diagnostics::span_lint;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::ty::is_type_lang_item;
use clippy_utils::SpanlessEq;
use if_chain::if_chain;
use rustc_ast::LitKind;
-use rustc_hir::ExprKind;
+use rustc_hir::{ExprKind, LangItem};
use rustc_lint::LateContext;
-use rustc_span::sym;
use super::NO_EFFECT_REPLACE;
@@ -16,7 +15,7 @@ pub(super) fn check<'tcx>(
arg2: &'tcx rustc_hir::Expr<'_>,
) {
let ty = cx.typeck_results().expr_ty(expr).peel_refs();
- if !(ty.is_str() || is_type_diagnostic_item(cx, ty, sym::String)) {
+ if !(ty.is_str() || is_type_lang_item(cx, ty, LangItem::String)) {
return;
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs
index 742483e6b..3e33f9193 100644
--- a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs
@@ -1,27 +1,27 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet;
use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{match_def_path, meets_msrv, msrvs, path_to_local_id, paths, peel_blocks};
+use clippy_utils::{match_def_path, path_to_local_id, paths, peel_blocks};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_middle::ty;
-use rustc_semver::RustcVersion;
use rustc_span::sym;
use super::OPTION_AS_REF_DEREF;
/// lint use of `_.as_ref().map(Deref::deref)` for `Option`s
-pub(super) fn check<'tcx>(
- cx: &LateContext<'tcx>,
+pub(super) fn check(
+ cx: &LateContext<'_>,
expr: &hir::Expr<'_>,
as_ref_recv: &hir::Expr<'_>,
map_arg: &hir::Expr<'_>,
is_mut: bool,
- msrv: Option<RustcVersion>,
+ msrv: &Msrv,
) {
- if !meets_msrv(msrv, msrvs::OPTION_AS_DEREF) {
+ if !msrv.meets(msrvs::OPTION_AS_DEREF) {
return;
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs
index 30421a6dd..910ee1485 100644
--- a/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs
@@ -97,7 +97,7 @@ struct UnwrapVisitor<'a, 'tcx> {
impl<'a, 'tcx> Visitor<'tcx> for UnwrapVisitor<'a, 'tcx> {
type NestedFilter = nested_filter::All;
- fn visit_path(&mut self, path: &'tcx Path<'_>, _id: HirId) {
+ fn visit_path(&mut self, path: &Path<'tcx>, _id: HirId) {
self.identifiers.insert(ident(path));
walk_path(self, path);
}
@@ -116,7 +116,7 @@ struct MapExprVisitor<'a, 'tcx> {
impl<'a, 'tcx> Visitor<'tcx> for MapExprVisitor<'a, 'tcx> {
type NestedFilter = nested_filter::All;
- fn visit_path(&mut self, path: &'tcx Path<'_>, _id: HirId) {
+ fn visit_path(&mut self, path: &Path<'tcx>, _id: HirId) {
if self.identifiers.contains(&ident(path)) {
self.found_identifier = true;
return;
diff --git a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
index 991d3dd53..4460f38fc 100644
--- a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
@@ -83,6 +83,8 @@ pub(super) fn check<'tcx>(
method_span: Span,
self_expr: &hir::Expr<'_>,
arg: &'tcx hir::Expr<'_>,
+ // `Some` if fn has second argument
+ second_arg: Option<&hir::Expr<'_>>,
span: Span,
// None if lambda is required
fun_span: Option<Span>,
@@ -109,30 +111,40 @@ pub(super) fn check<'tcx>(
if poss.contains(&name);
then {
- let macro_expanded_snipped;
- let sugg: Cow<'_, str> = {
+ let sugg = {
let (snippet_span, use_lambda) = match (fn_has_arguments, fun_span) {
(false, Some(fun_span)) => (fun_span, false),
_ => (arg.span, true),
};
- let snippet = {
- let not_macro_argument_snippet = snippet_with_macro_callsite(cx, snippet_span, "..");
- if not_macro_argument_snippet == "vec![]" {
- macro_expanded_snipped = snippet(cx, snippet_span, "..");
+
+ let format_span = |span: Span| {
+ let not_macro_argument_snippet = snippet_with_macro_callsite(cx, span, "..");
+ let snip = if not_macro_argument_snippet == "vec![]" {
+ let macro_expanded_snipped = snippet(cx, snippet_span, "..");
match macro_expanded_snipped.strip_prefix("$crate::vec::") {
- Some(stripped) => Cow::from(stripped),
+ Some(stripped) => Cow::Owned(stripped.to_owned()),
None => macro_expanded_snipped,
}
} else {
not_macro_argument_snippet
- }
+ };
+
+ snip.to_string()
};
- if use_lambda {
+ let snip = format_span(snippet_span);
+ let snip = if use_lambda {
let l_arg = if fn_has_arguments { "_" } else { "" };
- format!("|{l_arg}| {snippet}").into()
+ format!("|{l_arg}| {snip}")
} else {
- snippet
+ snip
+ };
+
+ if let Some(f) = second_arg {
+ let f = format_span(f.span);
+ format!("{snip}, {f}")
+ } else {
+ snip
}
};
let span_replace_word = method_span.with_hi(span.hi());
@@ -149,8 +161,8 @@ pub(super) fn check<'tcx>(
}
}
- if let [arg] = args {
- let inner_arg = if let hir::ExprKind::Block(
+ let extract_inner_arg = |arg: &'tcx hir::Expr<'_>| {
+ if let hir::ExprKind::Block(
hir::Block {
stmts: [],
expr: Some(expr),
@@ -162,19 +174,32 @@ pub(super) fn check<'tcx>(
expr
} else {
arg
- };
+ }
+ };
+
+ if let [arg] = args {
+ let inner_arg = extract_inner_arg(arg);
match inner_arg.kind {
hir::ExprKind::Call(fun, or_args) => {
let or_has_args = !or_args.is_empty();
if !check_unwrap_or_default(cx, name, fun, arg, or_has_args, expr.span, method_span) {
let fun_span = if or_has_args { None } else { Some(fun.span) };
- check_general_case(cx, name, method_span, receiver, arg, expr.span, fun_span);
+ check_general_case(cx, name, method_span, receiver, arg, None, expr.span, fun_span);
}
},
hir::ExprKind::Index(..) | hir::ExprKind::MethodCall(..) => {
- check_general_case(cx, name, method_span, receiver, arg, expr.span, None);
+ check_general_case(cx, name, method_span, receiver, arg, None, expr.span, None);
},
_ => (),
}
}
+
+ // `map_or` takes two arguments
+ if let [arg, lambda] = args {
+ let inner_arg = extract_inner_arg(arg);
+ if let hir::ExprKind::Call(fun, or_args) = inner_arg.kind {
+ let fun_span = if or_args.is_empty() { Some(fun.span) } else { None };
+ check_general_case(cx, name, method_span, receiver, arg, Some(lambda), expr.span, fun_span);
+ }
+ }
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/repeat_once.rs b/src/tools/clippy/clippy_lints/src/methods/repeat_once.rs
index 0a14f9216..a345ec813 100644
--- a/src/tools/clippy/clippy_lints/src/methods/repeat_once.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/repeat_once.rs
@@ -1,11 +1,10 @@
use clippy_utils::consts::{constant_context, Constant};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::ty::is_type_lang_item;
use rustc_errors::Applicability;
-use rustc_hir::Expr;
+use rustc_hir::{Expr, LangItem};
use rustc_lint::LateContext;
-use rustc_span::sym;
use super::REPEAT_ONCE;
@@ -37,7 +36,7 @@ pub(super) fn check<'tcx>(
format!("{}.to_vec()", snippet(cx, recv.span, r#""...""#)),
Applicability::MachineApplicable,
);
- } else if is_type_diagnostic_item(cx, ty, sym::String) {
+ } else if is_type_lang_item(cx, ty, LangItem::String) {
span_lint_and_sugg(
cx,
REPEAT_ONCE,
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 324c9c17b..1c031ad6a 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
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
use clippy_utils::source::{snippet, snippet_with_applicability};
use clippy_utils::sugg::deref_closure_args;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::ty::is_type_lang_item;
use clippy_utils::{is_trait_method, strip_pat_refs};
use if_chain::if_chain;
use rustc_errors::Applicability;
@@ -105,7 +105,7 @@ pub(super) fn check<'tcx>(
else if search_method == "find" {
let is_string_or_str_slice = |e| {
let self_ty = cx.typeck_results().expr_ty(e).peel_refs();
- if is_type_diagnostic_item(cx, self_ty, sym::String) {
+ if is_type_lang_item(cx, self_ty, hir::LangItem::String) {
true
} else {
*self_ty.kind() == ty::Str
diff --git a/src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs b/src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs
new file mode 100644
index 000000000..361a3082f
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs
@@ -0,0 +1,48 @@
+use rustc_ast::ast::{LitIntType, LitKind};
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::LateContext;
+
+use clippy_utils::{
+ diagnostics::span_lint_and_sugg, get_trait_def_id, match_def_path, paths, source::snippet_with_applicability,
+ ty::implements_trait,
+};
+
+use super::SEEK_FROM_CURRENT;
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>, arg: &'tcx Expr<'_>) {
+ let ty = cx.typeck_results().expr_ty(recv);
+
+ if let Some(def_id) = get_trait_def_id(cx, &paths::STD_IO_SEEK) {
+ if implements_trait(cx, ty, def_id, &[]) && arg_is_seek_from_current(cx, arg) {
+ let mut applicability = Applicability::MachineApplicable;
+ let snip = snippet_with_applicability(cx, recv.span, "..", &mut applicability);
+
+ span_lint_and_sugg(
+ cx,
+ SEEK_FROM_CURRENT,
+ expr.span,
+ "using `SeekFrom::Current` to start from current position",
+ "replace with",
+ format!("{snip}.stream_position()"),
+ applicability,
+ );
+ }
+ }
+}
+
+fn arg_is_seek_from_current<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool {
+ if let ExprKind::Call(f, args) = expr.kind &&
+ let ExprKind::Path(ref path) = f.kind &&
+ let Some(def_id) = cx.qpath_res(path, f.hir_id).opt_def_id() &&
+ match_def_path(cx, def_id, &paths::STD_IO_SEEK_FROM_CURRENT) {
+ // check if argument of `SeekFrom::Current` is `0`
+ if args.len() == 1 &&
+ let ExprKind::Lit(ref lit) = args[0].kind &&
+ let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node {
+ return true
+ }
+ }
+
+ false
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs b/src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs
new file mode 100644
index 000000000..7e3bed1e4
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs
@@ -0,0 +1,45 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::ty::implements_trait;
+use clippy_utils::{get_trait_def_id, match_def_path, paths};
+use rustc_ast::ast::{LitIntType, LitKind};
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::LateContext;
+use rustc_span::Span;
+
+use super::SEEK_TO_START_INSTEAD_OF_REWIND;
+
+pub(super) fn check<'tcx>(
+ cx: &LateContext<'tcx>,
+ expr: &'tcx Expr<'_>,
+ recv: &'tcx Expr<'_>,
+ arg: &'tcx Expr<'_>,
+ name_span: Span,
+) {
+ // Get receiver type
+ let ty = cx.typeck_results().expr_ty(recv).peel_refs();
+
+ if let Some(seek_trait_id) = get_trait_def_id(cx, &paths::STD_IO_SEEK) &&
+ implements_trait(cx, ty, seek_trait_id, &[]) &&
+ let ExprKind::Call(func, args1) = arg.kind &&
+ let ExprKind::Path(ref path) = func.kind &&
+ let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id() &&
+ match_def_path(cx, def_id, &paths::STD_IO_SEEKFROM_START) &&
+ args1.len() == 1 &&
+ let ExprKind::Lit(ref lit) = args1[0].kind &&
+ let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node
+ {
+ let method_call_span = expr.span.with_lo(name_span.lo());
+ span_lint_and_then(
+ cx,
+ SEEK_TO_START_INSTEAD_OF_REWIND,
+ method_call_span,
+ "used `seek` to go to the start of the stream",
+ |diag| {
+ let app = Applicability::MachineApplicable;
+
+ diag.span_suggestion(method_call_span, "replace with", "rewind()", app);
+ },
+ );
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
index 1acac5914..3c01ce1fe 100644
--- a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
@@ -1,9 +1,10 @@
use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_context;
use clippy_utils::usage::local_used_after_expr;
use clippy_utils::visitors::{for_each_expr_with_closures, Descend};
-use clippy_utils::{is_diag_item_method, match_def_path, meets_msrv, msrvs, path_to_local_id, paths};
+use clippy_utils::{is_diag_item_method, match_def_path, path_to_local_id, paths};
use core::ops::ControlFlow;
use if_chain::if_chain;
use rustc_errors::Applicability;
@@ -12,7 +13,6 @@ use rustc_hir::{
};
use rustc_lint::LateContext;
use rustc_middle::ty;
-use rustc_semver::RustcVersion;
use rustc_span::{sym, Span, Symbol, SyntaxContext};
use super::{MANUAL_SPLIT_ONCE, NEEDLESS_SPLITN};
@@ -24,7 +24,7 @@ pub(super) fn check(
self_arg: &Expr<'_>,
pat_arg: &Expr<'_>,
count: u128,
- msrv: Option<RustcVersion>,
+ msrv: &Msrv,
) {
if count < 2 || !cx.typeck_results().expr_ty_adjusted(self_arg).peel_refs().is_str() {
return;
@@ -34,7 +34,7 @@ pub(super) fn check(
IterUsageKind::Nth(n) => count > n + 1,
IterUsageKind::NextTuple => count > 2,
};
- let manual = count == 2 && meets_msrv(msrv, msrvs::STR_SPLIT_ONCE);
+ let manual = count == 2 && msrv.meets(msrvs::STR_SPLIT_ONCE);
match parse_iter_usage(cx, expr.span.ctxt(), cx.tcx.hir().parent_iter(expr.hir_id)) {
Some(usage) if needless(usage.kind) => lint_needless(cx, method_name, expr, self_arg, pat_arg),
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 6974260f7..f35d81cee 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
@@ -1,26 +1,29 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::method_chain_args;
use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::is_type_diagnostic_item;
+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 rustc_span::symbol::sym;
use super::STRING_EXTEND_CHARS;
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) {
let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs();
- if !is_type_diagnostic_item(cx, obj_ty, sym::String) {
+ if !is_type_lang_item(cx, obj_ty, hir::LangItem::String) {
return;
}
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 {
- ""
- } else if is_type_diagnostic_item(cx, self_ty, sym::String) {
+ if matches!(target.kind, hir::ExprKind::Index(..)) {
+ "&"
+ } else {
+ ""
+ }
+ } else if is_type_lang_item(cx, self_ty, hir::LangItem::String) {
"&"
} else {
return;
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 851cdf544..2ac0786b3 100644
--- a/src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs
@@ -8,7 +8,7 @@ use rustc_span::sym;
use super::SUSPICIOUS_MAP;
-pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, count_recv: &hir::Expr<'_>, map_arg: &hir::Expr<'_>) {
+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);
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs
index 1966a85f7..52a4ff7d1 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs
@@ -2,10 +2,10 @@ use super::utils::clone_or_copy_needed;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::higher::ForLoop;
use clippy_utils::source::snippet_opt;
-use clippy_utils::ty::{get_associated_type, get_iterator_item_ty, implements_trait};
+use clippy_utils::ty::{get_iterator_item_ty, implements_trait};
use clippy_utils::{fn_def_id, get_parent_expr};
use rustc_errors::Applicability;
-use rustc_hir::{def_id::DefId, Expr, ExprKind, LangItem};
+use rustc_hir::{def_id::DefId, Expr, ExprKind};
use rustc_lint::LateContext;
use rustc_span::{sym, Symbol};
@@ -54,7 +54,7 @@ pub fn check_for_loop_iter(
if let Some(into_iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::IntoIterator);
let collection_ty = cx.typeck_results().expr_ty(collection);
if implements_trait(cx, collection_ty, into_iterator_trait_id, &[]);
- if let Some(into_iter_item_ty) = get_associated_type(cx, collection_ty, into_iterator_trait_id, "Item");
+ if let Some(into_iter_item_ty) = cx.get_associated_type(collection_ty, into_iterator_trait_id, "Item");
if iter_item_ty == into_iter_item_ty;
if let Some(collection_snippet) = snippet_opt(cx, collection.span);
@@ -100,5 +100,5 @@ pub fn check_for_loop_iter(
/// Returns true if the named method is `IntoIterator::into_iter`.
pub fn is_into_iter(cx: &LateContext<'_>, callee_def_id: DefId) -> bool {
- cx.tcx.lang_items().require(LangItem::IntoIterIntoIter) == Ok(callee_def_id)
+ Some(callee_def_id) == cx.tcx.lang_items().into_iter_fn()
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_join.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_join.rs
index 973b8a7e6..087e1e434 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_join.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_join.rs
@@ -1,10 +1,10 @@
-use clippy_utils::{diagnostics::span_lint_and_sugg, ty::is_type_diagnostic_item};
+use clippy_utils::{diagnostics::span_lint_and_sugg, ty::is_type_lang_item};
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind};
+use rustc_hir::{Expr, ExprKind, LangItem};
use rustc_lint::LateContext;
use rustc_middle::ty::{Ref, Slice};
-use rustc_span::{sym, Span};
+use rustc_span::Span;
use super::UNNECESSARY_JOIN;
@@ -21,7 +21,7 @@ pub(super) fn check<'tcx>(
// the turbofish for collect is ::<Vec<String>>
if let Ref(_, ref_type, _) = collect_output_adjusted_type.kind();
if let Slice(slice) = ref_type.kind();
- if is_type_diagnostic_item(cx, *slice, sym::String);
+ if is_type_lang_item(cx, *slice, LangItem::String);
// the argument for join is ""
if let ExprKind::Lit(spanned) = &join_arg.kind;
if let LitKind::Str(symbol, _) = spanned.node;
@@ -31,7 +31,7 @@ pub(super) fn check<'tcx>(
cx,
UNNECESSARY_JOIN,
span.with_hi(expr.span.hi()),
- r#"called `.collect<Vec<String>>().join("")` on an iterator"#,
+ r#"called `.collect::<Vec<String>>().join("")` on an iterator"#,
"try using",
"collect::<String>()".to_owned(),
applicability,
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
index 3566fe9a0..9263f0519 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
@@ -1,25 +1,22 @@
use super::implicit_clone::is_clone_like;
use super::unnecessary_iter_cloned::{self, is_into_iter};
use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_opt;
-use clippy_utils::ty::{get_associated_type, get_iterator_item_ty, implements_trait, is_copy, peel_mid_ty_refs};
+use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy, peel_mid_ty_refs};
use clippy_utils::visitors::find_all_ret_expressions;
use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, return_ty};
-use clippy_utils::{meets_msrv, msrvs};
use rustc_errors::Applicability;
-use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind, ItemKind, LangItem, Node};
+use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind, ItemKind, Node};
use rustc_hir_typeck::{FnCtxt, Inherited};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::LateContext;
use rustc_middle::mir::Mutability;
use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref};
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
-use rustc_middle::ty::EarlyBinder;
-use rustc_middle::ty::{self, ParamTy, PredicateKind, ProjectionPredicate, TraitPredicate, Ty};
-use rustc_semver::RustcVersion;
+use rustc_middle::ty::{self, Clause, EarlyBinder, ParamTy, PredicateKind, ProjectionPredicate, TraitPredicate, Ty};
use rustc_span::{sym, Symbol};
use rustc_trait_selection::traits::{query::evaluate_obligation::InferCtxtExt as _, Obligation, ObligationCause};
-use std::cmp::max;
use super::UNNECESSARY_TO_OWNED;
@@ -29,7 +26,7 @@ pub fn check<'tcx>(
method_name: Symbol,
receiver: &'tcx Expr<'_>,
args: &'tcx [Expr<'_>],
- msrv: Option<RustcVersion>,
+ msrv: &Msrv,
) {
if_chain! {
if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
@@ -146,7 +143,7 @@ fn check_addr_of_expr(
if_chain! {
if let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref);
if implements_trait(cx, receiver_ty, deref_trait_id, &[]);
- if get_associated_type(cx, receiver_ty, deref_trait_id, "Target") == Some(target_ty);
+ if cx.get_associated_type(receiver_ty, deref_trait_id, "Target") == Some(target_ty);
then {
if n_receiver_refs > 0 {
span_lint_and_sugg(
@@ -200,7 +197,7 @@ fn check_into_iter_call_arg(
expr: &Expr<'_>,
method_name: Symbol,
receiver: &Expr<'_>,
- msrv: Option<RustcVersion>,
+ msrv: &Msrv,
) -> bool {
if_chain! {
if let Some(parent) = get_parent_expr(cx, expr);
@@ -215,7 +212,7 @@ fn check_into_iter_call_arg(
if unnecessary_iter_cloned::check_for_loop_iter(cx, parent, method_name, receiver, true) {
return true;
}
- let cloned_or_copied = if is_copy(cx, item_ty) && meets_msrv(msrv, msrvs::ITERATOR_COPIED) {
+ let cloned_or_copied = if is_copy(cx, item_ty) && msrv.meets(msrvs::ITERATOR_COPIED) {
"copied"
} else {
"cloned"
@@ -263,11 +260,22 @@ fn check_other_call_arg<'tcx>(
if let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef);
if trait_predicate.def_id() == deref_trait_id || trait_predicate.def_id() == as_ref_trait_id;
let receiver_ty = cx.typeck_results().expr_ty(receiver);
- if can_change_type(cx, maybe_arg, receiver_ty);
// We can't add an `&` when the trait is `Deref` because `Target = &T` won't match
// `Target = T`.
- if n_refs > 0 || is_copy(cx, receiver_ty) || trait_predicate.def_id() != deref_trait_id;
- let n_refs = max(n_refs, usize::from(!is_copy(cx, receiver_ty)));
+ if let Some((n_refs, receiver_ty)) = if n_refs > 0 || is_copy(cx, receiver_ty) {
+ Some((n_refs, receiver_ty))
+ } else if trait_predicate.def_id() != deref_trait_id {
+ Some((1, cx.tcx.mk_ref(
+ cx.tcx.lifetimes.re_erased,
+ ty::TypeAndMut {
+ ty: receiver_ty,
+ mutbl: Mutability::Not,
+ },
+ )))
+ } else {
+ None
+ };
+ if can_change_type(cx, maybe_arg, receiver_ty);
if let Some(receiver_snippet) = snippet_opt(cx, receiver.span);
then {
span_lint_and_sugg(
@@ -337,12 +345,12 @@ fn get_input_traits_and_projections<'tcx>(
let mut projection_predicates = Vec::new();
for predicate in cx.tcx.param_env(callee_def_id).caller_bounds() {
match predicate.kind().skip_binder() {
- PredicateKind::Trait(trait_predicate) => {
+ PredicateKind::Clause(Clause::Trait(trait_predicate)) => {
if trait_predicate.trait_ref.self_ty() == input {
trait_predicates.push(trait_predicate);
}
},
- PredicateKind::Projection(projection_predicate) => {
+ PredicateKind::Clause(Clause::Projection(projection_predicate)) => {
if projection_predicate.projection_ty.self_ty() == input {
projection_predicates.push(projection_predicate);
}
@@ -378,14 +386,12 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
Node::Expr(parent_expr) => {
if let Some((callee_def_id, call_substs, recv, call_args)) = get_callee_substs_and_args(cx, parent_expr)
{
- if cx.tcx.lang_items().require(LangItem::IntoFutureIntoFuture) == Ok(callee_def_id) {
- return false;
- }
-
let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder();
if let Some(arg_index) = recv.into_iter().chain(call_args).position(|arg| arg.hir_id == expr.hir_id)
&& let Some(param_ty) = fn_sig.inputs().get(arg_index)
&& let ty::Param(ParamTy { index: param_index , ..}) = param_ty.kind()
+ // https://github.com/rust-lang/rust-clippy/issues/9504 and https://github.com/rust-lang/rust-clippy/issues/10021
+ && (*param_index as usize) < call_substs.len()
{
if fn_sig
.inputs()
@@ -399,10 +405,12 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
let mut trait_predicates = cx.tcx.param_env(callee_def_id)
.caller_bounds().iter().filter(|predicate| {
- if let PredicateKind::Trait(trait_predicate) = predicate.kind().skip_binder()
- && trait_predicate.trait_ref.self_ty() == *param_ty {
- true
- } else {
+ if let PredicateKind::Clause(Clause::Trait(trait_predicate))
+ = predicate.kind().skip_binder()
+ && trait_predicate.trait_ref.self_ty() == *param_ty
+ {
+ true
+ } else {
false
}
});
@@ -419,7 +427,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
if trait_predicates.any(|predicate| {
let predicate = EarlyBinder(predicate).subst(cx.tcx, new_subst);
- let obligation = Obligation::new(ObligationCause::dummy(), cx.param_env, predicate);
+ let obligation = Obligation::new(cx.tcx, ObligationCause::dummy(), cx.param_env, predicate);
!cx.tcx.infer_ctxt().build().predicate_must_hold_modulo_regions(&obligation)
}) {
return false;
@@ -474,7 +482,7 @@ fn is_cow_into_owned(cx: &LateContext<'_>, method_name: Symbol, method_def_id: D
}
/// Returns true if the named method is `ToString::to_string` and it's called on a type that
-/// is string-like i.e. implements `AsRef<str>` or `Deref<str>`.
+/// is string-like i.e. implements `AsRef<str>` or `Deref<Target = str>`.
fn is_to_string_on_string_like<'a>(
cx: &LateContext<'_>,
call_expr: &'a Expr<'a>,
@@ -490,7 +498,7 @@ fn is_to_string_on_string_like<'a>(
&& let GenericArgKind::Type(ty) = generic_arg.unpack()
&& let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref)
&& let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef)
- && (implements_trait(cx, ty, deref_trait_id, &[cx.tcx.types.str_.into()]) ||
+ && (cx.get_associated_type(ty, deref_trait_id, "Target") == Some(cx.tcx.types.str_) ||
implements_trait(cx, ty, as_ref_trait_id, &[cx.tcx.types.str_.into()])) {
true
} else {
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 ee17f2d78..90983f249 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_test_function, is_lint_allowed};
+use clippy_utils::{is_in_cfg_test, is_lint_allowed};
use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_span::sym;
@@ -18,16 +18,16 @@ pub(super) fn check(
let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs();
let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) && !is_err {
- Some((UNWRAP_USED, "an Option", "None", ""))
+ Some((UNWRAP_USED, "an `Option`", "None", ""))
} else if is_type_diagnostic_item(cx, obj_ty, sym::Result) {
- Some((UNWRAP_USED, "a Result", if is_err { "Ok" } else { "Err" }, "an "))
+ Some((UNWRAP_USED, "a `Result`", if is_err { "Ok" } else { "Err" }, "an "))
} else {
None
};
let method_suffix = if is_err { "_err" } else { "" };
- if allow_unwrap_in_tests && is_in_test_function(cx.tcx, expr.hir_id) {
+ if allow_unwrap_in_tests && is_in_cfg_test(cx.tcx, expr.hir_id) {
return;
}
@@ -45,7 +45,7 @@ pub(super) fn check(
cx,
lint,
expr.span,
- &format!("used `unwrap{method_suffix}()` on `{kind}` value"),
+ &format!("used `unwrap{method_suffix}()` on {kind} value"),
None,
&help,
);
diff --git a/src/tools/clippy/clippy_lints/src/misc_early/literal_suffix.rs b/src/tools/clippy/clippy_lints/src/misc_early/literal_suffix.rs
index 27e7f8505..eda4376f2 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early/literal_suffix.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early/literal_suffix.rs
@@ -1,11 +1,11 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
-use rustc_ast::ast::Lit;
use rustc_errors::Applicability;
use rustc_lint::EarlyContext;
+use rustc_span::Span;
use super::{SEPARATED_LITERAL_SUFFIX, UNSEPARATED_LITERAL_SUFFIX};
-pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, lit_snip: &str, suffix: &str, sugg_type: &str) {
+pub(super) fn check(cx: &EarlyContext<'_>, lit_span: Span, lit_snip: &str, suffix: &str, sugg_type: &str) {
let Some(maybe_last_sep_idx) = lit_snip.len().checked_sub(suffix.len() + 1) else {
return; // It's useless so shouldn't lint.
};
@@ -15,7 +15,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, lit_snip: &str, suffix: &s
span_lint_and_sugg(
cx,
SEPARATED_LITERAL_SUFFIX,
- lit.span,
+ lit_span,
&format!("{sugg_type} type suffix should not be separated by an underscore"),
"remove the underscore",
format!("{}{suffix}", &lit_snip[..maybe_last_sep_idx]),
@@ -25,7 +25,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, lit_snip: &str, suffix: &s
span_lint_and_sugg(
cx,
UNSEPARATED_LITERAL_SUFFIX,
- lit.span,
+ lit_span,
&format!("{sugg_type} type suffix should be separated by an underscore"),
"add an underscore",
format!("{}_{suffix}", &lit_snip[..=maybe_last_sep_idx]),
diff --git a/src/tools/clippy/clippy_lints/src/misc_early/mixed_case_hex_literals.rs b/src/tools/clippy/clippy_lints/src/misc_early/mixed_case_hex_literals.rs
index 263ee1e94..ddb8b9173 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early/mixed_case_hex_literals.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early/mixed_case_hex_literals.rs
@@ -1,10 +1,10 @@
use clippy_utils::diagnostics::span_lint;
-use rustc_ast::ast::Lit;
use rustc_lint::EarlyContext;
+use rustc_span::Span;
use super::MIXED_CASE_HEX_LITERALS;
-pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, suffix: &str, lit_snip: &str) {
+pub(super) fn check(cx: &EarlyContext<'_>, lit_span: Span, suffix: &str, lit_snip: &str) {
let Some(maybe_last_sep_idx) = lit_snip.len().checked_sub(suffix.len() + 1) else {
return; // It's useless so shouldn't lint.
};
@@ -23,7 +23,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, suffix: &str, lit_snip: &s
span_lint(
cx,
MIXED_CASE_HEX_LITERALS,
- lit.span,
+ lit_span,
"inconsistent casing in hexadecimal literal",
);
break;
diff --git a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs
index c8227ca44..78be6b9e2 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs
@@ -9,7 +9,8 @@ mod zero_prefixed_literal;
use clippy_utils::diagnostics::span_lint;
use clippy_utils::source::snippet_opt;
-use rustc_ast::ast::{Expr, ExprKind, Generics, Lit, LitFloatType, LitIntType, LitKind, NodeId, Pat, PatKind};
+use rustc_ast::ast::{Expr, ExprKind, Generics, LitFloatType, LitIntType, LitKind, NodeId, Pat, PatKind};
+use rustc_ast::token;
use rustc_ast::visit::FnKind;
use rustc_data_structures::fx::FxHashMap;
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
@@ -374,42 +375,43 @@ impl EarlyLintPass for MiscEarlyLints {
return;
}
- if let ExprKind::Lit(ref lit) = expr.kind {
- MiscEarlyLints::check_lit(cx, lit);
+ if let ExprKind::Lit(lit) = expr.kind {
+ MiscEarlyLints::check_lit(cx, lit, expr.span);
}
double_neg::check(cx, expr);
}
}
impl MiscEarlyLints {
- fn check_lit(cx: &EarlyContext<'_>, lit: &Lit) {
+ fn check_lit(cx: &EarlyContext<'_>, lit: token::Lit, span: Span) {
// We test if first character in snippet is a number, because the snippet could be an expansion
// from a built-in macro like `line!()` or a proc-macro like `#[wasm_bindgen]`.
// Note that this check also covers special case that `line!()` is eagerly expanded by compiler.
// See <https://github.com/rust-lang/rust-clippy/issues/4507> for a regression.
// FIXME: Find a better way to detect those cases.
- let lit_snip = match snippet_opt(cx, lit.span) {
+ let lit_snip = match snippet_opt(cx, span) {
Some(snip) if snip.chars().next().map_or(false, |c| c.is_ascii_digit()) => snip,
_ => return,
};
- if let LitKind::Int(value, lit_int_type) = lit.kind {
+ let lit_kind = LitKind::from_token_lit(lit);
+ if let Ok(LitKind::Int(value, lit_int_type)) = lit_kind {
let suffix = match lit_int_type {
LitIntType::Signed(ty) => ty.name_str(),
LitIntType::Unsigned(ty) => ty.name_str(),
LitIntType::Unsuffixed => "",
};
- literal_suffix::check(cx, lit, &lit_snip, suffix, "integer");
+ literal_suffix::check(cx, span, &lit_snip, suffix, "integer");
if lit_snip.starts_with("0x") {
- mixed_case_hex_literals::check(cx, lit, suffix, &lit_snip);
+ mixed_case_hex_literals::check(cx, span, suffix, &lit_snip);
} else if lit_snip.starts_with("0b") || lit_snip.starts_with("0o") {
// nothing to do
} else if value != 0 && lit_snip.starts_with('0') {
- zero_prefixed_literal::check(cx, lit, &lit_snip);
+ zero_prefixed_literal::check(cx, span, &lit_snip);
}
- } else if let LitKind::Float(_, LitFloatType::Suffixed(float_ty)) = lit.kind {
+ } else if let Ok(LitKind::Float(_, LitFloatType::Suffixed(float_ty))) = lit_kind {
let suffix = float_ty.name_str();
- literal_suffix::check(cx, lit, &lit_snip, suffix, "float");
+ literal_suffix::check(cx, span, &lit_snip, suffix, "float");
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/misc_early/zero_prefixed_literal.rs b/src/tools/clippy/clippy_lints/src/misc_early/zero_prefixed_literal.rs
index 9ead43ea4..4f9578d1b 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early/zero_prefixed_literal.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early/zero_prefixed_literal.rs
@@ -1,20 +1,20 @@
use clippy_utils::diagnostics::span_lint_and_then;
-use rustc_ast::ast::Lit;
use rustc_errors::Applicability;
use rustc_lint::EarlyContext;
+use rustc_span::Span;
use super::ZERO_PREFIXED_LITERAL;
-pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, lit_snip: &str) {
+pub(super) fn check(cx: &EarlyContext<'_>, lit_span: Span, lit_snip: &str) {
let trimmed_lit_snip = lit_snip.trim_start_matches(|c| c == '_' || c == '0');
span_lint_and_then(
cx,
ZERO_PREFIXED_LITERAL,
- lit.span,
+ lit_span,
"this is a decimal constant",
|diag| {
diag.span_suggestion(
- lit.span,
+ lit_span,
"if you mean to use a decimal constant, remove the `0` to avoid confusion",
trimmed_lit_snip.to_string(),
Applicability::MaybeIncorrect,
@@ -22,7 +22,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, lit_snip: &str) {
// do not advise to use octal form if the literal cannot be expressed in base 8.
if !lit_snip.contains(|c| c == '8' || c == '9') {
diag.span_suggestion(
- lit.span,
+ lit_span,
"if you mean to use an octal constant, use `0o`",
format!("0o{trimmed_lit_snip}"),
Applicability::MaybeIncorrect,
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 71cc0d0a8..5bc04bc17 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
@@ -1,9 +1,8 @@
use clippy_utils::diagnostics::span_lint;
+use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::qualify_min_const_fn::is_min_const_fn;
use clippy_utils::ty::has_drop;
-use clippy_utils::{
- fn_has_unsatisfiable_preds, is_entrypoint_fn, is_from_proc_macro, meets_msrv, msrvs, trait_ref_of_method,
-};
+use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, is_from_proc_macro, trait_ref_of_method};
use rustc_hir as hir;
use rustc_hir::def_id::CRATE_DEF_ID;
use rustc_hir::intravisit::FnKind;
@@ -11,7 +10,6 @@ use rustc_hir::{Body, Constness, FnDecl, GenericParamKind, HirId};
use rustc_hir_analysis::hir_ty_to_ty;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::lint::in_external_macro;
-use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::Span;
@@ -75,12 +73,12 @@ declare_clippy_lint! {
impl_lint_pass!(MissingConstForFn => [MISSING_CONST_FOR_FN]);
pub struct MissingConstForFn {
- msrv: Option<RustcVersion>,
+ msrv: Msrv,
}
impl MissingConstForFn {
#[must_use]
- pub fn new(msrv: Option<RustcVersion>) -> Self {
+ pub fn new(msrv: Msrv) -> Self {
Self { msrv }
}
}
@@ -95,7 +93,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
span: Span,
hir_id: HirId,
) {
- if !meets_msrv(self.msrv, msrvs::CONST_IF_MATCH) {
+ if !self.msrv.meets(msrvs::CONST_IF_MATCH) {
return;
}
@@ -152,7 +150,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
let mir = cx.tcx.optimized_mir(def_id);
- if let Err((span, err)) = is_min_const_fn(cx.tcx, mir, self.msrv) {
+ if let Err((span, err)) = is_min_const_fn(cx.tcx, mir, &self.msrv) {
if cx.tcx.is_const_fn_raw(def_id.to_def_id()) {
cx.tcx.sess.span_err(span, err.as_ref());
}
diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs
index 2a63681db..6fd100762 100644
--- a/src/tools/clippy/clippy_lints/src/missing_doc.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs
@@ -199,7 +199,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.id);
+ 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");
}
diff --git a/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs b/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs
index 872679f25..773174679 100644
--- a/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs
@@ -59,42 +59,45 @@ impl LateLintPass<'_> for ImportRename {
fn check_crate(&mut self, cx: &LateContext<'_>) {
for Rename { path, rename } in &self.conf_renames {
let segs = path.split("::").collect::<Vec<_>>();
- if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &segs, None) {
+ for id in clippy_utils::def_path_def_ids(cx, &segs) {
self.renames.insert(id, Symbol::intern(rename));
}
}
}
fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
- if_chain! {
- if let ItemKind::Use(path, UseKind::Single) = &item.kind;
- if let Res::Def(_, id) = path.res;
- if let Some(name) = self.renames.get(&id);
- // Remove semicolon since it is not present for nested imports
- let span_without_semi = cx.sess().source_map().span_until_char(item.span, ';');
- if let Some(snip) = snippet_opt(cx, span_without_semi);
- if let Some(import) = match snip.split_once(" as ") {
- None => Some(snip.as_str()),
- Some((import, rename)) => {
- if rename.trim() == name.as_str() {
- None
- } else {
- Some(import.trim())
+ if let ItemKind::Use(path, UseKind::Single) = &item.kind {
+ for &res in &path.res {
+ if_chain! {
+ if let Res::Def(_, id) = res;
+ if let Some(name) = self.renames.get(&id);
+ // Remove semicolon since it is not present for nested imports
+ let span_without_semi = cx.sess().source_map().span_until_char(item.span, ';');
+ if let Some(snip) = snippet_opt(cx, span_without_semi);
+ if let Some(import) = match snip.split_once(" as ") {
+ None => Some(snip.as_str()),
+ Some((import, rename)) => {
+ if rename.trim() == name.as_str() {
+ None
+ } else {
+ Some(import.trim())
+ }
+ },
+ };
+ then {
+ span_lint_and_sugg(
+ cx,
+ MISSING_ENFORCED_IMPORT_RENAMES,
+ span_without_semi,
+ "this import should be renamed",
+ "try",
+ format!(
+ "{import} as {name}",
+ ),
+ Applicability::MachineApplicable,
+ );
}
- },
- };
- then {
- span_lint_and_sugg(
- cx,
- MISSING_ENFORCED_IMPORT_RENAMES,
- span_without_semi,
- "this import should be renamed",
- "try",
- format!(
- "{import} as {name}",
- ),
- Applicability::MachineApplicable,
- );
+ }
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
index 675297634..321fa4b7f 100644
--- a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
+++ b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
@@ -218,7 +218,7 @@ enum StopEarly {
Stop,
}
-fn check_expr<'a, 'tcx>(vis: &mut ReadVisitor<'a, 'tcx>, expr: &'tcx Expr<'_>) -> StopEarly {
+fn check_expr<'tcx>(vis: &mut ReadVisitor<'_, 'tcx>, expr: &'tcx Expr<'_>) -> StopEarly {
if expr.hir_id == vis.last_expr.hir_id {
return StopEarly::KeepGoing;
}
@@ -265,7 +265,7 @@ fn check_expr<'a, 'tcx>(vis: &mut ReadVisitor<'a, 'tcx>, expr: &'tcx Expr<'_>) -
StopEarly::KeepGoing
}
-fn check_stmt<'a, 'tcx>(vis: &mut ReadVisitor<'a, 'tcx>, stmt: &'tcx Stmt<'_>) -> StopEarly {
+fn check_stmt<'tcx>(vis: &mut ReadVisitor<'_, 'tcx>, stmt: &'tcx Stmt<'_>) -> StopEarly {
match stmt.kind {
StmtKind::Expr(expr) | StmtKind::Semi(expr) => check_expr(vis, expr),
// If the declaration is of a local variable, check its initializer
diff --git a/src/tools/clippy/clippy_lints/src/mut_key.rs b/src/tools/clippy/clippy_lints/src/mut_key.rs
index 4b62dcdff..a651020ca 100644
--- a/src/tools/clippy/clippy_lints/src/mut_key.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_key.rs
@@ -1,10 +1,11 @@
use clippy_utils::diagnostics::span_lint;
-use clippy_utils::trait_ref_of_method;
+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::{Adt, Array, Ref, Slice, Tuple, Ty};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Span;
use rustc_span::symbol::sym;
use std::iter;
@@ -78,26 +79,44 @@ declare_clippy_lint! {
"Check for mutable `Map`/`Set` key type"
}
-declare_lint_pass!(MutableKeyType => [ MUTABLE_KEY_TYPE ]);
+#[derive(Clone)]
+pub struct MutableKeyType {
+ ignore_interior_mutability: Vec<String>,
+ ignore_mut_def_ids: FxHashSet<hir::def_id::DefId>,
+}
+
+impl_lint_pass!(MutableKeyType => [ MUTABLE_KEY_TYPE ]);
impl<'tcx> LateLintPass<'tcx> for MutableKeyType {
+ fn check_crate(&mut self, cx: &LateContext<'tcx>) {
+ self.ignore_mut_def_ids.clear();
+ let mut path = Vec::new();
+ for ty in &self.ignore_interior_mutability {
+ path.extend(ty.split("::"));
+ for id in def_path_def_ids(cx, &path[..]) {
+ self.ignore_mut_def_ids.insert(id);
+ }
+ path.clear();
+ }
+ }
+
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
if let hir::ItemKind::Fn(ref sig, ..) = item.kind {
- check_sig(cx, item.hir_id(), sig.decl);
+ self.check_sig(cx, item.hir_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() {
- check_sig(cx, item.hir_id(), sig.decl);
+ self.check_sig(cx, item.hir_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 {
- check_sig(cx, item.hir_id(), sig.decl);
+ self.check_sig(cx, item.hir_id(), sig.decl);
}
}
@@ -105,73 +124,81 @@ impl<'tcx> LateLintPass<'tcx> for MutableKeyType {
if let hir::PatKind::Wild = local.pat.kind {
return;
}
- check_ty(cx, local.span, cx.typeck_results().pat_ty(local.pat));
+ self.check_ty_(cx, local.span, cx.typeck_results().pat_ty(local.pat));
}
}
-fn check_sig<'tcx>(cx: &LateContext<'tcx>, 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);
- for (hir_ty, ty) in iter::zip(decl.inputs, fn_sig.inputs().skip_binder()) {
- check_ty(cx, hir_ty.span, *ty);
+impl MutableKeyType {
+ pub fn new(ignore_interior_mutability: Vec<String>) -> Self {
+ Self {
+ ignore_interior_mutability,
+ ignore_mut_def_ids: FxHashSet::default(),
+ }
}
- check_ty(cx, decl.output.span(), cx.tcx.erase_late_bound_regions(fn_sig.output()));
-}
-// We want to lint 1. sets or maps with 2. not immutable key types and 3. no unerased
-// generics (because the compiler cannot ensure immutability for unknown types).
-fn check_ty<'tcx>(cx: &LateContext<'tcx>, span: Span, ty: Ty<'tcx>) {
- let ty = ty.peel_refs();
- if let Adt(def, substs) = ty.kind() {
- let is_keyed_type = [sym::HashMap, sym::BTreeMap, sym::HashSet, sym::BTreeSet]
- .iter()
- .any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def.did()));
- if is_keyed_type && is_interior_mutable_type(cx, substs.type_at(0), span) {
- span_lint(cx, MUTABLE_KEY_TYPE, span, "mutable key type");
+ 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);
+ for (hir_ty, ty) in iter::zip(decl.inputs, fn_sig.inputs().skip_binder()) {
+ self.check_ty_(cx, hir_ty.span, *ty);
}
+ self.check_ty_(cx, decl.output.span(), cx.tcx.erase_late_bound_regions(fn_sig.output()));
}
-}
-/// Determines if a type contains interior mutability which would affect its implementation of
-/// [`Hash`] or [`Ord`].
-fn is_interior_mutable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Span) -> bool {
- match *ty.kind() {
- Ref(_, inner_ty, mutbl) => {
- mutbl == hir::Mutability::Mut || is_interior_mutable_type(cx, inner_ty, span)
- }
- Slice(inner_ty) => is_interior_mutable_type(cx, inner_ty, span),
- Array(inner_ty, size) => {
- size.try_eval_usize(cx.tcx, cx.param_env).map_or(true, |u| u != 0)
- && is_interior_mutable_type(cx, inner_ty, span)
- }
- Tuple(fields) => fields.iter().any(|ty| is_interior_mutable_type(cx, ty, span)),
- Adt(def, substs) => {
- // Special case for collections in `std` who's impl of `Hash` or `Ord` delegates to
- // that of their type parameters. Note: we don't include `HashSet` and `HashMap`
- // because they have no impl for `Hash` or `Ord`.
- let is_std_collection = [
- sym::Option,
- sym::Result,
- sym::LinkedList,
- sym::Vec,
- sym::VecDeque,
- sym::BTreeMap,
- sym::BTreeSet,
- sym::Rc,
- sym::Arc,
- ]
- .iter()
- .any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def.did()));
- let is_box = Some(def.did()) == cx.tcx.lang_items().owned_box();
- if is_std_collection || is_box {
- // The type is mutable if any of its type parameters are
- substs.types().any(|ty| is_interior_mutable_type(cx, ty, span))
- } else {
- !ty.has_escaping_bound_vars()
- && cx.tcx.layout_of(cx.param_env.and(ty)).is_ok()
- && !ty.is_freeze(cx.tcx, cx.param_env)
+ // We want to lint 1. sets or maps with 2. not immutable key types and 3. no unerased
+ // generics (because the compiler cannot ensure immutability for unknown types).
+ fn check_ty_<'tcx>(&self, cx: &LateContext<'tcx>, span: Span, ty: Ty<'tcx>) {
+ let ty = ty.peel_refs();
+ if let Adt(def, substs) = ty.kind() {
+ let is_keyed_type = [sym::HashMap, sym::BTreeMap, sym::HashSet, sym::BTreeSet]
+ .iter()
+ .any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def.did()));
+ if is_keyed_type && self.is_interior_mutable_type(cx, substs.type_at(0)) {
+ span_lint(cx, MUTABLE_KEY_TYPE, span, "mutable key type");
}
}
- _ => false,
+ }
+
+ /// Determines if a type contains interior mutability which would affect its implementation of
+ /// [`Hash`] or [`Ord`].
+ fn is_interior_mutable_type<'tcx>(&self, cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
+ match *ty.kind() {
+ 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)
+ && self.is_interior_mutable_type(cx, inner_ty)
+ },
+ Tuple(fields) => fields.iter().any(|ty| self.is_interior_mutable_type(cx, ty)),
+ Adt(def, substs) => {
+ // Special case for collections in `std` who's impl of `Hash` or `Ord` delegates to
+ // that of their type parameters. Note: we don't include `HashSet` and `HashMap`
+ // because they have no impl for `Hash` or `Ord`.
+ let def_id = def.did();
+ let is_std_collection = [
+ sym::Option,
+ sym::Result,
+ sym::LinkedList,
+ sym::Vec,
+ sym::VecDeque,
+ sym::BTreeMap,
+ sym::BTreeSet,
+ sym::Rc,
+ sym::Arc,
+ ]
+ .iter()
+ .any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def_id));
+ let is_box = Some(def_id) == cx.tcx.lang_items().owned_box();
+ if is_std_collection || is_box || self.ignore_mut_def_ids.contains(&def_id) {
+ // The type is mutable if any of its type parameters are
+ substs.types().any(|ty| self.is_interior_mutable_type(cx, ty))
+ } else {
+ !ty.has_escaping_bound_vars()
+ && cx.tcx.layout_of(cx.param_env.and(ty)).is_ok()
+ && !ty.is_freeze(cx.tcx, cx.param_env)
+ }
+ },
+ _ => false,
+ }
}
}
diff --git a/src/tools/clippy/clippy_lints/src/mut_mut.rs b/src/tools/clippy/clippy_lints/src/mut_mut.rs
index cb16f0004..bc90e131b 100644
--- a/src/tools/clippy/clippy_lints/src/mut_mut.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_mut.rs
@@ -68,13 +68,15 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for MutVisitor<'a, 'tcx> {
expr.span,
"generally you want to avoid `&mut &mut _` if possible",
);
- } else if let ty::Ref(_, _, hir::Mutability::Mut) = self.cx.typeck_results().expr_ty(e).kind() {
- span_lint(
- self.cx,
- MUT_MUT,
- expr.span,
- "this expression mutably borrows a mutable reference. Consider reborrowing",
- );
+ } else if let ty::Ref(_, ty, hir::Mutability::Mut) = self.cx.typeck_results().expr_ty(e).kind() {
+ if ty.peel_refs().is_sized(self.cx.tcx, self.cx.param_env) {
+ span_lint(
+ self.cx,
+ MUT_MUT,
+ expr.span,
+ "this expression mutably borrows a mutable reference. Consider reborrowing",
+ );
+ }
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs b/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs
index 10c3ff026..498e1408e 100644
--- a/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs
@@ -36,14 +36,14 @@ declare_clippy_lint! {
declare_lint_pass!(NeedlessBorrowedRef => [NEEDLESS_BORROWED_REFERENCE]);
impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowedRef {
- fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
- if pat.span.from_expansion() {
+ fn check_pat(&mut self, cx: &LateContext<'tcx>, ref_pat: &'tcx Pat<'_>) {
+ if ref_pat.span.from_expansion() {
// OK, simple enough, lints doesn't check in macro.
return;
}
// Do not lint patterns that are part of an OR `|` pattern, the binding mode must match in all arms
- for (_, node) in cx.tcx.hir().parent_iter(pat.hir_id) {
+ for (_, node) in cx.tcx.hir().parent_iter(ref_pat.hir_id) {
let Node::Pat(pat) = node else { break };
if matches!(pat.kind, PatKind::Or(_)) {
@@ -52,20 +52,20 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowedRef {
}
// Only lint immutable refs, because `&mut ref T` may be useful.
- let PatKind::Ref(sub_pat, Mutability::Not) = pat.kind else { return };
+ let PatKind::Ref(pat, Mutability::Not) = ref_pat.kind else { return };
- match sub_pat.kind {
+ match pat.kind {
// Check sub_pat got a `ref` keyword (excluding `ref mut`).
PatKind::Binding(BindingAnnotation::REF, _, ident, None) => {
span_lint_and_then(
cx,
NEEDLESS_BORROWED_REFERENCE,
- pat.span,
+ ref_pat.span,
"this pattern takes a reference on something that is being dereferenced",
|diag| {
// `&ref ident`
// ^^^^^
- let span = pat.span.until(ident.span);
+ let span = ref_pat.span.until(ident.span);
diag.span_suggestion_verbose(
span,
"try removing the `&ref` part",
@@ -84,41 +84,71 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowedRef {
}),
after,
) => {
- let mut suggestions = Vec::new();
-
- for element_pat in itertools::chain(before, after) {
- if let PatKind::Binding(BindingAnnotation::REF, _, ident, None) = element_pat.kind {
- // `&[..., ref ident, ...]`
- // ^^^^
- let span = element_pat.span.until(ident.span);
- suggestions.push((span, String::new()));
- } else {
- return;
- }
- }
+ check_subpatterns(
+ cx,
+ "dereferencing a slice pattern where every element takes a reference",
+ ref_pat,
+ pat,
+ itertools::chain(before, after),
+ );
+ },
+ PatKind::Tuple(subpatterns, _) | PatKind::TupleStruct(_, subpatterns, _) => {
+ check_subpatterns(
+ cx,
+ "dereferencing a tuple pattern where every element takes a reference",
+ ref_pat,
+ pat,
+ subpatterns,
+ );
+ },
+ PatKind::Struct(_, fields, _) => {
+ check_subpatterns(
+ cx,
+ "dereferencing a struct pattern where every field's pattern takes a reference",
+ ref_pat,
+ pat,
+ fields.iter().map(|field| field.pat),
+ );
+ },
+ _ => {},
+ }
+ }
+}
- if !suggestions.is_empty() {
- span_lint_and_then(
- cx,
- NEEDLESS_BORROWED_REFERENCE,
- pat.span,
- "dereferencing a slice pattern where every element takes a reference",
- |diag| {
- // `&[...]`
- // ^
- let span = pat.span.until(sub_pat.span);
- suggestions.push((span, String::new()));
+fn check_subpatterns<'tcx>(
+ cx: &LateContext<'tcx>,
+ message: &str,
+ ref_pat: &Pat<'_>,
+ pat: &Pat<'_>,
+ subpatterns: impl IntoIterator<Item = &'tcx Pat<'tcx>>,
+) {
+ let mut suggestions = Vec::new();
- diag.multipart_suggestion(
- "try removing the `&` and `ref` parts",
- suggestions,
- Applicability::MachineApplicable,
- );
- },
- );
- }
+ for subpattern in subpatterns {
+ match subpattern.kind {
+ PatKind::Binding(BindingAnnotation::REF, _, ident, None) => {
+ // `ref ident`
+ // ^^^^
+ let span = subpattern.span.until(ident.span);
+ suggestions.push((span, String::new()));
},
- _ => {},
+ PatKind::Wild => {},
+ _ => return,
}
}
+
+ if !suggestions.is_empty() {
+ span_lint_and_then(cx, NEEDLESS_BORROWED_REFERENCE, ref_pat.span, message, |diag| {
+ // `&pat`
+ // ^
+ let span = ref_pat.span.until(pat.span);
+ suggestions.push((span, String::new()));
+
+ diag.multipart_suggestion(
+ "try removing the `&` and `ref` parts",
+ suggestions,
+ Applicability::MachineApplicable,
+ );
+ });
+ }
}
diff --git a/src/tools/clippy/clippy_lints/src/needless_continue.rs b/src/tools/clippy/clippy_lints/src/needless_continue.rs
index 6f0e75546..38a75034c 100644
--- a/src/tools/clippy/clippy_lints/src/needless_continue.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_continue.rs
@@ -287,7 +287,7 @@ const DROP_ELSE_BLOCK_MSG: &str = "consider dropping the `else` clause";
const DROP_CONTINUE_EXPRESSION_MSG: &str = "consider dropping the `continue` expression";
-fn emit_warning<'a>(cx: &EarlyContext<'_>, data: &'a LintData<'_>, header: &str, typ: LintType) {
+fn emit_warning(cx: &EarlyContext<'_>, data: &LintData<'_>, header: &str, typ: LintType) {
// snip is the whole *help* message that appears after the warning.
// message is the warning message.
// expr is the expression which the lint warning message refers to.
@@ -313,7 +313,7 @@ fn emit_warning<'a>(cx: &EarlyContext<'_>, data: &'a LintData<'_>, header: &str,
);
}
-fn suggestion_snippet_for_continue_inside_if<'a>(cx: &EarlyContext<'_>, data: &'a LintData<'_>) -> String {
+fn suggestion_snippet_for_continue_inside_if(cx: &EarlyContext<'_>, data: &LintData<'_>) -> String {
let cond_code = snippet(cx, data.if_cond.span, "..");
let continue_code = snippet_block(cx, data.if_block.span, "..", Some(data.if_expr.span));
@@ -327,7 +327,7 @@ fn suggestion_snippet_for_continue_inside_if<'a>(cx: &EarlyContext<'_>, data: &'
)
}
-fn suggestion_snippet_for_continue_inside_else<'a>(cx: &EarlyContext<'_>, data: &'a LintData<'_>) -> String {
+fn suggestion_snippet_for_continue_inside_else(cx: &EarlyContext<'_>, data: &LintData<'_>) -> String {
let cond_code = snippet(cx, data.if_cond.span, "..");
// Region B
@@ -361,7 +361,7 @@ fn suggestion_snippet_for_continue_inside_else<'a>(cx: &EarlyContext<'_>, data:
)
}
-fn check_and_warn<'a>(cx: &EarlyContext<'_>, expr: &'a ast::Expr) {
+fn check_and_warn(cx: &EarlyContext<'_>, expr: &ast::Expr) {
if_chain! {
if let ast::ExprKind::Loop(loop_block, ..) = &expr.kind;
if let Some(last_stmt) = loop_block.stmts.last();
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 b2e9ce5c9..2f0b7ce16 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
@@ -1,7 +1,9 @@
use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
use clippy_utils::ptr::get_spans;
use clippy_utils::source::{snippet, snippet_opt};
-use clippy_utils::ty::{implements_trait, is_copy, is_type_diagnostic_item};
+use clippy_utils::ty::{
+ implements_trait, implements_trait_with_env, is_copy, is_type_diagnostic_item, is_type_lang_item,
+};
use clippy_utils::{get_trait_def_id, is_self, paths};
use if_chain::if_chain;
use rustc_ast::ast::Attribute;
@@ -11,7 +13,7 @@ use rustc_hir::intravisit::FnKind;
use rustc_hir::{
BindingAnnotation, Body, FnDecl, GenericArg, HirId, Impl, ItemKind, Mutability, Node, PatKind, QPath, TyKind,
};
-use rustc_hir::{HirIdMap, HirIdSet};
+use rustc_hir::{HirIdMap, HirIdSet, LangItem};
use rustc_hir_typeck::expr_use_visitor as euv;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::{LateContext, LateLintPass};
@@ -124,7 +126,9 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
.filter_map(|obligation| {
// Note that we do not want to deal with qualified predicates here.
match obligation.predicate.kind().no_bound_vars() {
- Some(ty::PredicateKind::Trait(pred)) if pred.def_id() != sized_trait => Some(pred),
+ Some(ty::PredicateKind::Clause(ty::Clause::Trait(pred))) if pred.def_id() != sized_trait => {
+ Some(pred)
+ },
_ => None,
}
})
@@ -185,7 +189,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
if !ty.is_mutable_ptr();
if !is_copy(cx, ty);
if ty.is_sized(cx.tcx, cx.param_env);
- if !allowed_traits.iter().any(|&t| implements_trait(cx, ty, t, &[]));
+ if !allowed_traits.iter().any(|&t| implements_trait_with_env(cx.tcx, cx.param_env, ty, t, [None]));
if !implements_borrow_trait;
if !all_borrowable_trait;
@@ -249,7 +253,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
}
}
- if is_type_diagnostic_item(cx, ty, sym::String) {
+ if is_type_lang_item(cx, ty, LangItem::String) {
if let Some(clone_spans) =
get_spans(cx, Some(body.id()), idx, &[("clone", ".to_string()"), ("as_str", "")]) {
diag.span_suggestion(
@@ -340,11 +344,5 @@ impl<'tcx> euv::Delegate<'tcx> for MovedVariablesCtxt {
fn mutate(&mut self, _: &euv::PlaceWithHirId<'tcx>, _: HirId) {}
- fn fake_read(
- &mut self,
- _: &rustc_hir_typeck::expr_use_visitor::PlaceWithHirId<'tcx>,
- _: FakeReadCause,
- _: HirId,
- ) {
- }
+ fn fake_read(&mut self, _: &rustc_hir_typeck::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
}
diff --git a/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs b/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs
index 5c2b96f5b..a022fc156 100644
--- a/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs
+++ b/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs
@@ -65,7 +65,7 @@ impl<'tcx> LateLintPass<'tcx> for NoNegCompOpForPartialOrd {
let implements_partial_ord = {
if let Some(id) = cx.tcx.lang_items().partial_ord_trait() {
- implements_trait(cx, ty, id, &[])
+ implements_trait(cx, ty, id, &[ty.into()])
} else {
return;
}
diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs
index 819646bb6..79c1ae486 100644
--- a/src/tools/clippy/clippy_lints/src/no_effect.rs
+++ b/src/tools/clippy/clippy_lints/src/no_effect.rs
@@ -6,7 +6,8 @@ use clippy_utils::ty::has_drop;
use rustc_errors::Applicability;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::{is_range_literal, BinOpKind, BlockCheckMode, Expr, ExprKind, PatKind, Stmt, StmtKind, UnsafeSource};
-use rustc_lint::{LateContext, LateLintPass};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use std::ops::Deref;
@@ -159,8 +160,11 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
fn check_unnecessary_operation(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
if_chain! {
if let StmtKind::Semi(expr) = stmt.kind;
+ let ctxt = stmt.span.ctxt();
+ if expr.span.ctxt() == ctxt;
if let Some(reduced) = reduce_expression(cx, expr);
- if !&reduced.iter().any(|e| e.span.from_expansion());
+ if !in_external_macro(cx.sess(), stmt.span);
+ if reduced.iter().all(|e| e.span.ctxt() == ctxt);
then {
if let ExprKind::Index(..) = &expr.kind {
let snippet = if let (Some(arr), Some(func)) =
diff --git a/src/tools/clippy/clippy_lints/src/octal_escapes.rs b/src/tools/clippy/clippy_lints/src/octal_escapes.rs
index f380a5065..ae0a41db9 100644
--- a/src/tools/clippy/clippy_lints/src/octal_escapes.rs
+++ b/src/tools/clippy/clippy_lints/src/octal_escapes.rs
@@ -56,11 +56,11 @@ impl EarlyLintPass for OctalEscapes {
return;
}
- if let ExprKind::Lit(lit) = &expr.kind {
- if matches!(lit.token_lit.kind, LitKind::Str) {
- check_lit(cx, &lit.token_lit, lit.span, true);
- } else if matches!(lit.token_lit.kind, LitKind::ByteStr) {
- check_lit(cx, &lit.token_lit, lit.span, false);
+ if let ExprKind::Lit(token_lit) = &expr.kind {
+ if matches!(token_lit.kind, LitKind::Str) {
+ check_lit(cx, token_lit, expr.span, true);
+ } else if matches!(token_lit.kind, LitKind::ByteStr) {
+ check_lit(cx, token_lit, expr.span, false);
}
}
}
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 8827daaa3..20b82d81a 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,5 +1,9 @@
use super::ARITHMETIC_SIDE_EFFECTS;
-use clippy_utils::{consts::constant_simple, diagnostics::span_lint};
+use clippy_utils::{
+ consts::{constant, constant_simple},
+ diagnostics::span_lint,
+ peel_hir_expr_refs,
+};
use rustc_ast as ast;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
@@ -38,24 +42,6 @@ impl ArithmeticSideEffects {
}
}
- /// Assuming that `expr` is a literal integer, checks operators (+=, -=, *, /) in a
- /// non-constant environment that won't overflow.
- fn has_valid_op(op: &Spanned<hir::BinOpKind>, expr: &hir::Expr<'_>) -> bool {
- if let hir::ExprKind::Lit(ref lit) = expr.kind &&
- let ast::LitKind::Int(value, _) = lit.node
- {
- match (&op.node, value) {
- (hir::BinOpKind::Div | hir::BinOpKind::Rem, 0) => false,
- (hir::BinOpKind::Add | hir::BinOpKind::Sub, 0)
- | (hir::BinOpKind::Div | hir::BinOpKind::Rem, _)
- | (hir::BinOpKind::Mul, 0 | 1) => true,
- _ => false,
- }
- } else {
- false
- }
- }
-
/// Checks if the given `expr` has any of the inner `allowed` elements.
fn is_allowed_ty(&self, ty: Ty<'_>) -> bool {
self.allowed
@@ -74,15 +60,14 @@ impl ArithmeticSideEffects {
self.expr_span = Some(expr.span);
}
- /// If `expr` does not match any variant of `LiteralIntegerTy`, returns `None`.
- fn literal_integer<'expr, 'tcx>(expr: &'expr hir::Expr<'tcx>) -> Option<LiteralIntegerTy<'expr, 'tcx>> {
- if matches!(expr.kind, hir::ExprKind::Lit(_)) {
- return Some(LiteralIntegerTy::Value(expr));
+ /// If `expr` is not a literal integer like `1`, returns `None`.
+ fn literal_integer(expr: &hir::Expr<'_>) -> Option<u128> {
+ if let hir::ExprKind::Lit(ref lit) = expr.kind && let ast::LitKind::Int(n, _) = lit.node {
+ Some(n)
}
- if let hir::ExprKind::AddrOf(.., inn) = expr.kind && let hir::ExprKind::Lit(_) = inn.kind {
- return Some(LiteralIntegerTy::Ref(inn));
+ else {
+ None
}
- None
}
/// Manages when the lint should be triggered. Operations in constant environments, hard coded
@@ -117,10 +102,20 @@ impl ArithmeticSideEffects {
return;
}
let has_valid_op = if Self::is_integral(lhs_ty) && Self::is_integral(rhs_ty) {
- match (Self::literal_integer(lhs), Self::literal_integer(rhs)) {
- (None, Some(lit_int_ty)) | (Some(lit_int_ty), None) => Self::has_valid_op(op, lit_int_ty.into()),
- (Some(LiteralIntegerTy::Value(_)), Some(LiteralIntegerTy::Value(_))) => true,
- (None, None) | (Some(_), Some(_)) => false,
+ 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)) {
+ (None, None) => false,
+ (None, Some(n)) | (Some(n), None) => match (&op.node, n) {
+ (hir::BinOpKind::Div | hir::BinOpKind::Rem, 0) => false,
+ (hir::BinOpKind::Add | hir::BinOpKind::Sub, 0)
+ | (hir::BinOpKind::Div | hir::BinOpKind::Rem, _)
+ | (hir::BinOpKind::Mul, 0 | 1) => true,
+ _ => false,
+ },
+ (Some(_), Some(_)) => {
+ matches!((lhs_ref_counter, rhs_ref_counter), (0, 0))
+ },
}
} else {
false
@@ -129,21 +124,45 @@ impl ArithmeticSideEffects {
self.issue_lint(cx, expr);
}
}
+
+ fn manage_unary_ops<'tcx>(
+ &mut self,
+ cx: &LateContext<'tcx>,
+ expr: &hir::Expr<'tcx>,
+ un_expr: &hir::Expr<'tcx>,
+ un_op: hir::UnOp,
+ ) {
+ let hir::UnOp::Neg = un_op else { return; };
+ if constant(cx, cx.typeck_results(), un_expr).is_some() {
+ return;
+ }
+ let ty = cx.typeck_results().expr_ty(expr).peel_refs();
+ if self.is_allowed_ty(ty) {
+ return;
+ }
+ let actual_un_expr = peel_hir_expr_refs(un_expr).0;
+ if Self::literal_integer(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))
+ }
}
impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'tcx>) {
- if self.expr_span.is_some() || self.const_span.map_or(false, |sp| sp.contains(expr.span)) {
+ if self.should_skip_expr(expr) {
return;
}
match &expr.kind {
- hir::ExprKind::Binary(op, lhs, rhs) | hir::ExprKind::AssignOp(op, lhs, rhs) => {
+ hir::ExprKind::AssignOp(op, lhs, rhs) | hir::ExprKind::Binary(op, lhs, rhs) => {
self.manage_bin_ops(cx, expr, op, lhs, rhs);
},
- hir::ExprKind::Unary(hir::UnOp::Neg, _) => {
- if constant_simple(cx, cx.typeck_results(), expr).is_none() {
- self.issue_lint(cx, expr);
- }
+ hir::ExprKind::Unary(un_op, un_expr) => {
+ self.manage_unary_ops(cx, expr, un_expr, *un_op);
},
_ => {},
}
@@ -177,22 +196,3 @@ impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects {
}
}
}
-
-/// Tells if an expression is a integer declared by value or by reference.
-///
-/// If `LiteralIntegerTy::Ref`, then the contained value will be `hir::ExprKind::Lit` rather
-/// than `hirExprKind::Addr`.
-enum LiteralIntegerTy<'expr, 'tcx> {
- /// For example, `&199`
- Ref(&'expr hir::Expr<'tcx>),
- /// For example, `1` or `i32::MAX`
- Value(&'expr hir::Expr<'tcx>),
-}
-
-impl<'expr, 'tcx> From<LiteralIntegerTy<'expr, 'tcx>> for &'expr hir::Expr<'tcx> {
- fn from(from: LiteralIntegerTy<'expr, 'tcx>) -> Self {
- match from {
- LiteralIntegerTy::Ref(elem) | LiteralIntegerTy::Value(elem) => elem,
- }
- }
-}
diff --git a/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs b/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs
index ee9fd9406..9bbf385fb 100644
--- a/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs
@@ -28,7 +28,7 @@ pub(super) fn check<'tcx>(
let rty = cx.typeck_results().expr_ty(rhs);
if_chain! {
if let Some((_, lang_item)) = binop_traits(op.node);
- if let Ok(trait_id) = cx.tcx.lang_items().require(lang_item);
+ if let Some(trait_id) = cx.tcx.lang_items().get(lang_item);
let parent_fn = cx.tcx.hir().get_parent_item(e.hir_id).def_id;
if trait_ref_of_method(cx, parent_fn)
.map_or(true, |t| t.path.res.def_id() != trait_id);
diff --git a/src/tools/clippy/clippy_lints/src/operators/op_ref.rs b/src/tools/clippy/clippy_lints/src/operators/op_ref.rs
index 71b31b5e4..d7917e86a 100644
--- a/src/tools/clippy/clippy_lints/src/operators/op_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/op_ref.rs
@@ -199,7 +199,7 @@ fn in_impl<'tcx>(
}
}
-fn are_equal<'tcx>(cx: &LateContext<'tcx>, middle_ty: Ty<'_>, hir_ty: &rustc_hir::Ty<'_>) -> bool {
+fn are_equal(cx: &LateContext<'_>, middle_ty: Ty<'_>, hir_ty: &rustc_hir::Ty<'_>) -> bool {
if_chain! {
if let ty::Adt(adt_def, _) = middle_ty.kind();
if let Some(local_did) = adt_def.did().as_local();
diff --git a/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs b/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs
index d9ee031c9..377bddeaa 100644
--- a/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::is_direct_expn_of;
use if_chain::if_chain;
-use rustc_ast::ast::{Expr, ExprKind};
+use rustc_ast::ast::{Expr, ExprKind, MethodCall};
use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::sym;
@@ -37,8 +37,8 @@ declare_lint_pass!(OptionEnvUnwrap => [OPTION_ENV_UNWRAP]);
impl EarlyLintPass for OptionEnvUnwrap {
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
if_chain! {
- if let ExprKind::MethodCall(path_segment, receiver, _, _) = &expr.kind;
- if matches!(path_segment.ident.name, sym::expect | sym::unwrap);
+ if let ExprKind::MethodCall(box MethodCall { seg, receiver, .. }) = &expr.kind;
+ if matches!(seg.ident.name, sym::expect | sym::unwrap);
if let ExprKind::Call(caller, _) = &receiver.kind;
if is_direct_expn_of(caller.span, "option_env").is_some();
then {
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 4eb42da1f..472f52380 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
@@ -213,11 +213,14 @@ fn try_convert_match<'tcx>(
cx: &LateContext<'tcx>,
arms: &[Arm<'tcx>],
) -> Option<(&'tcx Pat<'tcx>, &'tcx Expr<'tcx>, &'tcx Expr<'tcx>)> {
- if arms.len() == 2 {
- return if is_none_or_err_arm(cx, &arms[1]) {
- Some((arms[0].pat, arms[0].body, arms[1].body))
- } else if is_none_or_err_arm(cx, &arms[0]) {
- Some((arms[1].pat, arms[1].body, arms[0].body))
+ if let [first_arm, second_arm] = arms
+ && first_arm.guard.is_none()
+ && second_arm.guard.is_none()
+ {
+ return if is_none_or_err_arm(cx, second_arm) {
+ Some((first_arm.pat, first_arm.body, second_arm.body))
+ } else if is_none_or_err_arm(cx, first_arm) {
+ Some((second_arm.pat, second_arm.body, first_arm.body))
} else {
None
};
diff --git a/src/tools/clippy/clippy_lints/src/partialeq_to_none.rs b/src/tools/clippy/clippy_lints/src/partialeq_to_none.rs
index 6810a2431..456ded3fc 100644
--- a/src/tools/clippy/clippy_lints/src/partialeq_to_none.rs
+++ b/src/tools/clippy/clippy_lints/src/partialeq_to_none.rs
@@ -33,7 +33,7 @@ declare_clippy_lint! {
/// if f.is_some() { "yay" } else { "nay" }
/// }
/// ```
- #[clippy::version = "1.64.0"]
+ #[clippy::version = "1.65.0"]
pub PARTIALEQ_TO_NONE,
style,
"Binary comparison to `Option<T>::None` relies on `T: PartialEq`, which is unneeded"
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 a4d265111..97b5a4ce3 100644
--- a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs
+++ b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs
@@ -130,7 +130,7 @@ enum DerefPossible {
Impossible,
}
-fn apply_lint<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'_>, deref_possible: DerefPossible) -> bool {
+fn apply_lint(cx: &LateContext<'_>, pat: &Pat<'_>, deref_possible: DerefPossible) -> bool {
let maybe_mismatch = find_first_mismatch(cx, pat);
if let Some((span, mutability, level)) = maybe_mismatch {
span_lint_and_help(
@@ -163,7 +163,7 @@ enum Level {
Lower,
}
-fn find_first_mismatch<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'_>) -> Option<(Span, Mutability, Level)> {
+fn find_first_mismatch(cx: &LateContext<'_>, pat: &Pat<'_>) -> Option<(Span, Mutability, Level)> {
let mut result = None;
pat.walk(|p| {
if result.is_some() {
diff --git a/src/tools/clippy/clippy_lints/src/precedence.rs b/src/tools/clippy/clippy_lints/src/precedence.rs
index e6e3ad05a..057b7e306 100644
--- a/src/tools/clippy/clippy_lints/src/precedence.rs
+++ b/src/tools/clippy/clippy_lints/src/precedence.rs
@@ -1,7 +1,8 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
use if_chain::if_chain;
-use rustc_ast::ast::{BinOpKind, Expr, ExprKind, LitKind, UnOp};
+use rustc_ast::ast::{BinOpKind, Expr, ExprKind, MethodCall, UnOp};
+use rustc_ast::token;
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -109,18 +110,18 @@ impl EarlyLintPass for Precedence {
let mut arg = operand;
let mut all_odd = true;
- while let ExprKind::MethodCall(path_segment, receiver, _, _) = &arg.kind {
- let path_segment_str = path_segment.ident.name.as_str();
+ while let ExprKind::MethodCall(box MethodCall { seg, receiver, .. }) = &arg.kind {
+ let seg_str = seg.ident.name.as_str();
all_odd &= ALLOWED_ODD_FUNCTIONS
.iter()
- .any(|odd_function| **odd_function == *path_segment_str);
+ .any(|odd_function| **odd_function == *seg_str);
arg = receiver;
}
if_chain! {
if !all_odd;
if let ExprKind::Lit(lit) = &arg.kind;
- if let LitKind::Int(..) | LitKind::Float(..) = &lit.kind;
+ if let token::LitKind::Integer | token::LitKind::Float = &lit.kind;
then {
let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg(
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index 0d74c90a8..e395ff54c 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -12,14 +12,14 @@ use rustc_hir::hir_id::HirIdMap;
use rustc_hir::intravisit::{walk_expr, Visitor};
use rustc_hir::{
self as hir, AnonConst, BinOpKind, BindingAnnotation, Body, Expr, ExprKind, FnRetTy, FnSig, GenericArg,
- ImplItemKind, ItemKind, Lifetime, LifetimeName, Mutability, Node, Param, ParamName, PatKind, QPath, TraitFn,
- TraitItem, TraitItemKind, TyKind, Unsafety,
+ ImplItemKind, ItemKind, Lifetime, Mutability, Node, Param, PatKind, QPath, TraitFn, TraitItem, TraitItemKind,
+ TyKind, Unsafety,
};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::traits::{Obligation, ObligationCause};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter;
-use rustc_middle::ty::{self, Binder, ExistentialPredicate, List, PredicateKind, Ty};
+use rustc_middle::ty::{self, Binder, Clause, ExistentialPredicate, List, PredicateKind, Ty};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;
use rustc_span::sym;
@@ -343,21 +343,16 @@ impl PtrArg<'_> {
}
struct RefPrefix {
- lt: LifetimeName,
+ lt: Lifetime,
mutability: Mutability,
}
impl fmt::Display for RefPrefix {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use fmt::Write;
f.write_char('&')?;
- match self.lt {
- LifetimeName::Param(_, ParamName::Plain(name)) => {
- name.fmt(f)?;
- f.write_char(' ')?;
- },
- LifetimeName::Infer => f.write_str("'_ ")?,
- LifetimeName::Static => f.write_str("'static ")?,
- _ => (),
+ if !self.lt.is_anonymous() {
+ self.lt.ident.fmt(f)?;
+ f.write_char(' ')?;
}
f.write_str(self.mutability.prefix_str())
}
@@ -450,7 +445,7 @@ fn check_fn_args<'cx, 'tcx: 'cx>(
substs.type_at(0),
),
),
- Some(sym::String) => (
+ _ if Some(adt.did()) == cx.tcx.lang_items().string() => (
[("clone", ".to_owned()"), ("as_str", "")].as_slice(),
DerefTy::Str,
),
@@ -495,7 +490,7 @@ fn check_fn_args<'cx, 'tcx: 'cx>(
ty_name: name.ident.name,
method_renames,
ref_prefix: RefPrefix {
- lt: lt.name,
+ lt: *lt,
mutability,
},
deref_ty,
@@ -687,23 +682,24 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args:
fn matches_preds<'tcx>(
cx: &LateContext<'tcx>,
ty: Ty<'tcx>,
- preds: &'tcx [Binder<'tcx, ExistentialPredicate<'tcx>>],
+ preds: &'tcx [ty::PolyExistentialPredicate<'tcx>],
) -> bool {
let infcx = cx.tcx.infer_ctxt().build();
preds.iter().all(|&p| match cx.tcx.erase_late_bound_regions(p) {
ExistentialPredicate::Trait(p) => infcx
- .type_implements_trait(p.def_id, ty, p.substs, cx.param_env)
+ .type_implements_trait(p.def_id, [ty.into()].into_iter().chain(p.substs.iter()), cx.param_env)
.must_apply_modulo_regions(),
ExistentialPredicate::Projection(p) => infcx.predicate_must_hold_modulo_regions(&Obligation::new(
+ cx.tcx,
ObligationCause::dummy(),
cx.param_env,
- cx.tcx.mk_predicate(Binder::bind_with_vars(
- PredicateKind::Projection(p.with_self_ty(cx.tcx, ty)),
- List::empty(),
- )),
+ cx.tcx
+ .mk_predicate(Binder::dummy(PredicateKind::Clause(Clause::Projection(
+ p.with_self_ty(cx.tcx, ty),
+ )))),
)),
ExistentialPredicate::AutoTrait(p) => infcx
- .type_implements_trait(p, ty, List::empty(), cx.param_env)
+ .type_implements_trait(p, [ty], cx.param_env)
.must_apply_modulo_regions(),
})
}
diff --git a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs b/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs
index 72dda67c7..47b8891e1 100644
--- a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs
@@ -105,17 +105,17 @@ fn expr_as_ptr_offset_call<'tcx>(
}
// Is the type of the expression a usize?
-fn is_expr_ty_usize<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> bool {
+fn is_expr_ty_usize(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
cx.typeck_results().expr_ty(expr) == cx.tcx.types.usize
}
// Is the type of the expression a raw pointer?
-fn is_expr_ty_raw_ptr<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> bool {
+fn is_expr_ty_raw_ptr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
cx.typeck_results().expr_ty(expr).is_unsafe_ptr()
}
-fn build_suggestion<'tcx>(
- cx: &LateContext<'tcx>,
+fn build_suggestion(
+ cx: &LateContext<'_>,
method: Method,
receiver_expr: &Expr<'_>,
cast_lhs_expr: &Expr<'_>,
diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs
index bb86fb3b7..5269bbd1f 100644
--- a/src/tools/clippy/clippy_lints/src/question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/question_mark.rs
@@ -189,6 +189,7 @@ fn is_early_return(smbl: Symbol, cx: &LateContext<'_>, if_block: &IfBlockType<'_
&& expr_return_none_or_err(smbl, cx, if_else.unwrap(), let_expr, Some(let_pat_sym)))
|| is_res_lang_ctor(cx, res, ResultErr)
&& expr_return_none_or_err(smbl, cx, if_then, let_expr, Some(let_pat_sym))
+ && if_else.is_none()
},
_ => false,
}
diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs
index c6fbb5e80..0a1b9d173 100644
--- a/src/tools/clippy/clippy_lints/src/ranges.rs
+++ b/src/tools/clippy/clippy_lints/src/ranges.rs
@@ -1,16 +1,16 @@
use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
use clippy_utils::higher;
+use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability};
use clippy_utils::sugg::Sugg;
-use clippy_utils::{get_parent_expr, in_constant, is_integer_const, meets_msrv, msrvs, path_to_local};
+use clippy_utils::{get_parent_expr, in_constant, is_integer_const, path_to_local};
use if_chain::if_chain;
use rustc_ast::ast::RangeLimits;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind, HirId};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
-use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::{Span, Spanned};
use std::cmp::Ordering;
@@ -161,12 +161,12 @@ declare_clippy_lint! {
}
pub struct Ranges {
- msrv: Option<RustcVersion>,
+ msrv: Msrv,
}
impl Ranges {
#[must_use]
- pub fn new(msrv: Option<RustcVersion>) -> Self {
+ pub fn new(msrv: Msrv) -> Self {
Self { msrv }
}
}
@@ -181,7 +181,7 @@ impl_lint_pass!(Ranges => [
impl<'tcx> LateLintPass<'tcx> for Ranges {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if let ExprKind::Binary(ref op, l, r) = expr.kind {
- if meets_msrv(self.msrv, msrvs::RANGE_CONTAINS) {
+ if self.msrv.meets(msrvs::RANGE_CONTAINS) {
check_possible_range_contains(cx, op.node, l, r, expr, expr.span);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/redundant_clone.rs b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
index aedbe08e3..c1677fb3d 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
@@ -1,12 +1,12 @@
use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then};
use clippy_utils::mir::{visit_local_usage, LocalUsage, PossibleBorrowerMap};
use clippy_utils::source::snippet_opt;
-use clippy_utils::ty::{has_drop, is_copy, is_type_diagnostic_item, walk_ptrs_ty_depth};
+use clippy_utils::ty::{has_drop, is_copy, is_type_diagnostic_item, is_type_lang_item, walk_ptrs_ty_depth};
use clippy_utils::{fn_has_unsatisfiable_preds, match_def_path, paths};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::intravisit::FnKind;
-use rustc_hir::{def_id, Body, FnDecl, HirId};
+use rustc_hir::{def_id, Body, FnDecl, HirId, LangItem};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::mir;
use rustc_middle::ty::{self, Ty};
@@ -102,7 +102,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
let from_borrow = match_def_path(cx, fn_def_id, &paths::CLONE_TRAIT_METHOD)
|| match_def_path(cx, fn_def_id, &paths::TO_OWNED_METHOD)
|| (match_def_path(cx, fn_def_id, &paths::TO_STRING_METHOD)
- && is_type_diagnostic_item(cx, arg_ty, sym::String));
+ && is_type_lang_item(cx, arg_ty, LangItem::String));
let from_deref = !from_borrow
&& (match_def_path(cx, fn_def_id, &paths::PATH_TO_PATH_BUF)
diff --git a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
index 74eea6de4..2a42e7348 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
@@ -69,10 +69,10 @@ impl EarlyLintPass for RedundantClosureCall {
if_chain! {
if let ast::ExprKind::Call(ref paren, _) = expr.kind;
if let ast::ExprKind::Paren(ref closure) = paren.kind;
- if let ast::ExprKind::Closure(_, _, ref r#async, _, ref decl, ref block, _) = closure.kind;
+ if let ast::ExprKind::Closure(box ast::Closure { ref asyncness, ref fn_decl, ref body, .. }) = closure.kind;
then {
let mut visitor = ReturnVisitor::new();
- visitor.visit_expr(block);
+ visitor.visit_expr(body);
if !visitor.found_return {
span_lint_and_then(
cx,
@@ -80,13 +80,13 @@ impl EarlyLintPass for RedundantClosureCall {
expr.span,
"try not to call a closure in the expression where it is declared",
|diag| {
- if decl.inputs.is_empty() {
- let app = Applicability::MachineApplicable;
- let mut hint = Sugg::ast(cx, block, "..");
+ if fn_decl.inputs.is_empty() {
+ let mut app = Applicability::MachineApplicable;
+ let mut hint = Sugg::ast(cx, body, "..", closure.span.ctxt(), &mut app);
- if r#async.is_async() {
+ if asyncness.is_async() {
// `async x` is a syntax error, so it becomes `async { x }`
- if !matches!(block.kind, ast::ExprKind::Block(_, _)) {
+ if !matches!(body.kind, ast::ExprKind::Block(_, _)) {
hint = hint.blockify();
}
@@ -105,8 +105,8 @@ impl EarlyLintPass for RedundantClosureCall {
impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall {
fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) {
- fn count_closure_usage<'a, 'tcx>(
- cx: &'a LateContext<'tcx>,
+ fn count_closure_usage<'tcx>(
+ cx: &LateContext<'tcx>,
block: &'tcx hir::Block<'_>,
path: &'tcx hir::Path<'tcx>,
) -> usize {
diff --git a/src/tools/clippy/clippy_lints/src/redundant_field_names.rs b/src/tools/clippy/clippy_lints/src/redundant_field_names.rs
index 40b03068f..61bff4a0e 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_field_names.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_field_names.rs
@@ -1,10 +1,9 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::{meets_msrv, msrvs};
+use clippy_utils::msrvs::{self, Msrv};
use rustc_ast::ast::{Expr, ExprKind};
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass};
declare_clippy_lint! {
@@ -37,12 +36,12 @@ declare_clippy_lint! {
}
pub struct RedundantFieldNames {
- msrv: Option<RustcVersion>,
+ msrv: Msrv,
}
impl RedundantFieldNames {
#[must_use]
- pub fn new(msrv: Option<RustcVersion>) -> Self {
+ pub fn new(msrv: Msrv) -> Self {
Self { msrv }
}
}
@@ -51,7 +50,7 @@ impl_lint_pass!(RedundantFieldNames => [REDUNDANT_FIELD_NAMES]);
impl EarlyLintPass for RedundantFieldNames {
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
- if !meets_msrv(self.msrv, msrvs::FIELD_INIT_SHORTHAND) {
+ if !self.msrv.meets(msrvs::FIELD_INIT_SHORTHAND) {
return;
}
diff --git a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
index 26075e9f7..d612d249c 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
@@ -70,7 +70,8 @@ impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate {
}
if let ItemKind::Mod { .. } = item.kind {
- self.is_exported.push(cx.effective_visibilities.is_exported(item.owner_id.def_id));
+ self.is_exported
+ .push(cx.effective_visibilities.is_exported(item.owner_id.def_id));
}
}
@@ -83,7 +84,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate {
fn is_not_macro_export<'tcx>(item: &'tcx Item<'tcx>) -> bool {
if let ItemKind::Use(path, _) = item.kind {
- if let Res::Def(DefKind::Macro(MacroKind::Bang), _) = path.res {
+ if path.res.iter().all(|res| matches!(res, Res::Def(DefKind::Macro(MacroKind::Bang), _))) {
return false;
}
} else if let ItemKind::Macro(..) = item.kind {
diff --git a/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs b/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs
index 60ba62c4a..3aa2490bc 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs
@@ -1,10 +1,9 @@
use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet;
-use clippy_utils::{meets_msrv, msrvs};
use rustc_ast::ast::{Item, ItemKind, Ty, TyKind};
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass};
-use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass};
declare_clippy_lint! {
@@ -34,12 +33,12 @@ declare_clippy_lint! {
}
pub struct RedundantStaticLifetimes {
- msrv: Option<RustcVersion>,
+ msrv: Msrv,
}
impl RedundantStaticLifetimes {
#[must_use]
- pub fn new(msrv: Option<RustcVersion>) -> Self {
+ pub fn new(msrv: Msrv) -> Self {
Self { msrv }
}
}
@@ -96,7 +95,7 @@ impl RedundantStaticLifetimes {
impl EarlyLintPass for RedundantStaticLifetimes {
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
- if !meets_msrv(self.msrv, msrvs::STATIC_IN_CONST) {
+ if !self.msrv.meets(msrvs::STATIC_IN_CONST) {
return;
}
diff --git a/src/tools/clippy/clippy_lints/src/renamed_lints.rs b/src/tools/clippy/clippy_lints/src/renamed_lints.rs
index 76d6ad0b2..8e214218f 100644
--- a/src/tools/clippy/clippy_lints/src/renamed_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/renamed_lints.rs
@@ -11,8 +11,6 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[
("clippy::disallowed_method", "clippy::disallowed_methods"),
("clippy::disallowed_type", "clippy::disallowed_types"),
("clippy::eval_order_dependence", "clippy::mixed_read_write_in_expression"),
- ("clippy::for_loop_over_option", "for_loops_over_fallibles"),
- ("clippy::for_loop_over_result", "for_loops_over_fallibles"),
("clippy::identity_conversion", "clippy::useless_conversion"),
("clippy::if_let_some_result", "clippy::match_result_ok"),
("clippy::logic_bug", "clippy::overly_complex_bool_expr"),
@@ -31,10 +29,13 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[
("clippy::to_string_in_display", "clippy::recursive_format_impl"),
("clippy::zero_width_space", "clippy::invisible_characters"),
("clippy::drop_bounds", "drop_bounds"),
+ ("clippy::for_loop_over_option", "for_loops_over_fallibles"),
+ ("clippy::for_loop_over_result", "for_loops_over_fallibles"),
("clippy::for_loops_over_fallibles", "for_loops_over_fallibles"),
("clippy::into_iter_on_array", "array_into_iter"),
("clippy::invalid_atomic_ordering", "invalid_atomic_ordering"),
("clippy::invalid_ref", "invalid_value"),
+ ("clippy::let_underscore_drop", "let_underscore_drop"),
("clippy::mem_discriminant_non_enum", "enum_intrinsics_non_enums"),
("clippy::panic_params", "non_fmt_panics"),
("clippy::positional_named_format_parameters", "named_arguments_used_positionally"),
diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs
index 2b2a41d16..81143d779 100644
--- a/src/tools/clippy/clippy_lints/src/returns.rs
+++ b/src/tools/clippy/clippy_lints/src/returns.rs
@@ -12,6 +12,7 @@ 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::source_map::Span;
+use rustc_span::{BytePos, Pos};
declare_clippy_lint! {
/// ### What it does
@@ -209,13 +210,14 @@ fn check_final_expr<'tcx>(
if cx.tcx.hir().attrs(expr.hir_id).is_empty() {
let borrows = inner.map_or(false, |inner| last_statement_borrows(cx, inner));
if !borrows {
- emit_return_lint(
- cx,
- peeled_drop_expr.span,
- semi_spans,
- inner.as_ref().map(|i| i.span),
- replacement,
- );
+ // 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);
}
}
},
@@ -289,3 +291,16 @@ fn last_statement_borrows<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>)
})
.is_some()
}
+
+// Go backwards while encountering whitespace and extend the given Span to that point.
+fn extend_span_to_previous_non_ws(cx: &LateContext<'_>, sp: Span) -> Span {
+ if let Ok(prev_source) = cx.sess().source_map().span_to_prev_source(sp) {
+ let ws = [' ', '\t', '\n'];
+ if let Some(non_ws_pos) = prev_source.rfind(|c| !ws.contains(&c)) {
+ let len = prev_source.len() - non_ws_pos - 1;
+ return sp.with_lo(sp.lo() - BytePos::from_usize(len));
+ }
+ }
+
+ sp
+}
diff --git a/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs b/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs
index 66b795130..d46f6a635 100644
--- a/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs
+++ b/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs
@@ -1,8 +1,9 @@
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
+use rustc_ast::node_id::{NodeId, NodeMap};
use rustc_ast::{ptr::P, Crate, Item, ItemKind, MacroDef, ModKind, UseTreeKind};
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{edition::Edition, symbol::kw, Span, Symbol};
declare_clippy_lint! {
@@ -33,51 +34,32 @@ declare_clippy_lint! {
"imports with single component path are redundant"
}
-declare_lint_pass!(SingleComponentPathImports => [SINGLE_COMPONENT_PATH_IMPORTS]);
+#[derive(Default)]
+pub struct SingleComponentPathImports {
+ /// Buffer found usages to emit when visiting that item so that `#[allow]` works as expected
+ found: NodeMap<Vec<SingleUse>>,
+}
+
+struct SingleUse {
+ name: Symbol,
+ span: Span,
+ item_id: NodeId,
+ can_suggest: bool,
+}
+
+impl_lint_pass!(SingleComponentPathImports => [SINGLE_COMPONENT_PATH_IMPORTS]);
impl EarlyLintPass for SingleComponentPathImports {
fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &Crate) {
if cx.sess().opts.edition < Edition::Edition2018 {
return;
}
- check_mod(cx, &krate.items);
- }
-}
-fn check_mod(cx: &EarlyContext<'_>, items: &[P<Item>]) {
- // keep track of imports reused with `self` keyword,
- // such as `self::crypto_hash` in the example below
- // ```rust,ignore
- // use self::crypto_hash::{Algorithm, Hasher};
- // ```
- let mut imports_reused_with_self = Vec::new();
-
- // keep track of single use statements
- // such as `crypto_hash` in the example below
- // ```rust,ignore
- // use crypto_hash;
- // ```
- let mut single_use_usages = Vec::new();
-
- // keep track of macros defined in the module as we don't want it to trigger on this (#7106)
- // ```rust,ignore
- // macro_rules! foo { () => {} };
- // pub(crate) use foo;
- // ```
- let mut macros = Vec::new();
-
- for item in items {
- track_uses(
- cx,
- item,
- &mut imports_reused_with_self,
- &mut single_use_usages,
- &mut macros,
- );
+ self.check_mod(cx, &krate.items);
}
- for (name, span, can_suggest) in single_use_usages {
- if !imports_reused_with_self.contains(&name) {
+ fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
+ for SingleUse { span, can_suggest, .. } in self.found.remove(&item.id).into_iter().flatten() {
if can_suggest {
span_lint_and_sugg(
cx,
@@ -102,74 +84,127 @@ fn check_mod(cx: &EarlyContext<'_>, items: &[P<Item>]) {
}
}
-fn track_uses(
- cx: &EarlyContext<'_>,
- item: &Item,
- imports_reused_with_self: &mut Vec<Symbol>,
- single_use_usages: &mut Vec<(Symbol, Span, bool)>,
- macros: &mut Vec<Symbol>,
-) {
- if item.span.from_expansion() || item.vis.kind.is_pub() {
- return;
- }
+impl SingleComponentPathImports {
+ fn check_mod(&mut self, cx: &EarlyContext<'_>, items: &[P<Item>]) {
+ // keep track of imports reused with `self` keyword, such as `self::crypto_hash` in the example
+ // below. Removing the `use crypto_hash;` would make this a compile error
+ // ```
+ // use crypto_hash;
+ //
+ // use self::crypto_hash::{Algorithm, Hasher};
+ // ```
+ let mut imports_reused_with_self = Vec::new();
- match &item.kind {
- ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) => {
- check_mod(cx, items);
- },
- ItemKind::MacroDef(MacroDef { macro_rules: true, .. }) => {
- macros.push(item.ident.name);
- },
- ItemKind::Use(use_tree) => {
- let segments = &use_tree.prefix.segments;
-
- // keep track of `use some_module;` usages
- if segments.len() == 1 {
- if let UseTreeKind::Simple(None, _, _) = use_tree.kind {
- let name = segments[0].ident.name;
- if !macros.contains(&name) {
- single_use_usages.push((name, item.span, true));
- }
- }
- return;
+ // keep track of single use statements such as `crypto_hash` in the example below
+ // ```
+ // use crypto_hash;
+ // ```
+ let mut single_use_usages = Vec::new();
+
+ // keep track of macros defined in the module as we don't want it to trigger on this (#7106)
+ // ```
+ // macro_rules! foo { () => {} };
+ // pub(crate) use foo;
+ // ```
+ let mut macros = Vec::new();
+
+ for item in items {
+ self.track_uses(
+ cx,
+ item,
+ &mut imports_reused_with_self,
+ &mut single_use_usages,
+ &mut macros,
+ );
+ }
+
+ for usage in single_use_usages {
+ if !imports_reused_with_self.contains(&usage.name) {
+ self.found.entry(usage.item_id).or_default().push(usage);
}
+ }
+ }
- if segments.is_empty() {
- // keep track of `use {some_module, some_other_module};` usages
- if let UseTreeKind::Nested(trees) = &use_tree.kind {
- for tree in trees {
- let segments = &tree.0.prefix.segments;
- if segments.len() == 1 {
- if let UseTreeKind::Simple(None, _, _) = tree.0.kind {
- let name = segments[0].ident.name;
- if !macros.contains(&name) {
- single_use_usages.push((name, tree.0.span, false));
- }
- }
+ fn track_uses(
+ &mut self,
+ cx: &EarlyContext<'_>,
+ item: &Item,
+ imports_reused_with_self: &mut Vec<Symbol>,
+ single_use_usages: &mut Vec<SingleUse>,
+ macros: &mut Vec<Symbol>,
+ ) {
+ if item.span.from_expansion() || item.vis.kind.is_pub() {
+ return;
+ }
+
+ match &item.kind {
+ ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) => {
+ self.check_mod(cx, items);
+ },
+ ItemKind::MacroDef(MacroDef { macro_rules: true, .. }) => {
+ macros.push(item.ident.name);
+ },
+ ItemKind::Use(use_tree) => {
+ let segments = &use_tree.prefix.segments;
+
+ // keep track of `use some_module;` usages
+ if segments.len() == 1 {
+ if let UseTreeKind::Simple(None) = use_tree.kind {
+ let name = segments[0].ident.name;
+ if !macros.contains(&name) {
+ single_use_usages.push(SingleUse {
+ name,
+ span: item.span,
+ item_id: item.id,
+ can_suggest: true,
+ });
}
}
+ return;
}
- } else {
- // keep track of `use self::some_module` usages
- if segments[0].ident.name == kw::SelfLower {
- // simple case such as `use self::module::SomeStruct`
- if segments.len() > 1 {
- imports_reused_with_self.push(segments[1].ident.name);
- return;
- }
- // nested case such as `use self::{module1::Struct1, module2::Struct2}`
+ if segments.is_empty() {
+ // keep track of `use {some_module, some_other_module};` usages
if let UseTreeKind::Nested(trees) = &use_tree.kind {
for tree in trees {
let segments = &tree.0.prefix.segments;
- if !segments.is_empty() {
- imports_reused_with_self.push(segments[0].ident.name);
+ if segments.len() == 1 {
+ if let UseTreeKind::Simple(None) = tree.0.kind {
+ let name = segments[0].ident.name;
+ if !macros.contains(&name) {
+ single_use_usages.push(SingleUse {
+ name,
+ span: tree.0.span,
+ item_id: item.id,
+ can_suggest: false,
+ });
+ }
+ }
+ }
+ }
+ }
+ } else {
+ // keep track of `use self::some_module` usages
+ if segments[0].ident.name == kw::SelfLower {
+ // simple case such as `use self::module::SomeStruct`
+ if segments.len() > 1 {
+ imports_reused_with_self.push(segments[1].ident.name);
+ return;
+ }
+
+ // nested case such as `use self::{module1::Struct1, module2::Struct2}`
+ if let UseTreeKind::Nested(trees) = &use_tree.kind {
+ for tree in trees {
+ let segments = &tree.0.prefix.segments;
+ if !segments.is_empty() {
+ imports_reused_with_self.push(segments[0].ident.name);
+ }
}
}
}
}
- }
- },
- _ => {},
+ },
+ _ => {},
+ }
}
}
diff --git a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
index 760399231..a2109038a 100644
--- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
+++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
@@ -168,7 +168,7 @@ impl SlowVectorInit {
};
}
- fn emit_lint<'tcx>(cx: &LateContext<'tcx>, slow_fill: &Expr<'_>, vec_alloc: &VecAllocation<'_>, msg: &str) {
+ fn emit_lint(cx: &LateContext<'_>, slow_fill: &Expr<'_>, vec_alloc: &VecAllocation<'_>, msg: &str) {
let len_expr = Sugg::hir(cx, vec_alloc.len_expr, "len");
span_lint_and_then(cx, SLOW_VECTOR_INITIALIZATION, slow_fill.span, msg, |diag| {
diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs
index d356c99c8..f4705481d 100644
--- a/src/tools/clippy/clippy_lints/src/strings.rs
+++ b/src/tools/clippy/clippy_lints/src/strings.rs
@@ -1,6 +1,6 @@
use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg};
use clippy_utils::source::{snippet, snippet_with_applicability};
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::ty::is_type_lang_item;
use clippy_utils::{get_parent_expr, is_lint_allowed, match_function_call, method_calls, paths};
use clippy_utils::{peel_blocks, SpanlessEq};
use if_chain::if_chain;
@@ -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_diagnostic_item(cx, e_ty, sym::String) {
+ if matches!(e_ty.kind(), ty::Str) || is_type_lang_item(cx, e_ty, LangItem::String) {
span_lint(
cx,
STRING_SLICE,
@@ -205,7 +205,7 @@ impl<'tcx> LateLintPass<'tcx> for StringAdd {
}
fn is_string(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
- is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(e).peel_refs(), sym::String)
+ is_type_lang_item(cx, cx.typeck_results().expr_ty(e).peel_refs(), LangItem::String)
}
fn is_add(cx: &LateContext<'_>, src: &Expr<'_>, target: &Expr<'_>) -> bool {
@@ -446,7 +446,7 @@ impl<'tcx> LateLintPass<'tcx> for StringToString {
if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind;
if path.ident.name == sym::to_string;
let ty = cx.typeck_results().expr_ty(self_arg);
- if is_type_diagnostic_item(cx, ty, sym::String);
+ if is_type_lang_item(cx, ty, LangItem::String);
then {
span_lint_and_help(
cx,
diff --git a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
index eef9bdc78..e111c7d22 100644
--- a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
+++ b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
@@ -580,9 +580,9 @@ fn ident_difference_expr_with_base_location(
| (Await(_), Await(_))
| (Async(_, _, _), Async(_, _, _))
| (Block(_, _), Block(_, _))
- | (Closure(_, _, _, _, _, _, _), Closure(_, _, _, _, _, _, _))
+ | (Closure(_), Closure(_))
| (Match(_, _), Match(_, _))
- | (Loop(_, _), Loop(_, _))
+ | (Loop(_, _, _), Loop(_, _, _))
| (ForLoop(_, _, _, _), ForLoop(_, _, _, _))
| (While(_, _, _), While(_, _, _))
| (If(_, _, _), If(_, _, _))
@@ -593,7 +593,7 @@ fn ident_difference_expr_with_base_location(
| (Unary(_, _), Unary(_, _))
| (Binary(_, _, _), Binary(_, _, _))
| (Tup(_), Tup(_))
- | (MethodCall(_, _, _, _), MethodCall(_, _, _, _))
+ | (MethodCall(_), MethodCall(_))
| (Call(_, _), Call(_, _))
| (ConstBlock(_), ConstBlock(_))
| (Array(_), Array(_))
diff --git a/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs b/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs
index b57b484bd..6271ea027 100644
--- a/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs
@@ -60,8 +60,8 @@ impl<'tcx> LateLintPass<'tcx> for SuspiciousImpl {
if_chain! {
if let hir::ExprKind::Binary(binop, _, _) | hir::ExprKind::AssignOp(binop, ..) = expr.kind;
if let Some((binop_trait_lang, op_assign_trait_lang)) = binop_traits(binop.node);
- if let Ok(binop_trait_id) = cx.tcx.lang_items().require(binop_trait_lang);
- if let Ok(op_assign_trait_id) = cx.tcx.lang_items().require(op_assign_trait_lang);
+ if let Some(binop_trait_id) = cx.tcx.lang_items().get(binop_trait_lang);
+ if let Some(op_assign_trait_id) = cx.tcx.lang_items().get(op_assign_trait_lang);
// Check for more than one binary operation in the implemented function
// Linting when multiple operations are involved can result in false positives
@@ -78,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for SuspiciousImpl {
(&OP_ASSIGN_TRAITS, SUSPICIOUS_OP_ASSIGN_IMPL),
]
.iter()
- .find(|&(ts, _)| ts.iter().any(|&t| Ok(trait_id) == cx.tcx.lang_items().require(t)));
+ .find(|&(ts, _)| ts.iter().any(|&t| Some(trait_id) == cx.tcx.lang_items().get(t)));
if count_binops(body.value) == 1;
then {
span_lint(
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
new file mode 100644
index 000000000..301aa5798
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs
@@ -0,0 +1,53 @@
+use clippy_utils::{numeric_literal::NumericLiteral, source::snippet_with_context};
+use rustc_errors::Applicability;
+use rustc_hir::{BinOpKind, Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::lint::in_external_macro;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+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.
+ /// ### Example
+ /// ```rust
+ /// let x = 3_i32 ^ 4_i32;
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// let x = 3_i32.pow(4);
+ /// ```
+ #[clippy::version = "1.66.0"]
+ pub SUSPICIOUS_XOR_USED_AS_POW,
+ restriction,
+ "XOR (`^`) operator possibly used as exponentiation operator"
+}
+declare_lint_pass!(ConfusingXorAndPow => [SUSPICIOUS_XOR_USED_AS_POW]);
+
+impl LateLintPass<'_> for ConfusingXorAndPow {
+ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+ if !in_external_macro(cx.sess(), expr.span) &&
+ let ExprKind::Binary(op, left, right) = &expr.kind &&
+ op.node == BinOpKind::BitXor &&
+ left.span.ctxt() == right.span.ctxt() &&
+ let ExprKind::Lit(lit_left) = &left.kind &&
+ let ExprKind::Lit(lit_right) = &right.kind &&
+ let snip_left = snippet_with_context(cx, lit_left.span, lit_left.span.ctxt(), "..", &mut Applicability::MaybeIncorrect) &&
+ let snip_right = snippet_with_context(cx, lit_right.span, lit_right.span.ctxt(), "..", &mut Applicability::MaybeIncorrect) &&
+ let Some(left_val) = NumericLiteral::from_lit_kind(&snip_left.0, &lit_left.node) &&
+ let Some(right_val) = NumericLiteral::from_lit_kind(&snip_right.0, &lit_right.node) &&
+ left_val.is_decimal() &&
+ right_val.is_decimal() {
+ clippy_utils::diagnostics::span_lint_and_sugg(
+ cx,
+ SUSPICIOUS_XOR_USED_AS_POW,
+ expr.span,
+ "`^` is not the exponentiation operator",
+ "did you mean to write",
+ format!("{}.pow({})", left_val.format(), right_val.format()),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/swap.rs b/src/tools/clippy/clippy_lints/src/swap.rs
index f46c21e12..c374529d1 100644
--- a/src/tools/clippy/clippy_lints/src/swap.rs
+++ b/src/tools/clippy/clippy_lints/src/swap.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{can_mut_borrow_both, eq_expr_value, std_or_core};
+use clippy_utils::{can_mut_borrow_both, eq_expr_value, in_constant, std_or_core};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Block, Expr, ExprKind, PatKind, QPath, Stmt, StmtKind};
@@ -16,6 +16,8 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for manual swapping.
///
+ /// Note that the lint will not be emitted in const blocks, as the suggestion would not be applicable.
+ ///
/// ### Why is this bad?
/// The `std::mem::swap` function exposes the intent better
/// without deinitializing or copying either variable.
@@ -138,6 +140,10 @@ fn generate_swap_warning(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>, spa
/// Implementation of the `MANUAL_SWAP` lint.
fn check_manual_swap(cx: &LateContext<'_>, block: &Block<'_>) {
+ if in_constant(cx, block.hir_id) {
+ return;
+ }
+
for w in block.stmts.windows(3) {
if_chain! {
// let t = foo();
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 8cf3efc8d..63b326048 100644
--- a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs
+++ b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs
@@ -1,9 +1,9 @@
use clippy_utils::diagnostics::span_lint_and_help;
-use rustc_hir::{HirId, Item, ItemKind};
+use clippy_utils::has_repr_attr;
+use rustc_hir::{Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::Const;
use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::sym;
declare_clippy_lint! {
/// ### What it does
@@ -72,7 +72,3 @@ fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'_>, item: &Item<'_
}
}
}
-
-fn has_repr_attr(cx: &LateContext<'_>, hir_id: HirId) -> bool {
- cx.tcx.hir().attrs(hir_id).iter().any(|attr| attr.has_name(sym::repr))
-}
diff --git a/src/tools/clippy/clippy_lints/src/transmute/mod.rs b/src/tools/clippy/clippy_lints/src/transmute/mod.rs
index 424a6e926..83e651aba 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/mod.rs
@@ -16,10 +16,10 @@ mod utils;
mod wrong_transmute;
use clippy_utils::in_constant;
+use clippy_utils::msrvs::Msrv;
use if_chain::if_chain;
use rustc_hir::{Expr, ExprKind, QPath};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::symbol::sym;
@@ -410,7 +410,7 @@ declare_clippy_lint! {
}
pub struct Transmute {
- msrv: Option<RustcVersion>,
+ msrv: Msrv,
}
impl_lint_pass!(Transmute => [
CROSSPOINTER_TRANSMUTE,
@@ -431,7 +431,7 @@ impl_lint_pass!(Transmute => [
]);
impl Transmute {
#[must_use]
- pub fn new(msrv: Option<RustcVersion>) -> Self {
+ pub fn new(msrv: Msrv) -> Self {
Self { msrv }
}
}
@@ -461,7 +461,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
let linted = wrong_transmute::check(cx, e, from_ty, to_ty)
| crosspointer_transmute::check(cx, e, from_ty, to_ty)
| transmuting_null::check(cx, e, arg, to_ty)
- | transmute_ptr_to_ref::check(cx, e, from_ty, to_ty, arg, path, self.msrv)
+ | transmute_ptr_to_ref::check(cx, e, from_ty, to_ty, arg, path, &self.msrv)
| transmute_int_to_char::check(cx, e, from_ty, to_ty, arg, const_context)
| transmute_ref_to_ref::check(cx, e, from_ty, to_ty, arg, const_context)
| transmute_ptr_to_ptr::check(cx, e, from_ty, to_ty, arg)
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 12d0b866e..3dde4eee6 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
@@ -1,12 +1,12 @@
use super::TRANSMUTE_PTR_TO_REF;
use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{meets_msrv, msrvs, sugg};
+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_semver::RustcVersion;
/// Checks for `transmute_ptr_to_ref` lint.
/// Returns `true` if it's triggered, otherwise returns `false`.
@@ -17,7 +17,7 @@ pub(super) fn check<'tcx>(
to_ty: Ty<'tcx>,
arg: &'tcx Expr<'_>,
path: &'tcx Path<'_>,
- msrv: Option<RustcVersion>,
+ msrv: &Msrv,
) -> bool {
match (&from_ty.kind(), &to_ty.kind()) {
(ty::RawPtr(from_ptr_ty), ty::Ref(_, to_ref_ty, mutbl)) => {
@@ -37,7 +37,7 @@ pub(super) fn check<'tcx>(
let sugg = if let Some(ty) = get_explicit_type(path) {
let ty_snip = snippet_with_applicability(cx, ty.span, "..", &mut app);
- if meets_msrv(msrv, msrvs::POINTER_CAST) {
+ if msrv.meets(msrvs::POINTER_CAST) {
format!("{deref}{}.cast::<{ty_snip}>()", arg.maybe_par())
} else if from_ptr_ty.has_erased_regions() {
sugg::make_unop(deref, arg.as_ty(format!("{cast} () as {cast} {ty_snip}"))).to_string()
@@ -46,7 +46,7 @@ pub(super) fn check<'tcx>(
}
} else if from_ptr_ty.ty == *to_ref_ty {
if from_ptr_ty.has_erased_regions() {
- if meets_msrv(msrv, msrvs::POINTER_CAST) {
+ if msrv.meets(msrvs::POINTER_CAST) {
format!("{deref}{}.cast::<{to_ref_ty}>()", arg.maybe_par())
} else {
sugg::make_unop(deref, arg.as_ty(format!("{cast} () as {cast} {to_ref_ty}")))
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 3d4bbbf64..34642f4b1 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
@@ -27,32 +27,24 @@ pub(super) fn check<'tcx>(
// `Repr(C)` <-> unordered type.
// If the first field of the `Repr(C)` type matches then the transmute is ok
- (
- ReducedTy::OrderedFields(_, Some(from_sub_ty)),
- ReducedTy::UnorderedFields(to_sub_ty),
- )
- | (
- ReducedTy::UnorderedFields(from_sub_ty),
- ReducedTy::OrderedFields(_, Some(to_sub_ty)),
- ) => {
+ (ReducedTy::OrderedFields(_, Some(from_sub_ty)), ReducedTy::UnorderedFields(to_sub_ty))
+ | (ReducedTy::UnorderedFields(from_sub_ty), ReducedTy::OrderedFields(_, Some(to_sub_ty))) => {
from_ty = from_sub_ty;
to_ty = to_sub_ty;
continue;
- }
- (ReducedTy::OrderedFields(_, Some(from_sub_ty)), ReducedTy::Other(to_sub_ty))
- if reduced_tys.to_fat_ptr =>
- {
+ },
+ (ReducedTy::OrderedFields(_, Some(from_sub_ty)), ReducedTy::Other(to_sub_ty)) if reduced_tys.to_fat_ptr => {
from_ty = from_sub_ty;
to_ty = to_sub_ty;
continue;
- }
+ },
(ReducedTy::Other(from_sub_ty), ReducedTy::OrderedFields(_, Some(to_sub_ty)))
if reduced_tys.from_fat_ptr =>
{
from_ty = from_sub_ty;
to_ty = to_sub_ty;
continue;
- }
+ },
// ptr <-> ptr
(ReducedTy::Other(from_sub_ty), ReducedTy::Other(to_sub_ty))
@@ -62,19 +54,19 @@ pub(super) fn check<'tcx>(
from_ty = from_sub_ty;
to_ty = to_sub_ty;
continue;
- }
+ },
// fat ptr <-> (*size, *size)
(ReducedTy::Other(_), ReducedTy::UnorderedFields(to_ty))
if reduced_tys.from_fat_ptr && is_size_pair(to_ty) =>
{
return false;
- }
+ },
(ReducedTy::UnorderedFields(from_ty), ReducedTy::Other(_))
if reduced_tys.to_fat_ptr && is_size_pair(from_ty) =>
{
return false;
- }
+ },
// fat ptr -> some struct | some struct -> fat ptr
(ReducedTy::Other(_), _) if reduced_tys.from_fat_ptr => {
@@ -85,14 +77,12 @@ pub(super) fn check<'tcx>(
&format!("transmute from `{from_ty_orig}` which has an undefined layout"),
|diag| {
if from_ty_orig.peel_refs() != from_ty.peel_refs() {
- diag.note(&format!(
- "the contained type `{from_ty}` has an undefined layout"
- ));
+ diag.note(&format!("the contained type `{from_ty}` has an undefined layout"));
}
},
);
return true;
- }
+ },
(_, ReducedTy::Other(_)) if reduced_tys.to_fat_ptr => {
span_lint_and_then(
cx,
@@ -101,18 +91,14 @@ pub(super) fn check<'tcx>(
&format!("transmute to `{to_ty_orig}` which has an undefined layout"),
|diag| {
if to_ty_orig.peel_refs() != to_ty.peel_refs() {
- diag.note(&format!(
- "the contained type `{to_ty}` has an undefined layout"
- ));
+ diag.note(&format!("the contained type `{to_ty}` has an undefined layout"));
}
},
);
return true;
- }
+ },
- (ReducedTy::UnorderedFields(from_ty), ReducedTy::UnorderedFields(to_ty))
- if from_ty != to_ty =>
- {
+ (ReducedTy::UnorderedFields(from_ty), ReducedTy::UnorderedFields(to_ty)) if from_ty != to_ty => {
let same_adt_did = if let (ty::Adt(from_def, from_subs), ty::Adt(to_def, to_subs))
= (from_ty.kind(), to_ty.kind())
&& from_def == to_def
@@ -139,25 +125,19 @@ pub(super) fn check<'tcx>(
));
} else {
if from_ty_orig.peel_refs() != from_ty {
- diag.note(&format!(
- "the contained type `{from_ty}` has an undefined layout"
- ));
+ diag.note(&format!("the contained type `{from_ty}` has an undefined layout"));
}
if to_ty_orig.peel_refs() != to_ty {
- diag.note(&format!(
- "the contained type `{to_ty}` has an undefined layout"
- ));
+ diag.note(&format!("the contained type `{to_ty}` has an undefined layout"));
}
}
},
);
return true;
- }
+ },
(
ReducedTy::UnorderedFields(from_ty),
- ReducedTy::Other(_)
- | ReducedTy::OrderedFields(..)
- | ReducedTy::TypeErasure { raw_ptr_only: true },
+ ReducedTy::Other(_) | ReducedTy::OrderedFields(..) | ReducedTy::TypeErasure { raw_ptr_only: true },
) => {
span_lint_and_then(
cx,
@@ -166,18 +146,14 @@ pub(super) fn check<'tcx>(
&format!("transmute from `{from_ty_orig}` which has an undefined layout"),
|diag| {
if from_ty_orig.peel_refs() != from_ty {
- diag.note(&format!(
- "the contained type `{from_ty}` has an undefined layout"
- ));
+ diag.note(&format!("the contained type `{from_ty}` has an undefined layout"));
}
},
);
return true;
- }
+ },
(
- ReducedTy::Other(_)
- | ReducedTy::OrderedFields(..)
- | ReducedTy::TypeErasure { raw_ptr_only: true },
+ ReducedTy::Other(_) | ReducedTy::OrderedFields(..) | ReducedTy::TypeErasure { raw_ptr_only: true },
ReducedTy::UnorderedFields(to_ty),
) => {
span_lint_and_then(
@@ -187,25 +163,19 @@ pub(super) fn check<'tcx>(
&format!("transmute into `{to_ty_orig}` which has an undefined layout"),
|diag| {
if to_ty_orig.peel_refs() != to_ty {
- diag.note(&format!(
- "the contained type `{to_ty}` has an undefined layout"
- ));
+ diag.note(&format!("the contained type `{to_ty}` has an undefined layout"));
}
},
);
return true;
- }
+ },
(
- ReducedTy::OrderedFields(..)
- | ReducedTy::Other(_)
- | ReducedTy::TypeErasure { raw_ptr_only: true },
- ReducedTy::OrderedFields(..)
- | ReducedTy::Other(_)
- | ReducedTy::TypeErasure { raw_ptr_only: true },
+ ReducedTy::OrderedFields(..) | ReducedTy::Other(_) | ReducedTy::TypeErasure { raw_ptr_only: true },
+ ReducedTy::OrderedFields(..) | ReducedTy::Other(_) | ReducedTy::TypeErasure { raw_ptr_only: true },
)
| (ReducedTy::UnorderedFields(_), ReducedTy::UnorderedFields(_)) => {
break;
- }
+ },
}
}
@@ -223,38 +193,42 @@ struct ReducedTys<'tcx> {
}
/// Remove references so long as both types are references.
-fn reduce_refs<'tcx>(
- cx: &LateContext<'tcx>,
- mut from_ty: Ty<'tcx>,
- mut to_ty: Ty<'tcx>,
-) -> ReducedTys<'tcx> {
+fn reduce_refs<'tcx>(cx: &LateContext<'tcx>, mut from_ty: Ty<'tcx>, mut to_ty: Ty<'tcx>) -> ReducedTys<'tcx> {
let mut from_raw_ptr = false;
let mut to_raw_ptr = false;
- let (from_fat_ptr, to_fat_ptr) =
- loop {
- break match (from_ty.kind(), to_ty.kind()) {
- (
- &(ty::Ref(_, from_sub_ty, _) | ty::RawPtr(TypeAndMut { ty: from_sub_ty, .. })),
- &(ty::Ref(_, to_sub_ty, _) | ty::RawPtr(TypeAndMut { ty: to_sub_ty, .. })),
- ) => {
- from_raw_ptr = matches!(*from_ty.kind(), ty::RawPtr(_));
- from_ty = from_sub_ty;
- to_raw_ptr = matches!(*to_ty.kind(), ty::RawPtr(_));
- to_ty = to_sub_ty;
- continue;
- }
- (
- &(ty::Ref(_, unsized_ty, _) | ty::RawPtr(TypeAndMut { ty: unsized_ty, .. })),
- _,
- ) if !unsized_ty.is_sized(cx.tcx, cx.param_env) => (true, false),
- (
- _,
- &(ty::Ref(_, unsized_ty, _) | ty::RawPtr(TypeAndMut { ty: unsized_ty, .. })),
- ) if !unsized_ty.is_sized(cx.tcx, cx.param_env) => (false, true),
- _ => (false, false),
- };
+ let (from_fat_ptr, to_fat_ptr) = loop {
+ break match (from_ty.kind(), to_ty.kind()) {
+ (
+ &(ty::Ref(_, from_sub_ty, _) | ty::RawPtr(TypeAndMut { ty: from_sub_ty, .. })),
+ &(ty::Ref(_, to_sub_ty, _) | ty::RawPtr(TypeAndMut { ty: to_sub_ty, .. })),
+ ) => {
+ from_raw_ptr = matches!(*from_ty.kind(), ty::RawPtr(_));
+ from_ty = from_sub_ty;
+ to_raw_ptr = matches!(*to_ty.kind(), ty::RawPtr(_));
+ to_ty = to_sub_ty;
+ continue;
+ },
+ (&(ty::Ref(_, unsized_ty, _) | ty::RawPtr(TypeAndMut { ty: unsized_ty, .. })), _)
+ if !unsized_ty.is_sized(cx.tcx, cx.param_env) =>
+ {
+ (true, false)
+ },
+ (_, &(ty::Ref(_, unsized_ty, _) | ty::RawPtr(TypeAndMut { ty: unsized_ty, .. })))
+ if !unsized_ty.is_sized(cx.tcx, cx.param_env) =>
+ {
+ (false, true)
+ },
+ _ => (false, false),
};
- ReducedTys { from_ty, to_ty, from_raw_ptr, to_raw_ptr, from_fat_ptr, to_fat_ptr }
+ };
+ ReducedTys {
+ from_ty,
+ to_ty,
+ from_raw_ptr,
+ to_raw_ptr,
+ from_fat_ptr,
+ to_fat_ptr,
+ }
}
enum ReducedTy<'tcx> {
@@ -277,11 +251,11 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx>
return match *ty.kind() {
ty::Array(sub_ty, _) if matches!(sub_ty.kind(), ty::Int(_) | ty::Uint(_)) => {
ReducedTy::TypeErasure { raw_ptr_only: false }
- }
+ },
ty::Array(sub_ty, _) | ty::Slice(sub_ty) => {
ty = sub_ty;
continue;
- }
+ },
ty::Tuple(args) if args.is_empty() => ReducedTy::TypeErasure { raw_ptr_only: false },
ty::Tuple(args) => {
let mut iter = args.iter();
@@ -293,7 +267,7 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx>
continue;
}
ReducedTy::UnorderedFields(ty)
- }
+ },
ty::Adt(def, substs) if def.is_struct() => {
let mut iter = def
.non_enum_variant()
@@ -312,12 +286,10 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx>
} else {
ReducedTy::UnorderedFields(ty)
}
- }
- ty::Adt(def, _)
- if def.is_enum() && (def.variants().is_empty() || is_c_void(cx, ty)) =>
- {
+ },
+ ty::Adt(def, _) if def.is_enum() && (def.variants().is_empty() || is_c_void(cx, ty)) => {
ReducedTy::TypeErasure { raw_ptr_only: false }
- }
+ },
// TODO: Check if the conversion to or from at least one of a union's fields is valid.
ty::Adt(def, _) if def.is_union() => ReducedTy::TypeErasure { raw_ptr_only: false },
ty::Foreign(_) | ty::Param(_) => ReducedTy::TypeErasure { raw_ptr_only: false },
@@ -356,11 +328,7 @@ fn same_except_params<'tcx>(subs1: SubstsRef<'tcx>, subs2: SubstsRef<'tcx>) -> b
for (ty1, ty2) in subs1.types().zip(subs2.types()).filter(|(ty1, ty2)| ty1 != ty2) {
match (ty1.kind(), ty2.kind()) {
(ty::Param(_), _) | (_, ty::Param(_)) => (),
- (ty::Adt(adt1, subs1), ty::Adt(adt2, subs2))
- if adt1 == adt2 && same_except_params(subs1, subs2) =>
- {
- ()
- }
+ (ty::Adt(adt1, subs1), ty::Adt(adt2, subs2)) if adt1 == adt2 && same_except_params(subs1, subs2) => (),
_ => return false,
}
}
diff --git a/src/tools/clippy/clippy_lints/src/transmute/utils.rs b/src/tools/clippy/clippy_lints/src/transmute/utils.rs
index 641cdf5d3..49d863ec0 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/utils.rs
@@ -1,9 +1,9 @@
+use rustc_hir as hir;
use rustc_hir::Expr;
use rustc_hir_typeck::{cast, FnCtxt, Inherited};
use rustc_lint::LateContext;
use rustc_middle::ty::{cast::CastKind, Ty};
use rustc_span::DUMMY_SP;
-use rustc_hir as hir;
// check if the component types of the transmuted collection and the result have different ABI,
// size or alignment
@@ -55,9 +55,14 @@ fn check_cast<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx>
);
if let Ok(check) = cast::CastCheck::new(
- &fn_ctxt, e, from_ty, to_ty,
+ &fn_ctxt,
+ e,
+ from_ty,
+ to_ty,
// We won't show any error to the user, so we don't care what the span is here.
- DUMMY_SP, DUMMY_SP, hir::Constness::NotConst,
+ DUMMY_SP,
+ DUMMY_SP,
+ hir::Constness::NotConst,
) {
let res = check.do_check(&fn_ctxt);
diff --git a/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs b/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs
index 9c6629958..65dfe7637 100644
--- a/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs
+++ b/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs
@@ -31,10 +31,10 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, m
return false;
}
- let ltopt = if lt.name.is_anonymous() {
+ let ltopt = if lt.is_anonymous() {
String::new()
} else {
- format!("{} ", lt.name.ident().as_str())
+ format!("{} ", lt.ident.as_str())
};
if mut_ty.mutbl == Mutability::Mut {
diff --git a/src/tools/clippy/clippy_lints/src/types/box_collection.rs b/src/tools/clippy/clippy_lints/src/types/box_collection.rs
index 08020ce66..43665a922 100644
--- a/src/tools/clippy/clippy_lints/src/types/box_collection.rs
+++ b/src/tools/clippy/clippy_lints/src/types/box_collection.rs
@@ -37,18 +37,26 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
fn get_std_collection(cx: &LateContext<'_>, qpath: &QPath<'_>) -> Option<Symbol> {
let param = qpath_generic_tys(qpath).next()?;
let id = path_def_id(cx, param)?;
- cx.tcx.get_diagnostic_name(id).filter(|&name| {
- matches!(
- name,
- sym::HashMap
- | sym::String
- | sym::Vec
- | sym::HashSet
- | sym::VecDeque
- | sym::LinkedList
- | sym::BTreeMap
- | sym::BTreeSet
- | sym::BinaryHeap
- )
- })
+ cx.tcx
+ .get_diagnostic_name(id)
+ .filter(|&name| {
+ matches!(
+ name,
+ sym::HashMap
+ | sym::Vec
+ | sym::HashSet
+ | sym::VecDeque
+ | sym::LinkedList
+ | sym::BTreeMap
+ | sym::BTreeSet
+ | sym::BinaryHeap
+ )
+ })
+ .or_else(|| {
+ cx.tcx
+ .lang_items()
+ .string()
+ .filter(|did| id == *did)
+ .map(|_| sym::String)
+ })
}
diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs
index f6de87b05..20978e81d 100644
--- a/src/tools/clippy/clippy_lints/src/types/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/types/mod.rs
@@ -379,7 +379,9 @@ 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(cx.tcx.hir().local_def_id(field.hir_id));
self.check_ty(
cx,
diff --git a/src/tools/clippy/clippy_lints/src/types/rc_buffer.rs b/src/tools/clippy/clippy_lints/src/types/rc_buffer.rs
index fa567b9b2..855137b14 100644
--- a/src/tools/clippy/clippy_lints/src/types/rc_buffer.rs
+++ b/src/tools/clippy/clippy_lints/src/types/rc_buffer.rs
@@ -91,10 +91,10 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
fn match_buffer_type(cx: &LateContext<'_>, qpath: &QPath<'_>) -> Option<&'static str> {
let ty = qpath_generic_tys(qpath).next()?;
let id = path_def_id(cx, ty)?;
- let path = match cx.tcx.get_diagnostic_name(id)? {
- sym::String => "str",
- sym::OsString => "std::ffi::OsStr",
- sym::PathBuf => "std::path::Path",
+ let path = match cx.tcx.get_diagnostic_name(id) {
+ Some(sym::OsString) => "std::ffi::OsStr",
+ Some(sym::PathBuf) => "std::path::Path",
+ _ if Some(id) == cx.tcx.lang_items().string() => "str",
_ => return None,
};
Some(path)
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 2b964b64a..fae5385ff 100644
--- a/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs
+++ b/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs
@@ -5,16 +5,12 @@ 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_span::symbol::sym;
use super::{utils, REDUNDANT_ALLOCATION};
-pub(super) fn check(
- cx: &LateContext<'_>,
- hir_ty: &hir::Ty<'_>,
- qpath: &QPath<'_>,
- def_id: DefId,
-) -> bool {
+pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool {
let mut applicability = Applicability::MaybeIncorrect;
let outer_sym = if Some(def_id) == cx.tcx.lang_items().owned_box() {
"Box"
@@ -34,12 +30,7 @@ pub(super) fn check(
hir_ty.span,
&format!("usage of `{outer_sym}<{generic_snippet}>`"),
|diag| {
- diag.span_suggestion(
- hir_ty.span,
- "try",
- format!("{generic_snippet}"),
- applicability,
- );
+ diag.span_suggestion(hir_ty.span, "try", format!("{generic_snippet}"), applicability);
diag.note(&format!(
"`{generic_snippet}` is already a pointer, `{outer_sym}<{generic_snippet}>` allocates a pointer on the heap"
));
@@ -61,15 +52,16 @@ pub(super) fn check(
return false
};
let inner_span = match qpath_generic_tys(inner_qpath).next() {
- Some(ty) => {
+ Some(hir_ty) => {
// Reallocation of a fat pointer causes it to become thin. `hir_ty_to_ty` is safe to use
// here because `mod.rs` guarantees this lint is only run on types outside of bodies and
// is not run on locals.
- if !hir_ty_to_ty(cx.tcx, ty).is_sized(cx.tcx, cx.param_env) {
+ let ty = hir_ty_to_ty(cx.tcx, hir_ty);
+ if ty.has_escaping_bound_vars() || !ty.is_sized(cx.tcx, cx.param_env) {
return false;
}
- ty.span
- }
+ hir_ty.span
+ },
None => return false,
};
if inner_sym == outer_sym {
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 9ad2cb853..7a3c7cd8a 100644
--- a/src/tools/clippy/clippy_lints/src/types/vec_box.rs
+++ b/src/tools/clippy/clippy_lints/src/types/vec_box.rs
@@ -42,7 +42,7 @@ pub(super) fn check(
if !ty_ty.has_escaping_bound_vars();
if ty_ty.is_sized(cx.tcx, cx.param_env);
if let Ok(ty_ty_size) = cx.layout_of(ty_ty).map(|l| l.size.bytes());
- if ty_ty_size <= box_size_threshold;
+ if ty_ty_size < box_size_threshold;
then {
span_lint_and_sugg(
cx,
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 d2e675a78..2e1b6d8d4 100644
--- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
+++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
@@ -1,6 +1,10 @@
+use std::ops::ControlFlow;
+
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::source::walk_span_to_context;
+use clippy_utils::visitors::{for_each_expr_with_closures, Descend};
use clippy_utils::{get_parent_node, is_lint_allowed};
+use hir::HirId;
use rustc_data_structures::sync::Lrc;
use rustc_hir as hir;
use rustc_hir::{Block, BlockCheckMode, ItemKind, Node, UnsafeSource};
@@ -59,16 +63,45 @@ declare_clippy_lint! {
restriction,
"creating an unsafe block without explaining why it is safe"
}
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for `// SAFETY: ` comments on safe code.
+ ///
+ /// ### Why is this bad?
+ /// Safe code has no safety requirements, so there is no need to
+ /// describe safety invariants.
+ ///
+ /// ### Example
+ /// ```rust
+ /// use std::ptr::NonNull;
+ /// let a = &mut 42;
+ ///
+ /// // SAFETY: references are guaranteed to be non-null.
+ /// let ptr = NonNull::new(a).unwrap();
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// use std::ptr::NonNull;
+ /// let a = &mut 42;
+ ///
+ /// let ptr = NonNull::new(a).unwrap();
+ /// ```
+ #[clippy::version = "1.67.0"]
+ pub UNNECESSARY_SAFETY_COMMENT,
+ restriction,
+ "annotating safe code with a safety comment"
+}
-declare_lint_pass!(UndocumentedUnsafeBlocks => [UNDOCUMENTED_UNSAFE_BLOCKS]);
+declare_lint_pass!(UndocumentedUnsafeBlocks => [UNDOCUMENTED_UNSAFE_BLOCKS, UNNECESSARY_SAFETY_COMMENT]);
-impl LateLintPass<'_> for UndocumentedUnsafeBlocks {
- fn check_block(&mut self, cx: &LateContext<'_>, block: &'_ Block<'_>) {
+impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
+ fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) {
if block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided)
&& !in_external_macro(cx.tcx.sess, block.span)
&& !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, block.hir_id)
&& !is_unsafe_from_proc_macro(cx, block.span)
- && !block_has_safety_comment(cx, block)
+ && !block_has_safety_comment(cx, block.span)
+ && !block_parents_have_safety_comment(cx, block.hir_id)
{
let source_map = cx.tcx.sess.source_map();
let span = if source_map.is_multiline(block.span) {
@@ -86,35 +119,175 @@ impl LateLintPass<'_> for UndocumentedUnsafeBlocks {
"consider adding a safety comment on the preceding line",
);
}
+
+ if let Some(tail) = block.expr
+ && !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, tail.hir_id)
+ && !in_external_macro(cx.tcx.sess, tail.span)
+ && let HasSafetyComment::Yes(pos) = stmt_has_safety_comment(cx, tail.span, tail.hir_id)
+ && let Some(help_span) = expr_has_unnecessary_safety_comment(cx, tail, pos)
+ {
+ span_lint_and_help(
+ cx,
+ UNNECESSARY_SAFETY_COMMENT,
+ tail.span,
+ "expression has unnecessary safety comment",
+ Some(help_span),
+ "consider removing the safety comment",
+ );
+ }
}
- fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
- if let hir::ItemKind::Impl(imple) = item.kind
- && imple.unsafety == hir::Unsafety::Unsafe
- && !in_external_macro(cx.tcx.sess, item.span)
- && !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, item.hir_id())
- && !is_unsafe_from_proc_macro(cx, item.span)
- && !item_has_safety_comment(cx, item)
+ fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &hir::Stmt<'tcx>) {
+ let (
+ hir::StmtKind::Local(&hir::Local { init: Some(expr), .. })
+ | hir::StmtKind::Expr(expr)
+ | hir::StmtKind::Semi(expr)
+ ) = stmt.kind else { return };
+ if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, stmt.hir_id)
+ && !in_external_macro(cx.tcx.sess, stmt.span)
+ && let HasSafetyComment::Yes(pos) = stmt_has_safety_comment(cx, stmt.span, stmt.hir_id)
+ && let Some(help_span) = expr_has_unnecessary_safety_comment(cx, expr, pos)
{
+ span_lint_and_help(
+ cx,
+ UNNECESSARY_SAFETY_COMMENT,
+ stmt.span,
+ "statement has unnecessary safety comment",
+ Some(help_span),
+ "consider removing the safety comment",
+ );
+ }
+ }
+
+ fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
+ if in_external_macro(cx.tcx.sess, item.span) {
+ return;
+ }
+
+ let mk_spans = |pos: BytePos| {
let source_map = cx.tcx.sess.source_map();
+ let span = Span::new(pos, pos, SyntaxContext::root(), None);
+ let help_span = source_map.span_extend_to_next_char(span, '\n', true);
let span = if source_map.is_multiline(item.span) {
source_map.span_until_char(item.span, '\n')
} else {
item.span
};
+ (span, help_span)
+ };
- span_lint_and_help(
- cx,
- UNDOCUMENTED_UNSAFE_BLOCKS,
- span,
- "unsafe impl missing a safety comment",
- None,
- "consider adding a safety comment on the preceding line",
- );
+ let item_has_safety_comment = item_has_safety_comment(cx, item);
+ match (&item.kind, item_has_safety_comment) {
+ // lint unsafe impl without safety comment
+ (hir::ItemKind::Impl(impl_), HasSafetyComment::No) if impl_.unsafety == hir::Unsafety::Unsafe => {
+ if !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, item.hir_id())
+ && !is_unsafe_from_proc_macro(cx, item.span)
+ {
+ let source_map = cx.tcx.sess.source_map();
+ let span = if source_map.is_multiline(item.span) {
+ source_map.span_until_char(item.span, '\n')
+ } else {
+ item.span
+ };
+
+ span_lint_and_help(
+ cx,
+ UNDOCUMENTED_UNSAFE_BLOCKS,
+ span,
+ "unsafe impl missing a safety comment",
+ None,
+ "consider adding a safety comment on the preceding line",
+ );
+ }
+ },
+ // lint safe impl with unnecessary safety comment
+ (hir::ItemKind::Impl(impl_), HasSafetyComment::Yes(pos)) if impl_.unsafety == hir::Unsafety::Normal => {
+ if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, item.hir_id()) {
+ let (span, help_span) = mk_spans(pos);
+
+ span_lint_and_help(
+ cx,
+ UNNECESSARY_SAFETY_COMMENT,
+ span,
+ "impl has unnecessary safety comment",
+ Some(help_span),
+ "consider removing the safety comment",
+ );
+ }
+ },
+ (hir::ItemKind::Impl(_), _) => {},
+ // const and static items only need a safety comment if their body is an unsafe block, lint otherwise
+ (&hir::ItemKind::Const(.., body) | &hir::ItemKind::Static(.., body), HasSafetyComment::Yes(pos)) => {
+ if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, body.hir_id) {
+ let body = cx.tcx.hir().body(body);
+ if !matches!(
+ body.value.kind, hir::ExprKind::Block(block, _)
+ if block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided)
+ ) {
+ let (span, help_span) = mk_spans(pos);
+
+ span_lint_and_help(
+ cx,
+ UNNECESSARY_SAFETY_COMMENT,
+ span,
+ &format!("{} has unnecessary safety comment", item.kind.descr()),
+ Some(help_span),
+ "consider removing the safety comment",
+ );
+ }
+ }
+ },
+ // Aside from unsafe impls and consts/statics with an unsafe block, items in general
+ // do not have safety invariants that need to be documented, so lint those.
+ (_, HasSafetyComment::Yes(pos)) => {
+ if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, item.hir_id()) {
+ let (span, help_span) = mk_spans(pos);
+
+ span_lint_and_help(
+ cx,
+ UNNECESSARY_SAFETY_COMMENT,
+ span,
+ &format!("{} has unnecessary safety comment", item.kind.descr()),
+ Some(help_span),
+ "consider removing the safety comment",
+ );
+ }
+ },
+ _ => (),
}
}
}
+fn expr_has_unnecessary_safety_comment<'tcx>(
+ cx: &LateContext<'tcx>,
+ expr: &'tcx hir::Expr<'tcx>,
+ comment_pos: BytePos,
+) -> Option<Span> {
+ // 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(
+ Block {
+ rules: BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided),
+ ..
+ },
+ _,
+ ) => ControlFlow::Break(()),
+ // statements will be handled by check_stmt itself again
+ hir::ExprKind::Block(..) => ControlFlow::Continue(Descend::No),
+ _ => ControlFlow::Continue(Descend::Yes),
+ })
+ .is_some()
+ {
+ return None;
+ }
+
+ let source_map = cx.tcx.sess.source_map();
+ let span = Span::new(comment_pos, comment_pos, SyntaxContext::root(), None);
+ let help_span = source_map.span_extend_to_next_char(span, '\n', true);
+
+ Some(help_span)
+}
+
fn is_unsafe_from_proc_macro(cx: &LateContext<'_>, span: Span) -> bool {
let source_map = cx.sess().source_map();
let file_pos = source_map.lookup_byte_offset(span.lo());
@@ -126,8 +299,41 @@ fn is_unsafe_from_proc_macro(cx: &LateContext<'_>, span: Span) -> bool {
.map_or(true, |src| !src.starts_with("unsafe"))
}
+// Checks if any parent {expression, statement, block, local, const, static}
+// has a safety comment
+fn block_parents_have_safety_comment(cx: &LateContext<'_>, id: hir::HirId) -> bool {
+ if let Some(node) = get_parent_node(cx.tcx, id) {
+ return match node {
+ Node::Expr(expr) => !is_branchy(expr) && span_in_body_has_safety_comment(cx, expr.span),
+ Node::Stmt(hir::Stmt {
+ kind:
+ hir::StmtKind::Local(hir::Local { span, .. })
+ | hir::StmtKind::Expr(hir::Expr { span, .. })
+ | hir::StmtKind::Semi(hir::Expr { span, .. }),
+ ..
+ })
+ | Node::Local(hir::Local { span, .. })
+ | Node::Item(hir::Item {
+ kind: hir::ItemKind::Const(..) | ItemKind::Static(..),
+ span,
+ ..
+ }) => span_in_body_has_safety_comment(cx, *span),
+ _ => false,
+ };
+ }
+ false
+}
+
+/// Checks if an expression is "branchy", e.g. loop, match/if/etc.
+fn is_branchy(expr: &hir::Expr<'_>) -> bool {
+ matches!(
+ expr.kind,
+ hir::ExprKind::If(..) | hir::ExprKind::Loop(..) | hir::ExprKind::Match(..)
+ )
+}
+
/// Checks if the lines immediately preceding the block contain a safety comment.
-fn block_has_safety_comment(cx: &LateContext<'_>, block: &hir::Block<'_>) -> bool {
+fn block_has_safety_comment(cx: &LateContext<'_>, span: Span) -> bool {
// This intentionally ignores text before the start of a function so something like:
// ```
// // SAFETY: reason
@@ -136,85 +342,134 @@ fn block_has_safety_comment(cx: &LateContext<'_>, block: &hir::Block<'_>) -> boo
// won't work. This is to avoid dealing with where such a comment should be place relative to
// attributes and doc comments.
- span_from_macro_expansion_has_safety_comment(cx, block.span) || span_in_body_has_safety_comment(cx, block.span)
+ matches!(
+ span_from_macro_expansion_has_safety_comment(cx, span),
+ HasSafetyComment::Yes(_)
+ ) || span_in_body_has_safety_comment(cx, span)
+}
+
+enum HasSafetyComment {
+ Yes(BytePos),
+ No,
+ Maybe,
}
/// Checks if the lines immediately preceding the item contain a safety comment.
#[allow(clippy::collapsible_match)]
-fn item_has_safety_comment(cx: &LateContext<'_>, item: &hir::Item<'_>) -> bool {
- if span_from_macro_expansion_has_safety_comment(cx, item.span) {
- return true;
+fn item_has_safety_comment(cx: &LateContext<'_>, item: &hir::Item<'_>) -> HasSafetyComment {
+ match span_from_macro_expansion_has_safety_comment(cx, item.span) {
+ HasSafetyComment::Maybe => (),
+ has_safety_comment => return has_safety_comment,
}
- if item.span.ctxt() == SyntaxContext::root() {
- if let Some(parent_node) = get_parent_node(cx.tcx, item.hir_id()) {
- let comment_start = match parent_node {
- Node::Crate(parent_mod) => {
- comment_start_before_impl_in_mod(cx, parent_mod, parent_mod.spans.inner_span, item)
- },
- Node::Item(parent_item) => {
- if let ItemKind::Mod(parent_mod) = &parent_item.kind {
- comment_start_before_impl_in_mod(cx, parent_mod, parent_item.span, item)
- } else {
- // Doesn't support impls in this position. Pretend a comment was found.
- return true;
- }
- },
- Node::Stmt(stmt) => {
- if let Some(stmt_parent) = get_parent_node(cx.tcx, stmt.hir_id) {
- match stmt_parent {
- Node::Block(block) => walk_span_to_context(block.span, SyntaxContext::root()).map(Span::lo),
- _ => {
- // Doesn't support impls in this position. Pretend a comment was found.
- return true;
- },
- }
- } else {
- // Problem getting the parent node. Pretend a comment was found.
- return true;
- }
- },
- _ => {
+ if item.span.ctxt() != SyntaxContext::root() {
+ return HasSafetyComment::No;
+ }
+ if let Some(parent_node) = get_parent_node(cx.tcx, item.hir_id()) {
+ let comment_start = match parent_node {
+ Node::Crate(parent_mod) => {
+ comment_start_before_item_in_mod(cx, parent_mod, parent_mod.spans.inner_span, item)
+ },
+ Node::Item(parent_item) => {
+ if let ItemKind::Mod(parent_mod) = &parent_item.kind {
+ comment_start_before_item_in_mod(cx, parent_mod, parent_item.span, item)
+ } else {
// Doesn't support impls in this position. Pretend a comment was found.
- return true;
- },
- };
+ return HasSafetyComment::Maybe;
+ }
+ },
+ Node::Stmt(stmt) => {
+ if let Some(Node::Block(block)) = get_parent_node(cx.tcx, stmt.hir_id) {
+ walk_span_to_context(block.span, SyntaxContext::root()).map(Span::lo)
+ } else {
+ // Problem getting the parent node. Pretend a comment was found.
+ return HasSafetyComment::Maybe;
+ }
+ },
+ _ => {
+ // Doesn't support impls in this position. Pretend a comment was found.
+ return HasSafetyComment::Maybe;
+ },
+ };
- let source_map = cx.sess().source_map();
- if let Some(comment_start) = comment_start
- && let Ok(unsafe_line) = source_map.lookup_line(item.span.lo())
- && let Ok(comment_start_line) = source_map.lookup_line(comment_start)
- && Lrc::ptr_eq(&unsafe_line.sf, &comment_start_line.sf)
- && let Some(src) = unsafe_line.sf.src.as_deref()
- {
- unsafe_line.sf.lines(|lines| {
- comment_start_line.line < unsafe_line.line && text_has_safety_comment(
+ let source_map = cx.sess().source_map();
+ if let Some(comment_start) = comment_start
+ && let Ok(unsafe_line) = source_map.lookup_line(item.span.lo())
+ && let Ok(comment_start_line) = source_map.lookup_line(comment_start)
+ && Lrc::ptr_eq(&unsafe_line.sf, &comment_start_line.sf)
+ && let Some(src) = unsafe_line.sf.src.as_deref()
+ {
+ return unsafe_line.sf.lines(|lines| {
+ if comment_start_line.line >= unsafe_line.line {
+ HasSafetyComment::No
+ } else {
+ match text_has_safety_comment(
src,
&lines[comment_start_line.line + 1..=unsafe_line.line],
unsafe_line.sf.start_pos.to_usize(),
- )
- })
- } else {
- // Problem getting source text. Pretend a comment was found.
- true
- }
- } else {
- // No parent node. Pretend a comment was found.
- true
+ ) {
+ Some(b) => HasSafetyComment::Yes(b),
+ None => HasSafetyComment::No,
+ }
+ }
+ });
+ }
+ }
+ HasSafetyComment::Maybe
+}
+
+/// Checks if the lines immediately preceding the item contain a safety comment.
+#[allow(clippy::collapsible_match)]
+fn stmt_has_safety_comment(cx: &LateContext<'_>, span: Span, hir_id: HirId) -> HasSafetyComment {
+ match span_from_macro_expansion_has_safety_comment(cx, span) {
+ HasSafetyComment::Maybe => (),
+ has_safety_comment => return has_safety_comment,
+ }
+
+ if span.ctxt() != SyntaxContext::root() {
+ return HasSafetyComment::No;
+ }
+
+ if let Some(parent_node) = get_parent_node(cx.tcx, hir_id) {
+ let comment_start = match parent_node {
+ Node::Block(block) => walk_span_to_context(block.span, SyntaxContext::root()).map(Span::lo),
+ _ => return HasSafetyComment::Maybe,
+ };
+
+ let source_map = cx.sess().source_map();
+ if let Some(comment_start) = comment_start
+ && let Ok(unsafe_line) = source_map.lookup_line(span.lo())
+ && let Ok(comment_start_line) = source_map.lookup_line(comment_start)
+ && Lrc::ptr_eq(&unsafe_line.sf, &comment_start_line.sf)
+ && let Some(src) = unsafe_line.sf.src.as_deref()
+ {
+ return unsafe_line.sf.lines(|lines| {
+ if comment_start_line.line >= unsafe_line.line {
+ HasSafetyComment::No
+ } else {
+ match text_has_safety_comment(
+ src,
+ &lines[comment_start_line.line + 1..=unsafe_line.line],
+ unsafe_line.sf.start_pos.to_usize(),
+ ) {
+ Some(b) => HasSafetyComment::Yes(b),
+ None => HasSafetyComment::No,
+ }
+ }
+ });
}
- } else {
- false
}
+ HasSafetyComment::Maybe
}
-fn comment_start_before_impl_in_mod(
+fn comment_start_before_item_in_mod(
cx: &LateContext<'_>,
parent_mod: &hir::Mod<'_>,
parent_mod_span: Span,
- imple: &hir::Item<'_>,
+ item: &hir::Item<'_>,
) -> Option<BytePos> {
parent_mod.item_ids.iter().enumerate().find_map(|(idx, item_id)| {
- if *item_id == imple.item_id() {
+ if *item_id == item.item_id() {
if idx == 0 {
// mod A { /* comment */ unsafe impl T {} ... }
// ^------------------------------------------^ returns the start of this span
@@ -236,11 +491,11 @@ fn comment_start_before_impl_in_mod(
})
}
-fn span_from_macro_expansion_has_safety_comment(cx: &LateContext<'_>, span: Span) -> bool {
+fn span_from_macro_expansion_has_safety_comment(cx: &LateContext<'_>, span: Span) -> HasSafetyComment {
let source_map = cx.sess().source_map();
let ctxt = span.ctxt();
if ctxt == SyntaxContext::root() {
- false
+ HasSafetyComment::Maybe
} else {
// From a macro expansion. Get the text from the start of the macro declaration to start of the
// unsafe block.
@@ -252,15 +507,22 @@ fn span_from_macro_expansion_has_safety_comment(cx: &LateContext<'_>, span: Span
&& let Some(src) = unsafe_line.sf.src.as_deref()
{
unsafe_line.sf.lines(|lines| {
- macro_line.line < unsafe_line.line && text_has_safety_comment(
- src,
- &lines[macro_line.line + 1..=unsafe_line.line],
- unsafe_line.sf.start_pos.to_usize(),
- )
+ if macro_line.line < unsafe_line.line {
+ match text_has_safety_comment(
+ src,
+ &lines[macro_line.line + 1..=unsafe_line.line],
+ unsafe_line.sf.start_pos.to_usize(),
+ ) {
+ Some(b) => HasSafetyComment::Yes(b),
+ None => HasSafetyComment::No,
+ }
+ } else {
+ HasSafetyComment::No
+ }
})
} else {
// Problem getting source text. Pretend a comment was found.
- true
+ HasSafetyComment::Maybe
}
}
}
@@ -299,7 +561,7 @@ fn span_in_body_has_safety_comment(cx: &LateContext<'_>, span: Span) -> bool {
src,
&lines[body_line.line + 1..=unsafe_line.line],
unsafe_line.sf.start_pos.to_usize(),
- )
+ ).is_some()
})
} else {
// Problem getting source text. Pretend a comment was found.
@@ -311,30 +573,34 @@ fn span_in_body_has_safety_comment(cx: &LateContext<'_>, span: Span) -> bool {
}
/// Checks if the given text has a safety comment for the immediately proceeding line.
-fn text_has_safety_comment(src: &str, line_starts: &[BytePos], offset: usize) -> bool {
+fn text_has_safety_comment(src: &str, line_starts: &[BytePos], offset: usize) -> Option<BytePos> {
let mut lines = line_starts
.array_windows::<2>()
.rev()
.map_while(|[start, end]| {
let start = start.to_usize() - offset;
let end = end.to_usize() - offset;
- src.get(start..end).map(|text| (start, text.trim_start()))
+ let text = src.get(start..end)?;
+ let trimmed = text.trim_start();
+ Some((start + (text.len() - trimmed.len()), trimmed))
})
.filter(|(_, text)| !text.is_empty());
let Some((line_start, line)) = lines.next() else {
- return false;
+ return None;
};
// Check for a sequence of line comments.
if line.starts_with("//") {
- let mut line = line;
+ let (mut line, mut line_start) = (line, line_start);
loop {
if line.to_ascii_uppercase().contains("SAFETY:") {
- return true;
+ return Some(BytePos(
+ u32::try_from(line_start).unwrap() + u32::try_from(offset).unwrap(),
+ ));
}
match lines.next() {
- Some((_, x)) if x.starts_with("//") => line = x,
- _ => return false,
+ Some((s, x)) if x.starts_with("//") => (line, line_start) = (x, s),
+ _ => return None,
}
}
}
@@ -343,16 +609,19 @@ fn text_has_safety_comment(src: &str, line_starts: &[BytePos], offset: usize) ->
let (mut line_start, mut line) = (line_start, line);
loop {
if line.starts_with("/*") {
- let src = src[line_start..line_starts.last().unwrap().to_usize() - offset].trim_start();
+ let src = &src[line_start..line_starts.last().unwrap().to_usize() - offset];
let mut tokens = tokenize(src);
- return src[..tokens.next().unwrap().len as usize]
+ return (src[..tokens.next().unwrap().len as usize]
.to_ascii_uppercase()
.contains("SAFETY:")
- && tokens.all(|t| t.kind == TokenKind::Whitespace);
+ && tokens.all(|t| t.kind == TokenKind::Whitespace))
+ .then_some(BytePos(
+ u32::try_from(line_start).unwrap() + u32::try_from(offset).unwrap(),
+ ));
}
match lines.next() {
Some(x) => (line_start, line) = x,
- None => return false,
+ None => return None,
}
}
}
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 130728862..a138a4baa 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
@@ -4,7 +4,7 @@ use rustc_hir::def_id::DefId;
use rustc_hir::{Closure, Expr, ExprKind, StmtKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
-use rustc_middle::ty::{GenericPredicates, PredicateKind, ProjectionPredicate, TraitPredicate};
+use rustc_middle::ty::{Clause, GenericPredicates, PredicateKind, ProjectionPredicate, TraitPredicate};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::{sym, BytePos, Span};
@@ -45,7 +45,7 @@ fn get_trait_predicates_for_trait_id<'tcx>(
let mut preds = Vec::new();
for (pred, _) in generics.predicates {
if_chain! {
- if let PredicateKind::Trait(poly_trait_pred) = pred.kind().skip_binder();
+ if let PredicateKind::Clause(Clause::Trait(poly_trait_pred)) = pred.kind().skip_binder();
let trait_pred = cx.tcx.erase_late_bound_regions(pred.kind().rebind(poly_trait_pred));
if let Some(trait_def_id) = trait_id;
if trait_def_id == trait_pred.trait_ref.def_id;
@@ -63,7 +63,7 @@ fn get_projection_pred<'tcx>(
trait_pred: TraitPredicate<'tcx>,
) -> Option<ProjectionPredicate<'tcx>> {
generics.predicates.iter().find_map(|(proj_pred, _)| {
- if let ty::PredicateKind::Projection(pred) = proj_pred.kind().skip_binder() {
+ if let ty::PredicateKind::Clause(Clause::Projection(pred)) = proj_pred.kind().skip_binder() {
let projection_pred = cx.tcx.erase_late_bound_regions(proj_pred.kind().rebind(pred));
if projection_pred.projection_ty.substs == trait_pred.trait_ref.substs {
return Some(projection_pred);
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 016aacbf9..9f207d32f 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs
@@ -1,4 +1,4 @@
-use clippy_utils::{diagnostics::span_lint_and_sugg, ty::is_type_diagnostic_item};
+use clippy_utils::{diagnostics::span_lint_and_sugg, ty::is_type_lang_item};
use clippy_utils::{match_def_path, paths};
use if_chain::if_chain;
use rustc_ast::ast::LitKind;
@@ -7,7 +7,6 @@ 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::sym;
declare_clippy_lint! {
/// ### What it does
@@ -55,13 +54,13 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryOwnedEmptyStrings {
);
} else {
if_chain! {
- if cx.tcx.lang_items().require(LangItem::FromFrom).ok() == Some(fun_def_id);
+ if Some(fun_def_id) == cx.tcx.lang_items().from_fn();
if let [.., last_arg] = args;
if let ExprKind::Lit(spanned) = &last_arg.kind;
if let LitKind::Str(symbol, _) = spanned.node;
if symbol.is_empty();
let inner_expr_type = cx.typeck_results().expr_ty(inner_expr);
- if is_type_diagnostic_item(cx, inner_expr_type, sym::String);
+ if is_type_lang_item(cx, inner_expr_type, LangItem::String);
then {
span_lint_and_sugg(
cx,
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_self_imports.rs b/src/tools/clippy/clippy_lints/src/unnecessary_self_imports.rs
index bc0dd263d..397633f53 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_self_imports.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_self_imports.rs
@@ -57,7 +57,7 @@ impl EarlyLintPass for UnnecessarySelfImports {
format!(
"{}{};",
last_segment.ident,
- if let UseTreeKind::Simple(Some(alias), ..) = self_tree.kind { format!(" as {alias}") } else { String::new() },
+ if let UseTreeKind::Simple(Some(alias)) = self_tree.kind { format!(" as {alias}") } else { String::new() },
),
Applicability::MaybeIncorrect,
);
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 b305dae76..7355260ae 100644
--- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
@@ -2,14 +2,14 @@
use clippy_utils::ast_utils::{eq_field_pat, eq_id, eq_maybe_qself, eq_pat, eq_path};
use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::{meets_msrv, msrvs, over};
+use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::over;
use rustc_ast::mut_visit::*;
use rustc_ast::ptr::P;
use rustc_ast::{self as ast, Mutability, Pat, PatKind, PatKind::*, DUMMY_NODE_ID};
use rustc_ast_pretty::pprust;
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass};
-use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::DUMMY_SP;
@@ -45,14 +45,13 @@ declare_clippy_lint! {
"unnested or-patterns, e.g., `Foo(Bar) | Foo(Baz) instead of `Foo(Bar | Baz)`"
}
-#[derive(Clone, Copy)]
pub struct UnnestedOrPatterns {
- msrv: Option<RustcVersion>,
+ msrv: Msrv,
}
impl UnnestedOrPatterns {
#[must_use]
- pub fn new(msrv: Option<RustcVersion>) -> Self {
+ pub fn new(msrv: Msrv) -> Self {
Self { msrv }
}
}
@@ -61,13 +60,13 @@ impl_lint_pass!(UnnestedOrPatterns => [UNNESTED_OR_PATTERNS]);
impl EarlyLintPass for UnnestedOrPatterns {
fn check_arm(&mut self, cx: &EarlyContext<'_>, a: &ast::Arm) {
- if meets_msrv(self.msrv, msrvs::OR_PATTERNS) {
+ if self.msrv.meets(msrvs::OR_PATTERNS) {
lint_unnested_or_patterns(cx, &a.pat);
}
}
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
- if meets_msrv(self.msrv, msrvs::OR_PATTERNS) {
+ if self.msrv.meets(msrvs::OR_PATTERNS) {
if let ast::ExprKind::Let(pat, _, _) = &e.kind {
lint_unnested_or_patterns(cx, pat);
}
@@ -75,13 +74,13 @@ impl EarlyLintPass for UnnestedOrPatterns {
}
fn check_param(&mut self, cx: &EarlyContext<'_>, p: &ast::Param) {
- if meets_msrv(self.msrv, msrvs::OR_PATTERNS) {
+ if self.msrv.meets(msrvs::OR_PATTERNS) {
lint_unnested_or_patterns(cx, &p.pat);
}
}
fn check_local(&mut self, cx: &EarlyContext<'_>, l: &ast::Local) {
- if meets_msrv(self.msrv, msrvs::OR_PATTERNS) {
+ if self.msrv.meets(msrvs::OR_PATTERNS) {
lint_unnested_or_patterns(cx, &l.pat);
}
}
@@ -292,7 +291,7 @@ fn transform_with_focus_on_idx(alternatives: &mut Vec<P<Pat>>, focus_idx: usize)
/// So when we fixate on some `ident_k: pat_k`, we try to find `ident_k` in the other pattern
/// and check that all `fp_i` where `i ∈ ((0...n) \ k)` between two patterns are equal.
fn extend_with_struct_pat(
- qself1: &Option<ast::QSelf>,
+ qself1: &Option<P<ast::QSelf>>,
path1: &ast::Path,
fps1: &mut [ast::PatField],
rest1: bool,
diff --git a/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs b/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs
index 32cd46812..7ee785804 100644
--- a/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs
+++ b/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs
@@ -39,7 +39,7 @@ impl EarlyLintPass for UnsafeNameRemoval {
fn check_use_tree(use_tree: &UseTree, cx: &EarlyContext<'_>, span: Span) {
match use_tree.kind {
- UseTreeKind::Simple(Some(new_name), ..) => {
+ UseTreeKind::Simple(Some(new_name)) => {
let old_name = use_tree
.prefix
.segments
@@ -48,9 +48,9 @@ fn check_use_tree(use_tree: &UseTree, cx: &EarlyContext<'_>, span: Span) {
.ident;
unsafe_to_safe_check(old_name, new_name, cx, span);
},
- UseTreeKind::Simple(None, ..) | UseTreeKind::Glob => {},
+ UseTreeKind::Simple(None) | UseTreeKind::Glob => {},
UseTreeKind::Nested(ref nested_use_tree) => {
- for &(ref use_tree, _) in nested_use_tree {
+ for (use_tree, _) in nested_use_tree {
check_use_tree(use_tree, cx, span);
}
},
diff --git a/src/tools/clippy/clippy_lints/src/unused_async.rs b/src/tools/clippy/clippy_lints/src/unused_async.rs
index bf487c7ca..3538bef6e 100644
--- a/src/tools/clippy/clippy_lints/src/unused_async.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_async.rs
@@ -1,6 +1,6 @@
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, IsAsync, YieldSource};
+use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirId, YieldSource};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter;
use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -68,7 +68,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAsync {
span: Span,
hir_id: HirId,
) {
- if !span.from_expansion() && fn_kind.asyncness() == IsAsync::Async {
+ 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);
if !visitor.found_await {
diff --git a/src/tools/clippy/clippy_lints/src/unused_peekable.rs b/src/tools/clippy/clippy_lints/src/unused_peekable.rs
index f1cebf0f9..4ee16d9a5 100644
--- a/src/tools/clippy/clippy_lints/src/unused_peekable.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_peekable.rs
@@ -3,7 +3,6 @@ use clippy_utils::ty::{match_type, peel_mid_ty_refs_is_mutable};
use clippy_utils::{fn_def_id, is_trait_method, path_to_local_id, paths, peel_ref_operators};
use rustc_ast::Mutability;
use rustc_hir::intravisit::{walk_expr, Visitor};
-use rustc_hir::lang_items::LangItem;
use rustc_hir::{Block, Expr, ExprKind, HirId, Local, Node, PatKind, PathSegment, StmtKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter::OnlyBodies;
@@ -37,7 +36,7 @@ declare_clippy_lint! {
/// // ...
/// }
/// ```
- #[clippy::version = "1.64.0"]
+ #[clippy::version = "1.65.0"]
pub UNUSED_PEEKABLE,
nursery,
"creating a peekable iterator without using any of its methods"
@@ -132,11 +131,11 @@ impl<'tcx> Visitor<'tcx> for PeekableVisitor<'_, 'tcx> {
// If the Peekable is passed to a function, stop
ExprKind::Call(_, args) => {
if let Some(func_did) = fn_def_id(self.cx, expr)
- && let Ok(into_iter_did) = self
+ && let Some(into_iter_did) = self
.cx
.tcx
.lang_items()
- .require(LangItem::IntoIterIntoIter)
+ .into_iter_fn()
&& func_did == into_iter_did
{
// Probably a for loop desugar, stop searching
diff --git a/src/tools/clippy/clippy_lints/src/unused_rounding.rs b/src/tools/clippy/clippy_lints/src/unused_rounding.rs
index 316493729..097568cd1 100644
--- a/src/tools/clippy/clippy_lints/src/unused_rounding.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_rounding.rs
@@ -1,5 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
-use rustc_ast::ast::{Expr, ExprKind, LitFloatType, LitKind};
+use clippy_utils::source::snippet;
+use rustc_ast::ast::{Expr, ExprKind, MethodCall};
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -29,23 +30,16 @@ declare_clippy_lint! {
}
declare_lint_pass!(UnusedRounding => [UNUSED_ROUNDING]);
-fn is_useless_rounding(expr: &Expr) -> Option<(&str, String)> {
- if let ExprKind::MethodCall(name_ident, receiver, _, _) = &expr.kind
+fn is_useless_rounding<'a>(cx: &EarlyContext<'_>, expr: &'a Expr) -> Option<(&'a str, String)> {
+ if let ExprKind::MethodCall(box MethodCall { seg:name_ident, receiver, .. }) = &expr.kind
&& let method_name = name_ident.ident.name.as_str()
&& (method_name == "ceil" || method_name == "round" || method_name == "floor")
- && let ExprKind::Lit(spanned) = &receiver.kind
- && let LitKind::Float(symbol, ty) = spanned.kind {
- let f = symbol.as_str().parse::<f64>().unwrap();
- let f_str = symbol.to_string() + if let LitFloatType::Suffixed(ty) = ty {
- ty.name_str()
- } else {
- ""
- };
- if f.fract() == 0.0 {
- Some((method_name, f_str))
- } else {
- None
- }
+ && let ExprKind::Lit(token_lit) = &receiver.kind
+ && token_lit.is_semantic_float()
+ && let Ok(f) = token_lit.symbol.as_str().replace('_', "").parse::<f64>() {
+ (f.fract() == 0.0).then(||
+ (method_name, snippet(cx, receiver.span, "..").to_string())
+ )
} else {
None
}
@@ -53,7 +47,7 @@ fn is_useless_rounding(expr: &Expr) -> Option<(&str, String)> {
impl EarlyLintPass for UnusedRounding {
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
- if let Some((method_name, float)) = is_useless_rounding(expr) {
+ if let Some((method_name, float)) = is_useless_rounding(cx, expr) {
span_lint_and_sugg(
cx,
UNUSED_ROUNDING,
diff --git a/src/tools/clippy/clippy_lints/src/unused_unit.rs b/src/tools/clippy/clippy_lints/src/unused_unit.rs
index cd1d90e86..cad8da18c 100644
--- a/src/tools/clippy/clippy_lints/src/unused_unit.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_unit.rs
@@ -1,8 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::{position_before_rarrow, snippet_opt};
use if_chain::if_chain;
-use rustc_ast::ast;
-use rustc_ast::visit::FnKind;
+use rustc_ast::{ast, visit::FnKind, ClosureBinder};
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -43,6 +42,11 @@ impl EarlyLintPass for UnusedUnit {
if let ast::TyKind::Tup(ref vals) = ty.kind;
if vals.is_empty() && !ty.span.from_expansion() && get_def(span) == get_def(ty.span);
then {
+ // implicit types in closure signatures are forbidden when `for<...>` is present
+ if let FnKind::Closure(&ClosureBinder::For { .. }, ..) = kind {
+ return;
+ }
+
lint_unneeded_unit_return(cx, ty, span);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs
index c6cdf3f85..4c755d812 100644
--- a/src/tools/clippy/clippy_lints/src/use_self.rs
+++ b/src/tools/clippy/clippy_lints/src/use_self.rs
@@ -1,6 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::is_from_proc_macro;
+use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::ty::same_type_and_consts;
-use clippy_utils::{is_from_proc_macro, meets_msrv, msrvs};
use if_chain::if_chain;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
@@ -14,7 +15,6 @@ use rustc_hir::{
};
use rustc_hir_analysis::hir_ty_to_ty;
use rustc_lint::{LateContext, LateLintPass};
-use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::Span;
@@ -30,7 +30,6 @@ declare_clippy_lint! {
///
/// ### Known problems
/// - Unaddressed false negative in fn bodies of trait implementations
- /// - False positive with associated types in traits (#4140)
///
/// ### Example
/// ```rust
@@ -58,13 +57,13 @@ declare_clippy_lint! {
#[derive(Default)]
pub struct UseSelf {
- msrv: Option<RustcVersion>,
+ msrv: Msrv,
stack: Vec<StackItem>,
}
impl UseSelf {
#[must_use]
- pub fn new(msrv: Option<RustcVersion>) -> Self {
+ pub fn new(msrv: Msrv) -> Self {
Self {
msrv,
..Self::default()
@@ -103,6 +102,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
if parameters.as_ref().map_or(true, |params| {
!params.parenthesized && !params.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_)))
});
+ if !item.span.from_expansion();
if !is_from_proc_macro(cx, item); // expensive, should be last check
then {
StackItem::Check {
@@ -199,7 +199,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
fn check_ty(&mut self, cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>) {
if_chain! {
if !hir_ty.span.from_expansion();
- if meets_msrv(self.msrv, msrvs::TYPE_ALIAS_ENUM_VARIANTS);
+ if self.msrv.meets(msrvs::TYPE_ALIAS_ENUM_VARIANTS);
if let Some(&StackItem::Check {
impl_id,
in_body,
@@ -228,30 +228,19 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
if_chain! {
if !expr.span.from_expansion();
- if meets_msrv(self.msrv, msrvs::TYPE_ALIAS_ENUM_VARIANTS);
+ 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);
then {} else { return; }
}
match expr.kind {
- ExprKind::Struct(QPath::Resolved(_, path), ..) => match path.res {
- Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } => (),
- Res::Def(DefKind::Variant, _) => lint_path_to_variant(cx, path),
- _ => span_lint(cx, path.span),
- },
- // tuple struct instantiation (`Foo(arg)` or `Enum::Foo(arg)`)
+ ExprKind::Struct(QPath::Resolved(_, path), ..) => check_path(cx, path),
ExprKind::Call(fun, _) => {
if let ExprKind::Path(QPath::Resolved(_, path)) = fun.kind {
- if let Res::Def(DefKind::Ctor(ctor_of, _), ..) = path.res {
- match ctor_of {
- CtorOf::Variant => lint_path_to_variant(cx, path),
- CtorOf::Struct => span_lint(cx, path.span),
- }
- }
+ check_path(cx, path);
}
},
- // unit enum variants (`Enum::A`)
- ExprKind::Path(QPath::Resolved(_, path)) => lint_path_to_variant(cx, path),
+ ExprKind::Path(QPath::Resolved(_, path)) => check_path(cx, path),
_ => (),
}
}
@@ -259,7 +248,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
fn check_pat(&mut self, cx: &LateContext<'_>, pat: &Pat<'_>) {
if_chain! {
if !pat.span.from_expansion();
- if meets_msrv(self.msrv, msrvs::TYPE_ALIAS_ENUM_VARIANTS);
+ if self.msrv.meets(msrvs::TYPE_ALIAS_ENUM_VARIANTS);
if let Some(&StackItem::Check { impl_id, .. }) = self.stack.last();
// get the path from the pattern
if let PatKind::Path(QPath::Resolved(_, path))
@@ -267,15 +256,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
| PatKind::Struct(QPath::Resolved(_, path), _, _) = pat.kind;
if cx.typeck_results().pat_ty(pat) == cx.tcx.type_of(impl_id);
then {
- match path.res {
- Res::Def(DefKind::Ctor(ctor_of, _), ..) => match ctor_of {
- CtorOf::Variant => lint_path_to_variant(cx, path),
- CtorOf::Struct => span_lint(cx, path.span),
- },
- Res::Def(DefKind::Variant, ..) => lint_path_to_variant(cx, path),
- Res::Def(DefKind::Struct, ..) => span_lint(cx, path.span),
- _ => ()
- }
+ check_path(cx, path);
}
}
}
@@ -313,6 +294,16 @@ fn span_lint(cx: &LateContext<'_>, span: Span) {
);
}
+fn check_path(cx: &LateContext<'_>, path: &Path<'_>) {
+ match path.res {
+ Res::Def(DefKind::Ctor(CtorOf::Variant, _) | DefKind::Variant, ..) => {
+ lint_path_to_variant(cx, path);
+ },
+ Res::Def(DefKind::Ctor(CtorOf::Struct, _) | DefKind::Struct, ..) => span_lint(cx, path.span),
+ _ => (),
+ }
+}
+
fn lint_path_to_variant(cx: &LateContext<'_>, path: &Path<'_>) {
if let [.., self_seg, _variant] = path.segments {
let span = path
diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
index 1f69db1cb..3743d5d97 100644
--- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs
+++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
@@ -5,7 +5,7 @@ use clippy_utils::ty::{is_type_diagnostic_item, same_type_and_consts};
use clippy_utils::{get_parent_expr, is_trait_method, match_def_path, paths};
use if_chain::if_chain;
use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, HirId, LangItem, MatchSource};
+use rustc_hir::{Expr, ExprKind, HirId, MatchSource};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_tool_lint, impl_lint_pass};
@@ -153,7 +153,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
}
if_chain! {
- if cx.tcx.lang_items().require(LangItem::FromFrom).ok() == Some(def_id);
+ if Some(def_id) == cx.tcx.lang_items().from_fn();
if same_type_and_consts(a, b);
then {
diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs
index 668123e4d..b6dc8cd7a 100644
--- a/src/tools/clippy/clippy_lints/src/utils/conf.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/conf.rs
@@ -53,11 +53,11 @@ impl DisallowedPath {
path
}
- pub fn reason(&self) -> Option<&str> {
+ pub fn reason(&self) -> Option<String> {
match self {
Self::WithReason {
reason: Some(reason), ..
- } => Some(reason),
+ } => Some(format!("{reason} (from clippy.toml)")),
_ => None,
}
}
@@ -213,7 +213,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.
+ /// 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.
///
/// The minimum rust version that the project supports
(msrv: Option<String> = None),
@@ -335,6 +335,12 @@ define_Conf! {
///
/// Enables verbose mode. Triggers if there is more than one uppercase char next to each other
(upper_case_acronyms_aggressive: bool = false),
+ /// Lint: MANUAL_LET_ELSE.
+ ///
+ /// Whether the matches should be considered by the lint, and whether there should
+ /// be filtering for common types.
+ (matches_for_let_else: crate::manual_let_else::MatchLintBehaviour =
+ crate::manual_let_else::MatchLintBehaviour::WellKnownTypes),
/// Lint: _CARGO_COMMON_METADATA.
///
/// For internal testing only, ignores the current `publish` settings in the Cargo manifest.
@@ -373,23 +379,40 @@ define_Conf! {
(max_include_file_size: u64 = 1_000_000),
/// Lint: EXPECT_USED.
///
- /// Whether `expect` should be allowed in test functions
+ /// Whether `expect` should be allowed within `#[cfg(test)]`
(allow_expect_in_tests: bool = false),
/// Lint: UNWRAP_USED.
///
- /// Whether `unwrap` should be allowed in test functions
+ /// Whether `unwrap` should be allowed in test cfg
(allow_unwrap_in_tests: bool = false),
/// Lint: DBG_MACRO.
///
/// Whether `dbg!` should be allowed in test functions
(allow_dbg_in_tests: bool = false),
- /// Lint: RESULT_LARGE_ERR
+ /// Lint: PRINT_STDOUT, PRINT_STDERR.
+ ///
+ /// Whether print macros (ex. `println!`) should be allowed in test functions
+ (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.
+ ///
+ /// A list of paths to types that should be treated like `Arc`, i.e. ignored but
+ /// for the generic parameters for determining interior mutability
+ (ignore_interior_mutability: Vec<String> = Vec::from(["bytes::Bytes".into()])),
+ /// Lint: UNINLINED_FORMAT_ARGS.
+ ///
+ /// Whether to allow mixed uninlined format args, e.g. `format!("{} {}", a, foo.bar)`
+ (allow_mixed_uninlined_format_args: bool = true),
}
/// Search for the configuration file.
+///
+/// # Errors
+///
+/// Returns any unexpected filesystem error encountered when searching for the config file
pub fn lookup_conf_file() -> io::Result<Option<PathBuf>> {
/// Possible filename to search for.
const CONFIG_FILE_NAMES: [&str; 2] = [".clippy.toml", "clippy.toml"];
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 096b60157..4b33d492a 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
@@ -2,7 +2,7 @@ use clippy_utils::consts::{constant_simple, Constant};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet;
use clippy_utils::ty::match_type;
-use clippy_utils::{def_path_res, is_expn_of, match_def_path, paths};
+use clippy_utils::{def_path_def_ids, is_expn_of, match_def_path, paths};
use if_chain::if_chain;
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::Applicability;
@@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol {
}
for &module in &[&paths::KW_MODULE, &paths::SYM_MODULE] {
- if let Some(def_id) = def_path_res(cx, module, None).opt_def_id() {
+ for def_id in def_path_def_ids(cx, module) {
for item in cx.tcx.module_children(def_id).iter() {
if_chain! {
if let Res::Def(DefKind::Const, item_def_id) = item.res;
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs
index 25532dd4e..680935f23 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs
@@ -3,7 +3,7 @@ use clippy_utils::def_path_res;
use clippy_utils::diagnostics::span_lint;
use if_chain::if_chain;
use rustc_hir as hir;
-use rustc_hir::def::{DefKind, Res};
+use rustc_hir::def::DefKind;
use rustc_hir::Item;
use rustc_hir_analysis::hir_ty_to_ty;
use rustc_lint::{LateContext, LateLintPass};
@@ -63,7 +63,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidPaths {
// This is not a complete resolver for paths. It works on all the paths currently used in the paths
// module. That's all it does and all it needs to do.
pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool {
- if def_path_res(cx, path, None) != Res::Err {
+ if !def_path_res(cx, path).is_empty() {
return true;
}
@@ -79,22 +79,22 @@ pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool {
SimplifiedTypeGen::StrSimplifiedType,
]
.iter()
- .flat_map(|&ty| cx.tcx.incoherent_impls(ty));
- for item_def_id in lang_items.items().iter().flatten().chain(incoherent_impls) {
- let lang_item_path = cx.get_def_path(*item_def_id);
+ .flat_map(|&ty| cx.tcx.incoherent_impls(ty).iter().copied());
+ for item_def_id in lang_items.iter().map(|(_, def_id)| def_id).chain(incoherent_impls) {
+ let lang_item_path = cx.get_def_path(item_def_id);
if path_syms.starts_with(&lang_item_path) {
if let [item] = &path_syms[lang_item_path.len()..] {
if matches!(
- cx.tcx.def_kind(*item_def_id),
+ cx.tcx.def_kind(item_def_id),
DefKind::Mod | DefKind::Enum | DefKind::Trait
) {
- for child in cx.tcx.module_children(*item_def_id) {
+ for child in cx.tcx.module_children(item_def_id) {
if child.ident.name == *item {
return true;
}
}
} else {
- for child in cx.tcx.associated_item_def_ids(*item_def_id) {
+ for child in cx.tcx.associated_item_def_ids(item_def_id) {
if cx.tcx.item_name(*child) == *item {
return true;
}
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 0dac64376..786d9608c 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
@@ -256,7 +256,7 @@ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass {
}
}
-pub(super) fn is_lint_ref_type<'tcx>(cx: &LateContext<'tcx>, ty: &hir::Ty<'_>) -> bool {
+pub(super) fn is_lint_ref_type(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool {
if let TyKind::Rptr(
_,
MutTy {
@@ -330,7 +330,7 @@ struct LintCollector<'a, 'tcx> {
impl<'a, 'tcx> Visitor<'tcx> for LintCollector<'a, 'tcx> {
type NestedFilter = nested_filter::All;
- fn visit_path(&mut self, path: &'tcx Path<'_>, _: HirId) {
+ fn visit_path(&mut self, path: &Path<'_>, _: HirId) {
if path.segments.len() == 1 {
self.output.insert(path.segments[0].ident.name);
}
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 d06a616e4..857abe77e 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
@@ -1019,7 +1019,7 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for ApplicabilityResolver<'a, 'hir> {
self.cx.tcx.hir()
}
- fn visit_path(&mut self, path: &'hir hir::Path<'hir>, _id: hir::HirId) {
+ fn visit_path(&mut self, path: &hir::Path<'hir>, _id: hir::HirId) {
for (index, enum_value) in paths::APPLICABILITY_VALUES.iter().enumerate() {
if match_path(path, enum_value) {
self.add_new_index(index);
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 1e994e3f2..9876a8a76 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
@@ -41,7 +41,7 @@ impl LateLintPass<'_> for MsrvAttrImpl {
.type_of(f.did)
.walk()
.filter(|t| matches!(t.unpack(), GenericArgKind::Type(_)))
- .any(|t| match_type(cx, t.expect_ty(), &paths::RUSTC_VERSION))
+ .any(|t| match_type(cx, t.expect_ty(), &paths::MSRV))
});
if !items.iter().any(|item| item.ident.name == sym!(enter_lint_attrs));
then {
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 4cf76f536..393988dba 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs
@@ -1,19 +1,19 @@
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then};
use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{def_path_res, is_lint_allowed, match_any_def_paths, peel_hir_expr_refs};
+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_errors::Applicability;
use rustc_hir as hir;
-use rustc_hir::def::{DefKind, Namespace, Res};
+use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::{Expr, ExprKind, Local, Mutability, Node};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::mir::interpret::{Allocation, ConstValue, GlobalAlloc};
-use rustc_middle::ty::{self, AssocKind, DefIdTree, Ty};
+use rustc_middle::ty::{self, DefIdTree, Ty};
use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::symbol::{Ident, Symbol};
+use rustc_span::symbol::Symbol;
use rustc_span::Span;
use std::str;
@@ -91,7 +91,7 @@ impl UnnecessaryDefPath {
#[allow(clippy::too_many_lines)]
fn check_call(&mut self, cx: &LateContext<'_>, func: &Expr<'_>, args: &[Expr<'_>], span: Span) {
enum Item {
- LangItem(Symbol),
+ LangItem(&'static str),
DiagnosticItem(Symbol),
}
static PATHS: &[&[&str]] = &[
@@ -110,7 +110,7 @@ impl UnnecessaryDefPath {
// Extract the path to the matched type
if let Some(segments) = path_to_matched_type(cx, item_arg);
let segments: Vec<&str> = segments.iter().map(|sym| &**sym).collect();
- if let Some(def_id) = inherent_def_path_res(cx, &segments[..]);
+ if let Some(def_id) = def_path_def_ids(cx, &segments[..]).next();
then {
// Check if the target item is a diagnostic item or LangItem.
#[rustfmt::skip]
@@ -133,11 +133,11 @@ impl UnnecessaryDefPath {
let has_ctor = match cx.tcx.def_kind(def_id) {
DefKind::Struct => {
let variant = cx.tcx.adt_def(def_id).non_enum_variant();
- variant.ctor_def_id.is_some() && variant.fields.iter().all(|f| f.vis.is_public())
+ variant.ctor.is_some() && variant.fields.iter().all(|f| f.vis.is_public())
},
DefKind::Variant => {
let variant = cx.tcx.adt_def(cx.tcx.parent(def_id)).variant_with_id(def_id);
- variant.ctor_def_id.is_some() && variant.fields.iter().all(|f| f.vis.is_public())
+ variant.ctor.is_some() && variant.fields.iter().all(|f| f.vis.is_public())
},
_ => false,
};
@@ -152,7 +152,7 @@ impl UnnecessaryDefPath {
has_ctor,
),
(0, Item::LangItem(item)) => (
- format!("{cx_snip}.tcx.lang_items().require(LangItem::{item}).ok() == Some({def_snip})"),
+ format!("{cx_snip}.tcx.lang_items().get(LangItem::{item}) == Some({def_snip})"),
has_ctor,
),
// match_trait_method
@@ -184,7 +184,7 @@ impl UnnecessaryDefPath {
(3, Item::LangItem(item)) => (
format!(
"path_res({cx_snip}, {def_snip}).opt_def_id()\
- .map_or(false, |id| {cx_snip}.tcx.lang_items().require(LangItem::{item}).ok() == Some(id))",
+ .map_or(false, |id| {cx_snip}.tcx.lang_items().get(LangItem::{item}) == Some(id))",
),
false,
),
@@ -209,7 +209,7 @@ impl UnnecessaryDefPath {
fn check_array(&mut self, cx: &LateContext<'_>, elements: &[Expr<'_>], span: Span) {
let Some(path) = path_from_array(elements) else { return };
- if let Some(def_id) = inherent_def_path_res(cx, &path.iter().map(AsRef::as_ref).collect::<Vec<_>>()) {
+ for def_id in def_path_def_ids(cx, &path.iter().map(AsRef::as_ref).collect::<Vec<_>>()) {
self.array_def_ids.insert((def_id, span));
}
}
@@ -246,7 +246,7 @@ fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Ve
fn read_mir_alloc_def_path<'tcx>(cx: &LateContext<'tcx>, alloc: &'tcx Allocation, ty: Ty<'_>) -> Option<Vec<String>> {
let (alloc, ty) = if let ty::Ref(_, ty, Mutability::Not) = *ty.kind() {
- let &alloc = alloc.provenance().values().next()?;
+ let &alloc = alloc.provenance().ptrs().values().next()?;
if let GlobalAlloc::Memory(alloc) = cx.tcx.global_alloc(alloc) {
(alloc.inner(), ty)
} else {
@@ -262,6 +262,7 @@ fn read_mir_alloc_def_path<'tcx>(cx: &LateContext<'tcx>, alloc: &'tcx Allocation
{
alloc
.provenance()
+ .ptrs()
.values()
.map(|&alloc| {
if let GlobalAlloc::Memory(alloc) = cx.tcx.global_alloc(alloc) {
@@ -293,50 +294,9 @@ fn path_from_array(exprs: &[Expr<'_>]) -> Option<Vec<String>> {
.collect()
}
-// def_path_res will match field names before anything else, but for this we want to match
-// inherent functions first.
-fn inherent_def_path_res(cx: &LateContext<'_>, segments: &[&str]) -> Option<DefId> {
- def_path_res(cx, segments, None).opt_def_id().map(|def_id| {
- if cx.tcx.def_kind(def_id) == DefKind::Field {
- let method_name = *segments.last().unwrap();
- cx.tcx
- .def_key(def_id)
- .parent
- .and_then(|parent_idx| {
- cx.tcx
- .inherent_impls(DefId {
- index: parent_idx,
- krate: def_id.krate,
- })
- .iter()
- .find_map(|impl_id| {
- cx.tcx.associated_items(*impl_id).find_by_name_and_kind(
- cx.tcx,
- Ident::from_str(method_name),
- AssocKind::Fn,
- *impl_id,
- )
- })
- })
- .map_or(def_id, |item| item.def_id)
- } else {
- def_id
- }
- })
-}
-
-fn get_lang_item_name(cx: &LateContext<'_>, def_id: DefId) -> Option<Symbol> {
- if let Some(lang_item) = cx.tcx.lang_items().items().iter().position(|id| *id == Some(def_id)) {
- let lang_items = def_path_res(cx, &["rustc_hir", "lang_items", "LangItem"], Some(Namespace::TypeNS)).def_id();
- let item_name = cx
- .tcx
- .adt_def(lang_items)
- .variants()
- .iter()
- .nth(lang_item)
- .unwrap()
- .name;
- Some(item_name)
+fn get_lang_item_name(cx: &LateContext<'_>, def_id: DefId) -> Option<&'static str> {
+ if let Some((lang_item, _)) = cx.tcx.lang_items().iter().find(|(_, id)| *id == def_id) {
+ Some(lang_item.variant_name())
} else {
None
}
diff --git a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
index be9834447..e4d1ee195 100644
--- a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
+++ b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
@@ -176,7 +176,8 @@ impl LateLintPass<'_> for WildcardImports {
format!("{import_source_snippet}::{imports_string}")
};
- let (lint, message) = if let Res::Def(DefKind::Enum, _) = use_path.res {
+ // Glob imports always have a single resolution.
+ let (lint, message) = if let Res::Def(DefKind::Enum, _) = use_path.res[0] {
(ENUM_GLOB_USE, "usage of wildcard import for enum variants")
} else {
(WILDCARD_IMPORTS, "usage of wildcard import")
diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs
index 36574198f..6b321765b 100644
--- a/src/tools/clippy/clippy_lints/src/write.rs
+++ b/src/tools/clippy/clippy_lints/src/write.rs
@@ -1,6 +1,7 @@
use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
use clippy_utils::macros::{root_macro_call_first_node, FormatArgsExpn, MacroCall};
use clippy_utils::source::{expand_past_previous_comma, snippet_opt};
+use clippy_utils::{is_in_cfg_test, is_in_test_function};
use rustc_ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, HirIdMap, Impl, Item, ItemKind};
@@ -232,6 +233,16 @@ declare_clippy_lint! {
#[derive(Default)]
pub struct Write {
in_debug_impl: bool,
+ allow_print_in_tests: bool,
+}
+
+impl Write {
+ pub fn new(allow_print_in_tests: bool) -> Self {
+ Self {
+ allow_print_in_tests,
+ ..Default::default()
+ }
+ }
}
impl_lint_pass!(Write => [
@@ -271,13 +282,15 @@ impl<'tcx> LateLintPass<'tcx> for Write {
.as_ref()
.map_or(false, |crate_name| crate_name == "build_script_build");
+ let allowed_in_tests = self.allow_print_in_tests
+ && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id));
match diag_name {
- sym::print_macro | sym::println_macro => {
+ sym::print_macro | sym::println_macro if !allowed_in_tests => {
if !is_build_script {
span_lint(cx, PRINT_STDOUT, macro_call.span, &format!("use of `{name}!`"));
}
},
- sym::eprint_macro | sym::eprintln_macro => {
+ sym::eprint_macro | sym::eprintln_macro if !allowed_in_tests => {
span_lint(cx, PRINT_STDERR, macro_call.span, &format!("use of `{name}!`"));
},
sym::write_macro | sym::writeln_macro => {},