From 22f57ff5842fde8acf78ea59528c149b0046b5fb Mon Sep 17 00:00:00 2001 From: bendn Date: Wed, 20 Mar 2024 23:33:16 +0700 Subject: [PATCH 01/47] fix `for x in y unsafe { }` --- clippy_lints/src/needless_for_each.rs | 5 +++-- tests/ui/needless_for_each_fixable.fixed | 4 ++++ tests/ui/needless_for_each_fixable.rs | 4 ++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/needless_for_each.rs b/clippy_lints/src/needless_for_each.rs index 84a07df1bb0a..fda15f469f42 100644 --- a/clippy_lints/src/needless_for_each.rs +++ b/clippy_lints/src/needless_for_each.rs @@ -1,6 +1,6 @@ use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, Visitor}; -use rustc_hir::{Closure, Expr, ExprKind, Stmt, StmtKind}; +use rustc_hir::{Block, BlockCheckMode, Closure, Expr, ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::{sym, Span, Symbol}; @@ -68,7 +68,8 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach { // e.g. `v.iter().for_each(f)` is simpler and clearer than using `for` loop. && let ExprKind::Closure(&Closure { body, .. }) = for_each_arg.kind && let body = cx.tcx.hir().body(body) - && let ExprKind::Block(..) = body.value.kind + // Skip the lint if the body is not safe. + && let ExprKind::Block(Block { rules: BlockCheckMode::DefaultBlock, .. }, ..) = body.value.kind { let mut ret_collector = RetCollector::default(); ret_collector.visit_expr(body.value); diff --git a/tests/ui/needless_for_each_fixable.fixed b/tests/ui/needless_for_each_fixable.fixed index 8c0e7ba76278..2362314290e6 100644 --- a/tests/ui/needless_for_each_fixable.fixed +++ b/tests/ui/needless_for_each_fixable.fixed @@ -113,6 +113,10 @@ fn should_not_lint() { let _ = v.iter().for_each(|elem| { acc += elem; }); + // `for_each` has a closure with an unsafe block. + v.iter().for_each(|elem| unsafe { + acc += elem; + }); } fn main() {} diff --git a/tests/ui/needless_for_each_fixable.rs b/tests/ui/needless_for_each_fixable.rs index cdc903a636c9..5b1186daa229 100644 --- a/tests/ui/needless_for_each_fixable.rs +++ b/tests/ui/needless_for_each_fixable.rs @@ -113,6 +113,10 @@ fn should_not_lint() { let _ = v.iter().for_each(|elem| { acc += elem; }); + // `for_each` has a closure with an unsafe block. + v.iter().for_each(|elem| unsafe { + acc += elem; + }); } fn main() {} From a356785065cd31d1501f533393f4b2bdbd04075e Mon Sep 17 00:00:00 2001 From: bendn Date: Thu, 21 Mar 2024 05:48:16 +0700 Subject: [PATCH 02/47] reasoning --- clippy_lints/src/needless_for_each.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/needless_for_each.rs b/clippy_lints/src/needless_for_each.rs index fda15f469f42..3fe3d50197d2 100644 --- a/clippy_lints/src/needless_for_each.rs +++ b/clippy_lints/src/needless_for_each.rs @@ -68,7 +68,8 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach { // e.g. `v.iter().for_each(f)` is simpler and clearer than using `for` loop. && let ExprKind::Closure(&Closure { body, .. }) = for_each_arg.kind && let body = cx.tcx.hir().body(body) - // Skip the lint if the body is not safe. + // Skip the lint if the body is not safe, so as not to suggest `for … in … unsafe {}` + // and suggesting `for … in … { unsafe { } }` is a little ugly. && let ExprKind::Block(Block { rules: BlockCheckMode::DefaultBlock, .. }, ..) = body.value.kind { let mut ret_collector = RetCollector::default(); From 58c53e8ea9fd56e1caea002f2a43b7a631508ba7 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Tue, 21 Nov 2023 14:35:02 +0100 Subject: [PATCH 03/47] reduce `single_char_pattern` to only lint on ascii chars --- clippy_lints/src/methods/mod.rs | 9 ++++++--- .../src/methods/single_char_insert_string.rs | 2 +- clippy_lints/src/methods/single_char_pattern.rs | 6 ++---- clippy_lints/src/methods/single_char_push_string.rs | 2 +- clippy_lints/src/methods/utils.rs | 8 +++++++- tests/ui/single_char_pattern.fixed | 12 +++++++----- tests/ui/single_char_pattern.rs | 6 ++++-- 7 files changed, 28 insertions(+), 17 deletions(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 0939c0285642..609deba73529 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1145,11 +1145,14 @@ declare_clippy_lint! { /// `str` as an argument, e.g., `_.split("x")`. /// /// ### Why is this bad? - /// Performing these methods using a `char` is faster than - /// using a `str`. + /// Performing these methods using a `char` can be faster than + /// using a `str` because it needs one less indirection. /// /// ### Known problems - /// Does not catch multi-byte unicode characters. + /// Does not catch multi-byte unicode characters. This is by + /// design, on many machines, splitting by a non-ascii char is + /// actually slower. Please do your own measurements instead of + /// relying solely on the results of this lint. /// /// ### Example /// ```rust,ignore diff --git a/clippy_lints/src/methods/single_char_insert_string.rs b/clippy_lints/src/methods/single_char_insert_string.rs index 44a7ad394fa0..20ec2b74d81e 100644 --- a/clippy_lints/src/methods/single_char_insert_string.rs +++ b/clippy_lints/src/methods/single_char_insert_string.rs @@ -10,7 +10,7 @@ use super::SINGLE_CHAR_ADD_STR; /// lint for length-1 `str`s as argument for `insert_str` pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { let mut applicability = Applicability::MachineApplicable; - if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[1], &mut applicability) { + if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[1], &mut applicability, false) { let base_string_snippet = snippet_with_applicability(cx, receiver.span.source_callsite(), "_", &mut applicability); let pos_arg = snippet_with_applicability(cx, args[0].span, "..", &mut applicability); diff --git a/clippy_lints/src/methods/single_char_pattern.rs b/clippy_lints/src/methods/single_char_pattern.rs index 363b1f2b8122..982a7901c453 100644 --- a/clippy_lints/src/methods/single_char_pattern.rs +++ b/clippy_lints/src/methods/single_char_pattern.rs @@ -8,7 +8,7 @@ use rustc_span::symbol::Symbol; use super::SINGLE_CHAR_PATTERN; -const PATTERN_METHODS: [(&str, usize); 24] = [ +const PATTERN_METHODS: [(&str, usize); 22] = [ ("contains", 0), ("starts_with", 0), ("ends_with", 0), @@ -27,8 +27,6 @@ const PATTERN_METHODS: [(&str, usize); 24] = [ ("rmatches", 0), ("match_indices", 0), ("rmatch_indices", 0), - ("strip_prefix", 0), - ("strip_suffix", 0), ("trim_start_matches", 0), ("trim_end_matches", 0), ("replace", 0), @@ -50,7 +48,7 @@ pub(super) fn check( && args.len() > pos && let arg = &args[pos] && let mut applicability = Applicability::MachineApplicable - && let Some(hint) = get_hint_if_single_char_arg(cx, arg, &mut applicability) + && let Some(hint) = get_hint_if_single_char_arg(cx, arg, &mut applicability, true) { span_lint_and_sugg( cx, diff --git a/clippy_lints/src/methods/single_char_push_string.rs b/clippy_lints/src/methods/single_char_push_string.rs index 0698bd6a0c52..97c13825bc10 100644 --- a/clippy_lints/src/methods/single_char_push_string.rs +++ b/clippy_lints/src/methods/single_char_push_string.rs @@ -10,7 +10,7 @@ use super::SINGLE_CHAR_ADD_STR; /// lint for length-1 `str`s as argument for `push_str` pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { let mut applicability = Applicability::MachineApplicable; - if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[0], &mut applicability) { + if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[0], &mut applicability, false) { let base_string_snippet = snippet_with_applicability(cx, receiver.span.source_callsite(), "..", &mut applicability); let sugg = format!("{base_string_snippet}.push({extension_string})"); diff --git a/clippy_lints/src/methods/utils.rs b/clippy_lints/src/methods/utils.rs index ef00c812d510..c50f24f824ab 100644 --- a/clippy_lints/src/methods/utils.rs +++ b/clippy_lints/src/methods/utils.rs @@ -52,11 +52,17 @@ pub(super) fn get_hint_if_single_char_arg( cx: &LateContext<'_>, arg: &Expr<'_>, applicability: &mut Applicability, + ascii_only: bool, ) -> Option { if let ExprKind::Lit(lit) = &arg.kind && let ast::LitKind::Str(r, style) = lit.node && let string = r.as_str() - && string.chars().count() == 1 + && let len = if ascii_only { + string.len() + } else { + string.chars().count() + } + && len == 1 { let snip = snippet_with_applicability(cx, arg.span, string, applicability); let ch = if let ast::StrStyle::Raw(nhash) = style { diff --git a/tests/ui/single_char_pattern.fixed b/tests/ui/single_char_pattern.fixed index 9573fdbcfde3..3ffdf4741968 100644 --- a/tests/ui/single_char_pattern.fixed +++ b/tests/ui/single_char_pattern.fixed @@ -10,9 +10,9 @@ fn main() { let y = "x"; x.split(y); - x.split('ß'); - x.split('ℝ'); - x.split('💣'); + x.split("ß"); + x.split("ℝ"); + x.split("💣"); // Can't use this lint for unicode code points which don't fit in a char x.split("❤️"); x.split_inclusive('x'); @@ -34,8 +34,6 @@ fn main() { x.rmatch_indices('x'); x.trim_start_matches('x'); x.trim_end_matches('x'); - x.strip_prefix('x'); - x.strip_suffix('x'); x.replace('x', "y"); x.replacen('x', "y", 3); // Make sure we escape characters correctly. @@ -64,4 +62,8 @@ fn main() { // Must escape backslash in raw strings when converting to char #8060 x.split('\\'); x.split('\\'); + + // should not warn, the char versions are actually slower in some cases + x.strip_prefix("x"); + x.strip_suffix("x"); } diff --git a/tests/ui/single_char_pattern.rs b/tests/ui/single_char_pattern.rs index 8a04480dbc64..74ab3aa5fb0a 100644 --- a/tests/ui/single_char_pattern.rs +++ b/tests/ui/single_char_pattern.rs @@ -34,8 +34,6 @@ fn main() { x.rmatch_indices("x"); x.trim_start_matches("x"); x.trim_end_matches("x"); - x.strip_prefix("x"); - x.strip_suffix("x"); x.replace("x", "y"); x.replacen("x", "y", 3); // Make sure we escape characters correctly. @@ -64,4 +62,8 @@ fn main() { // Must escape backslash in raw strings when converting to char #8060 x.split(r#"\"#); x.split(r"\"); + + // should not warn, the char versions are actually slower in some cases + x.strip_prefix("x"); + x.strip_suffix("x"); } From 54de78a2128ce1b9019f2bf2380c581e054bfe37 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Tue, 28 Nov 2023 22:31:24 +0100 Subject: [PATCH 04/47] downgrade to pedantic --- clippy_lints/src/methods/mod.rs | 8 ++-- tests/ui/single_char_pattern.fixed | 2 +- tests/ui/single_char_pattern.rs | 2 +- tests/ui/single_char_pattern.stderr | 62 ++++++++--------------------- 4 files changed, 23 insertions(+), 51 deletions(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 609deba73529..16e508bf4e1d 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1145,8 +1145,10 @@ declare_clippy_lint! { /// `str` as an argument, e.g., `_.split("x")`. /// /// ### Why is this bad? - /// Performing these methods using a `char` can be faster than - /// using a `str` because it needs one less indirection. + /// While this can make a perf difference on some systems, + /// benchmarks have proven inconclusive. But at least using a + /// char literal makes it clear that we are looking at a single + /// character. /// /// ### Known problems /// Does not catch multi-byte unicode characters. This is by @@ -1165,7 +1167,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "pre 1.29.0"] pub SINGLE_CHAR_PATTERN, - perf, + pedantic, "using a single-character str where a char could be used, e.g., `_.split(\"x\")`" } diff --git a/tests/ui/single_char_pattern.fixed b/tests/ui/single_char_pattern.fixed index 3ffdf4741968..a18d6319f89d 100644 --- a/tests/ui/single_char_pattern.fixed +++ b/tests/ui/single_char_pattern.fixed @@ -1,5 +1,5 @@ #![allow(clippy::needless_raw_strings, clippy::needless_raw_string_hashes, unused_must_use)] - +#![warn(clippy::single_char_pattern)] use std::collections::HashSet; fn main() { diff --git a/tests/ui/single_char_pattern.rs b/tests/ui/single_char_pattern.rs index 74ab3aa5fb0a..b52e6fb2fdfb 100644 --- a/tests/ui/single_char_pattern.rs +++ b/tests/ui/single_char_pattern.rs @@ -1,5 +1,5 @@ #![allow(clippy::needless_raw_strings, clippy::needless_raw_string_hashes, unused_must_use)] - +#![warn(clippy::single_char_pattern)] use std::collections::HashSet; fn main() { diff --git a/tests/ui/single_char_pattern.stderr b/tests/ui/single_char_pattern.stderr index 5a2ec6c764b1..b2deed23cbd5 100644 --- a/tests/ui/single_char_pattern.stderr +++ b/tests/ui/single_char_pattern.stderr @@ -7,24 +7,6 @@ LL | x.split("x"); = note: `-D clippy::single-char-pattern` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::single_char_pattern)]` -error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:13:13 - | -LL | x.split("ß"); - | ^^^ help: consider using a `char`: `'ß'` - -error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:14:13 - | -LL | x.split("ℝ"); - | ^^^ help: consider using a `char`: `'ℝ'` - -error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:15:13 - | -LL | x.split("💣"); - | ^^^^ help: consider using a `char`: `'💣'` - error: single-character string constant used as pattern --> tests/ui/single_char_pattern.rs:18:23 | @@ -140,106 +122,94 @@ LL | x.trim_end_matches("x"); | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:37:20 - | -LL | x.strip_prefix("x"); - | ^^^ help: consider using a `char`: `'x'` - -error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:38:20 - | -LL | x.strip_suffix("x"); - | ^^^ help: consider using a `char`: `'x'` - -error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:39:15 + --> tests/ui/single_char_pattern.rs:37:15 | LL | x.replace("x", "y"); | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:40:16 + --> tests/ui/single_char_pattern.rs:38:16 | LL | x.replacen("x", "y", 3); | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:42:13 + --> tests/ui/single_char_pattern.rs:40:13 | LL | x.split("\n"); | ^^^^ help: consider using a `char`: `'\n'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:43:13 + --> tests/ui/single_char_pattern.rs:41:13 | LL | x.split("'"); | ^^^ help: consider using a `char`: `'\''` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:44:13 + --> tests/ui/single_char_pattern.rs:42:13 | LL | x.split("\'"); | ^^^^ help: consider using a `char`: `'\''` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:46:13 + --> tests/ui/single_char_pattern.rs:44:13 | LL | x.split("\""); | ^^^^ help: consider using a `char`: `'"'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:51:31 + --> tests/ui/single_char_pattern.rs:49:31 | LL | x.replace(';', ",").split(","); // issue #2978 | ^^^ help: consider using a `char`: `','` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:52:19 + --> tests/ui/single_char_pattern.rs:50:19 | LL | x.starts_with("\x03"); // issue #2996 | ^^^^^^ help: consider using a `char`: `'\x03'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:59:13 + --> tests/ui/single_char_pattern.rs:57:13 | LL | x.split(r"a"); | ^^^^ help: consider using a `char`: `'a'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:60:13 + --> tests/ui/single_char_pattern.rs:58:13 | LL | x.split(r#"a"#); | ^^^^^^ help: consider using a `char`: `'a'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:61:13 + --> tests/ui/single_char_pattern.rs:59:13 | LL | x.split(r###"a"###); | ^^^^^^^^^^ help: consider using a `char`: `'a'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:62:13 + --> tests/ui/single_char_pattern.rs:60:13 | LL | x.split(r###"'"###); | ^^^^^^^^^^ help: consider using a `char`: `'\''` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:63:13 + --> tests/ui/single_char_pattern.rs:61:13 | LL | x.split(r###"#"###); | ^^^^^^^^^^ help: consider using a `char`: `'#'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:65:13 + --> tests/ui/single_char_pattern.rs:63:13 | LL | x.split(r#"\"#); | ^^^^^^ help: consider using a `char`: `'\\'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:66:13 + --> tests/ui/single_char_pattern.rs:64:13 | LL | x.split(r"\"); | ^^^^ help: consider using a `char`: `'\\'` -error: aborting due to 40 previous errors +error: aborting due to 35 previous errors From 666e2f286854cc3a4dbdb3cc8c934f986765c72b Mon Sep 17 00:00:00 2001 From: J-ZhengLi Date: Wed, 10 Apr 2024 15:53:36 +0800 Subject: [PATCH 05/47] fix [`large_stack_arrays`] linting in `vec` macro & add `matching_root_macro_call` function in `clippy_utils` --- clippy_lints/src/format_args.rs | 6 +-- clippy_lints/src/large_stack_arrays.rs | 25 +++++++++---- clippy_lints/src/manual_assert.rs | 5 +-- clippy_lints/src/manual_is_ascii_check.rs | 15 +------- clippy_lints/src/methods/filter_map.rs | 5 +-- clippy_lints/src/repeat_vec_with_capacity.rs | 5 +-- .../src/slow_vector_initialization.rs | 6 +-- clippy_utils/src/macros.rs | 10 +++++ tests/ui/large_stack_arrays.rs | 34 +++++++++++++++++ tests/ui/large_stack_arrays.stderr | 37 ++++++++++++++++++- 10 files changed, 110 insertions(+), 38 deletions(-) diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index 80db617c639a..003a9995c15f 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -4,7 +4,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::is_diag_trait_item; use clippy_utils::macros::{ find_format_arg_expr, find_format_args, format_arg_removal_span, format_placeholder_format_span, is_assert_macro, - is_format_macro, is_panic, root_macro_call, root_macro_call_first_node, FormatParamUsage, MacroCall, + is_format_macro, is_panic, matching_root_macro_call, root_macro_call_first_node, FormatParamUsage, MacroCall, }; use clippy_utils::source::snippet_opt; use clippy_utils::ty::{implements_trait, is_type_lang_item}; @@ -271,9 +271,7 @@ impl<'a, 'tcx> FormatArgsExpr<'a, 'tcx> { let mut suggest_format = |spec| { let message = format!("for the {spec} to apply consider using `format!()`"); - if let Some(mac_call) = root_macro_call(arg_span) - && self.cx.tcx.is_diagnostic_item(sym::format_args_macro, mac_call.def_id) - { + if let Some(mac_call) = matching_root_macro_call(self.cx, arg_span, sym::format_args_macro) { diag.span_suggestion( self.cx.sess().source_map().span_until_char(mac_call.span, '!'), message, diff --git a/clippy_lints/src/large_stack_arrays.rs b/clippy_lints/src/large_stack_arrays.rs index afcb67459476..9214e870e928 100644 --- a/clippy_lints/src/large_stack_arrays.rs +++ b/clippy_lints/src/large_stack_arrays.rs @@ -1,10 +1,12 @@ -use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::macros::macro_backtrace; use clippy_utils::source::snippet; use rustc_hir::{Expr, ExprKind, Item, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, ConstKind}; use rustc_session::impl_lint_pass; +use rustc_span::{sym, Span}; declare_clippy_lint! { /// ### What it does @@ -39,6 +41,7 @@ impl_lint_pass!(LargeStackArrays => [LARGE_STACK_ARRAYS]); impl<'tcx> LateLintPass<'tcx> for LargeStackArrays { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { if let ExprKind::Repeat(_, _) | ExprKind::Array(_) = expr.kind + && !is_from_vec_macro(cx, expr.span) && let ty::Array(element_type, cst) = cx.typeck_results().expr_ty(expr).kind() && let ConstKind::Value(ty::ValTree::Leaf(element_count)) = cst.kind() && let Ok(element_count) = element_count.try_to_target_usize(cx.tcx) @@ -54,7 +57,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackArrays { }) && self.maximum_allowed_size < u128::from(element_count) * u128::from(element_size) { - span_lint_and_help( + span_lint_and_then( cx, LARGE_STACK_ARRAYS, expr.span, @@ -62,12 +65,20 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackArrays { "allocating a local array larger than {} bytes", self.maximum_allowed_size ), - None, - format!( - "consider allocating on the heap with `vec!{}.into_boxed_slice()`", - snippet(cx, expr.span, "[...]") - ), + |diag| { + if !expr.span.from_expansion() { + diag.help(format!( + "consider allocating on the heap with `vec!{}.into_boxed_slice()`", + snippet(cx, expr.span, "[...]") + )); + } + }, ); } } } + +/// We shouldn't lint messages if the expr is already in a `vec!` call +fn is_from_vec_macro(cx: &LateContext<'_>, expr_span: Span) -> bool { + macro_backtrace(expr_span).any(|mac| cx.tcx.is_diagnostic_item(sym::vec_macro, mac.def_id)) +} diff --git a/clippy_lints/src/manual_assert.rs b/clippy_lints/src/manual_assert.rs index 76edbe8b755b..d76b94eba23e 100644 --- a/clippy_lints/src/manual_assert.rs +++ b/clippy_lints/src/manual_assert.rs @@ -1,12 +1,11 @@ use crate::rustc_lint::LintContext; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::macros::root_macro_call; +use clippy_utils::macros::{is_panic, root_macro_call}; use clippy_utils::{is_else_clause, is_parent_stmt, peel_blocks_with_stmt, span_extract_comment, sugg}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -42,7 +41,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualAssert { && !expr.span.from_expansion() && let then = peel_blocks_with_stmt(then) && let Some(macro_call) = root_macro_call(then.span) - && cx.tcx.item_name(macro_call.def_id) == sym::panic + && is_panic(cx, macro_call.def_id) && !cx.tcx.sess.source_map().is_multiline(cond.span) && let Ok(panic_snippet) = cx.sess().source_map().span_to_snippet(macro_call.span) && let Some(panic_snippet) = panic_snippet.strip_suffix(')') diff --git a/clippy_lints/src/manual_is_ascii_check.rs b/clippy_lints/src/manual_is_ascii_check.rs index 338a299740a8..ed7eabd9b994 100644 --- a/clippy_lints/src/manual_is_ascii_check.rs +++ b/clippy_lints/src/manual_is_ascii_check.rs @@ -1,6 +1,6 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::macros::root_macro_call; +use clippy_utils::macros::matching_root_macro_call; use clippy_utils::sugg::Sugg; use clippy_utils::{higher, in_constant}; use rustc_ast::ast::RangeLimits; @@ -9,7 +9,6 @@ use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, PatKind, RangeEnd}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::def_id::DefId; use rustc_span::{sym, Span}; declare_clippy_lint! { @@ -97,9 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck { return; } - if let Some(macro_call) = root_macro_call(expr.span) - && is_matches_macro(cx, macro_call.def_id) - { + if let Some(macro_call) = matching_root_macro_call(cx, expr.span, sym::matches_macro) { if let ExprKind::Match(recv, [arm, ..], _) = expr.kind { let range = check_pat(&arm.pat.kind); check_is_ascii(cx, macro_call.span, recv, &range); @@ -187,11 +184,3 @@ fn check_range(start: &Expr<'_>, end: &Expr<'_>) -> CharRange { 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/clippy_lints/src/methods/filter_map.rs b/clippy_lints/src/methods/filter_map.rs index 581e3b308c3c..02a11257007a 100644 --- a/clippy_lints/src/methods/filter_map.rs +++ b/clippy_lints/src/methods/filter_map.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::macros::{is_panic, root_macro_call}; +use clippy_utils::macros::{is_panic, matching_root_macro_call, root_macro_call}; use clippy_utils::source::{indent_of, reindent_multiline, snippet}; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{higher, is_trait_method, path_to_local_id, peel_blocks, SpanlessEq}; @@ -247,8 +247,7 @@ impl<'tcx> OffendingFilterExpr<'tcx> { } else { None } - } else if let Some(macro_call) = root_macro_call(expr.span) - && cx.tcx.get_diagnostic_name(macro_call.def_id) == Some(sym::matches_macro) + } else if matching_root_macro_call(cx, expr.span, sym::matches_macro).is_some() // we know for a fact that the wildcard pattern is the second arm && let ExprKind::Match(scrutinee, [arm, _], _) = expr.kind && path_to_local_id(scrutinee, filter_param_id) diff --git a/clippy_lints/src/repeat_vec_with_capacity.rs b/clippy_lints/src/repeat_vec_with_capacity.rs index a358881bf80e..792d8fc88f0b 100644 --- a/clippy_lints/src/repeat_vec_with_capacity.rs +++ b/clippy_lints/src/repeat_vec_with_capacity.rs @@ -1,7 +1,7 @@ use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::VecArgs; -use clippy_utils::macros::root_macro_call; +use clippy_utils::macros::matching_root_macro_call; use clippy_utils::source::snippet; use clippy_utils::{expr_or_init, fn_def_id, match_def_path, paths}; use rustc_errors::Applicability; @@ -65,8 +65,7 @@ fn emit_lint(cx: &LateContext<'_>, span: Span, kind: &str, note: &'static str, s /// Checks `vec![Vec::with_capacity(x); n]` fn check_vec_macro(cx: &LateContext<'_>, expr: &Expr<'_>) { - if let Some(mac_call) = root_macro_call(expr.span) - && cx.tcx.is_diagnostic_item(sym::vec_macro, mac_call.def_id) + if matching_root_macro_call(cx, expr.span, sym::vec_macro).is_some() && let Some(VecArgs::Repeat(repeat_expr, len_expr)) = VecArgs::hir(cx, expr) && fn_def_id(cx, repeat_expr).is_some_and(|did| match_def_path(cx, did, &paths::VEC_WITH_CAPACITY)) && !len_expr.span.from_expansion() diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index 8a9f02b6dcb1..8a01f9d3e0ab 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::macros::root_macro_call; +use clippy_utils::macros::matching_root_macro_call; use clippy_utils::sugg::Sugg; use clippy_utils::{ get_enclosing_block, is_expr_path_def_path, is_integer_literal, is_path_diagnostic_item, path_to_local, @@ -145,9 +145,7 @@ impl SlowVectorInit { // Generally don't warn if the vec initializer comes from an expansion, except for the vec! macro. // This lets us still warn on `vec![]`, while ignoring other kinds of macros that may output an // empty vec - if expr.span.from_expansion() - && root_macro_call(expr.span).map(|m| m.def_id) != cx.tcx.get_diagnostic_item(sym::vec_macro) - { + if expr.span.from_expansion() && matching_root_macro_call(cx, expr.span, sym::vec_macro).is_none() { return None; } diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs index f166087dc3ca..257dd76ab15c 100644 --- a/clippy_utils/src/macros.rs +++ b/clippy_utils/src/macros.rs @@ -119,10 +119,20 @@ pub fn macro_backtrace(span: Span) -> impl Iterator { /// If the macro backtrace of `span` has a macro call at the root expansion /// (i.e. not a nested macro call), returns `Some` with the `MacroCall` +/// +/// If you only want to check whether the root macro has a specific name, +/// consider using [`matching_root_macro_call`] instead. pub fn root_macro_call(span: Span) -> Option { macro_backtrace(span).last() } +/// A combination of [`root_macro_call`] and +/// [`is_diagnostic_item`](rustc_middle::ty::TyCtxt::is_diagnostic_item) that returns a `MacroCall` +/// at the root expansion if only it matches the given name. +pub fn matching_root_macro_call(cx: &LateContext<'_>, span: Span, name: Symbol) -> Option { + root_macro_call(span).filter(|mc| cx.tcx.is_diagnostic_item(name, mc.def_id)) +} + /// Like [`root_macro_call`], but only returns `Some` if `node` is the "first node" /// produced by the macro call, as in [`first_node_in_macro`]. pub fn root_macro_call_first_node(cx: &LateContext<'_>, node: &impl HirNode) -> Option { diff --git a/tests/ui/large_stack_arrays.rs b/tests/ui/large_stack_arrays.rs index d5c4f95f8c42..f41423962a19 100644 --- a/tests/ui/large_stack_arrays.rs +++ b/tests/ui/large_stack_arrays.rs @@ -55,3 +55,37 @@ fn main() { [(); 20_000_000], ); } + +#[allow(clippy::useless_vec)] +fn issue_12586() { + macro_rules! dummy { + ($n:expr) => { + $n + }; + // Weird rule to test help messages. + ($a:expr => $b:expr) => { + [$a, $b, $a, $b] + //~^ ERROR: allocating a local array larger than 512000 bytes + }; + ($id:ident; $n:literal) => { + dummy!(::std::vec![$id;$n]) + }; + ($($id:expr),+ $(,)?) => { + ::std::vec![$($id),*] + } + } + + let x = [0u32; 50_000]; + let y = vec![x, x, x, x, x]; + let y = vec![dummy![x, x, x, x, x]]; + let y = vec![dummy![[x, x, x, x, x]]]; + //~^ ERROR: allocating a local array larger than 512000 bytes + let y = dummy![x, x, x, x, x]; + let y = [x, x, dummy!(x), x, x]; + //~^ ERROR: allocating a local array larger than 512000 bytes + let y = dummy![x => x]; + let y = dummy![x;5]; + let y = dummy!(vec![dummy![x, x, x, x, x]]); + let y = dummy![[x, x, x, x, x]]; + //~^ ERROR: allocating a local array larger than 512000 bytes +} diff --git a/tests/ui/large_stack_arrays.stderr b/tests/ui/large_stack_arrays.stderr index 007ca61c2de1..ac4097a463f6 100644 --- a/tests/ui/large_stack_arrays.stderr +++ b/tests/ui/large_stack_arrays.stderr @@ -56,5 +56,40 @@ LL | [0u8; usize::MAX], | = help: consider allocating on the heap with `vec![0u8; usize::MAX].into_boxed_slice()` -error: aborting due to 7 previous errors +error: allocating a local array larger than 512000 bytes + --> tests/ui/large_stack_arrays.rs:81:25 + | +LL | let y = vec![dummy![[x, x, x, x, x]]]; + | ^^^^^^^^^^^^^^^ + | + = help: consider allocating on the heap with `vec![x, x, x, x, x].into_boxed_slice()` + +error: allocating a local array larger than 512000 bytes + --> tests/ui/large_stack_arrays.rs:84:13 + | +LL | let y = [x, x, dummy!(x), x, x]; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider allocating on the heap with `vec![x, x, dummy!(x), x, x].into_boxed_slice()` + +error: allocating a local array larger than 512000 bytes + --> tests/ui/large_stack_arrays.rs:67:13 + | +LL | [$a, $b, $a, $b] + | ^^^^^^^^^^^^^^^^ +... +LL | let y = dummy![x => x]; + | -------------- in this macro invocation + | + = note: this error originates in the macro `dummy` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: allocating a local array larger than 512000 bytes + --> tests/ui/large_stack_arrays.rs:89:20 + | +LL | let y = dummy![[x, x, x, x, x]]; + | ^^^^^^^^^^^^^^^ + | + = help: consider allocating on the heap with `vec![x, x, x, x, x].into_boxed_slice()` + +error: aborting due to 11 previous errors From 2861729dadfb7a3567840314311fee86e54299a2 Mon Sep 17 00:00:00 2001 From: J-ZhengLi Date: Wed, 17 Apr 2024 18:10:50 +0800 Subject: [PATCH 06/47] test [`large_stack_arrays`] with proc-macro and make sure not to offer false help messages if in one. --- clippy_lints/src/large_stack_arrays.rs | 50 +++++++++++++++++++++----- tests/ui/auxiliary/proc_macros.rs | 17 +++++++++ tests/ui/large_stack_arrays.rs | 16 ++++++++- tests/ui/large_stack_arrays.stderr | 47 ++++++++++++++---------- 4 files changed, 102 insertions(+), 28 deletions(-) diff --git a/clippy_lints/src/large_stack_arrays.rs b/clippy_lints/src/large_stack_arrays.rs index 9214e870e928..208d1bb6e68a 100644 --- a/clippy_lints/src/large_stack_arrays.rs +++ b/clippy_lints/src/large_stack_arrays.rs @@ -1,7 +1,8 @@ use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::is_from_proc_macro; use clippy_utils::macros::macro_backtrace; use clippy_utils::source::snippet; -use rustc_hir::{Expr, ExprKind, Item, ItemKind, Node}; +use rustc_hir::{ArrayLen, Expr, ExprKind, Item, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, ConstKind}; @@ -27,21 +28,41 @@ declare_clippy_lint! { pub struct LargeStackArrays { maximum_allowed_size: u128, + prev_vec_macro_callsite: Option, } impl LargeStackArrays { #[must_use] pub fn new(maximum_allowed_size: u128) -> Self { - Self { maximum_allowed_size } + Self { + maximum_allowed_size, + prev_vec_macro_callsite: None, + } + } + + /// Check if the given span of an expr is already in a `vec!` call. + fn is_from_vec_macro(&mut self, cx: &LateContext<'_>, span: Span) -> bool { + // First, we check if this is span is within the last encountered `vec!` macro's root callsite. + self.prev_vec_macro_callsite + .is_some_and(|vec_mac| vec_mac.contains(span)) + || { + // Then, we try backtracking the macro expansions, to see if there's a `vec!` macro, + // and update the `prev_vec_macro_callsite`. + let res = macro_backtrace(span).any(|mac| cx.tcx.is_diagnostic_item(sym::vec_macro, mac.def_id)); + if res { + self.prev_vec_macro_callsite = Some(span.source_callsite()); + } + res + } } } impl_lint_pass!(LargeStackArrays => [LARGE_STACK_ARRAYS]); impl<'tcx> LateLintPass<'tcx> for LargeStackArrays { - fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { if let ExprKind::Repeat(_, _) | ExprKind::Array(_) = expr.kind - && !is_from_vec_macro(cx, expr.span) + && !self.is_from_vec_macro(cx, expr.span) && let ty::Array(element_type, cst) = cx.typeck_results().expr_ty(expr).kind() && let ConstKind::Value(ty::ValTree::Leaf(element_count)) = cst.kind() && let Ok(element_count) = element_count.try_to_target_usize(cx.tcx) @@ -66,7 +87,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackArrays { self.maximum_allowed_size ), |diag| { - if !expr.span.from_expansion() { + if !might_be_expanded(cx, expr) { diag.help(format!( "consider allocating on the heap with `vec!{}.into_boxed_slice()`", snippet(cx, expr.span, "[...]") @@ -78,7 +99,20 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackArrays { } } -/// We shouldn't lint messages if the expr is already in a `vec!` call -fn is_from_vec_macro(cx: &LateContext<'_>, expr_span: Span) -> bool { - macro_backtrace(expr_span).any(|mac| cx.tcx.is_diagnostic_item(sym::vec_macro, mac.def_id)) +/// Only giving help messages if the expr does not contains macro expanded codes. +fn might_be_expanded<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> bool { + /// Check if the span of `ArrayLen` of a repeat expression is within the expr's span, + /// if not, meaning this repeat expr is definitely from some proc-macro. + /// + /// This is a fail-safe to a case where even the `is_from_proc_macro` is unable to determain the + /// correct result. + fn repeat_expr_might_be_expanded<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> bool { + let ExprKind::Repeat(_, ArrayLen::Body(anon_const)) = expr.kind else { + return false; + }; + let len_span = cx.tcx.def_span(anon_const.def_id); + !expr.span.contains(len_span) + } + + expr.span.from_expansion() || is_from_proc_macro(cx, expr) || repeat_expr_might_be_expanded(cx, expr) } diff --git a/tests/ui/auxiliary/proc_macros.rs b/tests/ui/auxiliary/proc_macros.rs index 3303eb145678..6e6919cd295c 100644 --- a/tests/ui/auxiliary/proc_macros.rs +++ b/tests/ui/auxiliary/proc_macros.rs @@ -9,6 +9,7 @@ use proc_macro::token_stream::IntoIter; use proc_macro::Delimiter::{self, Brace, Parenthesis}; use proc_macro::Spacing::{self, Alone, Joint}; use proc_macro::{Group, Ident, Literal, Punct, Span, TokenStream, TokenTree as TT}; +use syn::spanned::Spanned; type Result = core::result::Result; @@ -124,6 +125,22 @@ fn write_with_span(s: Span, mut input: IntoIter, out: &mut TokenStream) -> Resul Ok(()) } +/// Takes an array repeat expression such as `[0_u32; 2]`, and return the tokens with 10 times the +/// original size, which turns to `[0_u32; 20]`. +#[proc_macro] +pub fn make_it_big(input: TokenStream) -> TokenStream { + let mut expr_repeat = syn::parse_macro_input!(input as syn::ExprRepeat); + let len_span = expr_repeat.len.span(); + if let syn::Expr::Lit(expr_lit) = &mut *expr_repeat.len { + if let syn::Lit::Int(lit_int) = &expr_lit.lit { + let orig_val = lit_int.base10_parse::().expect("not a valid length parameter"); + let new_val = orig_val.saturating_mul(10); + expr_lit.lit = syn::parse_quote_spanned!( len_span => #new_val); + } + } + quote::quote!(#expr_repeat).into() +} + /// Within the item this attribute is attached to, an `inline!` macro is available which expands the /// contained tokens as though they came from a macro expansion. /// diff --git a/tests/ui/large_stack_arrays.rs b/tests/ui/large_stack_arrays.rs index f41423962a19..6bcaf481c9f7 100644 --- a/tests/ui/large_stack_arrays.rs +++ b/tests/ui/large_stack_arrays.rs @@ -1,6 +1,9 @@ +//@aux-build:proc_macros.rs #![warn(clippy::large_stack_arrays)] #![allow(clippy::large_enum_variant)] +extern crate proc_macros; + #[derive(Clone, Copy)] struct S { pub data: [u64; 32], @@ -74,12 +77,18 @@ fn issue_12586() { ::std::vec![$($id),*] } } + macro_rules! create_then_move { + ($id:ident; $n:literal) => {{ + let _x_ = [$id; $n]; + //~^ ERROR: allocating a local array larger than 512000 bytes + _x_ + }}; + } let x = [0u32; 50_000]; let y = vec![x, x, x, x, x]; let y = vec![dummy![x, x, x, x, x]]; let y = vec![dummy![[x, x, x, x, x]]]; - //~^ ERROR: allocating a local array larger than 512000 bytes let y = dummy![x, x, x, x, x]; let y = [x, x, dummy!(x), x, x]; //~^ ERROR: allocating a local array larger than 512000 bytes @@ -88,4 +97,9 @@ fn issue_12586() { let y = dummy!(vec![dummy![x, x, x, x, x]]); let y = dummy![[x, x, x, x, x]]; //~^ ERROR: allocating a local array larger than 512000 bytes + + let y = proc_macros::make_it_big!([x; 1]); + //~^ ERROR: allocating a local array larger than 512000 bytes + let y = vec![proc_macros::make_it_big!([x; 10])]; + let y = vec![create_then_move![x; 5]; 5]; } diff --git a/tests/ui/large_stack_arrays.stderr b/tests/ui/large_stack_arrays.stderr index ac4097a463f6..06294ee8b8cb 100644 --- a/tests/ui/large_stack_arrays.stderr +++ b/tests/ui/large_stack_arrays.stderr @@ -1,5 +1,5 @@ error: allocating a local array larger than 512000 bytes - --> tests/ui/large_stack_arrays.rs:29:14 + --> tests/ui/large_stack_arrays.rs:32:14 | LL | let _x = [build(); 3]; | ^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | let _x = [build(); 3]; = help: to override `-D warnings` add `#[allow(clippy::large_stack_arrays)]` error: allocating a local array larger than 512000 bytes - --> tests/ui/large_stack_arrays.rs:32:14 + --> tests/ui/large_stack_arrays.rs:35:14 | LL | let _y = [build(), build(), build()]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | let _y = [build(), build(), build()]; = help: consider allocating on the heap with `vec![build(), build(), build()].into_boxed_slice()` error: allocating a local array larger than 512000 bytes - --> tests/ui/large_stack_arrays.rs:38:9 + --> tests/ui/large_stack_arrays.rs:41:9 | LL | [0u32; 20_000_000], | ^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | [0u32; 20_000_000], = help: consider allocating on the heap with `vec![0u32; 20_000_000].into_boxed_slice()` error: allocating a local array larger than 512000 bytes - --> tests/ui/large_stack_arrays.rs:40:9 + --> tests/ui/large_stack_arrays.rs:43:9 | LL | [S { data: [0; 32] }; 5000], | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | [S { data: [0; 32] }; 5000], = help: consider allocating on the heap with `vec![S { data: [0; 32] }; 5000].into_boxed_slice()` error: allocating a local array larger than 512000 bytes - --> tests/ui/large_stack_arrays.rs:42:9 + --> tests/ui/large_stack_arrays.rs:45:9 | LL | [Some(""); 20_000_000], | ^^^^^^^^^^^^^^^^^^^^^^ @@ -41,7 +41,7 @@ LL | [Some(""); 20_000_000], = help: consider allocating on the heap with `vec![Some(""); 20_000_000].into_boxed_slice()` error: allocating a local array larger than 512000 bytes - --> tests/ui/large_stack_arrays.rs:44:9 + --> tests/ui/large_stack_arrays.rs:47:9 | LL | [E::T(0); 5000], | ^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL | [E::T(0); 5000], = help: consider allocating on the heap with `vec![E::T(0); 5000].into_boxed_slice()` error: allocating a local array larger than 512000 bytes - --> tests/ui/large_stack_arrays.rs:46:9 + --> tests/ui/large_stack_arrays.rs:49:9 | LL | [0u8; usize::MAX], | ^^^^^^^^^^^^^^^^^ @@ -57,15 +57,7 @@ LL | [0u8; usize::MAX], = help: consider allocating on the heap with `vec![0u8; usize::MAX].into_boxed_slice()` error: allocating a local array larger than 512000 bytes - --> tests/ui/large_stack_arrays.rs:81:25 - | -LL | let y = vec![dummy![[x, x, x, x, x]]]; - | ^^^^^^^^^^^^^^^ - | - = help: consider allocating on the heap with `vec![x, x, x, x, x].into_boxed_slice()` - -error: allocating a local array larger than 512000 bytes - --> tests/ui/large_stack_arrays.rs:84:13 + --> tests/ui/large_stack_arrays.rs:93:13 | LL | let y = [x, x, dummy!(x), x, x]; | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -73,7 +65,7 @@ LL | let y = [x, x, dummy!(x), x, x]; = help: consider allocating on the heap with `vec![x, x, dummy!(x), x, x].into_boxed_slice()` error: allocating a local array larger than 512000 bytes - --> tests/ui/large_stack_arrays.rs:67:13 + --> tests/ui/large_stack_arrays.rs:70:13 | LL | [$a, $b, $a, $b] | ^^^^^^^^^^^^^^^^ @@ -84,12 +76,29 @@ LL | let y = dummy![x => x]; = note: this error originates in the macro `dummy` (in Nightly builds, run with -Z macro-backtrace for more info) error: allocating a local array larger than 512000 bytes - --> tests/ui/large_stack_arrays.rs:89:20 + --> tests/ui/large_stack_arrays.rs:98:20 | LL | let y = dummy![[x, x, x, x, x]]; | ^^^^^^^^^^^^^^^ | = help: consider allocating on the heap with `vec![x, x, x, x, x].into_boxed_slice()` -error: aborting due to 11 previous errors +error: allocating a local array larger than 512000 bytes + --> tests/ui/large_stack_arrays.rs:101:39 + | +LL | let y = proc_macros::make_it_big!([x; 1]); + | ^^^^^^ + +error: allocating a local array larger than 512000 bytes + --> tests/ui/large_stack_arrays.rs:82:23 + | +LL | let _x_ = [$id; $n]; + | ^^^^^^^^^ +... +LL | let y = vec![create_then_move![x; 5]; 5]; + | ----------------------- in this macro invocation + | + = note: this error originates in the macro `create_then_move` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 12 previous errors From 876d5f00a0515f60b23d4e111249d6340159fa8b Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Tue, 16 Apr 2024 19:23:30 -0400 Subject: [PATCH 07/47] Rename `BindingAnnotation` to `BindingMode` --- clippy_lints/src/dereference.rs | 4 ++-- clippy_lints/src/eta_reduction.rs | 4 ++-- clippy_lints/src/explicit_write.rs | 4 ++-- clippy_lints/src/index_refutable_slice.rs | 2 +- clippy_lints/src/let_if_seq.rs | 4 ++-- clippy_lints/src/loops/manual_find.rs | 4 ++-- clippy_lints/src/loops/mut_range_bound.rs | 4 ++-- clippy_lints/src/loops/same_item_push.rs | 4 ++-- clippy_lints/src/manual_hash_one.rs | 4 ++-- clippy_lints/src/matches/manual_utils.rs | 4 ++-- clippy_lints/src/matches/match_as_ref.rs | 4 ++-- clippy_lints/src/matches/needless_match.rs | 4 ++-- clippy_lints/src/matches/single_match.rs | 4 ++-- clippy_lints/src/methods/clone_on_copy.rs | 4 ++-- clippy_lints/src/methods/filter_next.rs | 4 ++-- clippy_lints/src/methods/iter_kv_map.rs | 2 +- .../src/methods/iter_overeager_cloned.rs | 4 ++-- clippy_lints/src/methods/iter_skip_next.rs | 4 ++-- clippy_lints/src/methods/map_clone.rs | 4 ++-- clippy_lints/src/methods/needless_collect.rs | 4 ++-- clippy_lints/src/methods/str_splitn.rs | 6 +++--- clippy_lints/src/misc.rs | 6 +++--- clippy_lints/src/needless_arbitrary_self_type.rs | 6 +++--- clippy_lints/src/needless_borrowed_ref.rs | 6 +++--- clippy_lints/src/needless_late_init.rs | 4 ++-- clippy_lints/src/needless_pass_by_value.rs | 4 ++-- clippy_lints/src/option_if_let_else.rs | 8 ++++---- clippy_lints/src/pass_by_ref_or_value.rs | 4 ++-- clippy_lints/src/ptr.rs | 6 +++--- clippy_lints/src/question_mark.rs | 4 ++-- clippy_lints/src/redundant_locals.rs | 6 +++--- clippy_lints/src/ref_patterns.rs | 4 ++-- clippy_lints/src/reserve_after_initialization.rs | 4 ++-- clippy_lints/src/slow_vector_initialization.rs | 4 ++-- .../src/unnecessary_struct_initialization.rs | 4 ++-- clippy_lints/src/unnested_or_patterns.rs | 4 ++-- clippy_lints/src/useless_conversion.rs | 4 ++-- clippy_lints/src/utils/author.rs | 16 ++++++++-------- clippy_lints/src/vec_init_then_push.rs | 4 ++-- clippy_utils/src/hir_utils.rs | 4 ++-- clippy_utils/src/lib.rs | 4 ++-- tests/ui/author.stdout | 2 +- tests/ui/author/blocks.stdout | 6 +++--- tests/ui/author/loop.stdout | 4 ++-- tests/ui/author/macro_in_closure.stdout | 2 +- tests/ui/author/macro_in_loop.stdout | 2 +- tests/ui/author/matches.stdout | 4 ++-- 47 files changed, 104 insertions(+), 104 deletions(-) diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index f83fb1b90198..bff40c2ae75d 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -9,7 +9,7 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_ty, Visitor}; use rustc_hir::{ - self as hir, BindingAnnotation, Body, BodyId, BorrowKind, Expr, ExprKind, HirId, MatchSource, Mutability, Node, + self as hir, BindingMode, Body, BodyId, BorrowKind, Expr, ExprKind, HirId, MatchSource, Mutability, Node, Pat, PatKind, Path, QPath, TyKind, UnOp, }; use rustc_lint::{LateContext, LateLintPass}; @@ -599,7 +599,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { } fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) { - if let PatKind::Binding(BindingAnnotation::REF, id, name, _) = pat.kind { + if let PatKind::Binding(BindingMode::REF, id, name, _) = pat.kind { if let Some(opt_prev_pat) = self.ref_locals.get_mut(&id) { // This binding id has been seen before. Add this pattern to the list of changes. if let Some(prev_pat) = opt_prev_pat { diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index 850a4f0eec8e..306a4a9e55c9 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -5,7 +5,7 @@ use clippy_utils::ty::type_diagnostic_name; use clippy_utils::usage::{local_used_after_expr, local_used_in}; use clippy_utils::{get_path_from_caller_to_method_type, is_adjusted, path_to_local, path_to_local_id}; use rustc_errors::Applicability; -use rustc_hir::{BindingAnnotation, Expr, ExprKind, FnRetTy, Param, PatKind, QPath, TyKind, Unsafety}; +use rustc_hir::{BindingMode, Expr, ExprKind, FnRetTy, Param, PatKind, QPath, TyKind, Unsafety}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{ @@ -229,7 +229,7 @@ fn check_inputs( && params.iter().zip(self_arg.into_iter().chain(args)).all(|(p, arg)| { matches!( p.pat.kind, - PatKind::Binding(BindingAnnotation::NONE, id, _, None) + PatKind::Binding(BindingMode::NONE, id, _, None) if path_to_local_id(arg, id) ) // Only allow adjustments which change regions (i.e. re-borrowing). diff --git a/clippy_lints/src/explicit_write.rs b/clippy_lints/src/explicit_write.rs index 33bd5a5a9d3a..724e1843359b 100644 --- a/clippy_lints/src/explicit_write.rs +++ b/clippy_lints/src/explicit_write.rs @@ -4,7 +4,7 @@ use clippy_utils::source::snippet_with_applicability; use clippy_utils::{is_expn_of, path_def_id}; use rustc_errors::Applicability; use rustc_hir::def::Res; -use rustc_hir::{BindingAnnotation, Block, BlockCheckMode, Expr, ExprKind, Node, PatKind, QPath, Stmt, StmtKind}; +use rustc_hir::{BindingMode, Block, BlockCheckMode, Expr, ExprKind, Node, PatKind, QPath, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::{sym, ExpnId}; @@ -114,7 +114,7 @@ fn look_in_block<'tcx, 'hir>(cx: &LateContext<'tcx>, kind: &'tcx ExprKind<'hir>) && let Node::Pat(res_pat) = cx.tcx.hir_node(expr_res) // Find id of the local we found in the block - && let PatKind::Binding(BindingAnnotation::NONE, local_hir_id, _ident, None) = local.pat.kind + && let PatKind::Binding(BindingMode::NONE, local_hir_id, _ident, None) = local.pat.kind // If those two are the same hir id && res_pat.hir_id == local_hir_id diff --git a/clippy_lints/src/index_refutable_slice.rs b/clippy_lints/src/index_refutable_slice.rs index 6ddc8346511d..799ec9d553d4 100644 --- a/clippy_lints/src/index_refutable_slice.rs +++ b/clippy_lints/src/index_refutable_slice.rs @@ -94,7 +94,7 @@ fn find_slice_values(cx: &LateContext<'_>, pat: &hir::Pat<'_>) -> FxIndexMap LateLintPass<'tcx> for LetIfSeq { }; let mutability = match mode { - BindingAnnotation(_, Mutability::Mut) => " ", + BindingMode(_, Mutability::Mut) => " ", _ => "", }; diff --git a/clippy_lints/src/loops/manual_find.rs b/clippy_lints/src/loops/manual_find.rs index d484ce40d785..b27528c11d48 100644 --- a/clippy_lints/src/loops/manual_find.rs +++ b/clippy_lints/src/loops/manual_find.rs @@ -7,7 +7,7 @@ use clippy_utils::{higher, is_res_lang_ctor, path_res, peel_blocks_with_stmt}; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::lang_items::LangItem; -use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Node, Pat, PatKind, Stmt, StmtKind}; +use rustc_hir::{BindingMode, Block, Expr, ExprKind, HirId, Node, Pat, PatKind, Stmt, StmtKind}; use rustc_lint::LateContext; use rustc_span::Span; @@ -107,7 +107,7 @@ fn get_binding(pat: &Pat<'_>) -> Option { hir_id = None; return; } - if let BindingAnnotation::NONE = annotation { + if let BindingMode::NONE = annotation { hir_id = Some(id); } }); diff --git a/clippy_lints/src/loops/mut_range_bound.rs b/clippy_lints/src/loops/mut_range_bound.rs index 94330001e4f1..5047092192f4 100644 --- a/clippy_lints/src/loops/mut_range_bound.rs +++ b/clippy_lints/src/loops/mut_range_bound.rs @@ -2,7 +2,7 @@ use super::MUT_RANGE_BOUND; use clippy_utils::diagnostics::span_lint_and_note; use clippy_utils::{get_enclosing_block, higher, path_to_local}; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{BindingAnnotation, Expr, ExprKind, HirId, Node, PatKind}; +use rustc_hir::{BindingMode, Expr, ExprKind, HirId, Node, PatKind}; use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; @@ -41,7 +41,7 @@ fn mut_warn_with_span(cx: &LateContext<'_>, span: Option) { fn check_for_mutability(cx: &LateContext<'_>, bound: &Expr<'_>) -> Option { if let Some(hir_id) = path_to_local(bound) && let Node::Pat(pat) = cx.tcx.hir_node(hir_id) - && let PatKind::Binding(BindingAnnotation::MUT, ..) = pat.kind + && let PatKind::Binding(BindingMode::MUT, ..) = pat.kind { return Some(hir_id); } diff --git a/clippy_lints/src/loops/same_item_push.rs b/clippy_lints/src/loops/same_item_push.rs index 1d90d4a58f5e..9185cf1f8b2e 100644 --- a/clippy_lints/src/loops/same_item_push.rs +++ b/clippy_lints/src/loops/same_item_push.rs @@ -7,7 +7,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{walk_expr, Visitor}; -use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Mutability, Node, Pat, PatKind, Stmt, StmtKind}; +use rustc_hir::{BindingMode, Block, Expr, ExprKind, HirId, Mutability, Node, Pat, PatKind, Stmt, StmtKind}; use rustc_lint::LateContext; use rustc_span::symbol::sym; use rustc_span::SyntaxContext; @@ -61,7 +61,7 @@ pub(super) fn check<'tcx>( let node = cx.tcx.hir_node(hir_id); if let Node::Pat(pat) = node && let PatKind::Binding(bind_ann, ..) = pat.kind - && !matches!(bind_ann, BindingAnnotation(_, Mutability::Mut)) + && !matches!(bind_ann, BindingMode(_, Mutability::Mut)) && let Node::LetStmt(parent_let_expr) = cx.tcx.parent_hir_node(hir_id) && let Some(init) = parent_let_expr.init { diff --git a/clippy_lints/src/manual_hash_one.rs b/clippy_lints/src/manual_hash_one.rs index f8f33cfc82e9..daa8101aa5ff 100644 --- a/clippy_lints/src/manual_hash_one.rs +++ b/clippy_lints/src/manual_hash_one.rs @@ -4,7 +4,7 @@ use clippy_utils::source::snippet_opt; use clippy_utils::visitors::{is_local_used, local_used_once}; use clippy_utils::{is_trait_method, path_to_local_id}; use rustc_errors::Applicability; -use rustc_hir::{BindingAnnotation, ExprKind, LetStmt, Node, PatKind, StmtKind}; +use rustc_hir::{BindingMode, ExprKind, LetStmt, Node, PatKind, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; use rustc_span::sym; @@ -62,7 +62,7 @@ impl_lint_pass!(ManualHashOne => [MANUAL_HASH_ONE]); impl LateLintPass<'_> for ManualHashOne { fn check_local(&mut self, cx: &LateContext<'_>, local: &LetStmt<'_>) { // `let mut hasher = seg.build_hasher();` - if let PatKind::Binding(BindingAnnotation::MUT, hasher, _, None) = local.pat.kind + if let PatKind::Binding(BindingMode::MUT, hasher, _, None) = local.pat.kind && let Some(init) = local.init && !init.span.from_expansion() && let ExprKind::MethodCall(seg, build_hasher, [], _) = init.kind diff --git a/clippy_lints/src/matches/manual_utils.rs b/clippy_lints/src/matches/manual_utils.rs index 152aba99ce9b..183caab56c59 100644 --- a/clippy_lints/src/matches/manual_utils.rs +++ b/clippy_lints/src/matches/manual_utils.rs @@ -11,7 +11,7 @@ use rustc_ast::util::parser::PREC_POSTFIX; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::LangItem::{OptionNone, OptionSome}; -use rustc_hir::{BindingAnnotation, Expr, ExprKind, HirId, Mutability, Pat, PatKind, Path, QPath}; +use rustc_hir::{BindingMode, Expr, ExprKind, HirId, Mutability, Pat, PatKind, Path, QPath}; use rustc_lint::LateContext; use rustc_span::{sym, SyntaxContext}; @@ -139,7 +139,7 @@ where } // `ref` and `ref mut` annotations were handled earlier. - let annotation = if matches!(annotation, BindingAnnotation::MUT) { + let annotation = if matches!(annotation, BindingMode::MUT) { "mut " } else { "" diff --git a/clippy_lints/src/matches/match_as_ref.rs b/clippy_lints/src/matches/match_as_ref.rs index f5da8ec61874..6c123649afc2 100644 --- a/clippy_lints/src/matches/match_as_ref.rs +++ b/clippy_lints/src/matches/match_as_ref.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::{is_res_lang_ctor, path_res, peel_blocks}; use rustc_errors::Applicability; -use rustc_hir::{Arm, BindingAnnotation, ByRef, Expr, ExprKind, LangItem, Mutability, PatKind, QPath}; +use rustc_hir::{Arm, BindingMode, ByRef, Expr, ExprKind, LangItem, Mutability, PatKind, QPath}; use rustc_lint::LateContext; use rustc_middle::ty; @@ -67,7 +67,7 @@ fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool { fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option { if let PatKind::TupleStruct(ref qpath, [first_pat, ..], _) = arm.pat.kind && is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), LangItem::OptionSome) - && let PatKind::Binding(BindingAnnotation(ByRef::Yes(mutabl), _), .., ident, _) = first_pat.kind + && let PatKind::Binding(BindingMode(ByRef::Yes(mutabl), _), .., ident, _) = first_pat.kind && let ExprKind::Call(e, [arg]) = peel_blocks(arm.body).kind && is_res_lang_ctor(cx, path_res(cx, e), LangItem::OptionSome) && let ExprKind::Path(QPath::Resolved(_, path2)) = arg.kind diff --git a/clippy_lints/src/matches/needless_match.rs b/clippy_lints/src/matches/needless_match.rs index fe83e784c3c9..6f7d69026404 100644 --- a/clippy_lints/src/matches/needless_match.rs +++ b/clippy_lints/src/matches/needless_match.rs @@ -8,7 +8,7 @@ use clippy_utils::{ }; use rustc_errors::Applicability; use rustc_hir::LangItem::OptionNone; -use rustc_hir::{Arm, BindingAnnotation, ByRef, Expr, ExprKind, ItemKind, Node, Pat, PatKind, Path, QPath}; +use rustc_hir::{Arm, BindingMode, ByRef, Expr, ExprKind, ItemKind, Node, Pat, PatKind, Path, QPath}; use rustc_lint::LateContext; use rustc_span::sym; @@ -178,7 +178,7 @@ fn pat_same_as_expr(pat: &Pat<'_>, expr: &Expr<'_>) -> bool { }, )), ) => { - return !matches!(annot, BindingAnnotation(ByRef::Yes(_), _)) && pat_ident.name == first_seg.ident.name; + return !matches!(annot, BindingMode(ByRef::Yes(_), _)) && pat_ident.name == first_seg.ident.name; }, // Example: `Custom::TypeA => Custom::TypeB`, or `None => None` (PatKind::Path(QPath::Resolved(_, p_path)), ExprKind::Path(QPath::Resolved(_, e_path))) => { diff --git a/clippy_lints/src/matches/single_match.rs b/clippy_lints/src/matches/single_match.rs index a0db8e2db1f8..37f72528140f 100644 --- a/clippy_lints/src/matches/single_match.rs +++ b/clippy_lints/src/matches/single_match.rs @@ -4,7 +4,7 @@ use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, peel_mid_ty_re use clippy_utils::{is_lint_allowed, is_unit_expr, is_wild, peel_blocks, peel_hir_pat_refs, peel_n_hir_expr_refs}; use core::cmp::max; use rustc_errors::Applicability; -use rustc_hir::{Arm, BindingAnnotation, Block, Expr, ExprKind, Pat, PatKind}; +use rustc_hir::{Arm, BindingMode, Block, Expr, ExprKind, Pat, PatKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; use rustc_span::{sym, Span}; @@ -166,7 +166,7 @@ fn collect_pat_paths<'a>(acc: &mut Vec>, cx: &LateContext<'a>, pat: &Pat< let p_ty = cx.typeck_results().pat_ty(p); collect_pat_paths(acc, cx, p, p_ty); }), - PatKind::TupleStruct(..) | PatKind::Binding(BindingAnnotation::NONE, .., None) | PatKind::Path(_) => { + PatKind::TupleStruct(..) | PatKind::Binding(BindingMode::NONE, .., None) | PatKind::Path(_) => { acc.push(ty); }, _ => {}, diff --git a/clippy_lints/src/methods/clone_on_copy.rs b/clippy_lints/src/methods/clone_on_copy.rs index 4e6823e8220b..e7a2060be046 100644 --- a/clippy_lints/src/methods/clone_on_copy.rs +++ b/clippy_lints/src/methods/clone_on_copy.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::is_copy; use rustc_errors::Applicability; -use rustc_hir::{BindingAnnotation, ByRef, Expr, ExprKind, MatchSource, Node, PatKind, QPath}; +use rustc_hir::{BindingMode, ByRef, Expr, ExprKind, MatchSource, Node, PatKind, QPath}; use rustc_lint::LateContext; use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::print::with_forced_trimmed_paths; @@ -69,7 +69,7 @@ pub(super) fn check( _ => false, }, // local binding capturing a reference - Node::LetStmt(l) if matches!(l.pat.kind, PatKind::Binding(BindingAnnotation(ByRef::Yes(_), _), ..)) => { + Node::LetStmt(l) if matches!(l.pat.kind, PatKind::Binding(BindingMode(ByRef::Yes(_), _), ..)) => { return; }, _ => false, diff --git a/clippy_lints/src/methods/filter_next.rs b/clippy_lints/src/methods/filter_next.rs index 7339362193e5..e697ba656f5f 100644 --- a/clippy_lints/src/methods/filter_next.rs +++ b/clippy_lints/src/methods/filter_next.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::source::snippet; use clippy_utils::ty::implements_trait; -use rustc_ast::{BindingAnnotation, Mutability}; +use rustc_ast::{BindingMode, Mutability}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -45,7 +45,7 @@ pub(super) fn check<'tcx>( span_lint_and_then(cx, FILTER_NEXT, expr.span, msg, |diag| { let (applicability, pat) = if let Some(id) = path_to_local(recv) && let hir::Node::Pat(pat) = cx.tcx.hir_node(id) - && let hir::PatKind::Binding(BindingAnnotation(_, Mutability::Not), _, ident, _) = pat.kind + && let hir::PatKind::Binding(BindingMode(_, Mutability::Not), _, ident, _) = pat.kind { (Applicability::Unspecified, Some((pat.span, ident))) } else { diff --git a/clippy_lints/src/methods/iter_kv_map.rs b/clippy_lints/src/methods/iter_kv_map.rs index b9fec0c4f80a..7c852a3768d1 100644 --- a/clippy_lints/src/methods/iter_kv_map.rs +++ b/clippy_lints/src/methods/iter_kv_map.rs @@ -6,7 +6,7 @@ use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_sugg, span_lint_an use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{pat_is_wild, sugg}; -use rustc_hir::{BindingAnnotation, Body, BorrowKind, ByRef, Expr, ExprKind, Mutability, Pat, PatKind}; +use rustc_hir::{BindingMode, Body, BorrowKind, ByRef, Expr, ExprKind, Mutability, Pat, PatKind}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty; use rustc_span::{sym, Span}; diff --git a/clippy_lints/src/methods/iter_overeager_cloned.rs b/clippy_lints/src/methods/iter_overeager_cloned.rs index 4729481320eb..6d70989546a2 100644 --- a/clippy_lints/src/methods/iter_overeager_cloned.rs +++ b/clippy_lints/src/methods/iter_overeager_cloned.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_opt; use clippy_utils::ty::{implements_trait, is_copy}; -use rustc_ast::BindingAnnotation; +use rustc_ast::BindingMode; use rustc_errors::Applicability; use rustc_hir::{Body, Expr, ExprKind, HirId, HirIdSet, PatKind}; use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; @@ -89,7 +89,7 @@ pub(super) fn check<'tcx>( } match it.kind { - PatKind::Binding(BindingAnnotation(_, Mutability::Mut), _, _, _) + PatKind::Binding(BindingMode(_, Mutability::Mut), _, _, _) | PatKind::Ref(_, Mutability::Mut) => { to_be_discarded = true; false diff --git a/clippy_lints/src/methods/iter_skip_next.rs b/clippy_lints/src/methods/iter_skip_next.rs index d1215290dada..fedb7c22eded 100644 --- a/clippy_lints/src/methods/iter_skip_next.rs +++ b/clippy_lints/src/methods/iter_skip_next.rs @@ -3,7 +3,7 @@ use clippy_utils::source::snippet; use clippy_utils::{is_trait_method, path_to_local}; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::{BindingAnnotation, Node, PatKind}; +use rustc_hir::{BindingMode, Node, PatKind}; use rustc_lint::LateContext; use rustc_span::sym; @@ -22,7 +22,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr if let Some(id) = path_to_local(recv) && let Node::Pat(pat) = cx.tcx.hir_node(id) && let PatKind::Binding(ann, _, _, _) = pat.kind - && ann != BindingAnnotation::MUT + && ann != BindingMode::MUT { application = Applicability::Unspecified; diag.span_help( diff --git a/clippy_lints/src/methods/map_clone.rs b/clippy_lints/src/methods/map_clone.rs index 0901268e9bdc..a5ba5e5d8918 100644 --- a/clippy_lints/src/methods/map_clone.rs +++ b/clippy_lints/src/methods/map_clone.rs @@ -51,13 +51,13 @@ pub(super) fn check(cx: &LateContext<'_>, e: &hir::Expr<'_>, recv: &hir::Expr<'_ let closure_expr = peel_blocks(closure_body.value); match closure_body.params[0].pat.kind { hir::PatKind::Ref(inner, Mutability::Not) => { - if let hir::PatKind::Binding(hir::BindingAnnotation::NONE, .., name, None) = inner.kind { + if let hir::PatKind::Binding(hir::BindingMode::NONE, .., name, None) = inner.kind { if ident_eq(name, closure_expr) { lint_explicit_closure(cx, e.span, recv.span, true, msrv); } } }, - hir::PatKind::Binding(hir::BindingAnnotation::NONE, .., name, None) => { + hir::PatKind::Binding(hir::BindingMode::NONE, .., name, None) => { match closure_expr.kind { hir::ExprKind::Unary(hir::UnOp::Deref, inner) => { if ident_eq(name, inner) { diff --git a/clippy_lints/src/methods/needless_collect.rs b/clippy_lints/src/methods/needless_collect.rs index 662e7746496a..1c695655536c 100644 --- a/clippy_lints/src/methods/needless_collect.rs +++ b/clippy_lints/src/methods/needless_collect.rs @@ -11,7 +11,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, MultiSpan}; use rustc_hir::intravisit::{walk_block, walk_expr, Visitor}; use rustc_hir::{ - BindingAnnotation, Block, Expr, ExprKind, HirId, HirIdSet, LetStmt, Mutability, Node, PatKind, Stmt, StmtKind, + BindingMode, Block, Expr, ExprKind, HirId, HirIdSet, LetStmt, Mutability, Node, PatKind, Stmt, StmtKind, }; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; @@ -86,7 +86,7 @@ pub(super) fn check<'tcx>( } }, Node::LetStmt(l) => { - if let PatKind::Binding(BindingAnnotation::NONE | BindingAnnotation::MUT, id, _, None) = l.pat.kind + if let PatKind::Binding(BindingMode::NONE | BindingMode::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() diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs index 55ae9746298f..e8c12bbeea0e 100644 --- a/clippy_lints/src/methods/str_splitn.rs +++ b/clippy_lints/src/methods/str_splitn.rs @@ -8,7 +8,7 @@ use clippy_utils::{is_diag_item_method, match_def_path, path_to_local_id, paths} use core::ops::ControlFlow; use rustc_errors::Applicability; use rustc_hir::{ - BindingAnnotation, Expr, ExprKind, HirId, LangItem, LetStmt, MatchSource, Node, Pat, PatKind, QPath, Stmt, StmtKind, + BindingMode, Expr, ExprKind, HirId, LangItem, LetStmt, MatchSource, Node, Pat, PatKind, QPath, Stmt, StmtKind, }; use rustc_lint::LateContext; use rustc_middle::ty; @@ -129,7 +129,7 @@ fn check_manual_split_once_indirect( let ctxt = expr.span.ctxt(); let mut parents = cx.tcx.hir().parent_iter(expr.hir_id); if let (_, Node::LetStmt(local)) = parents.next()? - && let PatKind::Binding(BindingAnnotation::MUT, iter_binding_id, iter_ident, None) = local.pat.kind + && let PatKind::Binding(BindingMode::MUT, iter_binding_id, iter_ident, None) = local.pat.kind && let (iter_stmt_id, Node::Stmt(_)) = parents.next()? && let (_, Node::Block(enclosing_block)) = parents.next()? && let mut stmts = enclosing_block @@ -200,7 +200,7 @@ fn indirect_usage<'tcx>( ) -> Option> { if let StmtKind::Let(&LetStmt { pat: Pat { - kind: PatKind::Binding(BindingAnnotation::NONE, _, ident, None), + kind: PatKind::Binding(BindingMode::NONE, _, ident, None), .. }, init: Some(init_expr), diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 3cf054e72071..f3f9bf11a61c 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -9,7 +9,7 @@ use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::intravisit::FnKind; use rustc_hir::{ - BinOpKind, BindingAnnotation, Body, ByRef, Expr, ExprKind, FnDecl, Mutability, PatKind, QPath, Stmt, StmtKind, + BinOpKind, BindingMode, Body, ByRef, Expr, ExprKind, FnDecl, Mutability, PatKind, QPath, Stmt, StmtKind, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; @@ -129,7 +129,7 @@ impl<'tcx> LateLintPass<'tcx> for LintPass { if !is_lint_allowed(cx, REF_PATTERNS, arg.pat.hir_id) { return; } - if let PatKind::Binding(BindingAnnotation(ByRef::Yes(_), _), ..) = arg.pat.kind { + if let PatKind::Binding(BindingMode(ByRef::Yes(_), _), ..) = arg.pat.kind { span_lint( cx, TOPLEVEL_REF_ARG, @@ -144,7 +144,7 @@ impl<'tcx> LateLintPass<'tcx> for LintPass { fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { if !in_external_macro(cx.tcx.sess, stmt.span) && let StmtKind::Let(local) = stmt.kind - && let PatKind::Binding(BindingAnnotation(ByRef::Yes(mutabl), _), .., name, None) = local.pat.kind + && let PatKind::Binding(BindingMode(ByRef::Yes(mutabl), _), .., name, None) = local.pat.kind && let Some(init) = local.init // Do not emit if clippy::ref_patterns is not allowed to avoid having two lints for the same issue. && is_lint_allowed(cx, REF_PATTERNS, local.pat.hir_id) diff --git a/clippy_lints/src/needless_arbitrary_self_type.rs b/clippy_lints/src/needless_arbitrary_self_type.rs index 2ab83f733cb1..60c44382059a 100644 --- a/clippy_lints/src/needless_arbitrary_self_type.rs +++ b/clippy_lints/src/needless_arbitrary_self_type.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use rustc_ast::ast::{BindingAnnotation, ByRef, Lifetime, Mutability, Param, PatKind, Path, TyKind}; +use rustc_ast::ast::{BindingMode, ByRef, Lifetime, Mutability, Param, PatKind, Path, TyKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::declare_lint_pass; @@ -117,13 +117,13 @@ impl EarlyLintPass for NeedlessArbitrarySelfType { match &p.ty.kind { TyKind::Path(None, path) => { - if let PatKind::Ident(BindingAnnotation(ByRef::No, mutbl), _, _) = p.pat.kind { + if let PatKind::Ident(BindingMode(ByRef::No, mutbl), _, _) = p.pat.kind { check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Value, mutbl); } }, TyKind::Ref(lifetime, mut_ty) => { if let TyKind::Path(None, path) = &mut_ty.ty.kind - && let PatKind::Ident(BindingAnnotation::NONE, _, _) = p.pat.kind + && let PatKind::Ident(BindingMode::NONE, _, _) = p.pat.kind { check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Ref(*lifetime), mut_ty.mutbl); } diff --git a/clippy_lints/src/needless_borrowed_ref.rs b/clippy_lints/src/needless_borrowed_ref.rs index d91329eadcb4..fb02f24c9dc6 100644 --- a/clippy_lints/src/needless_borrowed_ref.rs +++ b/clippy_lints/src/needless_borrowed_ref.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use rustc_errors::Applicability; -use rustc_hir::{BindingAnnotation, Mutability, Node, Pat, PatKind}; +use rustc_hir::{BindingMode, Mutability, Node, Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -58,7 +58,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowedRef { match pat.kind { // Check sub_pat got a `ref` keyword (excluding `ref mut`). - PatKind::Binding(BindingAnnotation::REF, _, ident, None) => { + PatKind::Binding(BindingMode::REF, _, ident, None) => { span_lint_and_then( cx, NEEDLESS_BORROWED_REFERENCE, @@ -128,7 +128,7 @@ fn check_subpatterns<'tcx>( for subpattern in subpatterns { match subpattern.kind { - PatKind::Binding(BindingAnnotation::REF, _, ident, None) => { + PatKind::Binding(BindingMode::REF, _, ident, None) => { // `ref ident` // ^^^^ let span = subpattern.span.until(ident.span); diff --git a/clippy_lints/src/needless_late_init.rs b/clippy_lints/src/needless_late_init.rs index 810799acb2e2..0c0b1a73351f 100644 --- a/clippy_lints/src/needless_late_init.rs +++ b/clippy_lints/src/needless_late_init.rs @@ -6,7 +6,7 @@ use clippy_utils::visitors::{for_each_expr, for_each_expr_with_closures, is_loca use core::ops::ControlFlow; use rustc_errors::{Applicability, MultiSpan}; use rustc_hir::{ - BindingAnnotation, Block, Expr, ExprKind, HirId, LetStmt, LocalSource, MatchSource, Node, Pat, PatKind, Stmt, + BindingMode, Block, Expr, ExprKind, HirId, LetStmt, LocalSource, MatchSource, Node, Pat, PatKind, Stmt, StmtKind, }; use rustc_lint::{LateContext, LateLintPass}; @@ -369,7 +369,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessLateInit { init: None, pat: &Pat { - kind: PatKind::Binding(BindingAnnotation::NONE, binding_id, _, None), + kind: PatKind::Binding(BindingMode::NONE, binding_id, _, None), .. }, source: LocalSource::Normal, diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index f33e2e0ed71a..53bcde680876 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -9,7 +9,7 @@ use rustc_ast::ast::Attribute; use rustc_errors::{Applicability, Diag}; use rustc_hir::intravisit::FnKind; use rustc_hir::{ - BindingAnnotation, Body, FnDecl, GenericArg, HirId, HirIdSet, Impl, ItemKind, LangItem, Mutability, Node, PatKind, + BindingMode, Body, FnDecl, GenericArg, HirId, HirIdSet, Impl, ItemKind, LangItem, Mutability, Node, PatKind, QPath, TyKind, }; use rustc_hir_typeck::expr_use_visitor as euv; @@ -192,7 +192,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { }) && !implements_borrow_trait && !all_borrowable_trait - && let PatKind::Binding(BindingAnnotation(_, Mutability::Not), canonical_id, ..) = arg.pat.kind + && let PatKind::Binding(BindingMode(_, Mutability::Not), canonical_id, ..) = arg.pat.kind && !moved_vars.contains(&canonical_id) { // Dereference suggestion diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index 3cbd03a58c55..d4906328ccb9 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -7,7 +7,7 @@ use clippy_utils::{ use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk}; -use rustc_hir::{Arm, BindingAnnotation, Expr, ExprKind, MatchSource, Mutability, Pat, PatKind, Path, QPath, UnOp}; +use rustc_hir::{Arm, BindingMode, Expr, ExprKind, MatchSource, Mutability, Pat, PatKind, Path, QPath, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::SyntaxContext; @@ -129,7 +129,7 @@ fn try_get_option_occurrence<'tcx>( .filter_map(|(id, &c)| none_captures.get(id).map(|&c2| (c, c2))) .all(|(x, y)| x.is_imm_ref() && y.is_imm_ref()) { - let capture_mut = if bind_annotation == BindingAnnotation::MUT { + let capture_mut = if bind_annotation == BindingMode::MUT { "mut " } else { "" @@ -149,8 +149,8 @@ fn try_get_option_occurrence<'tcx>( (mutb == Mutability::Not, mutb == Mutability::Mut) }, _ => ( - bind_annotation == BindingAnnotation::REF, - bind_annotation == BindingAnnotation::REF_MUT, + bind_annotation == BindingMode::REF, + bind_annotation == BindingMode::REF_MUT, ), }; diff --git a/clippy_lints/src/pass_by_ref_or_value.rs b/clippy_lints/src/pass_by_ref_or_value.rs index bb4a1de9f77d..128bfd49d9e5 100644 --- a/clippy_lints/src/pass_by_ref_or_value.rs +++ b/clippy_lints/src/pass_by_ref_or_value.rs @@ -10,7 +10,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::intravisit::FnKind; -use rustc_hir::{BindingAnnotation, Body, FnDecl, Impl, ItemKind, MutTy, Mutability, Node, PatKind}; +use rustc_hir::{BindingMode, Body, FnDecl, Impl, ItemKind, MutTy, Mutability, Node, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::adjustment::{Adjust, PointerCoercion}; use rustc_middle::ty::layout::LayoutOf; @@ -221,7 +221,7 @@ impl<'tcx> PassByRefOrValue { // if function has a body and parameter is annotated with mut, ignore if let Some(param) = fn_body.and_then(|body| body.params.get(index)) { match param.pat.kind { - PatKind::Binding(BindingAnnotation::NONE, _, _, _) => {}, + PatKind::Binding(BindingMode::NONE, _, _, _) => {}, _ => continue, } } diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index d6592622f0bb..cc61ef9184cd 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -11,7 +11,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::hir_id::{HirId, HirIdMap}; use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{ - self as hir, AnonConst, BinOpKind, BindingAnnotation, Body, Expr, ExprKind, FnRetTy, FnSig, GenericArg, + self as hir, AnonConst, BinOpKind, BindingMode, Body, Expr, ExprKind, FnRetTy, FnSig, GenericArg, ImplItemKind, ItemKind, Lifetime, Mutability, Node, Param, PatKind, QPath, TraitFn, TraitItem, TraitItemKind, TyKind, Unsafety, }; @@ -606,7 +606,7 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args: Some((Node::Stmt(_), _)) => (), Some((Node::LetStmt(l), _)) => { // Only trace simple bindings. e.g `let x = y;` - if let PatKind::Binding(BindingAnnotation::NONE, id, _, None) = l.pat.kind { + if let PatKind::Binding(BindingMode::NONE, id, _, None) = l.pat.kind { self.bindings.insert(id, args_idx); } else { set_skip_flag(); @@ -687,7 +687,7 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args: .filter_map(|(i, arg)| { let param = &body.params[arg.idx]; match param.pat.kind { - PatKind::Binding(BindingAnnotation::NONE, id, _, None) + PatKind::Binding(BindingMode::NONE, id, _, None) if !is_lint_allowed(cx, PTR_ARG, param.hir_id) => { Some((id, i)) diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index 927c6f1d519e..4ad967589a54 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -14,7 +14,7 @@ use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::LangItem::{self, OptionNone, OptionSome, ResultErr, ResultOk}; use rustc_hir::{ - BindingAnnotation, Block, Body, ByRef, Expr, ExprKind, LetStmt, Mutability, Node, PatKind, PathSegment, QPath, + BindingMode, Block, Body, ByRef, Expr, ExprKind, LetStmt, Mutability, Node, PatKind, PathSegment, QPath, Stmt, StmtKind, }; use rustc_lint::{LateContext, LateLintPass}; @@ -283,7 +283,7 @@ fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: && !is_else_clause(cx.tcx, expr) && let PatKind::TupleStruct(ref path1, [field], ddpos) = let_pat.kind && ddpos.as_opt_usize().is_none() - && let PatKind::Binding(BindingAnnotation(by_ref, _), bind_id, ident, None) = field.kind + && let PatKind::Binding(BindingMode(by_ref, _), bind_id, ident, None) = field.kind && let caller_ty = cx.typeck_results().expr_ty(let_expr) && let if_block = IfBlockType::IfLet( cx.qpath_res(path1, let_pat.hir_id), diff --git a/clippy_lints/src/redundant_locals.rs b/clippy_lints/src/redundant_locals.rs index 7202266deeb2..d94ca5bc7ec2 100644 --- a/clippy_lints/src/redundant_locals.rs +++ b/clippy_lints/src/redundant_locals.rs @@ -3,7 +3,7 @@ use clippy_utils::is_from_proc_macro; use clippy_utils::ty::needs_ordered_drop; use rustc_ast::Mutability; use rustc_hir::def::Res; -use rustc_hir::{BindingAnnotation, ByRef, ExprKind, HirId, LetStmt, Node, Pat, PatKind, QPath}; +use rustc_hir::{BindingMode, ByRef, ExprKind, HirId, LetStmt, Node, Pat, PatKind, QPath}; use rustc_hir_typeck::expr_use_visitor::PlaceBase; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; @@ -50,7 +50,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantLocals { fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) { if !local.span.is_desugaring(DesugaringKind::Async) // the pattern is a single by-value binding - && let PatKind::Binding(BindingAnnotation(ByRef::No, mutability), _, ident, None) = local.pat.kind + && let PatKind::Binding(BindingMode(ByRef::No, mutability), _, ident, None) = local.pat.kind // the binding is not type-ascribed && local.ty.is_none() // the expression is a resolved path @@ -109,7 +109,7 @@ fn is_by_value_closure_capture(cx: &LateContext<'_>, redefinition: HirId, root_v } /// Find the annotation of a binding introduced by a pattern, or `None` if it's not introduced. -fn find_binding(pat: &Pat<'_>, name: Ident) -> Option { +fn find_binding(pat: &Pat<'_>, name: Ident) -> Option { let mut ret = None; pat.each_binding_or_first(&mut |annotation, _, _, ident| { diff --git a/clippy_lints/src/ref_patterns.rs b/clippy_lints/src/ref_patterns.rs index a4be78b310b4..607a0740b843 100644 --- a/clippy_lints/src/ref_patterns.rs +++ b/clippy_lints/src/ref_patterns.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_help; -use rustc_ast::ast::{BindingAnnotation, Pat, PatKind}; +use rustc_ast::ast::{BindingMode, Pat, PatKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::declare_lint_pass; @@ -28,7 +28,7 @@ declare_lint_pass!(RefPatterns => [REF_PATTERNS]); impl EarlyLintPass for RefPatterns { fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &Pat) { - if let PatKind::Ident(BindingAnnotation::REF, _, _) = pat.kind + if let PatKind::Ident(BindingMode::REF, _, _) = pat.kind && !pat.span.from_expansion() { span_lint_and_help( diff --git a/clippy_lints/src/reserve_after_initialization.rs b/clippy_lints/src/reserve_after_initialization.rs index c227b5b22f4d..caf3fb8707da 100644 --- a/clippy_lints/src/reserve_after_initialization.rs +++ b/clippy_lints/src/reserve_after_initialization.rs @@ -4,7 +4,7 @@ use clippy_utils::source::snippet; use clippy_utils::{is_from_proc_macro, path_to_local_id}; use rustc_errors::Applicability; use rustc_hir::def::Res; -use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, LetStmt, PatKind, QPath, Stmt, StmtKind}; +use rustc_hir::{BindingMode, Block, Expr, ExprKind, HirId, LetStmt, PatKind, QPath, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; @@ -71,7 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization { fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) { if let Some(init_expr) = local.init - && let PatKind::Binding(BindingAnnotation::MUT, id, _, None) = local.pat.kind + && let PatKind::Binding(BindingMode::MUT, id, _, None) = local.pat.kind && !in_external_macro(cx.sess(), local.span) && let Some(init) = get_vec_init_kind(cx, init_expr) && !matches!( diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index 8a9f02b6dcb1..28c254537abd 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -7,7 +7,7 @@ use clippy_utils::{ }; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_block, walk_expr, walk_stmt, Visitor}; -use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, PatKind, Stmt, StmtKind}; +use rustc_hir::{BindingMode, Block, Expr, ExprKind, HirId, PatKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; @@ -120,7 +120,7 @@ impl<'tcx> LateLintPass<'tcx> for SlowVectorInit { // Matches statements which initializes vectors. For example: `let mut vec = Vec::with_capacity(10)` // or `Vec::new()` if let StmtKind::Let(local) = stmt.kind - && let PatKind::Binding(BindingAnnotation::MUT, local_id, _, None) = local.pat.kind + && let PatKind::Binding(BindingMode::MUT, local_id, _, None) = local.pat.kind && let Some(init) = local.init && let Some(size_expr) = Self::as_vec_initializer(cx, init) { diff --git a/clippy_lints/src/unnecessary_struct_initialization.rs b/clippy_lints/src/unnecessary_struct_initialization.rs index 333ea0c82df6..2da753343448 100644 --- a/clippy_lints/src/unnecessary_struct_initialization.rs +++ b/clippy_lints/src/unnecessary_struct_initialization.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::ty::is_copy; use clippy_utils::{get_parent_expr, path_to_local}; -use rustc_hir::{BindingAnnotation, Expr, ExprKind, Node, PatKind, UnOp}; +use rustc_hir::{BindingMode, Expr, ExprKind, Node, PatKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -84,7 +84,7 @@ fn is_mutable(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { if let Some(hir_id) = path_to_local(expr) && let Node::Pat(pat) = cx.tcx.hir_node(hir_id) { - matches!(pat.kind, PatKind::Binding(BindingAnnotation::MUT, ..)) + matches!(pat.kind, PatKind::Binding(BindingMode::MUT, ..)) } else { true } diff --git a/clippy_lints/src/unnested_or_patterns.rs b/clippy_lints/src/unnested_or_patterns.rs index 0049de931f4f..fcc41b51542f 100644 --- a/clippy_lints/src/unnested_or_patterns.rs +++ b/clippy_lints/src/unnested_or_patterns.rs @@ -137,12 +137,12 @@ fn insert_necessary_parens(pat: &mut P) { struct Visitor; impl MutVisitor for Visitor { fn visit_pat(&mut self, pat: &mut P) { - use ast::BindingAnnotation; + use ast::BindingMode; noop_visit_pat(pat, self); let target = match &mut pat.kind { // `i @ a | b`, `box a | b`, and `& mut? a | b`. Ident(.., Some(p)) | Box(p) | Ref(p, _) if matches!(&p.kind, Or(ps) if ps.len() > 1) => p, - Ref(p, Mutability::Not) if matches!(p.kind, Ident(BindingAnnotation::MUT, ..)) => p, // `&(mut x)` + Ref(p, Mutability::Not) if matches!(p.kind, Ident(BindingMode::MUT, ..)) => p, // `&(mut x)` _ => return, }; target.kind = Paren(P(take_pat(target))); diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index 755417661565..2f7d54e73ed7 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -5,7 +5,7 @@ use clippy_utils::ty::{is_copy, is_type_diagnostic_item, same_type_and_consts}; use clippy_utils::{get_parent_expr, is_trait_method, is_ty_alias, path_to_local}; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; -use rustc_hir::{BindingAnnotation, Expr, ExprKind, HirId, MatchSource, Node, PatKind}; +use rustc_hir::{BindingMode, Expr, ExprKind, HirId, MatchSource, Node, PatKind}; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::Obligation; use rustc_lint::{LateContext, LateLintPass}; @@ -282,7 +282,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { if let Some(id) = path_to_local(recv) && let Node::Pat(pat) = cx.tcx.hir_node(id) && let PatKind::Binding(ann, ..) = pat.kind - && ann != BindingAnnotation::MUT + && ann != BindingMode::MUT { // Do not remove .into_iter() applied to a non-mutable local variable used in // a larger expression context as it would differ in mutability. diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index 7b43abeef671..7f0769452c73 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -7,7 +7,7 @@ use rustc_ast::LitIntType; use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; use rustc_hir::{ - ArrayLen, BindingAnnotation, CaptureBy, Closure, ClosureKind, CoroutineKind, ExprKind, FnRetTy, HirId, Lit, + ArrayLen, BindingMode, CaptureBy, Closure, ClosureKind, CoroutineKind, ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -645,14 +645,14 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { bind!(self, name); opt_bind!(self, sub); let ann = match ann { - BindingAnnotation::NONE => "NONE", - BindingAnnotation::REF => "REF", - BindingAnnotation::MUT => "MUT", - BindingAnnotation::REF_MUT => "REF_MUT", - BindingAnnotation::MUT_REF => "MUT_REF", - BindingAnnotation::MUT_REF_MUT => "MUT_REF_MUT", + BindingMode::NONE => "NONE", + BindingMode::REF => "REF", + BindingMode::MUT => "MUT", + BindingMode::REF_MUT => "REF_MUT", + BindingMode::MUT_REF => "MUT_REF", + BindingMode::MUT_REF_MUT => "MUT_REF_MUT", }; - kind!("Binding(BindingAnnotation::{ann}, _, {name}, {sub})"); + kind!("Binding(BindingMode::{ann}, _, {name}, {sub})"); self.ident(name); sub.if_some(|p| self.pat(p)); }, diff --git a/clippy_lints/src/vec_init_then_push.rs b/clippy_lints/src/vec_init_then_push.rs index b58a4fb84746..c46f0298cc8b 100644 --- a/clippy_lints/src/vec_init_then_push.rs +++ b/clippy_lints/src/vec_init_then_push.rs @@ -7,7 +7,7 @@ use core::ops::ControlFlow; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::{ - BindingAnnotation, Block, Expr, ExprKind, HirId, LetStmt, Mutability, PatKind, QPath, Stmt, StmtKind, UnOp, + BindingMode, Block, Expr, ExprKind, HirId, LetStmt, Mutability, PatKind, QPath, Stmt, StmtKind, UnOp, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; @@ -159,7 +159,7 @@ impl<'tcx> LateLintPass<'tcx> for VecInitThenPush { fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) { if let Some(init_expr) = local.init - && let PatKind::Binding(BindingAnnotation::MUT, id, name, None) = local.pat.kind + && let PatKind::Binding(BindingMode::MUT, id, name, None) = local.pat.kind && !in_external_macro(cx.sess(), local.span) && let Some(init) = get_vec_init_kind(cx, init_expr) && !matches!(init, VecInitKind::WithExprCapacity(_)) diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index 6c3d93299322..07c443acb05f 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -7,7 +7,7 @@ use rustc_data_structures::fx::FxHasher; use rustc_hir::def::Res; use rustc_hir::MatchSource::TryDesugar; use rustc_hir::{ - ArrayLen, BinOpKind, BindingAnnotation, Block, BodyId, Closure, Expr, ExprField, ExprKind, FnRetTy, GenericArg, + ArrayLen, BinOpKind, BindingMode, Block, BodyId, Closure, Expr, ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime, LifetimeName, Pat, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, Ty, TyKind, TypeBinding, }; @@ -947,7 +947,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { pub fn hash_pat(&mut self, pat: &Pat<'_>) { std::mem::discriminant(&pat.kind).hash(&mut self.s); match pat.kind { - PatKind::Binding(BindingAnnotation(by_ref, mutability), _, _, pat) => { + PatKind::Binding(BindingMode(by_ref, mutability), _, _, pat) => { std::mem::discriminant(&by_ref).hash(&mut self.s); std::mem::discriminant(&mutability).hash(&mut self.s); if let Some(pat) = pat { diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 37c12dd850c2..aac699eed239 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -99,7 +99,7 @@ use rustc_hir::hir_id::{HirIdMap, HirIdSet}; use rustc_hir::intravisit::{walk_expr, FnKind, Visitor}; use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk}; use rustc_hir::{ - self as hir, def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, ByRef, Closure, Destination, Expr, + self as hir, def, Arm, ArrayLen, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp, @@ -184,7 +184,7 @@ pub fn expr_or_init<'a, 'b, 'tcx: 'b>(cx: &LateContext<'tcx>, mut expr: &'a Expr /// canonical binding `HirId`. pub fn find_binding_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Expr<'tcx>> { if let Node::Pat(pat) = cx.tcx.hir_node(hir_id) - && matches!(pat.kind, PatKind::Binding(BindingAnnotation::NONE, ..)) + && matches!(pat.kind, PatKind::Binding(BindingMode::NONE, ..)) && let Node::LetStmt(local) = cx.tcx.parent_hir_node(hir_id) { return local.init; diff --git a/tests/ui/author.stdout b/tests/ui/author.stdout index 27ad538f24d8..d448db097a7e 100644 --- a/tests/ui/author.stdout +++ b/tests/ui/author.stdout @@ -5,7 +5,7 @@ if let StmtKind::Local(local) = stmt.kind && match_qpath(qpath, &["char"]) && let ExprKind::Lit(ref lit) = expr.kind && let LitKind::Int(69, LitIntType::Unsuffixed) = lit.node - && let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = local.pat.kind + && let PatKind::Binding(BindingMode::NONE, _, name, None) = local.pat.kind && name.as_str() == "x" { // report your lint here diff --git a/tests/ui/author/blocks.stdout b/tests/ui/author/blocks.stdout index 579f137f861e..80b928dd6cb5 100644 --- a/tests/ui/author/blocks.stdout +++ b/tests/ui/author/blocks.stdout @@ -4,13 +4,13 @@ if let ExprKind::Block(block, None) = expr.kind && let Some(init) = local.init && let ExprKind::Lit(ref lit) = init.kind && let LitKind::Int(42, LitIntType::Signed(IntTy::I32)) = lit.node - && let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = local.pat.kind + && let PatKind::Binding(BindingMode::NONE, _, name, None) = local.pat.kind && name.as_str() == "x" && let StmtKind::Local(local1) = block.stmts[1].kind && let Some(init1) = local1.init && let ExprKind::Lit(ref lit1) = init1.kind && let LitKind::Float(_, LitFloatType::Suffixed(FloatTy::F32)) = lit1.node - && let PatKind::Binding(BindingAnnotation::NONE, _, name1, None) = local1.pat.kind + && let PatKind::Binding(BindingMode::NONE, _, name1, None) = local1.pat.kind && name1.as_str() == "_t" && let StmtKind::Semi(e) = block.stmts[2].kind && let ExprKind::Unary(UnOp::Neg, inner) = e.kind @@ -28,7 +28,7 @@ if let ExprKind::Block(block, None) = expr.kind && let ExprKind::Path(ref qpath) = func.kind && match_qpath(qpath, &["String", "new"]) && args.is_empty() - && let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = local.pat.kind + && let PatKind::Binding(BindingMode::NONE, _, name, None) = local.pat.kind && name.as_str() == "expr" && let Some(trailing_expr) = block.expr && let ExprKind::Call(func1, args1) = trailing_expr.kind diff --git a/tests/ui/author/loop.stdout b/tests/ui/author/loop.stdout index 94a6436ed547..631105a2238d 100644 --- a/tests/ui/author/loop.stdout +++ b/tests/ui/author/loop.stdout @@ -1,5 +1,5 @@ if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::ForLoop::hir(expr) - && let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = pat.kind + && let PatKind::Binding(BindingMode::NONE, _, name, None) = pat.kind && name.as_str() == "y" && let ExprKind::Struct(qpath, fields, None) = arg.kind && matches!(qpath, QPath::LangItem(LangItem::Range, _)) @@ -16,7 +16,7 @@ if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::Fo && let Some(init) = local.init && let ExprKind::Path(ref qpath1) = init.kind && match_qpath(qpath1, &["y"]) - && let PatKind::Binding(BindingAnnotation::NONE, _, name1, None) = local.pat.kind + && let PatKind::Binding(BindingMode::NONE, _, name1, None) = local.pat.kind && name1.as_str() == "z" && block.expr.is_none() { diff --git a/tests/ui/author/macro_in_closure.stdout b/tests/ui/author/macro_in_closure.stdout index f2e54c2c1c86..b90c830e0307 100644 --- a/tests/ui/author/macro_in_closure.stdout +++ b/tests/ui/author/macro_in_closure.stdout @@ -34,7 +34,7 @@ if let StmtKind::Local(local) = stmt.kind && let ExprKind::Path(ref qpath3) = inner2.kind && match_qpath(qpath3, &["x"]) && block.expr.is_none() - && let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = local.pat.kind + && let PatKind::Binding(BindingMode::NONE, _, name, None) = local.pat.kind && name.as_str() == "print_text" { // report your lint here diff --git a/tests/ui/author/macro_in_loop.stdout b/tests/ui/author/macro_in_loop.stdout index a719e3af7e76..3f9be297c33c 100644 --- a/tests/ui/author/macro_in_loop.stdout +++ b/tests/ui/author/macro_in_loop.stdout @@ -1,5 +1,5 @@ if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::ForLoop::hir(expr) - && let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = pat.kind + && let PatKind::Binding(BindingMode::NONE, _, name, None) = pat.kind && name.as_str() == "i" && let ExprKind::Struct(qpath, fields, None) = arg.kind && matches!(qpath, QPath::LangItem(LangItem::Range, _)) diff --git a/tests/ui/author/matches.stdout b/tests/ui/author/matches.stdout index 88e2ca656a4f..30e4a9b2560a 100644 --- a/tests/ui/author/matches.stdout +++ b/tests/ui/author/matches.stdout @@ -20,7 +20,7 @@ if let StmtKind::Local(local) = stmt.kind && let Some(init1) = local1.init && let ExprKind::Lit(ref lit4) = init1.kind && let LitKind::Int(3, LitIntType::Unsuffixed) = lit4.node - && let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = local1.pat.kind + && let PatKind::Binding(BindingMode::NONE, _, name, None) = local1.pat.kind && name.as_str() == "x" && let Some(trailing_expr) = block.expr && let ExprKind::Path(ref qpath) = trailing_expr.kind @@ -29,7 +29,7 @@ if let StmtKind::Local(local) = stmt.kind && arms[2].guard.is_none() && let ExprKind::Lit(ref lit5) = arms[2].body.kind && let LitKind::Int(1, LitIntType::Unsuffixed) = lit5.node - && let PatKind::Binding(BindingAnnotation::NONE, _, name1, None) = local.pat.kind + && let PatKind::Binding(BindingMode::NONE, _, name1, None) = local.pat.kind && name1.as_str() == "a" { // report your lint here From 66362efb09bfaa8ee85a97b350d6c97174c0ad93 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Wed, 17 Apr 2024 14:40:00 +0000 Subject: [PATCH 08/47] Don't suggest `Box::default()` in functions with differing generics --- clippy_lints/src/box_default.rs | 4 ++-- tests/ui/box_default.fixed | 12 ++++++++++++ tests/ui/box_default.rs | 12 ++++++++++++ tests/ui/box_default.stderr | 8 +++++++- 4 files changed, 33 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/box_default.rs b/clippy_lints/src/box_default.rs index 4062212f408e..8459f051d3d9 100644 --- a/clippy_lints/src/box_default.rs +++ b/clippy_lints/src/box_default.rs @@ -121,9 +121,9 @@ fn given_type(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { if let Some(index) = args.iter().position(|arg| arg.hir_id == expr.hir_id) && let Some(sig) = expr_sig(cx, path) && let Some(input) = sig.input(index) - && !cx.typeck_results().expr_ty_adjusted(expr).boxed_ty().is_trait() + && let Some(input_ty) = input.no_bound_vars() { - input.no_bound_vars().is_some() + input_ty == cx.typeck_results().expr_ty_adjusted(expr) } else { false } diff --git a/tests/ui/box_default.fixed b/tests/ui/box_default.fixed index 6c2896b3aa0f..1f2f57c2507d 100644 --- a/tests/ui/box_default.fixed +++ b/tests/ui/box_default.fixed @@ -65,6 +65,8 @@ fn main() { // Would have a suggestion after https://github.com/rust-lang/rust/blob/fdd030127cc68afec44a8d3f6341525dd34e50ae/compiler/rustc_middle/src/ty/diagnostics.rs#L554-L563 let mut unnameable = Box::new(Option::default()); let _ = unnameable.insert(|| {}); + + let _ = Box::into_raw(Box::new(String::default())); } fn ret_ty_fn() -> Box { @@ -75,6 +77,16 @@ fn call_ty_fn(_b: Box) { issue_9621_dyn_trait(); } +struct X(T); + +impl X { + fn x(_: Box) {} + + fn same_generic_param() { + Self::x(Box::default()); + } +} + use std::io::{Read, Result}; impl Read for ImplementsDefault { diff --git a/tests/ui/box_default.rs b/tests/ui/box_default.rs index e19a62a90221..addfebc24f58 100644 --- a/tests/ui/box_default.rs +++ b/tests/ui/box_default.rs @@ -65,6 +65,8 @@ fn main() { // Would have a suggestion after https://github.com/rust-lang/rust/blob/fdd030127cc68afec44a8d3f6341525dd34e50ae/compiler/rustc_middle/src/ty/diagnostics.rs#L554-L563 let mut unnameable = Box::new(Option::default()); let _ = unnameable.insert(|| {}); + + let _ = Box::into_raw(Box::new(String::default())); } fn ret_ty_fn() -> Box { @@ -75,6 +77,16 @@ fn call_ty_fn(_b: Box) { issue_9621_dyn_trait(); } +struct X(T); + +impl X { + fn x(_: Box) {} + + fn same_generic_param() { + Self::x(Box::new(T::default())); + } +} + use std::io::{Read, Result}; impl Read for ImplementsDefault { diff --git a/tests/ui/box_default.stderr b/tests/ui/box_default.stderr index f172a875dce4..39fd0d29bbf9 100644 --- a/tests/ui/box_default.stderr +++ b/tests/ui/box_default.stderr @@ -55,5 +55,11 @@ error: `Box::new(_)` of default value LL | call_ty_fn(Box::new(u8::default())); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()` -error: aborting due to 9 previous errors +error: `Box::new(_)` of default value + --> tests/ui/box_default.rs:86:17 + | +LL | Self::x(Box::new(T::default())); + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()` + +error: aborting due to 10 previous errors From 81106c5691bc05136a5ce679d94ac31b682769ed Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 15 Apr 2024 18:56:44 -0400 Subject: [PATCH 09/47] has_typeck_results doesnt need to be a query --- clippy_lints/src/functions/must_use.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/functions/must_use.rs b/clippy_lints/src/functions/must_use.rs index d0c66900c006..e7ec2b3151e6 100644 --- a/clippy_lints/src/functions/must_use.rs +++ b/clippy_lints/src/functions/must_use.rs @@ -185,7 +185,7 @@ fn is_mutable_pat(cx: &LateContext<'_>, pat: &hir::Pat<'_>, tys: &mut DefIdSet) if let hir::PatKind::Wild = pat.kind { return false; // ignore `_` patterns } - if cx.tcx.has_typeck_results(pat.hir_id.owner.to_def_id()) { + if cx.tcx.has_typeck_results(pat.hir_id.owner.def_id) { is_mutable_ty(cx, cx.tcx.typeck(pat.hir_id.owner.def_id).pat_ty(pat), tys) } else { false @@ -233,7 +233,7 @@ fn mutates_static<'tcx>(cx: &LateContext<'tcx>, body: &'tcx hir::Body<'_>) -> bo Call(_, args) => { let mut tys = DefIdSet::default(); for arg in args { - if cx.tcx.has_typeck_results(arg.hir_id.owner.to_def_id()) + if cx.tcx.has_typeck_results(arg.hir_id.owner.def_id) && is_mutable_ty(cx, cx.tcx.typeck(arg.hir_id.owner.def_id).expr_ty(arg), &mut tys) && is_mutated_static(arg) { @@ -246,7 +246,7 @@ fn mutates_static<'tcx>(cx: &LateContext<'tcx>, body: &'tcx hir::Body<'_>) -> bo MethodCall(_, receiver, args, _) => { 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()) + if cx.tcx.has_typeck_results(arg.hir_id.owner.def_id) && is_mutable_ty(cx, cx.tcx.typeck(arg.hir_id.owner.def_id).expr_ty(arg), &mut tys) && is_mutated_static(arg) { From a5aaf33422f110d7a4ca6ba53fc5f2995dd6b0ce Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 18 Apr 2024 17:48:52 +0200 Subject: [PATCH 10/47] Merge commit 'ca3b393750ee8d870bf3215dcf6509cafa5c0445' into clippy-subtree-update --- .github/workflows/remark.yml | 2 +- CHANGELOG.md | 1 + book/src/README.md | 28 ++-- book/src/development/adding_lints.md | 26 +-- book/src/lint_configuration.md | 26 +++ clippy_config/src/conf.rs | 22 +++ clippy_dev/src/fmt.rs | 1 - clippy_dev/src/lib.rs | 1 + clippy_dev/src/main.rs | 55 +++++-- clippy_dev/src/new_lint.rs | 1 - clippy_dev/src/setup/mod.rs | 1 + clippy_dev/src/setup/toolchain.rs | 75 +++++++++ clippy_lints/src/arc_with_non_send_sync.rs | 26 ++- .../src/attrs/duplicated_attributes.rs | 8 +- clippy_lints/src/attrs/mod.rs | 11 +- clippy_lints/src/booleans.rs | 17 +- clippy_lints/src/casts/mod.rs | 10 +- clippy_lints/src/dereference.rs | 9 ++ clippy_lints/src/derive.rs | 2 +- clippy_lints/src/doc/missing_headers.rs | 2 +- clippy_lints/src/doc/mod.rs | 151 +++++++----------- clippy_lints/src/index_refutable_slice.rs | 2 +- clippy_lints/src/item_name_repetitions.rs | 12 +- clippy_lints/src/legacy_numeric_constants.rs | 2 +- clippy_lints/src/lib.rs | 2 + clippy_lints/src/lifetimes.rs | 5 +- clippy_lints/src/manual_unwrap_or_default.rs | 95 +++++------ clippy_lints/src/methods/mod.rs | 1 - clippy_lints/src/methods/search_is_some.rs | 38 ++++- .../src/needless_borrows_for_generic_args.rs | 2 +- clippy_lints/src/non_copy_const.rs | 9 +- clippy_lints/src/strings.rs | 7 +- .../transmute/transmute_int_to_non_zero.rs | 4 +- .../transmutes_expressible_as_ptr_casts.rs | 2 +- clippy_utils/src/ast_utils.rs | 8 +- clippy_utils/src/lib.rs | 2 +- clippy_utils/src/ty.rs | 2 +- clippy_utils/src/ty/type_certainty/mod.rs | 2 +- lintcheck/src/main.rs | 96 +++++++---- rust-toolchain | 2 +- tests/ui-internal/custom_ice_message.rs | 1 - tests/ui-internal/custom_ice_message.stderr | 7 +- .../allowed_prefixes/clippy.toml | 1 + .../allowed_prefixes/item_name_repetitions.rs | 15 ++ .../item_name_repetitions.stderr | 11 ++ .../allowed_prefixes_extend/clippy.toml | 1 + .../item_name_repetitions.rs | 21 +++ .../item_name_repetitions.stderr | 11 ++ .../toml_unknown_key/conf_unknown_key.stderr | 3 + tests/ui/arc_with_non_send_sync.rs | 7 - tests/ui/arc_with_non_send_sync.stderr | 29 ++-- tests/ui/auxiliary/proc_macro_attr.rs | 14 ++ tests/ui/cast.rs | 12 ++ tests/ui/cast.stderr | 45 +++++- tests/ui/crashes/ice-12585.rs | 26 +++ tests/ui/crashes/ice-12616.stderr | 10 +- tests/ui/doc/doc-fixable.fixed | 5 + tests/ui/doc/doc-fixable.rs | 5 + tests/ui/doc/doc-fixable.stderr | 13 +- tests/ui/duplicated_attributes.rs | 10 +- tests/ui/duplicated_attributes.stderr | 31 +--- tests/ui/manual_unwrap_or_default.fixed | 10 ++ tests/ui/manual_unwrap_or_default.rs | 10 ++ tests/ui/manual_unwrap_or_default.stderr | 2 +- tests/ui/module_name_repetitions.rs | 14 ++ tests/ui/multiple_unsafe_ops_per_block.rs | 1 + tests/ui/multiple_unsafe_ops_per_block.stderr | 58 +++---- tests/ui/needless_borrow.fixed | 8 + tests/ui/needless_borrow.rs | 8 + tests/ui/needless_borrow.stderr | 8 +- tests/ui/nonminimal_bool_methods.fixed | 8 + tests/ui/nonminimal_bool_methods.rs | 8 + tests/ui/nonminimal_bool_methods.stderr | 20 ++- tests/ui/ptr_as_ptr.fixed | 1 - tests/ui/ptr_as_ptr.rs | 1 - tests/ui/ptr_as_ptr.stderr | 66 ++++---- tests/ui/search_is_some_fixable_none.fixed | 50 ++++++ tests/ui/search_is_some_fixable_none.rs | 50 ++++++ tests/ui/search_is_some_fixable_none.stderr | 74 ++++++++- tests/ui/unconditional_recursion.rs | 2 +- tests/ui/unnecessary_clippy_cfg.stderr | 38 ++++- tests/ui/useless_attribute.fixed | 2 +- tests/ui/useless_attribute.rs | 2 +- triagebot.toml | 7 +- 84 files changed, 1067 insertions(+), 427 deletions(-) create mode 100644 clippy_dev/src/setup/toolchain.rs create mode 100644 tests/ui-toml/item_name_repetitions/allowed_prefixes/clippy.toml create mode 100644 tests/ui-toml/item_name_repetitions/allowed_prefixes/item_name_repetitions.rs create mode 100644 tests/ui-toml/item_name_repetitions/allowed_prefixes/item_name_repetitions.stderr create mode 100644 tests/ui-toml/item_name_repetitions/allowed_prefixes_extend/clippy.toml create mode 100644 tests/ui-toml/item_name_repetitions/allowed_prefixes_extend/item_name_repetitions.rs create mode 100644 tests/ui-toml/item_name_repetitions/allowed_prefixes_extend/item_name_repetitions.stderr create mode 100644 tests/ui/crashes/ice-12585.rs diff --git a/.github/workflows/remark.yml b/.github/workflows/remark.yml index 05e1b3b9202b..348d52020fd2 100644 --- a/.github/workflows/remark.yml +++ b/.github/workflows/remark.yml @@ -24,7 +24,7 @@ jobs: node-version: '18.x' - name: Install remark - run: npm install remark-cli remark-lint remark-lint-maximum-line-length remark-preset-lint-recommended remark-gfm + run: npm install remark-cli remark-lint remark-lint-maximum-line-length@^3.1.3 remark-preset-lint-recommended remark-gfm - name: Install mdbook run: | diff --git a/CHANGELOG.md b/CHANGELOG.md index f7e7ed86eed8..bd3a04e34ae3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5894,6 +5894,7 @@ Released 2018-09-13 [`allowed-dotfiles`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-dotfiles [`allowed-duplicate-crates`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-duplicate-crates [`allowed-idents-below-min-chars`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-idents-below-min-chars +[`allowed-prefixes`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-prefixes [`allowed-scripts`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-scripts [`allowed-wildcard-imports`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-wildcard-imports [`arithmetic-side-effects-allowed`]: https://doc.rust-lang.org/clippy/lint_configuration.html#arithmetic-side-effects-allowed diff --git a/book/src/README.md b/book/src/README.md index e7972b0db19c..7bdfb97c3acf 100644 --- a/book/src/README.md +++ b/book/src/README.md @@ -18,17 +18,27 @@ category. | `clippy::all` | all lints that are on by default (correctness, suspicious, style, complexity, perf) | **warn/deny** | | `clippy::correctness` | code that is outright wrong or useless | **deny** | | `clippy::suspicious` | code that is most likely wrong or useless | **warn** | +| `clippy::style` | code that should be written in a more idiomatic way | **warn** | | `clippy::complexity` | code that does something simple but in a complex way | **warn** | | `clippy::perf` | code that can be written to run faster | **warn** | -| `clippy::style` | code that should be written in a more idiomatic way | **warn** | -| `clippy::pedantic` | lints which are rather strict or might have false positives | allow | +| `clippy::pedantic` | lints which are rather strict or have occasional false positives | allow | +| `clippy::restriction` | lints which prevent the use of language and library features[^restrict] | allow | | `clippy::nursery` | new lints that are still under development | allow | -| `clippy::cargo` | lints for the cargo manifest | allow | | allow | +| `clippy::cargo` | lints for the cargo manifest | allow | -More to come, please [file an -issue](https://github.com/rust-lang/rust-clippy/issues) if you have ideas! +More to come, please [file an issue](https://github.com/rust-lang/rust-clippy/issues) if you have ideas! -The [lint list](https://rust-lang.github.io/rust-clippy/master/index.html) also -contains "restriction lints", which are for things which are usually not -considered "bad", but may be useful to turn on in specific cases. These should -be used very selectively, if at all. +The `restriction` category should, *emphatically*, not be enabled as a whole. The contained +lints may lint against perfectly reasonable code, may not have an alternative suggestion, +and may contradict any other lints (including other categories). Lints should be considered +on a case-by-case basis before enabling. + +[^restrict]: Some use cases for `restriction` lints include: + - Strict coding styles (e.g. [`clippy::else_if_without_else`]). + - Additional restrictions on CI (e.g. [`clippy::todo`]). + - Preventing panicking in certain functions (e.g. [`clippy::unwrap_used`]). + - Running a lint only on a subset of code (e.g. `#[forbid(clippy::float_arithmetic)]` on a module). + +[`clippy::else_if_without_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#else_if_without_else +[`clippy::todo`]: https://rust-lang.github.io/rust-clippy/master/index.html#todo +[`clippy::unwrap_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_used diff --git a/book/src/development/adding_lints.md b/book/src/development/adding_lints.md index e30a5f9fe10b..b80ac6370e7a 100644 --- a/book/src/development/adding_lints.md +++ b/book/src/development/adding_lints.md @@ -18,7 +18,6 @@ because that's clearly a non-descriptive name. - [Cargo lints](#cargo-lints) - [Rustfix tests](#rustfix-tests) - [Testing manually](#testing-manually) - - [Running directly](#running-directly) - [Lint declaration](#lint-declaration) - [Lint registration](#lint-registration) - [Lint passes](#lint-passes) @@ -176,23 +175,26 @@ the tests. Manually testing against an example file can be useful if you have added some `println!`s and the test suite output becomes unreadable. To try Clippy with -your local modifications, run +your local modifications, run the following from the Clippy directory: -``` +```bash cargo dev lint input.rs ``` -from the working copy root. With tests in place, let's have a look at -implementing our lint now. +To run Clippy on an existing project rather than a single file you can use -## Running directly +```bash +cargo dev lint /path/to/project +``` -While it's easier to just use `cargo dev lint`, it might be desirable to get -`target/release/cargo-clippy` and `target/release/clippy-driver` to work as well in some cases. -By default, they don't work because clippy dynamically links rustc. To help them find rustc, -add the path printed by`rustc --print target-libdir` (ran inside this workspace so that the rustc version matches) -to your library search path. -On linux, this can be done by setting the `LD_LIBRARY_PATH` environment variable to that path. +Or set up a rustup toolchain that points to the local Clippy binaries + +```bash +cargo dev setup toolchain + +# Then in `/path/to/project` you can run +cargo +clippy clippy +``` ## Lint declaration diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index 4a2727c5197f..7cefa6852642 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -164,6 +164,32 @@ configuration of Clippy. By default, any configuration will replace the default * [`min_ident_chars`](https://rust-lang.github.io/rust-clippy/master/index.html#min_ident_chars) +## `allowed-prefixes` +List of prefixes to allow when determining whether an item's name ends with the module's name. +If the rest of an item's name is an allowed prefix (e.g. item `ToFoo` or `to_foo` in module `foo`), +then don't emit a warning. + +#### Example + +```toml +allowed-prefixes = [ "to", "from" ] +``` + +#### Noteworthy + +- By default, the following prefixes are allowed: `to`, `as`, `into`, `from`, `try_into` and `try_from` +- PascalCase variant is included automatically for each snake_case variant (e.g. if `try_into` is included, + `TryInto` will also be included) +- Use `".."` as part of the list to indicate that the configured values should be appended to the +default configuration of Clippy. By default, any configuration will replace the default value + +**Default Value:** `["to", "as", "into", "from", "try_into", "try_from"]` + +--- +**Affected lints:** +* [`module_name_repetitions`](https://rust-lang.github.io/rust-clippy/master/index.html#module_name_repetitions) + + ## `allowed-scripts` The list of unicode scripts allowed to be used in the scope. diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index 53c10f7cee8b..781282213cc4 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -39,6 +39,7 @@ const DEFAULT_DOC_VALID_IDENTS: &[&str] = &[ ]; const DEFAULT_DISALLOWED_NAMES: &[&str] = &["foo", "baz", "quux"]; const DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS: &[&str] = &["i", "j", "x", "y", "z", "w", "n"]; +const DEFAULT_ALLOWED_PREFIXES: &[&str] = &["to", "as", "into", "from", "try_into", "try_from"]; /// Conf with parse errors #[derive(Default)] @@ -589,6 +590,26 @@ define_Conf! { /// 2. Paths with any segment that containing the word 'prelude' /// are already allowed by default. (allowed_wildcard_imports: FxHashSet = FxHashSet::default()), + /// Lint: MODULE_NAME_REPETITIONS. + /// + /// List of prefixes to allow when determining whether an item's name ends with the module's name. + /// If the rest of an item's name is an allowed prefix (e.g. item `ToFoo` or `to_foo` in module `foo`), + /// then don't emit a warning. + /// + /// #### Example + /// + /// ```toml + /// allowed-prefixes = [ "to", "from" ] + /// ``` + /// + /// #### Noteworthy + /// + /// - By default, the following prefixes are allowed: `to`, `as`, `into`, `from`, `try_into` and `try_from` + /// - PascalCase variant is included automatically for each snake_case variant (e.g. if `try_into` is included, + /// `TryInto` will also be included) + /// - Use `".."` as part of the list to indicate that the configured values should be appended to the + /// default configuration of Clippy. By default, any configuration will replace the default value + (allowed_prefixes: Vec = DEFAULT_ALLOWED_PREFIXES.iter().map(ToString::to_string).collect()), } /// Search for the configuration file. @@ -649,6 +670,7 @@ fn deserialize(file: &SourceFile) -> TryConf { Ok(mut conf) => { extend_vec_if_indicator_present(&mut conf.conf.doc_valid_idents, DEFAULT_DOC_VALID_IDENTS); extend_vec_if_indicator_present(&mut conf.conf.disallowed_names, DEFAULT_DISALLOWED_NAMES); + extend_vec_if_indicator_present(&mut conf.conf.allowed_prefixes, DEFAULT_ALLOWED_PREFIXES); // TODO: THIS SHOULD BE TESTED, this comment will be gone soon if conf.conf.allowed_idents_below_min_chars.contains("..") { conf.conf diff --git a/clippy_dev/src/fmt.rs b/clippy_dev/src/fmt.rs index ee559d45dd16..256231441817 100644 --- a/clippy_dev/src/fmt.rs +++ b/clippy_dev/src/fmt.rs @@ -35,7 +35,6 @@ struct FmtContext { } // the "main" function of cargo dev fmt -#[allow(clippy::missing_panics_doc)] pub fn run(check: bool, verbose: bool) { fn try_run(context: &FmtContext) -> Result { let mut success = true; diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs index bb62e902cd54..385191e0361b 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -9,6 +9,7 @@ unused_lifetimes, unused_qualifications )] +#![allow(clippy::missing_panics_doc)] // The `rustc_driver` crate seems to be required in order to use the `rust_lexer` crate. #[allow(unused_extern_crates)] diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index 5bd9994e18d5..397a0e990829 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -46,6 +46,13 @@ fn main() { } }, Some(("setup", sub_command)) => match sub_command.subcommand() { + Some(("git-hook", matches)) => { + if matches.get_flag("remove") { + setup::git_hook::remove_hook(); + } else { + setup::git_hook::install_hook(matches.get_flag("force-override")); + } + }, Some(("intellij", matches)) => { if matches.get_flag("remove") { setup::intellij::remove_rustc_src(); @@ -57,12 +64,12 @@ fn main() { ); } }, - Some(("git-hook", matches)) => { - if matches.get_flag("remove") { - setup::git_hook::remove_hook(); - } else { - setup::git_hook::install_hook(matches.get_flag("force-override")); - } + Some(("toolchain", matches)) => { + setup::toolchain::create( + matches.get_flag("force"), + matches.get_flag("release"), + matches.get_one::("name").unwrap(), + ); }, Some(("vscode-tasks", matches)) => { if matches.get_flag("remove") { @@ -210,6 +217,19 @@ fn get_clap_config() -> ArgMatches { .about("Support for setting up your personal development environment") .arg_required_else_help(true) .subcommands([ + Command::new("git-hook") + .about("Add a pre-commit git hook that formats your code to make it look pretty") + .args([ + Arg::new("remove") + .long("remove") + .action(ArgAction::SetTrue) + .help("Remove the pre-commit hook added with 'cargo dev setup git-hook'"), + Arg::new("force-override") + .long("force-override") + .short('f') + .action(ArgAction::SetTrue) + .help("Forces the override of an existing git pre-commit hook"), + ]), Command::new("intellij") .about("Alter dependencies so Intellij Rust can find rustc internals") .args([ @@ -225,18 +245,23 @@ fn get_clap_config() -> ArgMatches { .conflicts_with("remove") .required(true), ]), - Command::new("git-hook") - .about("Add a pre-commit git hook that formats your code to make it look pretty") + Command::new("toolchain") + .about("Install a rustup toolchain pointing to the local clippy build") .args([ - Arg::new("remove") - .long("remove") - .action(ArgAction::SetTrue) - .help("Remove the pre-commit hook added with 'cargo dev setup git-hook'"), - Arg::new("force-override") - .long("force-override") + Arg::new("force") + .long("force") .short('f') .action(ArgAction::SetTrue) - .help("Forces the override of an existing git pre-commit hook"), + .help("Override an existing toolchain"), + Arg::new("release") + .long("release") + .short('r') + .action(ArgAction::SetTrue) + .help("Point to --release clippy binaries"), + Arg::new("name") + .long("name") + .default_value("clippy") + .help("The name of the created toolchain"), ]), Command::new("vscode-tasks") .about("Add several tasks to vscode for formatting, validation and testing") diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index 5d9cde06cd86..2940d56350f4 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -36,7 +36,6 @@ impl Context for io::Result { /// # Errors /// /// This function errors out if the files couldn't be created or written to. -#[allow(clippy::missing_panics_doc)] pub fn create( pass: &String, lint_name: Option<&String>, diff --git a/clippy_dev/src/setup/mod.rs b/clippy_dev/src/setup/mod.rs index f691ae4fa45d..b0d318146391 100644 --- a/clippy_dev/src/setup/mod.rs +++ b/clippy_dev/src/setup/mod.rs @@ -1,5 +1,6 @@ pub mod git_hook; pub mod intellij; +pub mod toolchain; pub mod vscode; use std::path::Path; diff --git a/clippy_dev/src/setup/toolchain.rs b/clippy_dev/src/setup/toolchain.rs new file mode 100644 index 000000000000..8d98c6c92d9d --- /dev/null +++ b/clippy_dev/src/setup/toolchain.rs @@ -0,0 +1,75 @@ +use std::env::consts::EXE_SUFFIX; +use std::env::current_dir; +use std::ffi::OsStr; +use std::fs; +use std::path::{Path, PathBuf}; +use walkdir::WalkDir; + +use super::verify_inside_clippy_dir; + +pub fn create(force: bool, release: bool, name: &str) { + if !verify_inside_clippy_dir() { + return; + } + + let rustup_home = std::env::var("RUSTUP_HOME").unwrap(); + let toolchain = std::env::var("RUSTUP_TOOLCHAIN").unwrap(); + + let src = PathBuf::from_iter([&rustup_home, "toolchains", &toolchain]); + let dest = PathBuf::from_iter([&rustup_home, "toolchains", name]); + + if dest.exists() { + if force { + fs::remove_dir_all(&dest).unwrap(); + } else { + println!("{} already exists, pass `--force` to override it", dest.display()); + return; + } + } + + for entry in WalkDir::new(&src) { + let entry = entry.unwrap(); + let relative = entry.path().strip_prefix(&src).unwrap(); + + if relative.starts_with("bin") + && matches!( + relative.file_stem().and_then(OsStr::to_str), + Some("cargo-clippy" | "clippy-driver") + ) + { + continue; + } + + let target = dest.join(relative); + if entry.file_type().is_dir() { + fs::create_dir(&target).unwrap(); + } else { + fs::hard_link(entry.path(), target).unwrap(); + } + } + + symlink_bin("cargo-clippy", &dest, release); + symlink_bin("clippy-driver", &dest, release); + + println!("Created toolchain {name}, use it in other projects with e.g. `cargo +{name} clippy`"); + println!("Note: This will need to be re-run whenever the Clippy `rust-toolchain` changes"); +} + +fn symlink_bin(bin: &str, dest: &Path, release: bool) { + #[cfg(windows)] + use std::os::windows::fs::symlink_file as symlink; + + #[cfg(not(windows))] + use std::os::unix::fs::symlink; + + let profile = if release { "release" } else { "debug" }; + let file_name = format!("{bin}{EXE_SUFFIX}"); + + let mut src = current_dir().unwrap(); + src.extend(["target", profile, &file_name]); + + let mut dest = dest.to_path_buf(); + dest.extend(["bin", &file_name]); + + symlink(src, dest).unwrap(); +} diff --git a/clippy_lints/src/arc_with_non_send_sync.rs b/clippy_lints/src/arc_with_non_send_sync.rs index 1102c7fb236b..389338973894 100644 --- a/clippy_lints/src/arc_with_non_send_sync.rs +++ b/clippy_lints/src/arc_with_non_send_sync.rs @@ -56,7 +56,12 @@ impl<'tcx> LateLintPass<'tcx> for ArcWithNonSendSync { && let Some(send) = cx.tcx.get_diagnostic_item(sym::Send) && let Some(sync) = cx.tcx.lang_items().sync_trait() && let [is_send, is_sync] = [send, sync].map(|id| implements_trait(cx, arg_ty, id, &[])) - && !(is_send && is_sync) + && let reason = match (is_send, is_sync) { + (false, false) => "neither `Send` nor `Sync`", + (false, true) => "not `Send`", + (true, false) => "not `Sync`", + _ => return, + } && !is_from_proc_macro(cx, expr) { span_lint_and_then( @@ -66,21 +71,12 @@ impl<'tcx> LateLintPass<'tcx> for ArcWithNonSendSync { "usage of an `Arc` that is not `Send` and `Sync`", |diag| { with_forced_trimmed_paths!({ - diag.note(format!("`Arc<{arg_ty}>` is not `Send` and `Sync` as:")); - - if !is_send { - diag.note(format!("- the trait `Send` is not implemented for `{arg_ty}`")); - } - if !is_sync { - diag.note(format!("- the trait `Sync` is not implemented for `{arg_ty}`")); - } - - diag.help("consider using an `Rc` instead. `Arc` does not provide benefits for non `Send` and `Sync` types"); - - diag.note("if you intend to use `Arc` with `Send` and `Sync` traits"); - diag.note(format!( - "wrap the inner type with a `Mutex` or implement `Send` and `Sync` for `{arg_ty}`" + "`Arc<{arg_ty}>` is not `Send` and `Sync` as `{arg_ty}` is {reason}" + )); + diag.help("if the `Arc` will not used be across threads replace it with an `Rc`"); + diag.help(format!( + "otherwise make `{arg_ty}` `Send` and `Sync` or consider a wrapper type such as `Mutex`" )); }); }, diff --git a/clippy_lints/src/attrs/duplicated_attributes.rs b/clippy_lints/src/attrs/duplicated_attributes.rs index 3a8844d07548..736ee48641d8 100644 --- a/clippy_lints/src/attrs/duplicated_attributes.rs +++ b/clippy_lints/src/attrs/duplicated_attributes.rs @@ -2,12 +2,12 @@ use super::DUPLICATED_ATTRIBUTES; use clippy_utils::diagnostics::span_lint_and_then; use rustc_ast::{Attribute, MetaItem}; use rustc_data_structures::fx::FxHashMap; -use rustc_lint::EarlyContext; +use rustc_lint::LateContext; use rustc_span::{sym, Span}; use std::collections::hash_map::Entry; fn emit_if_duplicated( - cx: &EarlyContext<'_>, + cx: &LateContext<'_>, attr: &MetaItem, attr_paths: &mut FxHashMap, complete_path: String, @@ -26,7 +26,7 @@ fn emit_if_duplicated( } fn check_duplicated_attr( - cx: &EarlyContext<'_>, + cx: &LateContext<'_>, attr: &MetaItem, attr_paths: &mut FxHashMap, parent: &mut Vec, @@ -64,7 +64,7 @@ fn check_duplicated_attr( } } -pub fn check(cx: &EarlyContext<'_>, attrs: &[Attribute]) { +pub fn check(cx: &LateContext<'_>, attrs: &[Attribute]) { let mut attr_paths = FxHashMap::default(); for attr in attrs { diff --git a/clippy_lints/src/attrs/mod.rs b/clippy_lints/src/attrs/mod.rs index 684ad7de2f05..8f47bc7653b7 100644 --- a/clippy_lints/src/attrs/mod.rs +++ b/clippy_lints/src/attrs/mod.rs @@ -17,7 +17,7 @@ mod useless_attribute; mod utils; use clippy_config::msrvs::Msrv; -use rustc_ast::{Attribute, Crate, MetaItemKind, NestedMetaItem}; +use rustc_ast::{Attribute, MetaItemKind, NestedMetaItem}; use rustc_hir::{ImplItem, Item, ItemKind, TraitItem}; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, impl_lint_pass}; @@ -534,11 +534,13 @@ declare_lint_pass!(Attributes => [ BLANKET_CLIPPY_RESTRICTION_LINTS, SHOULD_PANIC_WITHOUT_EXPECT, MIXED_ATTRIBUTES_STYLE, + DUPLICATED_ATTRIBUTES, ]); impl<'tcx> LateLintPass<'tcx> for Attributes { fn check_crate(&mut self, cx: &LateContext<'tcx>) { blanket_clippy_restriction_lints::check_command_line(cx); + duplicated_attributes::check(cx, cx.tcx.hir().krate_attrs()); } fn check_attribute(&mut self, cx: &LateContext<'tcx>, attr: &'tcx Attribute) { @@ -578,6 +580,7 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { _ => {}, } mixed_attributes_style::check(cx, item.span, attrs); + duplicated_attributes::check(cx, attrs); } fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) { @@ -606,17 +609,11 @@ impl_lint_pass!(EarlyAttributes => [ MAYBE_MISUSED_CFG, DEPRECATED_CLIPPY_CFG_ATTR, UNNECESSARY_CLIPPY_CFG, - DUPLICATED_ATTRIBUTES, ]); impl EarlyLintPass for EarlyAttributes { - fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &Crate) { - duplicated_attributes::check(cx, &krate.attrs); - } - fn check_item(&mut self, cx: &EarlyContext<'_>, item: &rustc_ast::Item) { empty_line_after::check(cx, item); - duplicated_attributes::check(cx, &item.attrs); } fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) { diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 6edfebb5534f..b6341b3fe8e7 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -346,11 +346,18 @@ fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { _ => None, } .and_then(|op| { - Some(format!( - "{}{op}{}", - snippet_opt(cx, lhs.span)?, - snippet_opt(cx, rhs.span)? - )) + let lhs_snippet = snippet_opt(cx, lhs.span)?; + let rhs_snippet = snippet_opt(cx, rhs.span)?; + + if !(lhs_snippet.starts_with('(') && lhs_snippet.ends_with(')')) { + if let (ExprKind::Cast(..), BinOpKind::Ge) = (&lhs.kind, binop.node) { + // e.g. `(a as u64) < b`. Without the parens the `<` is + // interpreted as a start of generic arguments for `u64` + return Some(format!("({lhs_snippet}){op}{rhs_snippet}")); + } + } + + Some(format!("{lhs_snippet}{op}{rhs_snippet}")) }) }, ExprKind::MethodCall(path, receiver, [], _) => { diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index 063aab282384..d14898a8196c 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -754,11 +754,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); - } - - if expr.span.from_expansion() { + if in_external_macro(cx.sess(), expr.span) { return; } @@ -771,7 +767,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts { cx.typeck_results().expr_ty(expr), ); - if unnecessary_cast::check(cx, expr, cast_expr, cast_from, cast_to) { + if !expr.span.from_expansion() && 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); @@ -782,7 +778,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts { fn_to_numeric_cast_with_truncation::check(cx, expr, cast_expr, cast_from, cast_to); zero_ptr::check(cx, expr, cast_expr, cast_to_hir); - if cast_to.is_numeric() && !in_external_macro(cx.sess(), expr.span) { + if cast_to.is_numeric() { cast_possible_truncation::check(cx, expr, cast_expr, cast_from, cast_to, cast_to_hir.span); if cast_from.is_numeric() { cast_possible_wrap::check(cx, expr, cast_from, cast_to); diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index bff40c2ae75d..89e2b3449680 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -1016,9 +1016,18 @@ fn report<'tcx>( }, _ => (0, false), }; + let is_in_tuple = matches!( + get_parent_expr(cx, data.first_expr), + Some(Expr { + kind: ExprKind::Tup(..), + .. + }) + ); + let sugg = if !snip_is_macro && (calls_field || expr.precedence().order() < precedence) && !has_enclosing_paren(&snip) + && !is_in_tuple { format!("({snip})") } else { diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index 5f9700b76d94..42cd19fb8eca 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -132,7 +132,7 @@ declare_clippy_lint! { /// /// ### Why is this bad? /// Deriving `serde::Deserialize` will create a constructor - /// that may violate invariants hold by another constructor. + /// that may violate invariants held by another constructor. /// /// ### Example /// ```rust,ignore diff --git a/clippy_lints/src/doc/missing_headers.rs b/clippy_lints/src/doc/missing_headers.rs index 26f120cb33f0..f935ae2e3e48 100644 --- a/clippy_lints/src/doc/missing_headers.rs +++ b/clippy_lints/src/doc/missing_headers.rs @@ -11,7 +11,7 @@ use super::{DocHeaders, MISSING_ERRORS_DOC, MISSING_PANICS_DOC, MISSING_SAFETY_D pub fn check( cx: &LateContext<'_>, owner_id: OwnerId, - sig: &FnSig<'_>, + sig: FnSig<'_>, headers: DocHeaders, body_id: Option, panic_span: Option, diff --git a/clippy_lints/src/doc/mod.rs b/clippy_lints/src/doc/mod.rs index b135e4e35771..4bced104d3bc 100644 --- a/clippy_lints/src/doc/mod.rs +++ b/clippy_lints/src/doc/mod.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::macros::{is_panic, root_macro_call_first_node}; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::Visitable; -use clippy_utils::{is_entrypoint_fn, method_chain_args}; +use clippy_utils::{is_entrypoint_fn, is_trait_impl_item, method_chain_args}; use pulldown_cmark::Event::{ Code, End, FootnoteReference, HardBreak, Html, Rule, SoftBreak, Start, TaskListMarker, Text, }; @@ -11,9 +11,8 @@ use pulldown_cmark::Tag::{BlockQuote, CodeBlock, Heading, Item, Link, Paragraph} use pulldown_cmark::{BrokenLink, CodeBlockKind, CowStr, Options}; use rustc_ast::ast::Attribute; use rustc_data_structures::fx::FxHashSet; -use rustc_hir as hir; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{AnonConst, Expr}; +use rustc_hir::{AnonConst, Expr, ImplItemKind, ItemKind, Node, TraitItemKind, Unsafety}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::nested_filter; use rustc_middle::lint::in_external_macro; @@ -366,7 +365,6 @@ declare_clippy_lint! { #[derive(Clone)] pub struct Documentation { valid_idents: FxHashSet, - in_trait_impl: bool, check_private_items: bool, } @@ -374,7 +372,6 @@ impl Documentation { pub fn new(valid_idents: &[String], check_private_items: bool) -> Self { Self { valid_idents: valid_idents.iter().cloned().collect(), - in_trait_impl: false, check_private_items, } } @@ -394,36 +391,72 @@ impl_lint_pass!(Documentation => [ ]); impl<'tcx> LateLintPass<'tcx> for Documentation { - fn check_crate(&mut self, cx: &LateContext<'tcx>) { - let attrs = cx.tcx.hir().attrs(hir::CRATE_HIR_ID); - check_attrs(cx, &self.valid_idents, attrs); - } - - fn check_variant(&mut self, cx: &LateContext<'tcx>, variant: &'tcx hir::Variant<'tcx>) { - let attrs = cx.tcx.hir().attrs(variant.hir_id); - check_attrs(cx, &self.valid_idents, attrs); - } - - fn check_field_def(&mut self, cx: &LateContext<'tcx>, variant: &'tcx hir::FieldDef<'tcx>) { - let attrs = cx.tcx.hir().attrs(variant.hir_id); - check_attrs(cx, &self.valid_idents, attrs); - } - - fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { - let attrs = cx.tcx.hir().attrs(item.hir_id()); + fn check_attributes(&mut self, cx: &LateContext<'tcx>, attrs: &'tcx [Attribute]) { 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)) { - let body = cx.tcx.hir().body(body_id); + match cx.tcx.hir_node(cx.last_node_with_lint_attrs) { + Node::Item(item) => match item.kind { + ItemKind::Fn(sig, _, body_id) => { + if !(is_entrypoint_fn(cx, item.owner_id.to_def_id()) || in_external_macro(cx.tcx.sess, item.span)) { + let body = cx.tcx.hir().body(body_id); - let panic_span = FindPanicUnwrap::find_span(cx, cx.tcx.typeck(item.owner_id), body.value); + let panic_span = FindPanicUnwrap::find_span(cx, cx.tcx.typeck(item.owner_id), body.value); + missing_headers::check( + cx, + item.owner_id, + sig, + headers, + Some(body_id), + panic_span, + self.check_private_items, + ); + } + }, + ItemKind::Trait(_, unsafety, ..) => match (headers.safety, unsafety) { + (false, Unsafety::Unsafe) => span_lint( + cx, + MISSING_SAFETY_DOC, + cx.tcx.def_span(item.owner_id), + "docs for unsafe trait missing `# Safety` section", + ), + (true, Unsafety::Normal) => span_lint( + cx, + UNNECESSARY_SAFETY_DOC, + cx.tcx.def_span(item.owner_id), + "docs for safe trait have unnecessary `# Safety` section", + ), + _ => (), + }, + _ => (), + }, + Node::TraitItem(trait_item) => { + if let TraitItemKind::Fn(sig, ..) = trait_item.kind + && !in_external_macro(cx.tcx.sess, trait_item.span) + { missing_headers::check( cx, - item.owner_id, + trait_item.owner_id, + sig, + headers, + None, + None, + self.check_private_items, + ); + } + }, + Node::ImplItem(impl_item) => { + if let ImplItemKind::Fn(sig, body_id) = impl_item.kind + && !in_external_macro(cx.tcx.sess, impl_item.span) + && !is_trait_impl_item(cx, impl_item.hir_id()) + { + let body = cx.tcx.hir().body(body_id); + + let panic_span = FindPanicUnwrap::find_span(cx, cx.tcx.typeck(impl_item.owner_id), body.value); + missing_headers::check( + cx, + impl_item.owner_id, sig, headers, Some(body_id), @@ -432,67 +465,7 @@ impl<'tcx> LateLintPass<'tcx> for Documentation { ); } }, - hir::ItemKind::Impl(impl_) => { - self.in_trait_impl = impl_.of_trait.is_some(); - }, - 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", - ), - _ => (), - }, - _ => (), - } - } - - fn check_item_post(&mut self, _cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { - if let hir::ItemKind::Impl { .. } = item.kind { - self.in_trait_impl = false; - } - } - - fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) { - let attrs = cx.tcx.hir().attrs(item.hir_id()); - let Some(headers) = check_attrs(cx, &self.valid_idents, attrs) else { - return; - }; - if let hir::TraitItemKind::Fn(ref sig, ..) = item.kind { - if !in_external_macro(cx.tcx.sess, item.span) { - missing_headers::check(cx, item.owner_id, sig, headers, None, None, self.check_private_items); - } - } - } - - fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) { - let attrs = cx.tcx.hir().attrs(item.hir_id()); - let Some(headers) = check_attrs(cx, &self.valid_idents, attrs) else { - return; - }; - if self.in_trait_impl || in_external_macro(cx.tcx.sess, item.span) { - return; - } - if let hir::ImplItemKind::Fn(ref sig, body_id) = item.kind { - let body = cx.tcx.hir().body(body_id); - - let panic_span = FindPanicUnwrap::find_span(cx, cx.tcx.typeck(item.owner_id), body.value); - missing_headers::check( - cx, - item.owner_id, - sig, - headers, - Some(body_id), - panic_span, - self.check_private_items, - ); + _ => {}, } } } diff --git a/clippy_lints/src/index_refutable_slice.rs b/clippy_lints/src/index_refutable_slice.rs index 799ec9d553d4..a4c3b06046e8 100644 --- a/clippy_lints/src/index_refutable_slice.rs +++ b/clippy_lints/src/index_refutable_slice.rs @@ -7,8 +7,8 @@ use clippy_utils::{is_expn_of, is_lint_allowed, path_to_local}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::HirId; use rustc_hir::intravisit::{self, Visitor}; +use rustc_hir::HirId; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::ty; diff --git a/clippy_lints/src/item_name_repetitions.rs b/clippy_lints/src/item_name_repetitions.rs index 6615122567dc..33764d3eb094 100644 --- a/clippy_lints/src/item_name_repetitions.rs +++ b/clippy_lints/src/item_name_repetitions.rs @@ -5,6 +5,7 @@ use clippy_utils::is_bool; use clippy_utils::macros::span_is_local; use clippy_utils::source::is_present_in_source; use clippy_utils::str_utils::{camel_case_split, count_match_end, count_match_start, to_camel_case, to_snake_case}; +use rustc_data_structures::fx::FxHashSet; use rustc_hir::{EnumDef, FieldDef, Item, ItemKind, OwnerId, Variant, VariantData}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; @@ -147,6 +148,7 @@ pub struct ItemNameRepetitions { struct_threshold: u64, avoid_breaking_exported_api: bool, allow_private_module_inception: bool, + allowed_prefixes: FxHashSet, } impl ItemNameRepetitions { @@ -156,6 +158,7 @@ impl ItemNameRepetitions { struct_threshold: u64, avoid_breaking_exported_api: bool, allow_private_module_inception: bool, + allowed_prefixes: &[String], ) -> Self { Self { modules: Vec::new(), @@ -163,8 +166,13 @@ impl ItemNameRepetitions { struct_threshold, avoid_breaking_exported_api, allow_private_module_inception, + allowed_prefixes: allowed_prefixes.iter().map(|s| to_camel_case(s)).collect(), } } + + fn is_allowed_prefix(&self, prefix: &str) -> bool { + self.allowed_prefixes.contains(prefix) + } } impl_lint_pass!(ItemNameRepetitions => [ @@ -423,7 +431,9 @@ impl LateLintPass<'_> for ItemNameRepetitions { _ => (), } } - if rmatching.char_count == nchars { + if rmatching.char_count == nchars + && !self.is_allowed_prefix(&item_camel[..item_camel.len() - rmatching.byte_count]) + { span_lint( cx, MODULE_NAME_REPETITIONS, diff --git a/clippy_lints/src/legacy_numeric_constants.rs b/clippy_lints/src/legacy_numeric_constants.rs index c5f1afe68c3f..00124dcdd91d 100644 --- a/clippy_lints/src/legacy_numeric_constants.rs +++ b/clippy_lints/src/legacy_numeric_constants.rs @@ -17,7 +17,7 @@ declare_clippy_lint! { /// `std::::EPSILON`, etc. /// /// ### Why is this bad? - /// All of these have been superceded by the associated constants on their respective types, + /// All of these have been superseded by the associated constants on their respective types, /// such as `i128::MAX`. These legacy items may be deprecated in a future version of rust. /// /// ### Example diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index b92364a9d147..e2aac58bf979 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -594,6 +594,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { pub_underscore_fields_behavior, ref allowed_duplicate_crates, allow_comparison_to_zero, + ref allowed_prefixes, blacklisted_names: _, cyclomatic_complexity_threshold: _, @@ -864,6 +865,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { struct_field_name_threshold, avoid_breaking_exported_api, allow_private_module_inception, + allowed_prefixes, )) }); store.register_early_pass(|| Box::new(tabs_in_doc_comments::TabsInDocComments)); diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 2bb63ec2b046..443d6189c1f7 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -291,10 +291,7 @@ fn elision_suggestions( }) => { // expand `&'a T` to `&'a T` // ^^ ^^^ - let span = cx - .sess() - .source_map() - .span_extend_while_whitespace(usage.ident.span); + let span = cx.sess().source_map().span_extend_while_whitespace(usage.ident.span); (span, String::new()) }, diff --git a/clippy_lints/src/manual_unwrap_or_default.rs b/clippy_lints/src/manual_unwrap_or_default.rs index c562ceb5bcee..84fb183e3f79 100644 --- a/clippy_lints/src/manual_unwrap_or_default.rs +++ b/clippy_lints/src/manual_unwrap_or_default.rs @@ -1,13 +1,14 @@ -use clippy_utils::sugg::Sugg; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::{Arm, Expr, ExprKind, HirId, LangItem, MatchSource, Pat, PatKind, QPath}; use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::ty::GenericArgKind; use rustc_session::declare_lint_pass; use rustc_span::sym; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_opt; +use clippy_utils::higher::IfLetOrMatch; +use clippy_utils::sugg::Sugg; use clippy_utils::ty::implements_trait; use clippy_utils::{in_constant, is_default_equivalent, peel_blocks, span_contains_comment}; @@ -105,19 +106,39 @@ fn get_some_and_none_bodies<'tcx>( } } -fn handle_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { - let ExprKind::Match(match_expr, [arm1, arm2], MatchSource::Normal | MatchSource::ForLoopDesugar) = expr.kind else { - return false; +#[allow(clippy::needless_pass_by_value)] +fn handle<'tcx>(cx: &LateContext<'tcx>, if_let_or_match: IfLetOrMatch<'tcx>, expr: &'tcx Expr<'tcx>) { + // Get expr_name ("if let" or "match" depending on kind of expression), the condition, the body for + // the some arm, the body for the none arm and the binding id of the some arm + let (expr_name, condition, body_some, body_none, binding_id) = match if_let_or_match { + IfLetOrMatch::Match(condition, [arm1, arm2], MatchSource::Normal | MatchSource::ForLoopDesugar) + // Make sure there are no guards to keep things simple + if arm1.guard.is_none() + && arm2.guard.is_none() + // Get the some and none bodies and the binding id of the some arm + && let Some(((body_some, binding_id), body_none)) = get_some_and_none_bodies(cx, arm1, arm2) => + { + ("match", condition, body_some, body_none, binding_id) + }, + IfLetOrMatch::IfLet(condition, pat, if_expr, Some(else_expr), _) + if let Some(binding_id) = get_some(cx, pat) => + { + ("if let", condition, if_expr, else_expr, binding_id) + }, + _ => { + // All other cases (match with number of arms != 2, if let without else, etc.) + return; + }, }; - // We don't want conditions on the arms to simplify things. - if arm1.guard.is_none() - && arm2.guard.is_none() - // We check that the returned type implements the `Default` trait. - && let match_ty = cx.typeck_results().expr_ty(expr) - && let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default) - && implements_trait(cx, match_ty, default_trait_id, &[]) - // We now get the bodies for both the `Some` and `None` arms. - && let Some(((body_some, binding_id), body_none)) = get_some_and_none_bodies(cx, arm1, arm2) + + // We check if the return type of the expression implements Default. + let expr_type = cx.typeck_results().expr_ty(expr); + if let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default) + && implements_trait(cx, expr_type, default_trait_id, &[]) + // We check if the initial condition implements Default. + && let Some(condition_ty) = cx.typeck_results().expr_ty(condition).walk().nth(1) + && let GenericArgKind::Type(condition_ty) = condition_ty.unpack() + && implements_trait(cx, condition_ty, default_trait_id, &[]) // We check that the `Some(x) => x` doesn't do anything apart "returning" the value in `Some`. && let ExprKind::Path(QPath::Resolved(_, path)) = peel_blocks(body_some).kind && let Res::Local(local_id) = path.res @@ -125,8 +146,9 @@ fn handle_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { // We now check the `None` arm is calling a method equivalent to `Default::default`. && let body_none = peel_blocks(body_none) && is_default_equivalent(cx, body_none) - && let Some(receiver) = Sugg::hir_opt(cx, match_expr).map(Sugg::maybe_par) + && let Some(receiver) = Sugg::hir_opt(cx, condition).map(Sugg::maybe_par) { + // Machine applicable only if there are no comments present let applicability = if span_contains_comment(cx.sess().source_map(), expr.span) { Applicability::MaybeIncorrect } else { @@ -136,48 +158,12 @@ fn handle_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { cx, MANUAL_UNWRAP_OR_DEFAULT, expr.span, - "match can be simplified with `.unwrap_or_default()`", + format!("{expr_name} can be simplified with `.unwrap_or_default()`"), "replace it with", format!("{receiver}.unwrap_or_default()"), applicability, ); } - true -} - -fn handle_if_let<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if let ExprKind::If(cond, if_block, Some(else_expr)) = expr.kind - && let ExprKind::Let(let_) = cond.kind - && let ExprKind::Block(_, _) = else_expr.kind - // We check that the returned type implements the `Default` trait. - && let match_ty = cx.typeck_results().expr_ty(expr) - && let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default) - && implements_trait(cx, match_ty, default_trait_id, &[]) - && let Some(binding_id) = get_some(cx, let_.pat) - // We check that the `Some(x) => x` doesn't do anything apart "returning" the value in `Some`. - && let ExprKind::Path(QPath::Resolved(_, path)) = peel_blocks(if_block).kind - && let Res::Local(local_id) = path.res - && local_id == binding_id - // We now check the `None` arm is calling a method equivalent to `Default::default`. - && let body_else = peel_blocks(else_expr) - && is_default_equivalent(cx, body_else) - && let Some(if_let_expr_snippet) = snippet_opt(cx, let_.init.span) - { - let applicability = if span_contains_comment(cx.sess().source_map(), expr.span) { - Applicability::MaybeIncorrect - } else { - Applicability::MachineApplicable - }; - span_lint_and_sugg( - cx, - MANUAL_UNWRAP_OR_DEFAULT, - expr.span, - "if let can be simplified with `.unwrap_or_default()`", - "replace it with", - format!("{if_let_expr_snippet}.unwrap_or_default()"), - applicability, - ); - } } impl<'tcx> LateLintPass<'tcx> for ManualUnwrapOrDefault { @@ -185,8 +171,9 @@ impl<'tcx> LateLintPass<'tcx> for ManualUnwrapOrDefault { if expr.span.from_expansion() || in_constant(cx, expr.hir_id) { return; } - if !handle_match(cx, expr) { - handle_if_let(cx, expr); + // Call handle only if the expression is `if let` or `match` + if let Some(if_let_or_match) = IfLetOrMatch::parse(cx, expr) { + handle(cx, if_let_or_match, expr); } } } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 2fb317c8c68e..0939c0285642 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3938,7 +3938,6 @@ declare_clippy_lint! { /// This lint cannot detect if the split is intentionally restricted to a single type of newline (`"\n"` or /// `"\r\n"`), for example during the parsing of a specific file format in which precisely one newline type is /// valid. - /// ``` #[clippy::version = "1.77.0"] pub STR_SPLIT_AT_NEWLINE, pedantic, diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs index ac5cc2f01e53..f5f1e94bbf45 100644 --- a/clippy_lints/src/methods/search_is_some.rs +++ b/clippy_lints/src/methods/search_is_some.rs @@ -2,7 +2,8 @@ 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_lang_item; -use clippy_utils::{is_trait_method, strip_pat_refs}; +use clippy_utils::{get_parent_expr, is_trait_method, strip_pat_refs}; +use hir::ExprKind; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::PatKind; @@ -35,7 +36,7 @@ pub(super) fn check<'tcx>( // suggest `any(|..| *..)` instead of `any(|..| **..)` for `find(|..| **..).is_some()` let mut applicability = Applicability::MachineApplicable; let any_search_snippet = if search_method == "find" - && let hir::ExprKind::Closure(&hir::Closure { body, .. }) = search_arg.kind + && let ExprKind::Closure(&hir::Closure { body, .. }) = search_arg.kind && let closure_body = cx.tcx.hir().body(body) && let Some(closure_arg) = closure_body.params.first() { @@ -72,16 +73,24 @@ pub(super) fn check<'tcx>( ); } else { let iter = snippet(cx, search_recv.span, ".."); + let sugg = if is_receiver_of_method_call(cx, expr) { + format!( + "(!{iter}.any({}))", + any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str) + ) + } else { + format!( + "!{iter}.any({})", + any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str) + ) + }; span_lint_and_sugg( cx, SEARCH_IS_SOME, expr.span, msg, "consider using", - format!( - "!{iter}.any({})", - any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str) - ), + sugg, applicability, ); } @@ -127,13 +136,18 @@ pub(super) fn check<'tcx>( let string = snippet(cx, search_recv.span, ".."); let mut applicability = Applicability::MachineApplicable; let find_arg = snippet_with_applicability(cx, search_arg.span, "..", &mut applicability); + let sugg = if is_receiver_of_method_call(cx, expr) { + format!("(!{string}.contains({find_arg}))") + } else { + format!("!{string}.contains({find_arg})") + }; span_lint_and_sugg( cx, SEARCH_IS_SOME, expr.span, msg, "consider using", - format!("!{string}.contains({find_arg})"), + sugg, applicability, ); }, @@ -142,3 +156,13 @@ pub(super) fn check<'tcx>( } } } + +fn is_receiver_of_method_call(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { + if let Some(parent_expr) = get_parent_expr(cx, expr) + && let ExprKind::MethodCall(_, receiver, ..) = parent_expr.kind + && receiver.hir_id == expr.hir_id + { + return true; + } + false +} diff --git a/clippy_lints/src/needless_borrows_for_generic_args.rs b/clippy_lints/src/needless_borrows_for_generic_args.rs index c555fc8675c8..a24cd4f9c8a3 100644 --- a/clippy_lints/src/needless_borrows_for_generic_args.rs +++ b/clippy_lints/src/needless_borrows_for_generic_args.rs @@ -23,7 +23,7 @@ use std::collections::VecDeque; declare_clippy_lint! { /// ### What it does - /// Checks for borrow operations (`&`) that used as a generic argument to a + /// Checks for borrow operations (`&`) that are used as a generic argument to a /// function when the borrowed value could be used. /// /// ### Why is this bad? diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 5ca388d67a17..ff10a841aef1 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -18,7 +18,7 @@ use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult, GlobalId}; use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::impl_lint_pass; -use rustc_span::{sym, DUMMY_SP, InnerSpan, Span}; +use rustc_span::{sym, InnerSpan, Span, DUMMY_SP}; use rustc_target::abi::VariantIdx; // FIXME: this is a correctness problem but there's no suitable @@ -297,12 +297,7 @@ impl NonCopyConst { fn is_value_unfrozen_expr<'tcx>(&self, cx: &LateContext<'tcx>, hir_id: HirId, def_id: DefId, ty: Ty<'tcx>) -> bool { let args = cx.typeck_results().node_args(hir_id); - let result = Self::const_eval_resolve( - cx.tcx, - cx.param_env, - ty::UnevaluatedConst::new(def_id, args), - DUMMY_SP, - ); + let result = Self::const_eval_resolve(cx.tcx, cx.param_env, ty::UnevaluatedConst::new(def_id, args), DUMMY_SP); self.is_value_unfrozen_raw(cx, result, ty) } diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 3aa979cb11b9..87a3c3874d77 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -300,11 +300,8 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { e.span, "calling `as_bytes()` on `include_str!(..)`", "consider using `include_bytes!(..)` instead", - snippet_with_applicability(cx, receiver.span.source_callsite(), r#""foo""#, &mut applicability).replacen( - "include_str", - "include_bytes", - 1, - ), + snippet_with_applicability(cx, receiver.span.source_callsite(), r#""foo""#, &mut applicability) + .replacen("include_str", "include_bytes", 1), applicability, ); } else if lit_content.as_str().is_ascii() diff --git a/clippy_lints/src/transmute/transmute_int_to_non_zero.rs b/clippy_lints/src/transmute/transmute_int_to_non_zero.rs index 234021f0f479..2bea3be3d603 100644 --- a/clippy_lints/src/transmute/transmute_int_to_non_zero.rs +++ b/clippy_lints/src/transmute/transmute_int_to_non_zero.rs @@ -27,7 +27,7 @@ pub(super) fn check<'tcx>( }; // FIXME: This can be simplified once `NonZero` is stable. - let coercable_types = [ + let coercible_types = [ ("NonZeroU8", tcx.types.u8), ("NonZeroU16", tcx.types.u16), ("NonZeroU32", tcx.types.u32), @@ -44,7 +44,7 @@ pub(super) fn check<'tcx>( let int_type = substs.type_at(0); - let Some(nonzero_alias) = coercable_types.iter().find_map(|(nonzero_alias, t)| { + let Some(nonzero_alias) = coercible_types.iter().find_map(|(nonzero_alias, t)| { if *t == int_type && *t == from_ty { Some(nonzero_alias) } else { diff --git a/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs b/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs index a6a6e9a3bac3..ba8c7d6bfcb4 100644 --- a/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs +++ b/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs @@ -1,10 +1,10 @@ -use rustc_hir_typeck::cast::check_cast; use super::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::sugg::Sugg; use rustc_ast::ExprPrecedence; use rustc_errors::Applicability; use rustc_hir::{Expr, Node}; +use rustc_hir_typeck::cast::check_cast; use rustc_lint::LateContext; use rustc_middle::ty::cast::CastKind; use rustc_middle::ty::Ty; diff --git a/clippy_utils/src/ast_utils.rs b/clippy_utils/src/ast_utils.rs index 9f0bd4ea7e2e..0395eb1449b4 100644 --- a/clippy_utils/src/ast_utils.rs +++ b/clippy_utils/src/ast_utils.rs @@ -709,8 +709,12 @@ pub fn eq_ty(l: &Ty, r: &Ty) -> bool { (Tup(l), Tup(r)) => over(l, r, |l, r| eq_ty(l, r)), (Path(lq, lp), Path(rq, rp)) => both(lq, rq, eq_qself) && eq_path(lp, rp), (TraitObject(lg, ls), TraitObject(rg, rs)) => ls == rs && over(lg, rg, eq_generic_bound), - (ImplTrait(_, lg, lc), ImplTrait(_, rg, rc)) => - over(lg, rg, eq_generic_bound) && both(lc, rc, |lc, rc| over(lc.0.as_slice(), rc.0.as_slice(), eq_precise_capture)), + (ImplTrait(_, lg, lc), ImplTrait(_, rg, rc)) => { + over(lg, rg, eq_generic_bound) + && both(lc, rc, |lc, rc| { + over(lc.0.as_slice(), rc.0.as_slice(), eq_precise_capture) + }) + }, (Typeof(l), Typeof(r)) => eq_expr(&l.value, &r.value), (MacCall(l), MacCall(r)) => eq_mac_call(l, r), _ => false, diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index aac699eed239..5e242aea354a 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -3285,7 +3285,7 @@ fn maybe_get_relative_path(from: &DefPath, to: &DefPath, max_super: usize) -> St Right(r) => Right(r.data), }); - // 2. for the remaning segments, construct relative path using only mod names and `super` + // 2. for the remaining segments, construct relative path using only mod names and `super` let mut go_up_by = 0; let mut path = Vec::new(); for el in unique_parts { diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 1afc5ed0157a..a06a82c56530 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -10,7 +10,7 @@ use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::{Expr, FnDecl, LangItem, TyKind, Unsafety}; -use rustc_infer::infer::type_variable::{TypeVariableOrigin}; +use rustc_infer::infer::type_variable::TypeVariableOrigin; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; use rustc_middle::mir::interpret::Scalar; diff --git a/clippy_utils/src/ty/type_certainty/mod.rs b/clippy_utils/src/ty/type_certainty/mod.rs index 762830ffd78d..2241494b484a 100644 --- a/clippy_utils/src/ty/type_certainty/mod.rs +++ b/clippy_utils/src/ty/type_certainty/mod.rs @@ -90,7 +90,7 @@ fn expr_type_certainty(cx: &LateContext<'_>, expr: &Expr<'_>) -> Certainty { if let Some(def_id) = adt_def_id(expr_ty) { certainty.with_def_id(def_id) } else { - certainty + certainty.clear_def_id() } } diff --git a/lintcheck/src/main.rs b/lintcheck/src/main.rs index 4251151c4543..deb06094d83b 100644 --- a/lintcheck/src/main.rs +++ b/lintcheck/src/main.rs @@ -26,12 +26,12 @@ use std::env::consts::EXE_SUFFIX; use std::fmt::{self, Write as _}; use std::io::{self, ErrorKind}; use std::path::{Path, PathBuf}; -use std::process::Command; +use std::process::{Command, ExitStatus}; use std::sync::atomic::{AtomicUsize, Ordering}; use std::time::Duration; use std::{env, fs, thread}; -use cargo_metadata::diagnostic::{Diagnostic, DiagnosticLevel}; +use cargo_metadata::diagnostic::Diagnostic; use cargo_metadata::Message; use rayon::prelude::*; use serde::{Deserialize, Serialize}; @@ -97,16 +97,43 @@ struct Crate { options: Option>, } +/// A single emitted output from clippy being executed on a crate. It may either be a +/// `ClippyWarning`, or a `RustcIce` caused by a panic within clippy. A crate may have many +/// `ClippyWarning`s but a maximum of one `RustcIce` (at which point clippy halts execution). +#[derive(Debug)] +enum ClippyCheckOutput { + ClippyWarning(ClippyWarning), + RustcIce(RustcIce), +} + +#[derive(Debug)] +struct RustcIce { + pub crate_name: String, + pub ice_content: String, +} +impl RustcIce { + pub fn from_stderr_and_status(crate_name: &str, status: ExitStatus, stderr: &str) -> Option { + if status.code().unwrap_or(0) == 101 + /* ice exit status */ + { + Some(Self { + crate_name: crate_name.to_owned(), + ice_content: stderr.to_owned(), + }) + } else { + None + } + } +} + /// A single warning that clippy issued while checking a `Crate` #[derive(Debug)] struct ClippyWarning { - crate_name: String, file: String, line: usize, column: usize, lint_type: String, message: String, - is_ice: bool, } #[allow(unused)] @@ -131,13 +158,11 @@ impl ClippyWarning { }; Some(Self { - crate_name: crate_name.to_owned(), file, line: span.line_start, column: span.column_start, lint_type, message: diag.message, - is_ice: diag.level == DiagnosticLevel::Ice, }) } @@ -318,7 +343,7 @@ impl Crate { config: &LintcheckConfig, lint_filter: &[String], server: &Option, - ) -> Vec { + ) -> Vec { // advance the atomic index by one let index = target_dir_index.fetch_add(1, Ordering::SeqCst); // "loop" the index within 0..thread_limit @@ -342,9 +367,9 @@ impl Crate { let shared_target_dir = clippy_project_root().join("target/lintcheck/shared_target_dir"); let mut cargo_clippy_args = if config.fix { - vec!["--fix", "--"] + vec!["--quiet", "--fix", "--"] } else { - vec!["--", "--message-format=json", "--"] + vec!["--quiet", "--message-format=json", "--"] }; let mut clippy_args = Vec::<&str>::new(); @@ -435,14 +460,21 @@ impl Crate { } // get all clippy warnings and ICEs - let warnings: Vec = Message::parse_stream(stdout.as_bytes()) + let mut entries: Vec = Message::parse_stream(stdout.as_bytes()) .filter_map(|msg| match msg { Ok(Message::CompilerMessage(message)) => ClippyWarning::new(message.message, &self.name, &self.version), _ => None, }) + .map(ClippyCheckOutput::ClippyWarning) .collect(); - warnings + if let Some(ice) = RustcIce::from_stderr_and_status(&self.name, *status, &stderr) { + entries.push(ClippyCheckOutput::RustcIce(ice)); + } else if !status.success() { + println!("non-ICE bad exit status for {} {}: {}", self.name, self.version, stderr); + } + + entries } } @@ -642,7 +674,7 @@ fn main() { LintcheckServer::spawn(recursive_options) }); - let mut clippy_warnings: Vec = crates + let mut clippy_entries: Vec = crates .par_iter() .flat_map(|krate| { krate.run_clippy_lints( @@ -658,7 +690,9 @@ fn main() { .collect(); if let Some(server) = server { - clippy_warnings.extend(server.warnings()); + let server_clippy_entries = server.warnings().map(ClippyCheckOutput::ClippyWarning); + + clippy_entries.extend(server_clippy_entries); } // if we are in --fix mode, don't change the log files, terminate here @@ -666,20 +700,21 @@ fn main() { return; } + // split up warnings and ices + let mut warnings: Vec = vec![]; + let mut raw_ices: Vec = vec![]; + for entry in clippy_entries { + if let ClippyCheckOutput::ClippyWarning(x) = entry { + warnings.push(x); + } else if let ClippyCheckOutput::RustcIce(x) = entry { + raw_ices.push(x); + } + } + // generate some stats - let (stats_formatted, new_stats) = gather_stats(&clippy_warnings); + let (stats_formatted, new_stats) = gather_stats(&warnings); - // grab crashes/ICEs, save the crate name and the ice message - let ices: Vec<(&String, &String)> = clippy_warnings - .iter() - .filter(|warning| warning.is_ice) - .map(|w| (&w.crate_name, &w.message)) - .collect(); - - let mut all_msgs: Vec = clippy_warnings - .iter() - .map(|warn| warn.to_output(config.markdown)) - .collect(); + let mut all_msgs: Vec = warnings.iter().map(|warn| warn.to_output(config.markdown)).collect(); all_msgs.sort(); all_msgs.push("\n\n### Stats:\n\n".into()); all_msgs.push(stats_formatted); @@ -693,11 +728,18 @@ fn main() { } write!(text, "{}", all_msgs.join("")).unwrap(); text.push_str("\n\n### ICEs:\n"); - for (cratename, msg) in &ices { - let _: fmt::Result = write!(text, "{cratename}: '{msg}'"); + for ice in &raw_ices { + let _: fmt::Result = write!( + text, + "{}:\n{}\n========================================\n\n", + ice.crate_name, ice.ice_content + ); } println!("Writing logs to {}", config.lintcheck_results_path.display()); + if !raw_ices.is_empty() { + println!("WARNING: at least one ICE reported, check log file"); + } fs::create_dir_all(config.lintcheck_results_path.parent().unwrap()).unwrap(); fs::write(&config.lintcheck_results_path, text).unwrap(); diff --git a/rust-toolchain b/rust-toolchain index b2fe5c8bee7a..521c0d12983d 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2024-04-04" +channel = "nightly-2024-04-18" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] diff --git a/tests/ui-internal/custom_ice_message.rs b/tests/ui-internal/custom_ice_message.rs index 400bfd5d9751..9b0db660c997 100644 --- a/tests/ui-internal/custom_ice_message.rs +++ b/tests/ui-internal/custom_ice_message.rs @@ -5,7 +5,6 @@ //@normalize-stderr-test: "'rustc'" -> "''" //@normalize-stderr-test: "rustc 1\.\d+.* running on .*" -> "rustc running on " //@normalize-stderr-test: "(?ms)query stack during panic:\n.*end of query stack\n" -> "" -//@normalize-stderr-test: "this compiler `.*` is outdated" -> "this compiler is outdated" #![deny(clippy::internal)] #![allow(clippy::missing_clippy_version_attribute)] diff --git a/tests/ui-internal/custom_ice_message.stderr b/tests/ui-internal/custom_ice_message.stderr index 763ce59ba1d9..b99e8c0e76f0 100644 --- a/tests/ui-internal/custom_ice_message.stderr +++ b/tests/ui-internal/custom_ice_message.stderr @@ -4,10 +4,9 @@ note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace error: the compiler unexpectedly panicked. this is a bug. -note: it seems that this compiler is outdated, a newer nightly should have been released in the meantime - | - = note: please consider running `rustup update nightly` to update the nightly channel and check if this problem still persists - = note: if the problem still persists, we would appreciate a bug report: https://github.com/rust-lang/rust-clippy/issues/new?template=ice.yml +note: we would appreciate a bug report: https://github.com/rust-lang/rust-clippy/issues/new?template=ice.yml + +note: please make sure that you have updated to the latest nightly note: rustc running on diff --git a/tests/ui-toml/item_name_repetitions/allowed_prefixes/clippy.toml b/tests/ui-toml/item_name_repetitions/allowed_prefixes/clippy.toml new file mode 100644 index 000000000000..35145551b600 --- /dev/null +++ b/tests/ui-toml/item_name_repetitions/allowed_prefixes/clippy.toml @@ -0,0 +1 @@ +allowed-prefixes = ["bar"] diff --git a/tests/ui-toml/item_name_repetitions/allowed_prefixes/item_name_repetitions.rs b/tests/ui-toml/item_name_repetitions/allowed_prefixes/item_name_repetitions.rs new file mode 100644 index 000000000000..4142ced5f6b5 --- /dev/null +++ b/tests/ui-toml/item_name_repetitions/allowed_prefixes/item_name_repetitions.rs @@ -0,0 +1,15 @@ +#![warn(clippy::module_name_repetitions)] +#![allow(dead_code)] + +mod foo { + // #12544 - shouldn't warn if item name consists only of an allowed prefix and a module name. + // In this test, allowed prefixes are configured to be ["bar"]. + + // this line should produce a warning: + pub fn to_foo() {} + + // but this line shouldn't + pub fn bar_foo() {} +} + +fn main() {} diff --git a/tests/ui-toml/item_name_repetitions/allowed_prefixes/item_name_repetitions.stderr b/tests/ui-toml/item_name_repetitions/allowed_prefixes/item_name_repetitions.stderr new file mode 100644 index 000000000000..6cfe0eab4792 --- /dev/null +++ b/tests/ui-toml/item_name_repetitions/allowed_prefixes/item_name_repetitions.stderr @@ -0,0 +1,11 @@ +error: item name ends with its containing module's name + --> tests/ui-toml/item_name_repetitions/allowed_prefixes/item_name_repetitions.rs:9:12 + | +LL | pub fn to_foo() {} + | ^^^^^^ + | + = note: `-D clippy::module-name-repetitions` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::module_name_repetitions)]` + +error: aborting due to 1 previous error + diff --git a/tests/ui-toml/item_name_repetitions/allowed_prefixes_extend/clippy.toml b/tests/ui-toml/item_name_repetitions/allowed_prefixes_extend/clippy.toml new file mode 100644 index 000000000000..31ef524671d1 --- /dev/null +++ b/tests/ui-toml/item_name_repetitions/allowed_prefixes_extend/clippy.toml @@ -0,0 +1 @@ +allowed-prefixes = ["..", "bar"] diff --git a/tests/ui-toml/item_name_repetitions/allowed_prefixes_extend/item_name_repetitions.rs b/tests/ui-toml/item_name_repetitions/allowed_prefixes_extend/item_name_repetitions.rs new file mode 100644 index 000000000000..b132305d01cf --- /dev/null +++ b/tests/ui-toml/item_name_repetitions/allowed_prefixes_extend/item_name_repetitions.rs @@ -0,0 +1,21 @@ +#![warn(clippy::module_name_repetitions)] +#![allow(dead_code)] + +mod foo { + // #12544 - shouldn't warn if item name consists only of an allowed prefix and a module name. + // In this test, allowed prefixes are configured to be all of the default prefixes and ["bar"]. + + // this line should produce a warning: + pub fn something_foo() {} + + // but none of the following should: + pub fn bar_foo() {} + pub fn to_foo() {} + pub fn as_foo() {} + pub fn into_foo() {} + pub fn from_foo() {} + pub fn try_into_foo() {} + pub fn try_from_foo() {} +} + +fn main() {} diff --git a/tests/ui-toml/item_name_repetitions/allowed_prefixes_extend/item_name_repetitions.stderr b/tests/ui-toml/item_name_repetitions/allowed_prefixes_extend/item_name_repetitions.stderr new file mode 100644 index 000000000000..f495ec421841 --- /dev/null +++ b/tests/ui-toml/item_name_repetitions/allowed_prefixes_extend/item_name_repetitions.stderr @@ -0,0 +1,11 @@ +error: item name ends with its containing module's name + --> tests/ui-toml/item_name_repetitions/allowed_prefixes_extend/item_name_repetitions.rs:9:12 + | +LL | pub fn something_foo() {} + | ^^^^^^^^^^^^^ + | + = note: `-D clippy::module-name-repetitions` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::module_name_repetitions)]` + +error: aborting due to 1 previous error + diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index 737c062ea562..24645b61fdb0 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -14,6 +14,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect allowed-dotfiles allowed-duplicate-crates allowed-idents-below-min-chars + allowed-prefixes allowed-scripts allowed-wildcard-imports arithmetic-side-effects-allowed @@ -93,6 +94,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect allowed-dotfiles allowed-duplicate-crates allowed-idents-below-min-chars + allowed-prefixes allowed-scripts allowed-wildcard-imports arithmetic-side-effects-allowed @@ -172,6 +174,7 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni allowed-dotfiles allowed-duplicate-crates allowed-idents-below-min-chars + allowed-prefixes allowed-scripts allowed-wildcard-imports arithmetic-side-effects-allowed diff --git a/tests/ui/arc_with_non_send_sync.rs b/tests/ui/arc_with_non_send_sync.rs index 349e81912e3c..c287480bb1fd 100644 --- a/tests/ui/arc_with_non_send_sync.rs +++ b/tests/ui/arc_with_non_send_sync.rs @@ -33,16 +33,9 @@ fn main() { let _ = Arc::new(42); let _ = Arc::new(RefCell::new(42)); - //~^ ERROR: usage of an `Arc` that is not `Send` and `Sync` - //~| NOTE: the trait `Sync` is not implemented for `RefCell` let mutex = Mutex::new(1); let _ = Arc::new(mutex.lock().unwrap()); - //~^ ERROR: usage of an `Arc` that is not `Send` and `Sync` - //~| NOTE: the trait `Send` is not implemented for `MutexGuard<'_, i32>` let _ = Arc::new(&42 as *const i32); - //~^ ERROR: usage of an `Arc` that is not `Send` and `Sync` - //~| NOTE: the trait `Send` is not implemented for `*const i32` - //~| NOTE: the trait `Sync` is not implemented for `*const i32` } diff --git a/tests/ui/arc_with_non_send_sync.stderr b/tests/ui/arc_with_non_send_sync.stderr index d4e630376204..da363a3ebdd9 100644 --- a/tests/ui/arc_with_non_send_sync.stderr +++ b/tests/ui/arc_with_non_send_sync.stderr @@ -4,38 +4,31 @@ error: usage of an `Arc` that is not `Send` and `Sync` LL | let _ = Arc::new(RefCell::new(42)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `Arc>` is not `Send` and `Sync` as: - = note: - the trait `Sync` is not implemented for `RefCell` - = help: consider using an `Rc` instead. `Arc` does not provide benefits for non `Send` and `Sync` types - = note: if you intend to use `Arc` with `Send` and `Sync` traits - = note: wrap the inner type with a `Mutex` or implement `Send` and `Sync` for `RefCell` + = note: `Arc>` is not `Send` and `Sync` as `RefCell` is not `Sync` + = help: if the `Arc` will not used be across threads replace it with an `Rc` + = help: otherwise make `RefCell` `Send` and `Sync` or consider a wrapper type such as `Mutex` = note: `-D clippy::arc-with-non-send-sync` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::arc_with_non_send_sync)]` error: usage of an `Arc` that is not `Send` and `Sync` - --> tests/ui/arc_with_non_send_sync.rs:40:13 + --> tests/ui/arc_with_non_send_sync.rs:38:13 | LL | let _ = Arc::new(mutex.lock().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `Arc>` is not `Send` and `Sync` as: - = note: - the trait `Send` is not implemented for `MutexGuard<'_, i32>` - = help: consider using an `Rc` instead. `Arc` does not provide benefits for non `Send` and `Sync` types - = note: if you intend to use `Arc` with `Send` and `Sync` traits - = note: wrap the inner type with a `Mutex` or implement `Send` and `Sync` for `MutexGuard<'_, i32>` + = note: `Arc>` is not `Send` and `Sync` as `MutexGuard<'_, i32>` is not `Send` + = help: if the `Arc` will not used be across threads replace it with an `Rc` + = help: otherwise make `MutexGuard<'_, i32>` `Send` and `Sync` or consider a wrapper type such as `Mutex` error: usage of an `Arc` that is not `Send` and `Sync` - --> tests/ui/arc_with_non_send_sync.rs:44:13 + --> tests/ui/arc_with_non_send_sync.rs:40:13 | LL | let _ = Arc::new(&42 as *const i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `Arc<*const i32>` is not `Send` and `Sync` as: - = note: - the trait `Send` is not implemented for `*const i32` - = note: - the trait `Sync` is not implemented for `*const i32` - = help: consider using an `Rc` instead. `Arc` does not provide benefits for non `Send` and `Sync` types - = note: if you intend to use `Arc` with `Send` and `Sync` traits - = note: wrap the inner type with a `Mutex` or implement `Send` and `Sync` for `*const i32` + = note: `Arc<*const i32>` is not `Send` and `Sync` as `*const i32` is neither `Send` nor `Sync` + = help: if the `Arc` will not used be across threads replace it with an `Rc` + = help: otherwise make `*const i32` `Send` and `Sync` or consider a wrapper type such as `Mutex` error: aborting due to 3 previous errors diff --git a/tests/ui/auxiliary/proc_macro_attr.rs b/tests/ui/auxiliary/proc_macro_attr.rs index a6f3b164c9ba..f6fdebaf2527 100644 --- a/tests/ui/auxiliary/proc_macro_attr.rs +++ b/tests/ui/auxiliary/proc_macro_attr.rs @@ -176,3 +176,17 @@ pub fn with_empty_docs(_attr: TokenStream, input: TokenStream) -> TokenStream { } .into() } + +#[proc_macro_attribute] +pub fn duplicated_attr(_attr: TokenStream, input: TokenStream) -> TokenStream { + let item = parse_macro_input!(input as syn::Item); + let attrs: Vec = vec![]; + quote! { + #(#attrs)* + #[allow(unused)] + #[allow(unused)] + #[allow(unused)] + #item + } + .into() +} diff --git a/tests/ui/cast.rs b/tests/ui/cast.rs index ce76ad3d3ad1..215c008902d2 100644 --- a/tests/ui/cast.rs +++ b/tests/ui/cast.rs @@ -463,6 +463,18 @@ fn issue11642() { } } +fn issue11738() { + macro_rules! m { + () => { + let _ = i32::MIN as u32; // cast_sign_loss + let _ = u32::MAX as u8; // cast_possible_truncation + let _ = std::f64::consts::PI as f32; // cast_possible_truncation + let _ = 0i8 as i32; // cast_lossless + }; + } + m!(); +} + fn issue12506() -> usize { let bar: Result, u32> = Ok(Some(10)); bar.unwrap().unwrap() as usize diff --git a/tests/ui/cast.stderr b/tests/ui/cast.stderr index 3736e8aee0af..8b269c471765 100644 --- a/tests/ui/cast.stderr +++ b/tests/ui/cast.stderr @@ -650,8 +650,47 @@ error: casting `i32` to `u32` may lose the sign of the value LL | (a.abs() * b.pow(2) / c.abs()) as u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: casting `i32` to `u32` may lose the sign of the value + --> tests/ui/cast.rs:469:21 + | +LL | let _ = i32::MIN as u32; // cast_sign_loss + | ^^^^^^^^^^^^^^^ +... +LL | m!(); + | ---- in this macro invocation + | + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: casting `u32` to `u8` may truncate the value + --> tests/ui/cast.rs:470:21 + | +LL | let _ = u32::MAX as u8; // cast_possible_truncation + | ^^^^^^^^^^^^^^ +... +LL | m!(); + | ---- in this macro invocation + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) +help: ... or use `try_from` and handle the error accordingly + | +LL | let _ = u8::try_from(u32::MAX); // cast_possible_truncation + | ~~~~~~~~~~~~~~~~~~~~~~ + +error: casting `f64` to `f32` may truncate the value + --> tests/ui/cast.rs:471:21 + | +LL | let _ = std::f64::consts::PI as f32; // cast_possible_truncation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | m!(); + | ---- in this macro invocation + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + error: casting `i64` to `usize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:468:5 + --> tests/ui/cast.rs:480:5 | LL | bar.unwrap().unwrap() as usize | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -663,10 +702,10 @@ LL | usize::try_from(bar.unwrap().unwrap()) | error: casting `i64` to `usize` may lose the sign of the value - --> tests/ui/cast.rs:468:5 + --> tests/ui/cast.rs:480:5 | LL | bar.unwrap().unwrap() as usize | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 87 previous errors +error: aborting due to 90 previous errors diff --git a/tests/ui/crashes/ice-12585.rs b/tests/ui/crashes/ice-12585.rs new file mode 100644 index 000000000000..7928115c0a94 --- /dev/null +++ b/tests/ui/crashes/ice-12585.rs @@ -0,0 +1,26 @@ +#![allow(clippy::unit_arg)] + +struct One { + x: i32, +} +struct Two { + x: i32, +} + +struct Product {} + +impl Product { + pub fn a_method(self, _: ()) {} +} + +fn from_array(_: [i32; 2]) -> Product { + todo!() +} + +pub fn main() { + let one = One { x: 1 }; + let two = Two { x: 2 }; + + let product = from_array([one.x, two.x]); + product.a_method(<()>::default()); +} diff --git a/tests/ui/crashes/ice-12616.stderr b/tests/ui/crashes/ice-12616.stderr index ef573f55cf36..c7cf5cf5483f 100644 --- a/tests/ui/crashes/ice-12616.stderr +++ b/tests/ui/crashes/ice-12616.stderr @@ -7,13 +7,5 @@ LL | s() as *const (); = note: `-D clippy::ptr-as-ptr` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::ptr_as_ptr)]` -error: `as` casting between raw pointers without changing its mutability - --> tests/ui/crashes/ice-12616.rs:6:5 - | -LL | s() as *const (); - | ^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `s().cast::<()>()` - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error diff --git a/tests/ui/doc/doc-fixable.fixed b/tests/ui/doc/doc-fixable.fixed index 178d4a1aa2bb..7e22c847b1bc 100644 --- a/tests/ui/doc/doc-fixable.fixed +++ b/tests/ui/doc/doc-fixable.fixed @@ -235,3 +235,8 @@ fn parenthesized_word() {} /// OSes /// UXes fn plural_acronym_test() {} + +extern { + /// `foo()` + fn in_extern(); +} diff --git a/tests/ui/doc/doc-fixable.rs b/tests/ui/doc/doc-fixable.rs index 01edb44c64c1..3e2cb0df54b0 100644 --- a/tests/ui/doc/doc-fixable.rs +++ b/tests/ui/doc/doc-fixable.rs @@ -235,3 +235,8 @@ fn parenthesized_word() {} /// OSes /// UXes fn plural_acronym_test() {} + +extern { + /// foo() + fn in_extern(); +} diff --git a/tests/ui/doc/doc-fixable.stderr b/tests/ui/doc/doc-fixable.stderr index ac876306b39c..cd2228c47e35 100644 --- a/tests/ui/doc/doc-fixable.stderr +++ b/tests/ui/doc/doc-fixable.stderr @@ -352,5 +352,16 @@ help: try LL | /// `ABes` | ~~~~~~ -error: aborting due to 32 previous errors +error: item in documentation is missing backticks + --> tests/ui/doc/doc-fixable.rs:240:9 + | +LL | /// foo() + | ^^^^^ + | +help: try + | +LL | /// `foo()` + | ~~~~~~~ + +error: aborting due to 33 previous errors diff --git a/tests/ui/duplicated_attributes.rs b/tests/ui/duplicated_attributes.rs index d051c881f15b..d51e7e37beb6 100644 --- a/tests/ui/duplicated_attributes.rs +++ b/tests/ui/duplicated_attributes.rs @@ -1,9 +1,14 @@ +//@aux-build:proc_macro_attr.rs + #![warn(clippy::duplicated_attributes)] #![cfg(any(unix, windows))] #![allow(dead_code)] #![allow(dead_code)] //~ ERROR: duplicated attribute #![cfg(any(unix, windows))] // Should not warn! +#[macro_use] +extern crate proc_macro_attr; + #[cfg(any(unix, windows, target_os = "linux"))] #[allow(dead_code)] #[allow(dead_code)] //~ ERROR: duplicated attribute @@ -12,7 +17,10 @@ fn foo() {} #[cfg(unix)] #[cfg(windows)] -#[cfg(unix)] //~ ERROR: duplicated attribute +#[cfg(unix)] // cfgs are not handled fn bar() {} +#[proc_macro_attr::duplicated_attr()] // Should not warn! +fn babar() {} + fn main() {} diff --git a/tests/ui/duplicated_attributes.stderr b/tests/ui/duplicated_attributes.stderr index 9e26ba990ac1..0903617a8d1f 100644 --- a/tests/ui/duplicated_attributes.stderr +++ b/tests/ui/duplicated_attributes.stderr @@ -1,16 +1,16 @@ error: duplicated attribute - --> tests/ui/duplicated_attributes.rs:4:10 + --> tests/ui/duplicated_attributes.rs:6:10 | LL | #![allow(dead_code)] | ^^^^^^^^^ | note: first defined here - --> tests/ui/duplicated_attributes.rs:3:10 + --> tests/ui/duplicated_attributes.rs:5:10 | LL | #![allow(dead_code)] | ^^^^^^^^^ help: remove this attribute - --> tests/ui/duplicated_attributes.rs:4:10 + --> tests/ui/duplicated_attributes.rs:6:10 | LL | #![allow(dead_code)] | ^^^^^^^^^ @@ -18,38 +18,21 @@ LL | #![allow(dead_code)] = help: to override `-D warnings` add `#[allow(clippy::duplicated_attributes)]` error: duplicated attribute - --> tests/ui/duplicated_attributes.rs:9:9 + --> tests/ui/duplicated_attributes.rs:14:9 | LL | #[allow(dead_code)] | ^^^^^^^^^ | note: first defined here - --> tests/ui/duplicated_attributes.rs:8:9 + --> tests/ui/duplicated_attributes.rs:13:9 | LL | #[allow(dead_code)] | ^^^^^^^^^ help: remove this attribute - --> tests/ui/duplicated_attributes.rs:9:9 + --> tests/ui/duplicated_attributes.rs:14:9 | LL | #[allow(dead_code)] | ^^^^^^^^^ -error: duplicated attribute - --> tests/ui/duplicated_attributes.rs:15:7 - | -LL | #[cfg(unix)] - | ^^^^ - | -note: first defined here - --> tests/ui/duplicated_attributes.rs:13:7 - | -LL | #[cfg(unix)] - | ^^^^ -help: remove this attribute - --> tests/ui/duplicated_attributes.rs:15:7 - | -LL | #[cfg(unix)] - | ^^^^ - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors diff --git a/tests/ui/manual_unwrap_or_default.fixed b/tests/ui/manual_unwrap_or_default.fixed index a0b707628a88..d6e736ba9cc2 100644 --- a/tests/ui/manual_unwrap_or_default.fixed +++ b/tests/ui/manual_unwrap_or_default.fixed @@ -16,6 +16,16 @@ fn main() { let x: Option> = None; x.unwrap_or_default(); + + // Issue #12564 + // No error as &Vec<_> doesn't implement std::default::Default + let mut map = std::collections::HashMap::from([(0, vec![0; 3]), (1, vec![1; 3]), (2, vec![2])]); + let x: &[_] = if let Some(x) = map.get(&0) { x } else { &[] }; + // Same code as above written using match. + let x: &[_] = match map.get(&0) { + Some(x) => x, + None => &[], + }; } // Issue #12531 diff --git a/tests/ui/manual_unwrap_or_default.rs b/tests/ui/manual_unwrap_or_default.rs index 1d4cca12f6c7..462d5d90ee77 100644 --- a/tests/ui/manual_unwrap_or_default.rs +++ b/tests/ui/manual_unwrap_or_default.rs @@ -37,6 +37,16 @@ fn main() { } else { Vec::default() }; + + // Issue #12564 + // No error as &Vec<_> doesn't implement std::default::Default + let mut map = std::collections::HashMap::from([(0, vec![0; 3]), (1, vec![1; 3]), (2, vec![2])]); + let x: &[_] = if let Some(x) = map.get(&0) { x } else { &[] }; + // Same code as above written using match. + let x: &[_] = match map.get(&0) { + Some(x) => x, + None => &[], + }; } // Issue #12531 diff --git a/tests/ui/manual_unwrap_or_default.stderr b/tests/ui/manual_unwrap_or_default.stderr index d89212e60459..3f1da444301f 100644 --- a/tests/ui/manual_unwrap_or_default.stderr +++ b/tests/ui/manual_unwrap_or_default.stderr @@ -53,7 +53,7 @@ LL | | }; | |_____^ help: replace it with: `x.unwrap_or_default()` error: match can be simplified with `.unwrap_or_default()` - --> tests/ui/manual_unwrap_or_default.rs:46:20 + --> tests/ui/manual_unwrap_or_default.rs:56:20 | LL | Some(_) => match *b { | ____________________^ diff --git a/tests/ui/module_name_repetitions.rs b/tests/ui/module_name_repetitions.rs index a6cf03890983..b75ef87ab364 100644 --- a/tests/ui/module_name_repetitions.rs +++ b/tests/ui/module_name_repetitions.rs @@ -19,6 +19,20 @@ mod foo { // Should not warn pub struct Foobar; + + // #12544 - shouldn't warn if item name consists only of an allowed prefix and a module name. + pub fn to_foo() {} + pub fn into_foo() {} + pub fn as_foo() {} + pub fn from_foo() {} + pub fn try_into_foo() {} + pub fn try_from_foo() {} + pub trait IntoFoo {} + pub trait ToFoo {} + pub trait AsFoo {} + pub trait FromFoo {} + pub trait TryIntoFoo {} + pub trait TryFromFoo {} } fn main() {} diff --git a/tests/ui/multiple_unsafe_ops_per_block.rs b/tests/ui/multiple_unsafe_ops_per_block.rs index 8afb4df20af4..6b8a103d4a94 100644 --- a/tests/ui/multiple_unsafe_ops_per_block.rs +++ b/tests/ui/multiple_unsafe_ops_per_block.rs @@ -1,3 +1,4 @@ +//@needs-asm-support //@aux-build:proc_macros.rs #![allow(unused)] #![allow(deref_nullptr)] diff --git a/tests/ui/multiple_unsafe_ops_per_block.stderr b/tests/ui/multiple_unsafe_ops_per_block.stderr index cff85ae115e0..e732bde0707e 100644 --- a/tests/ui/multiple_unsafe_ops_per_block.stderr +++ b/tests/ui/multiple_unsafe_ops_per_block.stderr @@ -1,5 +1,5 @@ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:36:5 + --> tests/ui/multiple_unsafe_ops_per_block.rs:37:5 | LL | / unsafe { LL | | STATIC += 1; @@ -8,12 +8,12 @@ LL | | } | |_____^ | note: modification of a mutable static occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:37:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:38:9 | LL | STATIC += 1; | ^^^^^^^^^^^ note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:38:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:39:9 | LL | not_very_safe(); | ^^^^^^^^^^^^^^^ @@ -21,7 +21,7 @@ LL | not_very_safe(); = help: to override `-D warnings` add `#[allow(clippy::multiple_unsafe_ops_per_block)]` error: this `unsafe` block contains 2 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:45:5 + --> tests/ui/multiple_unsafe_ops_per_block.rs:46:5 | LL | / unsafe { LL | | drop(u.u); @@ -30,18 +30,18 @@ LL | | } | |_____^ | note: union field access occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:46:14 + --> tests/ui/multiple_unsafe_ops_per_block.rs:47:14 | LL | drop(u.u); | ^^^ note: raw pointer dereference occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:47:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:48:9 | LL | *raw_ptr(); | ^^^^^^^^^^ error: this `unsafe` block contains 3 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:52:5 + --> tests/ui/multiple_unsafe_ops_per_block.rs:53:5 | LL | / unsafe { LL | | asm!("nop"); @@ -51,23 +51,23 @@ LL | | } | |_____^ | note: inline assembly used here - --> tests/ui/multiple_unsafe_ops_per_block.rs:53:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:54:9 | LL | asm!("nop"); | ^^^^^^^^^^^ note: unsafe method call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:54:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:55:9 | LL | sample.not_very_safe(); | ^^^^^^^^^^^^^^^^^^^^^^ note: modification of a mutable static occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:55:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:56:9 | LL | STATIC = 0; | ^^^^^^^^^^ error: this `unsafe` block contains 6 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:61:5 + --> tests/ui/multiple_unsafe_ops_per_block.rs:62:5 | LL | / unsafe { LL | | drop(u.u); @@ -79,55 +79,55 @@ LL | | } | |_____^ | note: union field access occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:62:14 + --> tests/ui/multiple_unsafe_ops_per_block.rs:63:14 | LL | drop(u.u); | ^^^ note: access of a mutable static occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:63:14 + --> tests/ui/multiple_unsafe_ops_per_block.rs:64:14 | LL | drop(STATIC); | ^^^^^^ note: unsafe method call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:64:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:65:9 | LL | sample.not_very_safe(); | ^^^^^^^^^^^^^^^^^^^^^^ note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:65:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:66:9 | LL | not_very_safe(); | ^^^^^^^^^^^^^^^ note: raw pointer dereference occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:66:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:67:9 | LL | *raw_ptr(); | ^^^^^^^^^^ note: inline assembly used here - --> tests/ui/multiple_unsafe_ops_per_block.rs:67:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:68:9 | LL | asm!("nop"); | ^^^^^^^^^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:105:5 + --> tests/ui/multiple_unsafe_ops_per_block.rs:106:5 | LL | unsafe { char::from_u32_unchecked(*ptr.cast::()) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:105:14 + --> tests/ui/multiple_unsafe_ops_per_block.rs:106:14 | LL | unsafe { char::from_u32_unchecked(*ptr.cast::()) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: raw pointer dereference occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:105:39 + --> tests/ui/multiple_unsafe_ops_per_block.rs:106:39 | LL | unsafe { char::from_u32_unchecked(*ptr.cast::()) } | ^^^^^^^^^^^^^^^^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:123:5 + --> tests/ui/multiple_unsafe_ops_per_block.rs:124:5 | LL | / unsafe { LL | | x(); @@ -136,18 +136,18 @@ LL | | } | |_____^ | note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:124:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:125:9 | LL | x(); | ^^^ note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:125:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:126:9 | LL | x(); | ^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:134:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:135:9 | LL | / unsafe { LL | | T::X(); @@ -156,18 +156,18 @@ LL | | } | |_________^ | note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:135:13 + --> tests/ui/multiple_unsafe_ops_per_block.rs:136:13 | LL | T::X(); | ^^^^^^ note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:136:13 + --> tests/ui/multiple_unsafe_ops_per_block.rs:137:13 | LL | T::X(); | ^^^^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:144:5 + --> tests/ui/multiple_unsafe_ops_per_block.rs:145:5 | LL | / unsafe { LL | | x.0(); @@ -176,12 +176,12 @@ LL | | } | |_____^ | note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:145:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:146:9 | LL | x.0(); | ^^^^^ note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:146:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:147:9 | LL | x.0(); | ^^^^^ diff --git a/tests/ui/needless_borrow.fixed b/tests/ui/needless_borrow.fixed index 998f5430fdf0..5121077b4cab 100644 --- a/tests/ui/needless_borrow.fixed +++ b/tests/ui/needless_borrow.fixed @@ -251,3 +251,11 @@ mod issue_10253 { (&S).f::<()>(); } } + +fn issue_12268() { + let option = Some((&1,)); + let x = (&1,); + option.unwrap_or((x.0,)); + //~^ ERROR: this expression creates a reference which is immediately dereferenced by the + // compiler +} diff --git a/tests/ui/needless_borrow.rs b/tests/ui/needless_borrow.rs index acb2c74d849a..e3a5cb280bad 100644 --- a/tests/ui/needless_borrow.rs +++ b/tests/ui/needless_borrow.rs @@ -251,3 +251,11 @@ mod issue_10253 { (&S).f::<()>(); } } + +fn issue_12268() { + let option = Some((&1,)); + let x = (&1,); + option.unwrap_or((&x.0,)); + //~^ ERROR: this expression creates a reference which is immediately dereferenced by the + // compiler +} diff --git a/tests/ui/needless_borrow.stderr b/tests/ui/needless_borrow.stderr index 5f0283387642..4b2b17e7e570 100644 --- a/tests/ui/needless_borrow.stderr +++ b/tests/ui/needless_borrow.stderr @@ -163,5 +163,11 @@ error: this expression borrows a value the compiler would automatically borrow LL | let _ = &mut (&mut { x.u }).x; | ^^^^^^^^^^^^^^ help: change this to: `{ x.u }` -error: aborting due to 27 previous errors +error: this expression creates a reference which is immediately dereferenced by the compiler + --> tests/ui/needless_borrow.rs:258:23 + | +LL | option.unwrap_or((&x.0,)); + | ^^^^ help: change this to: `x.0` + +error: aborting due to 28 previous errors diff --git a/tests/ui/nonminimal_bool_methods.fixed b/tests/ui/nonminimal_bool_methods.fixed index bd4be3e5a440..aba599678e39 100644 --- a/tests/ui/nonminimal_bool_methods.fixed +++ b/tests/ui/nonminimal_bool_methods.fixed @@ -109,4 +109,12 @@ fn dont_warn_for_negated_partial_ord_comparison() { let _ = !(a >= b); } +fn issue_12625() { + let a = 0; + let b = 0; + if (a as u64) < b {} //~ ERROR: this boolean expression can be simplified + if (a as u64) < b {} //~ ERROR: this boolean expression can be simplified + if a as u64 > b {} //~ ERROR: this boolean expression can be simplified +} + fn main() {} diff --git a/tests/ui/nonminimal_bool_methods.rs b/tests/ui/nonminimal_bool_methods.rs index 4523c7385df9..35f22db1d36a 100644 --- a/tests/ui/nonminimal_bool_methods.rs +++ b/tests/ui/nonminimal_bool_methods.rs @@ -109,4 +109,12 @@ fn dont_warn_for_negated_partial_ord_comparison() { let _ = !(a >= b); } +fn issue_12625() { + let a = 0; + let b = 0; + if !(a as u64 >= b) {} //~ ERROR: this boolean expression can be simplified + if !((a as u64) >= b) {} //~ ERROR: this boolean expression can be simplified + if !(a as u64 <= b) {} //~ ERROR: this boolean expression can be simplified +} + fn main() {} diff --git a/tests/ui/nonminimal_bool_methods.stderr b/tests/ui/nonminimal_bool_methods.stderr index e32c8dacd2fa..18da4e0d380b 100644 --- a/tests/ui/nonminimal_bool_methods.stderr +++ b/tests/ui/nonminimal_bool_methods.stderr @@ -79,5 +79,23 @@ error: this boolean expression can be simplified LL | if !res.is_none() {} | ^^^^^^^^^^^^^^ help: try: `res.is_some()` -error: aborting due to 13 previous errors +error: this boolean expression can be simplified + --> tests/ui/nonminimal_bool_methods.rs:115:8 + | +LL | if !(a as u64 >= b) {} + | ^^^^^^^^^^^^^^^^ help: try: `(a as u64) < b` + +error: this boolean expression can be simplified + --> tests/ui/nonminimal_bool_methods.rs:116:8 + | +LL | if !((a as u64) >= b) {} + | ^^^^^^^^^^^^^^^^^^ help: try: `(a as u64) < b` + +error: this boolean expression can be simplified + --> tests/ui/nonminimal_bool_methods.rs:117:8 + | +LL | if !(a as u64 <= b) {} + | ^^^^^^^^^^^^^^^^ help: try: `a as u64 > b` + +error: aborting due to 16 previous errors diff --git a/tests/ui/ptr_as_ptr.fixed b/tests/ui/ptr_as_ptr.fixed index 61d37b8ba3af..fa15c323540f 100644 --- a/tests/ui/ptr_as_ptr.fixed +++ b/tests/ui/ptr_as_ptr.fixed @@ -1,5 +1,4 @@ //@aux-build:proc_macros.rs -//@compile-flags: -Zdeduplicate-diagnostics=yes #![warn(clippy::ptr_as_ptr)] diff --git a/tests/ui/ptr_as_ptr.rs b/tests/ui/ptr_as_ptr.rs index 8f2068cd2684..7ab52e63da55 100644 --- a/tests/ui/ptr_as_ptr.rs +++ b/tests/ui/ptr_as_ptr.rs @@ -1,5 +1,4 @@ //@aux-build:proc_macros.rs -//@compile-flags: -Zdeduplicate-diagnostics=yes #![warn(clippy::ptr_as_ptr)] diff --git a/tests/ui/ptr_as_ptr.stderr b/tests/ui/ptr_as_ptr.stderr index e6cd697c7baf..e162f35baf55 100644 --- a/tests/ui/ptr_as_ptr.stderr +++ b/tests/ui/ptr_as_ptr.stderr @@ -1,5 +1,5 @@ error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:19:33 + --> tests/ui/ptr_as_ptr.rs:18:33 | LL | *unsafe { Box::from_raw(Box::into_raw(Box::new(o)) as *mut super::issue_11278_a::T) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `Box::into_raw(Box::new(o)).cast::>()` @@ -8,37 +8,37 @@ LL | *unsafe { Box::from_raw(Box::into_raw(Box::new(o)) as *mut super::i = help: to override `-D warnings` add `#[allow(clippy::ptr_as_ptr)]` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:28:13 + --> tests/ui/ptr_as_ptr.rs:27:13 | LL | let _ = ptr as *const i32; | ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:29:13 + --> tests/ui/ptr_as_ptr.rs:28:13 | LL | let _ = mut_ptr as *mut i32; | ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:34:17 + --> tests/ui/ptr_as_ptr.rs:33:17 | LL | let _ = *ptr_ptr as *const i32; | ^^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `(*ptr_ptr).cast::()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:47:25 + --> tests/ui/ptr_as_ptr.rs:46:25 | LL | let _: *const i32 = ptr as *const _; | ^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:48:23 + --> tests/ui/ptr_as_ptr.rs:47:23 | LL | let _: *mut i32 = mut_ptr as _; | ^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:51:21 + --> tests/ui/ptr_as_ptr.rs:50:21 | LL | let _ = inline!($ptr as *const i32); | ^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `$ptr.cast::()` @@ -46,157 +46,157 @@ LL | let _ = inline!($ptr as *const i32); = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:72:13 + --> tests/ui/ptr_as_ptr.rs:71:13 | LL | let _ = ptr as *const i32; | ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:73:13 + --> tests/ui/ptr_as_ptr.rs:72:13 | LL | let _ = mut_ptr as *mut i32; | ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:80:9 + --> tests/ui/ptr_as_ptr.rs:79:9 | LL | ptr::null_mut() as *mut u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut::()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:84:9 + --> tests/ui/ptr_as_ptr.rs:83:9 | LL | std::ptr::null_mut() as *mut u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut::()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:89:9 + --> tests/ui/ptr_as_ptr.rs:88:9 | LL | ptr::null_mut() as *mut u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut::()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:93:9 + --> tests/ui/ptr_as_ptr.rs:92:9 | LL | core::ptr::null_mut() as *mut u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut::()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:98:9 + --> tests/ui/ptr_as_ptr.rs:97:9 | LL | ptr::null() as *const u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null::()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:102:9 + --> tests/ui/ptr_as_ptr.rs:101:9 | LL | std::ptr::null() as *const u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null::()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:107:9 + --> tests/ui/ptr_as_ptr.rs:106:9 | LL | ptr::null() as *const u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null::()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:111:9 + --> tests/ui/ptr_as_ptr.rs:110:9 | LL | core::ptr::null() as *const u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null::()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:118:9 + --> tests/ui/ptr_as_ptr.rs:117:9 | LL | ptr::null_mut() as *mut _ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:122:9 + --> tests/ui/ptr_as_ptr.rs:121:9 | LL | std::ptr::null_mut() as *mut _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:127:9 + --> tests/ui/ptr_as_ptr.rs:126:9 | LL | ptr::null_mut() as *mut _ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:131:9 + --> tests/ui/ptr_as_ptr.rs:130:9 | LL | core::ptr::null_mut() as *mut _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:136:9 + --> tests/ui/ptr_as_ptr.rs:135:9 | LL | ptr::null() as *const _ | ^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:140:9 + --> tests/ui/ptr_as_ptr.rs:139:9 | LL | std::ptr::null() as *const _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:145:9 + --> tests/ui/ptr_as_ptr.rs:144:9 | LL | ptr::null() as *const _ | ^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:149:9 + --> tests/ui/ptr_as_ptr.rs:148:9 | LL | core::ptr::null() as *const _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:156:9 + --> tests/ui/ptr_as_ptr.rs:155:9 | LL | ptr::null_mut() as _ | ^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:160:9 + --> tests/ui/ptr_as_ptr.rs:159:9 | LL | std::ptr::null_mut() as _ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:165:9 + --> tests/ui/ptr_as_ptr.rs:164:9 | LL | ptr::null_mut() as _ | ^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:169:9 + --> tests/ui/ptr_as_ptr.rs:168:9 | LL | core::ptr::null_mut() as _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:174:9 + --> tests/ui/ptr_as_ptr.rs:173:9 | LL | ptr::null() as _ | ^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:178:9 + --> tests/ui/ptr_as_ptr.rs:177:9 | LL | std::ptr::null() as _ | ^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:183:9 + --> tests/ui/ptr_as_ptr.rs:182:9 | LL | ptr::null() as _ | ^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:187:9 + --> tests/ui/ptr_as_ptr.rs:186:9 | LL | core::ptr::null() as _ | ^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null()` diff --git a/tests/ui/search_is_some_fixable_none.fixed b/tests/ui/search_is_some_fixable_none.fixed index 51636392f2bc..86a937b4dae1 100644 --- a/tests/ui/search_is_some_fixable_none.fixed +++ b/tests/ui/search_is_some_fixable_none.fixed @@ -213,3 +213,53 @@ mod issue7392 { let _ = !v.iter().any(|fp| test_u32_2(*fp.field)); } } + +mod issue_11910 { + fn computations() -> u32 { + 0 + } + + struct Foo; + impl Foo { + fn bar(&self, _: bool) {} + } + + fn test_normal_for_iter() { + let v = vec![3, 2, 1, 0, -1, -2, -3]; + let _ = !v.iter().any(|x| *x == 42); + Foo.bar(!v.iter().any(|x| *x == 42)); + } + + fn test_then_for_iter() { + let v = vec![3, 2, 1, 0, -1, -2, -3]; + (!v.iter().any(|x| *x == 42)).then(computations); + } + + fn test_then_some_for_iter() { + let v = vec![3, 2, 1, 0, -1, -2, -3]; + (!v.iter().any(|x| *x == 42)).then_some(0); + } + + fn test_normal_for_str() { + let s = "hello"; + let _ = !s.contains("world"); + Foo.bar(!s.contains("world")); + let s = String::from("hello"); + let _ = !s.contains("world"); + Foo.bar(!s.contains("world")); + } + + fn test_then_for_str() { + let s = "hello"; + let _ = (!s.contains("world")).then(computations); + let s = String::from("hello"); + let _ = (!s.contains("world")).then(computations); + } + + fn test_then_some_for_str() { + let s = "hello"; + let _ = (!s.contains("world")).then_some(0); + let s = String::from("hello"); + let _ = (!s.contains("world")).then_some(0); + } +} diff --git a/tests/ui/search_is_some_fixable_none.rs b/tests/ui/search_is_some_fixable_none.rs index c7d773e18a32..c0103a015097 100644 --- a/tests/ui/search_is_some_fixable_none.rs +++ b/tests/ui/search_is_some_fixable_none.rs @@ -219,3 +219,53 @@ mod issue7392 { let _ = v.iter().find(|fp| test_u32_2(*fp.field)).is_none(); } } + +mod issue_11910 { + fn computations() -> u32 { + 0 + } + + struct Foo; + impl Foo { + fn bar(&self, _: bool) {} + } + + fn test_normal_for_iter() { + let v = vec![3, 2, 1, 0, -1, -2, -3]; + let _ = v.iter().find(|x| **x == 42).is_none(); + Foo.bar(v.iter().find(|x| **x == 42).is_none()); + } + + fn test_then_for_iter() { + let v = vec![3, 2, 1, 0, -1, -2, -3]; + v.iter().find(|x| **x == 42).is_none().then(computations); + } + + fn test_then_some_for_iter() { + let v = vec![3, 2, 1, 0, -1, -2, -3]; + v.iter().find(|x| **x == 42).is_none().then_some(0); + } + + fn test_normal_for_str() { + let s = "hello"; + let _ = s.find("world").is_none(); + Foo.bar(s.find("world").is_none()); + let s = String::from("hello"); + let _ = s.find("world").is_none(); + Foo.bar(s.find("world").is_none()); + } + + fn test_then_for_str() { + let s = "hello"; + let _ = s.find("world").is_none().then(computations); + let s = String::from("hello"); + let _ = s.find("world").is_none().then(computations); + } + + fn test_then_some_for_str() { + let s = "hello"; + let _ = s.find("world").is_none().then_some(0); + let s = String::from("hello"); + let _ = s.find("world").is_none().then_some(0); + } +} diff --git a/tests/ui/search_is_some_fixable_none.stderr b/tests/ui/search_is_some_fixable_none.stderr index 4ad1e2508c48..2c858b9fb10e 100644 --- a/tests/ui/search_is_some_fixable_none.stderr +++ b/tests/ui/search_is_some_fixable_none.stderr @@ -282,5 +282,77 @@ error: called `is_none()` after searching an `Iterator` with `find` LL | let _ = v.iter().find(|fp| test_u32_2(*fp.field)).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|fp| test_u32_2(*fp.field))` -error: aborting due to 43 previous errors +error: called `is_none()` after searching an `Iterator` with `find` + --> tests/ui/search_is_some_fixable_none.rs:235:17 + | +LL | let _ = v.iter().find(|x| **x == 42).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|x| *x == 42)` + +error: called `is_none()` after searching an `Iterator` with `find` + --> tests/ui/search_is_some_fixable_none.rs:236:17 + | +LL | Foo.bar(v.iter().find(|x| **x == 42).is_none()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|x| *x == 42)` + +error: called `is_none()` after searching an `Iterator` with `find` + --> tests/ui/search_is_some_fixable_none.rs:241:9 + | +LL | v.iter().find(|x| **x == 42).is_none().then(computations); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(!v.iter().any(|x| *x == 42))` + +error: called `is_none()` after searching an `Iterator` with `find` + --> tests/ui/search_is_some_fixable_none.rs:246:9 + | +LL | v.iter().find(|x| **x == 42).is_none().then_some(0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(!v.iter().any(|x| *x == 42))` + +error: called `is_none()` after calling `find()` on a string + --> tests/ui/search_is_some_fixable_none.rs:251:17 + | +LL | let _ = s.find("world").is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!s.contains("world")` + +error: called `is_none()` after calling `find()` on a string + --> tests/ui/search_is_some_fixable_none.rs:252:17 + | +LL | Foo.bar(s.find("world").is_none()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!s.contains("world")` + +error: called `is_none()` after calling `find()` on a string + --> tests/ui/search_is_some_fixable_none.rs:254:17 + | +LL | let _ = s.find("world").is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!s.contains("world")` + +error: called `is_none()` after calling `find()` on a string + --> tests/ui/search_is_some_fixable_none.rs:255:17 + | +LL | Foo.bar(s.find("world").is_none()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!s.contains("world")` + +error: called `is_none()` after calling `find()` on a string + --> tests/ui/search_is_some_fixable_none.rs:260:17 + | +LL | let _ = s.find("world").is_none().then(computations); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(!s.contains("world"))` + +error: called `is_none()` after calling `find()` on a string + --> tests/ui/search_is_some_fixable_none.rs:262:17 + | +LL | let _ = s.find("world").is_none().then(computations); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(!s.contains("world"))` + +error: called `is_none()` after calling `find()` on a string + --> tests/ui/search_is_some_fixable_none.rs:267:17 + | +LL | let _ = s.find("world").is_none().then_some(0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(!s.contains("world"))` + +error: called `is_none()` after calling `find()` on a string + --> tests/ui/search_is_some_fixable_none.rs:269:17 + | +LL | let _ = s.find("world").is_none().then_some(0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(!s.contains("world"))` + +error: aborting due to 55 previous errors diff --git a/tests/ui/unconditional_recursion.rs b/tests/ui/unconditional_recursion.rs index 70b390b00e27..a51fc567f50c 100644 --- a/tests/ui/unconditional_recursion.rs +++ b/tests/ui/unconditional_recursion.rs @@ -266,7 +266,7 @@ struct S13 { impl S13 { fn new() -> Self { - // Shoud not warn! + // Should not warn! Self::default() } } diff --git a/tests/ui/unnecessary_clippy_cfg.stderr b/tests/ui/unnecessary_clippy_cfg.stderr index fbc05743ca74..3d58c9eb5dae 100644 --- a/tests/ui/unnecessary_clippy_cfg.stderr +++ b/tests/ui/unnecessary_clippy_cfg.stderr @@ -57,5 +57,41 @@ error: no need to put clippy lints behind a `clippy` cfg LL | #![cfg_attr(clippy, deny(clippy::non_minimal_cfg, clippy::maybe_misused_cfg))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `#![deny(clippy::non_minimal_cfg, clippy::maybe_misused_cfg)]` -error: aborting due to 8 previous errors +error: duplicated attribute + --> tests/ui/unnecessary_clippy_cfg.rs:8:26 + | +LL | #![cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg, clippy::maybe_misused_cfg))] + | ^^^^^^^^^ + | +note: first defined here + --> tests/ui/unnecessary_clippy_cfg.rs:6:26 + | +LL | #![cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))] + | ^^^^^^^^^ +help: remove this attribute + --> tests/ui/unnecessary_clippy_cfg.rs:8:26 + | +LL | #![cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg, clippy::maybe_misused_cfg))] + | ^^^^^^^^^ + = note: `-D clippy::duplicated-attributes` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::duplicated_attributes)]` + +error: duplicated attribute + --> tests/ui/unnecessary_clippy_cfg.rs:17:25 + | +LL | #[cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg, clippy::maybe_misused_cfg))] + | ^^^^^^^^^ + | +note: first defined here + --> tests/ui/unnecessary_clippy_cfg.rs:15:25 + | +LL | #[cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))] + | ^^^^^^^^^ +help: remove this attribute + --> tests/ui/unnecessary_clippy_cfg.rs:17:25 + | +LL | #[cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg, clippy::maybe_misused_cfg))] + | ^^^^^^^^^ + +error: aborting due to 10 previous errors diff --git a/tests/ui/useless_attribute.fixed b/tests/ui/useless_attribute.fixed index d1cdf73d559f..81759086f79e 100644 --- a/tests/ui/useless_attribute.fixed +++ b/tests/ui/useless_attribute.fixed @@ -1,6 +1,6 @@ //@aux-build:proc_macro_derive.rs -#![allow(unused)] +#![allow(unused, clippy::duplicated_attributes)] #![warn(clippy::useless_attribute)] #![warn(unreachable_pub)] #![feature(rustc_private)] diff --git a/tests/ui/useless_attribute.rs b/tests/ui/useless_attribute.rs index d6aa7fa242cf..59a9dcf093bc 100644 --- a/tests/ui/useless_attribute.rs +++ b/tests/ui/useless_attribute.rs @@ -1,6 +1,6 @@ //@aux-build:proc_macro_derive.rs -#![allow(unused)] +#![allow(unused, clippy::duplicated_attributes)] #![warn(clippy::useless_attribute)] #![warn(unreachable_pub)] #![feature(rustc_private)] diff --git a/triagebot.toml b/triagebot.toml index d8131044ff2e..901977da25be 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -19,7 +19,12 @@ new_pr = true [assign] contributing_url = "https://github.com/rust-lang/rust-clippy/blob/master/CONTRIBUTING.md" -users_on_vacation = ["y21"] +users_on_vacation = [ + "y21", + "matthiaskrgr", + "giraffate", + "Centri3", +] [assign.owners] "/.github" = ["@flip1995"] From f7aef635c14c70b59b7d0b53c05ef5e8a4dae401 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Thu, 18 Apr 2024 17:05:07 +0000 Subject: [PATCH 11/47] Rework interior mutability detection --- book/src/lint_configuration.md | 5 +- clippy_config/src/conf.rs | 5 +- clippy_lints/src/copies.rs | 44 +++---- clippy_lints/src/mut_key.rs | 67 +++------- clippy_lints/src/non_copy_const.rs | 99 +++++--------- clippy_lints/src/trait_bounds.rs | 1 + clippy_utils/src/lib.rs | 6 +- clippy_utils/src/ty.rs | 124 ++++++++++++------ tests/ui-toml/mut_key/mut_key.rs | 8 ++ .../borrow_interior_mutable_const/traits.rs | 4 +- .../traits.stderr | 18 ++- .../declare_interior_mutable_const/traits.rs | 5 +- .../traits.stderr | 20 ++- tests/ui/mut_key.rs | 10 +- tests/ui/mut_key.stderr | 32 ++--- 15 files changed, 225 insertions(+), 223 deletions(-) diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index 7cefa6852642..fe0e9b80b11e 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -506,13 +506,14 @@ The maximum byte size a `Future` can have, before it triggers the `clippy::large ## `ignore-interior-mutability` -A list of paths to types that should be treated like `Arc`, i.e. ignored but -for the generic parameters for determining interior mutability +A list of paths to types that should be treated as if they do not contain interior mutability **Default Value:** `["bytes::Bytes"]` --- **Affected lints:** +* [`borrow_interior_mutable_const`](https://rust-lang.github.io/rust-clippy/master/index.html#borrow_interior_mutable_const) +* [`declare_interior_mutable_const`](https://rust-lang.github.io/rust-clippy/master/index.html#declare_interior_mutable_const) * [`ifs_same_cond`](https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond) * [`mutable_key_type`](https://rust-lang.github.io/rust-clippy/master/index.html#mutable_key_type) diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index 781282213cc4..bbce4180dc4d 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -467,10 +467,9 @@ define_Conf! { /// /// The maximum size of the `Err`-variant in a `Result` returned from a function (large_error_threshold: u64 = 128), - /// Lint: MUTABLE_KEY_TYPE, IFS_SAME_COND. + /// Lint: MUTABLE_KEY_TYPE, IFS_SAME_COND, BORROW_INTERIOR_MUTABLE_CONST, DECLARE_INTERIOR_MUTABLE_CONST. /// - /// A list of paths to types that should be treated like `Arc`, i.e. ignored but - /// for the generic parameters for determining interior mutability + /// A list of paths to types that should be treated as if they do not contain interior mutability (ignore_interior_mutability: Vec = Vec::from(["bytes::Bytes".into()])), /// Lint: UNINLINED_FORMAT_ARGS. /// diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index acdcb54be271..ccf1d9d6f8c0 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -1,15 +1,14 @@ use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_then}; use clippy_utils::source::{first_line_of_span, indent_of, reindent_multiline, snippet, snippet_opt}; -use clippy_utils::ty::{is_interior_mut_ty, needs_ordered_drop}; +use clippy_utils::ty::{needs_ordered_drop, InteriorMut}; use clippy_utils::visitors::for_each_expr; use clippy_utils::{ - capture_local_usage, def_path_def_ids, eq_expr_value, find_binding_init, get_enclosing_block, hash_expr, hash_stmt, - if_sequence, is_else_clause, is_lint_allowed, path_to_local, search_same, ContainsName, HirEqInterExpr, SpanlessEq, + capture_local_usage, eq_expr_value, find_binding_init, get_enclosing_block, hash_expr, hash_stmt, if_sequence, + is_else_clause, is_lint_allowed, path_to_local, search_same, ContainsName, HirEqInterExpr, SpanlessEq, }; use core::iter; use core::ops::ControlFlow; use rustc_errors::Applicability; -use rustc_hir::def_id::DefIdSet; use rustc_hir::{intravisit, BinOpKind, Block, Expr, ExprKind, HirId, HirIdSet, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; @@ -159,40 +158,36 @@ declare_clippy_lint! { "`if` statement with shared code in all blocks" } -pub struct CopyAndPaste { +pub struct CopyAndPaste<'tcx> { ignore_interior_mutability: Vec, - ignored_ty_ids: DefIdSet, + interior_mut: InteriorMut<'tcx>, } -impl CopyAndPaste { +impl CopyAndPaste<'_> { pub fn new(ignore_interior_mutability: Vec) -> Self { Self { ignore_interior_mutability, - ignored_ty_ids: DefIdSet::new(), + interior_mut: InteriorMut::default(), } } } -impl_lint_pass!(CopyAndPaste => [ +impl_lint_pass!(CopyAndPaste<'_> => [ IFS_SAME_COND, SAME_FUNCTIONS_IN_IF_CONDITION, IF_SAME_THEN_ELSE, BRANCHES_SHARING_CODE ]); -impl<'tcx> LateLintPass<'tcx> for CopyAndPaste { +impl<'tcx> LateLintPass<'tcx> for CopyAndPaste<'tcx> { fn check_crate(&mut self, cx: &LateContext<'tcx>) { - for ignored_ty in &self.ignore_interior_mutability { - let path: Vec<&str> = ignored_ty.split("::").collect(); - for id in def_path_def_ids(cx, path.as_slice()) { - self.ignored_ty_ids.insert(id); - } - } + self.interior_mut = InteriorMut::new(cx, &self.ignore_interior_mutability); } + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if !expr.span.from_expansion() && matches!(expr.kind, ExprKind::If(..)) && !is_else_clause(cx.tcx, expr) { let (conds, blocks) = if_sequence(expr); - lint_same_cond(cx, &conds, &self.ignored_ty_ids); + lint_same_cond(cx, &conds, &mut self.interior_mut); lint_same_fns_in_if_cond(cx, &conds); let all_same = !is_lint_allowed(cx, IF_SAME_THEN_ELSE, expr.hir_id) && lint_if_same_then_else(cx, &conds, &blocks); @@ -570,13 +565,14 @@ fn check_for_warn_of_moved_symbol(cx: &LateContext<'_>, symbols: &[(HirId, Symbo }) } -fn method_caller_is_mutable(cx: &LateContext<'_>, caller_expr: &Expr<'_>, ignored_ty_ids: &DefIdSet) -> bool { +fn method_caller_is_mutable<'tcx>( + cx: &LateContext<'tcx>, + caller_expr: &Expr<'_>, + interior_mut: &mut InteriorMut<'tcx>, +) -> bool { let caller_ty = cx.typeck_results().expr_ty(caller_expr); - // Check if given type has inner mutability and was not set to ignored by the configuration - let is_inner_mut_ty = is_interior_mut_ty(cx, caller_ty) - && !matches!(caller_ty.ty_adt_def(), Some(adt) if ignored_ty_ids.contains(&adt.did())); - is_inner_mut_ty + interior_mut.is_interior_mut_ty(cx, caller_ty) || caller_ty.is_mutable_ptr() // `find_binding_init` will return the binding iff its not mutable || path_to_local(caller_expr) @@ -585,7 +581,7 @@ fn method_caller_is_mutable(cx: &LateContext<'_>, caller_expr: &Expr<'_>, ignore } /// Implementation of `IFS_SAME_COND`. -fn lint_same_cond(cx: &LateContext<'_>, conds: &[&Expr<'_>], ignored_ty_ids: &DefIdSet) { +fn lint_same_cond<'tcx>(cx: &LateContext<'tcx>, conds: &[&Expr<'_>], interior_mut: &mut InteriorMut<'tcx>) { for (i, j) in search_same( conds, |e| hash_expr(cx, e), @@ -593,7 +589,7 @@ fn lint_same_cond(cx: &LateContext<'_>, conds: &[&Expr<'_>], ignored_ty_ids: &De // Ignore eq_expr side effects iff one of the expression kind is a method call // and the caller is not a mutable, including inner mutable type. if let ExprKind::MethodCall(_, caller, _, _) = lhs.kind { - if method_caller_is_mutable(cx, caller, ignored_ty_ids) { + if method_caller_is_mutable(cx, caller, interior_mut) { false } else { SpanlessEq::new(cx).eq_expr(lhs, rhs) diff --git a/clippy_lints/src/mut_key.rs b/clippy_lints/src/mut_key.rs index 8c2f43c97f4d..2eb534da0925 100644 --- a/clippy_lints/src/mut_key.rs +++ b/clippy_lints/src/mut_key.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::ty::is_interior_mut_ty; -use clippy_utils::{def_path_def_ids, trait_ref_of_method}; -use rustc_data_structures::fx::FxHashSet; +use clippy_utils::trait_ref_of_method; +use clippy_utils::ty::InteriorMut; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; @@ -23,27 +22,15 @@ declare_clippy_lint! { /// ### Known problems /// /// #### False Positives - /// It's correct to use a struct that contains interior mutability as a key, when its + /// It's correct to use a struct that contains interior mutability as a key when its /// implementation of `Hash` or `Ord` doesn't access any of the interior mutable types. /// However, this lint is unable to recognize this, so it will often cause false positives in - /// theses cases. The `bytes` crate is a great example of this. + /// these cases. /// /// #### False Negatives - /// For custom `struct`s/`enum`s, this lint is unable to check for interior mutability behind - /// indirection. For example, `struct BadKey<'a>(&'a Cell)` will be seen as immutable - /// and cause a false negative if its implementation of `Hash`/`Ord` accesses the `Cell`. - /// - /// This lint does check a few cases for indirection. Firstly, using some standard library - /// types (`Option`, `Result`, `Box`, `Rc`, `Arc`, `Vec`, `VecDeque`, `BTreeMap` and - /// `BTreeSet`) directly as keys (e.g. in `HashMap>, ()>`) **will** trigger the - /// lint, because the impls of `Hash`/`Ord` for these types directly call `Hash`/`Ord` on their - /// contained type. - /// - /// Secondly, the implementations of `Hash` and `Ord` for raw pointers (`*const T` or `*mut T`) - /// apply only to the **address** of the contained value. Therefore, interior mutability - /// behind raw pointers (e.g. in `HashSet<*mut Cell>`) can't impact the value of `Hash` - /// or `Ord`, and therefore will not trigger this link. For more info, see issue - /// [#6745](https://github.com/rust-lang/rust-clippy/issues/6745). + /// This lint does not follow raw pointers (`*const T` or `*mut T`) as `Hash` and `Ord` + /// apply only to the **address** of the contained value. This can cause false negatives for + /// custom collections that use raw pointers internally. /// /// ### Example /// ```no_run @@ -51,13 +38,12 @@ declare_clippy_lint! { /// use std::collections::HashSet; /// use std::hash::{Hash, Hasher}; /// use std::sync::atomic::AtomicUsize; - ///# #[allow(unused)] /// /// struct Bad(AtomicUsize); /// impl PartialEq for Bad { /// fn eq(&self, rhs: &Self) -> bool { /// .. - /// ; unimplemented!(); + /// # ; true /// } /// } /// @@ -66,7 +52,7 @@ declare_clippy_lint! { /// impl Hash for Bad { /// fn hash(&self, h: &mut H) { /// .. - /// ; unimplemented!(); + /// # ; /// } /// } /// @@ -80,25 +66,16 @@ declare_clippy_lint! { "Check for mutable `Map`/`Set` key type" } -#[derive(Clone)] -pub struct MutableKeyType { +pub struct MutableKeyType<'tcx> { ignore_interior_mutability: Vec, - ignore_mut_def_ids: FxHashSet, + interior_mut: InteriorMut<'tcx>, } -impl_lint_pass!(MutableKeyType => [ MUTABLE_KEY_TYPE ]); +impl_lint_pass!(MutableKeyType<'_> => [ MUTABLE_KEY_TYPE ]); -impl<'tcx> LateLintPass<'tcx> for MutableKeyType { +impl<'tcx> LateLintPass<'tcx> for MutableKeyType<'tcx> { 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(); - } + self.interior_mut = InteriorMut::without_pointers(cx, &self.ignore_interior_mutability); } fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { @@ -121,7 +98,7 @@ impl<'tcx> LateLintPass<'tcx> for MutableKeyType { } } - fn check_local(&mut self, cx: &LateContext<'_>, local: &hir::LetStmt<'_>) { + fn check_local(&mut self, cx: &LateContext<'tcx>, local: &hir::LetStmt<'tcx>) { if let hir::PatKind::Wild = local.pat.kind { return; } @@ -129,15 +106,15 @@ impl<'tcx> LateLintPass<'tcx> for MutableKeyType { } } -impl MutableKeyType { +impl<'tcx> MutableKeyType<'tcx> { pub fn new(ignore_interior_mutability: Vec) -> Self { Self { ignore_interior_mutability, - ignore_mut_def_ids: FxHashSet::default(), + interior_mut: InteriorMut::default(), } } - fn check_sig(&self, cx: &LateContext<'_>, fn_def_id: LocalDefId, decl: &hir::FnDecl<'_>) { + fn check_sig(&mut self, cx: &LateContext<'tcx>, fn_def_id: LocalDefId, decl: &hir::FnDecl<'tcx>) { let fn_sig = cx.tcx.fn_sig(fn_def_id).instantiate_identity(); for (hir_ty, ty) in iter::zip(decl.inputs, fn_sig.inputs().skip_binder()) { self.check_ty_(cx, hir_ty.span, *ty); @@ -151,7 +128,7 @@ impl MutableKeyType { // 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>) { + fn check_ty_(&mut self, cx: &LateContext<'tcx>, span: Span, ty: Ty<'tcx>) { let ty = ty.peel_refs(); if let ty::Adt(def, args) = ty.kind() { let is_keyed_type = [sym::HashMap, sym::BTreeMap, sym::HashSet, sym::BTreeSet] @@ -162,11 +139,7 @@ impl MutableKeyType { } let subst_ty = args.type_at(0); - // Determines if a type contains interior mutability which would affect its implementation of - // [`Hash`] or [`Ord`]. - if is_interior_mut_ty(cx, subst_ty) - && !matches!(subst_ty.ty_adt_def(), Some(adt) if self.ignore_mut_def_ids.contains(&adt.did())) - { + if self.interior_mut.is_interior_mut_ty(cx, subst_ty) { span_lint(cx, MUTABLE_KEY_TYPE, span, "mutable key type"); } } diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index ff10a841aef1..76d9cee18aa7 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -5,9 +5,9 @@ use std::ptr; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::in_constant; use clippy_utils::macros::macro_backtrace; -use clippy_utils::{def_path_def_ids, in_constant}; -use rustc_data_structures::fx::FxHashSet; +use clippy_utils::ty::InteriorMut; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::{ @@ -52,8 +52,8 @@ declare_clippy_lint! { /// There're other enums plus associated constants cases that the lint cannot handle. /// /// Types that have underlying or potential interior mutability trigger the lint whether - /// the interior mutable field is used or not. See issues - /// [#5812](https://github.com/rust-lang/rust-clippy/issues/5812) and + /// the interior mutable field is used or not. See issue + /// [#5812](https://github.com/rust-lang/rust-clippy/issues/5812) /// /// ### Example /// ```no_run @@ -170,42 +170,22 @@ fn lint(cx: &LateContext<'_>, source: Source) { }); } -#[derive(Clone)] -pub struct NonCopyConst { +pub struct NonCopyConst<'tcx> { ignore_interior_mutability: Vec, - ignore_mut_def_ids: FxHashSet, + interior_mut: InteriorMut<'tcx>, } -impl_lint_pass!(NonCopyConst => [DECLARE_INTERIOR_MUTABLE_CONST, BORROW_INTERIOR_MUTABLE_CONST]); +impl_lint_pass!(NonCopyConst<'_> => [DECLARE_INTERIOR_MUTABLE_CONST, BORROW_INTERIOR_MUTABLE_CONST]); -impl NonCopyConst { +impl<'tcx> NonCopyConst<'tcx> { pub fn new(ignore_interior_mutability: Vec) -> Self { Self { ignore_interior_mutability, - ignore_mut_def_ids: FxHashSet::default(), + interior_mut: InteriorMut::default(), } } - fn is_ty_ignored(&self, ty: Ty<'_>) -> bool { - matches!(ty.ty_adt_def(), Some(adt) if self.ignore_mut_def_ids.contains(&adt.did())) - } - - fn is_unfrozen<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { - // Ignore types whose layout is unknown since `is_freeze` reports every generic types as `!Freeze`, - // making it indistinguishable from `UnsafeCell`. i.e. it isn't a tool to prove a type is - // 'unfrozen'. However, this code causes a false negative in which - // a type contains a layout-unknown type, but also an unsafe cell like `const CELL: Cell`. - // Yet, it's better than `ty.has_type_flags(TypeFlags::HAS_TY_PARAM | TypeFlags::HAS_PROJECTION)` - // since it works when a pointer indirection involves (`Cell<*const T>`). - // Making up a `ParamEnv` where every generic params and assoc types are `Freeze`is another option; - // but I'm not sure whether it's a decent way, if possible. - cx.tcx.layout_of(cx.param_env.and(ty)).is_ok() && !ty.is_freeze(cx.tcx, cx.param_env) - } - - fn is_value_unfrozen_raw_inner<'tcx>(&self, cx: &LateContext<'tcx>, val: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> bool { - if self.is_ty_ignored(ty) { - return false; - } + fn is_value_unfrozen_raw_inner(cx: &LateContext<'tcx>, val: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> bool { match *ty.kind() { // the fact that we have to dig into every structs to search enums // leads us to the point checking `UnsafeCell` directly is the only option. @@ -216,8 +196,7 @@ impl NonCopyConst { ty::Array(ty, _) => val .unwrap_branch() .iter() - .any(|field| self.is_value_unfrozen_raw_inner(cx, *field, ty)), - ty::Adt(def, _) if def.is_union() => false, + .any(|field| Self::is_value_unfrozen_raw_inner(cx, *field, ty)), ty::Adt(def, args) if def.is_enum() => { let (&variant_index, fields) = val.unwrap_branch().split_first().unwrap(); let variant_index = VariantIdx::from_u32(variant_index.unwrap_leaf().try_to_u32().ok().unwrap()); @@ -230,24 +209,23 @@ impl NonCopyConst { .iter() .map(|field| field.ty(cx.tcx, args)), ) - .any(|(field, ty)| self.is_value_unfrozen_raw_inner(cx, field, ty)) + .any(|(field, ty)| Self::is_value_unfrozen_raw_inner(cx, field, ty)) }, ty::Adt(def, args) => val .unwrap_branch() .iter() .zip(def.non_enum_variant().fields.iter().map(|field| field.ty(cx.tcx, args))) - .any(|(field, ty)| self.is_value_unfrozen_raw_inner(cx, *field, ty)), + .any(|(field, ty)| Self::is_value_unfrozen_raw_inner(cx, *field, ty)), ty::Tuple(tys) => val .unwrap_branch() .iter() .zip(tys) - .any(|(field, ty)| self.is_value_unfrozen_raw_inner(cx, *field, ty)), + .any(|(field, ty)| Self::is_value_unfrozen_raw_inner(cx, *field, ty)), _ => false, } } - fn is_value_unfrozen_raw<'tcx>( - &self, + fn is_value_unfrozen_raw( cx: &LateContext<'tcx>, result: Result>, ErrorHandled>, ty: Ty<'tcx>, @@ -277,11 +255,11 @@ impl NonCopyConst { // I chose this way because unfrozen enums as assoc consts are rare (or, hopefully, none). matches!(err, ErrorHandled::TooGeneric(..)) }, - |val| val.map_or(true, |val| self.is_value_unfrozen_raw_inner(cx, val, ty)), + |val| val.map_or(true, |val| Self::is_value_unfrozen_raw_inner(cx, val, ty)), ) } - fn is_value_unfrozen_poly<'tcx>(&self, cx: &LateContext<'tcx>, body_id: BodyId, ty: Ty<'tcx>) -> bool { + fn is_value_unfrozen_poly(cx: &LateContext<'tcx>, body_id: BodyId, ty: Ty<'tcx>) -> bool { let def_id = body_id.hir_id.owner.to_def_id(); let args = ty::GenericArgs::identity_for_item(cx.tcx, def_id); let instance = ty::Instance::new(def_id, args); @@ -291,17 +269,17 @@ impl NonCopyConst { }; let param_env = cx.tcx.param_env(def_id).with_reveal_all_normalized(cx.tcx); let result = cx.tcx.const_eval_global_id_for_typeck(param_env, cid, DUMMY_SP); - self.is_value_unfrozen_raw(cx, result, ty) + Self::is_value_unfrozen_raw(cx, result, ty) } - fn is_value_unfrozen_expr<'tcx>(&self, cx: &LateContext<'tcx>, hir_id: HirId, def_id: DefId, ty: Ty<'tcx>) -> bool { + fn is_value_unfrozen_expr(cx: &LateContext<'tcx>, hir_id: HirId, def_id: DefId, ty: Ty<'tcx>) -> bool { let args = cx.typeck_results().node_args(hir_id); let result = Self::const_eval_resolve(cx.tcx, cx.param_env, ty::UnevaluatedConst::new(def_id, args), DUMMY_SP); - self.is_value_unfrozen_raw(cx, result, ty) + Self::is_value_unfrozen_raw(cx, result, ty) } - pub fn const_eval_resolve<'tcx>( + pub fn const_eval_resolve( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, ct: ty::UnevaluatedConst<'tcx>, @@ -321,26 +299,17 @@ impl NonCopyConst { } } -impl<'tcx> LateLintPass<'tcx> for NonCopyConst { +impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> { 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(); - } + self.interior_mut = InteriorMut::new(cx, &self.ignore_interior_mutability); } fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx Item<'_>) { if let ItemKind::Const(.., body_id) = it.kind { let ty = cx.tcx.type_of(it.owner_id).instantiate_identity(); if !ignored_macro(cx, it) - && !self.is_ty_ignored(ty) - && Self::is_unfrozen(cx, ty) - && self.is_value_unfrozen_poly(cx, body_id, ty) + && self.interior_mut.is_interior_mut_ty(cx, ty) + && Self::is_value_unfrozen_poly(cx, body_id, ty) { lint(cx, Source::Item { item: it.span }); } @@ -354,7 +323,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { // Normalize assoc types because ones originated from generic params // bounded other traits could have their bound. let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty); - if !self.is_ty_ignored(ty) && Self::is_unfrozen(cx, normalized) + if self.interior_mut.is_interior_mut_ty(cx, normalized) // When there's no default value, lint it only according to its type; // in other words, lint consts whose value *could* be unfrozen, not definitely is. // This feels inconsistent with how the lint treats generic types, @@ -367,7 +336,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { // i.e. having an enum doesn't necessary mean a type has a frozen variant. // And, implementing it isn't a trivial task; it'll probably end up // re-implementing the trait predicate evaluation specific to `Freeze`. - && body_id_opt.map_or(true, |body_id| self.is_value_unfrozen_poly(cx, body_id, normalized)) + && body_id_opt.map_or(true, |body_id| Self::is_value_unfrozen_poly(cx, body_id, normalized)) { lint(cx, Source::Assoc { item: trait_item.span }); } @@ -409,8 +378,8 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { // e.g. `layout_of(...).is_err() || has_frozen_variant(...);` && let ty = cx.tcx.type_of(impl_item.owner_id).instantiate_identity() && let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty) - && !self.is_ty_ignored(ty) && Self::is_unfrozen(cx, normalized) - && self.is_value_unfrozen_poly(cx, *body_id, normalized) + && self.interior_mut.is_interior_mut_ty(cx, normalized) + && Self::is_value_unfrozen_poly(cx, *body_id, normalized) { lint(cx, Source::Assoc { item: impl_item.span }); } @@ -420,9 +389,8 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { // Normalize assoc types originated from generic params. let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty); - if !self.is_ty_ignored(ty) - && Self::is_unfrozen(cx, ty) - && self.is_value_unfrozen_poly(cx, *body_id, normalized) + if self.interior_mut.is_interior_mut_ty(cx, normalized) + && Self::is_value_unfrozen_poly(cx, *body_id, normalized) { lint(cx, Source::Assoc { item: impl_item.span }); } @@ -517,9 +485,8 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { cx.typeck_results().expr_ty(dereferenced_expr) }; - if !self.is_ty_ignored(ty) - && Self::is_unfrozen(cx, ty) - && self.is_value_unfrozen_expr(cx, expr.hir_id, item_def_id, ty) + if self.interior_mut.is_interior_mut_ty(cx, ty) + && Self::is_value_unfrozen_expr(cx, expr.hir_id, item_def_id, ty) { lint(cx, Source::Expr { expr: expr.span }); } diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index 9468d367a926..c05cd9ed5934 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -237,6 +237,7 @@ impl TraitBounds { } } + #[allow(clippy::mutable_key_type)] fn check_type_repetition<'tcx>(&self, cx: &LateContext<'tcx>, gen: &'tcx Generics<'_>) { struct SpanlessTy<'cx, 'tcx> { ty: &'tcx Ty<'tcx>, diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index a13885b022f6..196ccf9df164 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -2328,10 +2328,10 @@ pub fn is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option(exprs: &[T], hash: Hash, eq: Eq) -> Vec<(&T, &T)> +pub fn search_same(exprs: &[T], mut hash: Hash, mut eq: Eq) -> Vec<(&T, &T)> where - Hash: Fn(&T) -> u64, - Eq: Fn(&T, &T) -> bool, + Hash: FnMut(&T) -> u64, + Eq: FnMut(&T, &T) -> bool, { match exprs { [a, b] if eq(a, b) => return vec![(a, b)], diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index a06a82c56530..23750ed4d1ba 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -29,9 +29,10 @@ use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _ use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; use rustc_trait_selection::traits::{Obligation, ObligationCause}; use std::assert_matches::debug_assert_matches; +use std::collections::hash_map::Entry; use std::iter; -use crate::{match_def_path, path_res}; +use crate::{def_path_def_ids, match_def_path, path_res}; mod type_certainty; pub use type_certainty::expr_type_is_certain; @@ -1198,47 +1199,88 @@ pub fn make_normalized_projection<'tcx>( helper(tcx, param_env, make_projection(tcx, container_id, assoc_ty, args)?) } -/// Check if given type has inner mutability such as [`std::cell::Cell`] or [`std::cell::RefCell`] -/// etc. -pub fn is_interior_mut_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { - match *ty.kind() { - ty::Ref(_, inner_ty, mutbl) => mutbl == Mutability::Mut || is_interior_mut_ty(cx, inner_ty), - ty::Slice(inner_ty) => is_interior_mut_ty(cx, inner_ty), - ty::Array(inner_ty, size) => { - size.try_eval_target_usize(cx.tcx, cx.param_env) - .map_or(true, |u| u != 0) - && is_interior_mut_ty(cx, inner_ty) - }, - ty::Tuple(fields) => fields.iter().any(|ty| is_interior_mut_ty(cx, ty)), - ty::Adt(def, args) => { - // Special case for collections in `std` who's impl of `Hash` or `Ord` delegates to - // that of their type parameters. Note: we don't include `HashSet` and `HashMap` - // because they have no impl for `Hash` or `Ord`. - 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, - ] +/// Helper to check if given type has inner mutability such as [`std::cell::Cell`] or +/// [`std::cell::RefCell`]. +#[derive(Default, Debug)] +pub struct InteriorMut<'tcx> { + ignored_def_ids: FxHashSet, + ignore_pointers: bool, + tys: FxHashMap, Option>, +} + +impl<'tcx> InteriorMut<'tcx> { + pub fn new(cx: &LateContext<'tcx>, ignore_interior_mutability: &[String]) -> Self { + let ignored_def_ids = ignore_interior_mutability .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 { - // The type is mutable if any of its type parameters are - args.types().any(|ty| is_interior_mut_ty(cx, ty)) - } else { - !ty.has_escaping_bound_vars() - && cx.tcx.layout_of(cx.param_env.and(ty)).is_ok() - && !ty.is_freeze(cx.tcx, cx.param_env) - } - }, - _ => false, + .flat_map(|ignored_ty| { + let path: Vec<&str> = ignored_ty.split("::").collect(); + def_path_def_ids(cx, path.as_slice()) + }) + .collect(); + + Self { + ignored_def_ids, + ..Self::default() + } + } + + pub fn without_pointers(cx: &LateContext<'tcx>, ignore_interior_mutability: &[String]) -> Self { + Self { + ignore_pointers: true, + ..Self::new(cx, ignore_interior_mutability) + } + } + + /// Check if given type has inner mutability such as [`std::cell::Cell`] or + /// [`std::cell::RefCell`] etc. + pub fn is_interior_mut_ty(&mut self, cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { + match self.tys.entry(ty) { + Entry::Occupied(o) => return *o.get() == Some(true), + // Temporarily insert a `None` to break cycles + Entry::Vacant(v) => v.insert(None), + }; + + let interior_mut = match *ty.kind() { + ty::RawPtr(inner_ty, _) if !self.ignore_pointers => self.is_interior_mut_ty(cx, inner_ty), + ty::Ref(_, inner_ty, _) | ty::Slice(inner_ty) => self.is_interior_mut_ty(cx, inner_ty), + ty::Array(inner_ty, size) => { + size.try_eval_target_usize(cx.tcx, cx.param_env) + .map_or(true, |u| u != 0) + && self.is_interior_mut_ty(cx, inner_ty) + }, + ty::Tuple(fields) => fields.iter().any(|ty| self.is_interior_mut_ty(cx, ty)), + ty::Adt(def, _) if def.is_unsafe_cell() => true, + ty::Adt(def, args) => { + let is_std_collection = matches!( + cx.tcx.get_diagnostic_name(def.did()), + Some( + sym::LinkedList + | sym::Vec + | sym::VecDeque + | sym::BTreeMap + | sym::BTreeSet + | sym::HashMap + | sym::HashSet + | sym::Arc + | sym::Rc + ) + ); + + if is_std_collection || def.is_box() { + // Include the types from std collections that are behind pointers internally + args.types().any(|ty| self.is_interior_mut_ty(cx, ty)) + } else if self.ignored_def_ids.contains(&def.did()) || def.is_phantom_data() { + false + } else { + def.all_fields() + .any(|f| self.is_interior_mut_ty(cx, f.ty(cx.tcx, args))) + } + }, + _ => false, + }; + + self.tys.insert(ty, Some(interior_mut)); + interior_mut } } diff --git a/tests/ui-toml/mut_key/mut_key.rs b/tests/ui-toml/mut_key/mut_key.rs index 095e0d15448a..3a8e3741e20c 100644 --- a/tests/ui-toml/mut_key/mut_key.rs +++ b/tests/ui-toml/mut_key/mut_key.rs @@ -44,10 +44,18 @@ impl Deref for Counted { } } +#[derive(Hash, PartialEq, Eq)] +struct ContainsCounted { + inner: Counted, +} + // This is not linted because `"mut_key::Counted"` is in // `arc_like_types` in `clippy.toml` fn should_not_take_this_arg(_v: HashSet>) {} +fn indirect(_: HashMap) {} + fn main() { should_not_take_this_arg(HashSet::new()); + indirect(HashMap::new()); } diff --git a/tests/ui/borrow_interior_mutable_const/traits.rs b/tests/ui/borrow_interior_mutable_const/traits.rs index 4da3833cbf5a..5570e7cd6d2e 100644 --- a/tests/ui/borrow_interior_mutable_const/traits.rs +++ b/tests/ui/borrow_interior_mutable_const/traits.rs @@ -158,7 +158,7 @@ trait BothOfCellAndGeneric { const INDIRECT: Cell<*const T>; fn function() { - let _ = &Self::DIRECT; + let _ = &Self::DIRECT; //~ ERROR: interior mutability let _ = &Self::INDIRECT; //~ ERROR: interior mutability } } @@ -168,7 +168,7 @@ impl BothOfCellAndGeneric for Vec { const INDIRECT: Cell<*const T> = Cell::new(std::ptr::null()); fn function() { - let _ = &Self::DIRECT; + let _ = &Self::DIRECT; //~ ERROR: interior mutability let _ = &Self::INDIRECT; //~ ERROR: interior mutability } } diff --git a/tests/ui/borrow_interior_mutable_const/traits.stderr b/tests/ui/borrow_interior_mutable_const/traits.stderr index 582b744b49ff..8602b46b0dcf 100644 --- a/tests/ui/borrow_interior_mutable_const/traits.stderr +++ b/tests/ui/borrow_interior_mutable_const/traits.stderr @@ -75,6 +75,14 @@ LL | let _ = &Self::WRAPPED_SELF; | = help: assign this const to a local or static variable, and use the variable here +error: a `const` item with interior mutability should not be borrowed + --> tests/ui/borrow_interior_mutable_const/traits.rs:161:18 + | +LL | let _ = &Self::DIRECT; + | ^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + error: a `const` item with interior mutability should not be borrowed --> tests/ui/borrow_interior_mutable_const/traits.rs:162:18 | @@ -83,6 +91,14 @@ LL | let _ = &Self::INDIRECT; | = help: assign this const to a local or static variable, and use the variable here +error: a `const` item with interior mutability should not be borrowed + --> tests/ui/borrow_interior_mutable_const/traits.rs:171:18 + | +LL | let _ = &Self::DIRECT; + | ^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + error: a `const` item with interior mutability should not be borrowed --> tests/ui/borrow_interior_mutable_const/traits.rs:172:18 | @@ -123,5 +139,5 @@ LL | assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); | = help: assign this const to a local or static variable, and use the variable here -error: aborting due to 15 previous errors +error: aborting due to 17 previous errors diff --git a/tests/ui/declare_interior_mutable_const/traits.rs b/tests/ui/declare_interior_mutable_const/traits.rs index adc53891ef54..490073f97fb1 100644 --- a/tests/ui/declare_interior_mutable_const/traits.rs +++ b/tests/ui/declare_interior_mutable_const/traits.rs @@ -121,13 +121,12 @@ impl SelfType for AtomicUsize { // Even though a constant contains a generic type, if it also have an interior mutable type, // it should be linted at the definition site. trait BothOfCellAndGeneric { - // this is a false negative in the current implementation. - const DIRECT: Cell; + const DIRECT: Cell; //~ ERROR: interior mutable const INDIRECT: Cell<*const T>; //~ ERROR: interior mutable } impl BothOfCellAndGeneric for u64 { - const DIRECT: Cell = Cell::new(T::DEFAULT); + const DIRECT: Cell = Cell::new(T::DEFAULT); //~ ERROR: interior mutable const INDIRECT: Cell<*const T> = Cell::new(std::ptr::null()); } diff --git a/tests/ui/declare_interior_mutable_const/traits.stderr b/tests/ui/declare_interior_mutable_const/traits.stderr index 328453efa244..1d1e9e2002fa 100644 --- a/tests/ui/declare_interior_mutable_const/traits.stderr +++ b/tests/ui/declare_interior_mutable_const/traits.stderr @@ -55,22 +55,34 @@ LL | const WRAPPED_SELF: Option = Some(AtomicUsize::new(21)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable - --> tests/ui/declare_interior_mutable_const/traits.rs:126:5 + --> tests/ui/declare_interior_mutable_const/traits.rs:124:5 + | +LL | const DIRECT: Cell; + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: a `const` item should never be interior mutable + --> tests/ui/declare_interior_mutable_const/traits.rs:125:5 | LL | const INDIRECT: Cell<*const T>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable - --> tests/ui/declare_interior_mutable_const/traits.rs:142:5 + --> tests/ui/declare_interior_mutable_const/traits.rs:129:5 + | +LL | const DIRECT: Cell = Cell::new(T::DEFAULT); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: a `const` item should never be interior mutable + --> tests/ui/declare_interior_mutable_const/traits.rs:141:5 | LL | const ATOMIC: AtomicUsize = AtomicUsize::new(18); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable - --> tests/ui/declare_interior_mutable_const/traits.rs:148:5 + --> tests/ui/declare_interior_mutable_const/traits.rs:147:5 | LL | const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 11 previous errors +error: aborting due to 13 previous errors diff --git a/tests/ui/mut_key.rs b/tests/ui/mut_key.rs index 2d70bfd4c770..81d8732b3b21 100644 --- a/tests/ui/mut_key.rs +++ b/tests/ui/mut_key.rs @@ -5,7 +5,7 @@ use std::rc::Rc; use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering::Relaxed; use std::sync::Arc; -//@no-rustfix + struct Key(AtomicUsize); impl Clone for Key { @@ -77,8 +77,6 @@ fn main() { //~^ ERROR: mutable key type let _map = HashMap::<&mut Cell, usize>::new(); //~^ ERROR: mutable key type - let _map = HashMap::<&mut usize, usize>::new(); - //~^ ERROR: mutable key type // Collection types from `std` who's impl of `Hash` or `Ord` delegate their type parameters let _map = HashMap::>, usize>::new(); //~^ ERROR: mutable key type @@ -92,8 +90,6 @@ fn main() { //~^ ERROR: mutable key type let _map = HashMap::>>, usize>::new(); //~^ ERROR: mutable key type - let _map = HashMap::, usize>::new(); - //~^ ERROR: mutable key type // Smart pointers from `std` who's impl of `Hash` or `Ord` delegate their type parameters let _map = HashMap::>, usize>::new(); //~^ ERROR: mutable key type @@ -101,4 +97,8 @@ fn main() { //~^ ERROR: mutable key type let _map = HashMap::>, usize>::new(); //~^ ERROR: mutable key type + + // Not interior mutability + let _map = HashMap::<&mut usize, usize>::new(); + let _map = HashMap::, usize>::new(); } diff --git a/tests/ui/mut_key.stderr b/tests/ui/mut_key.stderr index e54c3075d4f1..5ad9aad2d0a5 100644 --- a/tests/ui/mut_key.stderr +++ b/tests/ui/mut_key.stderr @@ -38,70 +38,58 @@ LL | let _map = HashMap::<&mut Cell, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> tests/ui/mut_key.rs:80:5 - | -LL | let _map = HashMap::<&mut usize, usize>::new(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: mutable key type - --> tests/ui/mut_key.rs:83:5 + --> tests/ui/mut_key.rs:81:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> tests/ui/mut_key.rs:85:5 + --> tests/ui/mut_key.rs:83:5 | LL | let _map = HashMap::, ()>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> tests/ui/mut_key.rs:87:5 + --> tests/ui/mut_key.rs:85:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> tests/ui/mut_key.rs:89:5 + --> tests/ui/mut_key.rs:87:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> tests/ui/mut_key.rs:91:5 + --> tests/ui/mut_key.rs:89:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> tests/ui/mut_key.rs:93:5 + --> tests/ui/mut_key.rs:91:5 | LL | let _map = HashMap::>>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> tests/ui/mut_key.rs:95:5 - | -LL | let _map = HashMap::, usize>::new(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: mutable key type - --> tests/ui/mut_key.rs:98:5 + --> tests/ui/mut_key.rs:94:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> tests/ui/mut_key.rs:100:5 + --> tests/ui/mut_key.rs:96:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> tests/ui/mut_key.rs:102:5 + --> tests/ui/mut_key.rs:98:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 17 previous errors +error: aborting due to 15 previous errors From 26484cefb6e93b81ceed576a78db78f2c9ebe7fe Mon Sep 17 00:00:00 2001 From: Dominik Stolz Date: Wed, 17 Apr 2024 23:40:03 +0200 Subject: [PATCH 12/47] Disallow ambiguous attributes on expressions --- tests/ui/cfg_attr_rustfmt.fixed | 6 +++--- tests/ui/cfg_attr_rustfmt.rs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/ui/cfg_attr_rustfmt.fixed b/tests/ui/cfg_attr_rustfmt.fixed index 05d5b3d10eaf..84dac431169a 100644 --- a/tests/ui/cfg_attr_rustfmt.fixed +++ b/tests/ui/cfg_attr_rustfmt.fixed @@ -16,7 +16,7 @@ fn foo( fn skip_on_statements() { #[rustfmt::skip] - 5+3; + { 5+3; } } #[rustfmt::skip] @@ -33,11 +33,11 @@ mod foo { #[clippy::msrv = "1.29"] fn msrv_1_29() { #[cfg_attr(rustfmt, rustfmt::skip)] - 1+29; + { 1+29; } } #[clippy::msrv = "1.30"] fn msrv_1_30() { #[rustfmt::skip] - 1+30; + { 1+30; } } diff --git a/tests/ui/cfg_attr_rustfmt.rs b/tests/ui/cfg_attr_rustfmt.rs index bc29e20210e8..4ab5c70e13b5 100644 --- a/tests/ui/cfg_attr_rustfmt.rs +++ b/tests/ui/cfg_attr_rustfmt.rs @@ -16,7 +16,7 @@ fn foo( fn skip_on_statements() { #[cfg_attr(rustfmt, rustfmt::skip)] - 5+3; + { 5+3; } } #[cfg_attr(rustfmt, rustfmt_skip)] @@ -33,11 +33,11 @@ mod foo { #[clippy::msrv = "1.29"] fn msrv_1_29() { #[cfg_attr(rustfmt, rustfmt::skip)] - 1+29; + { 1+29; } } #[clippy::msrv = "1.30"] fn msrv_1_30() { #[cfg_attr(rustfmt, rustfmt::skip)] - 1+30; + { 1+30; } } From 2a4dae368c109d0029e12787a78b6c028b61ca08 Mon Sep 17 00:00:00 2001 From: Caio Date: Thu, 18 Apr 2024 17:24:47 -0300 Subject: [PATCH 13/47] [arithmetic_side_effects] Fix #12318 --- .../src/operators/arithmetic_side_effects.rs | 53 +++++++++++++------ tests/ui/arithmetic_side_effects.rs | 10 ++++ tests/ui/arithmetic_side_effects.stderr | 14 ++++- 3 files changed, 61 insertions(+), 16 deletions(-) diff --git a/clippy_lints/src/operators/arithmetic_side_effects.rs b/clippy_lints/src/operators/arithmetic_side_effects.rs index 96ea063aa74d..7d6f26cde3e9 100644 --- a/clippy_lints/src/operators/arithmetic_side_effects.rs +++ b/clippy_lints/src/operators/arithmetic_side_effects.rs @@ -7,14 +7,13 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; use rustc_session::impl_lint_pass; -use rustc_span::source_map::Spanned; use rustc_span::symbol::sym; use rustc_span::{Span, Symbol}; use {rustc_ast as ast, rustc_hir as hir}; const HARD_CODED_ALLOWED_BINARY: &[[&str; 2]] = &[["f32", "f32"], ["f64", "f64"], ["std::string::String", "str"]]; const HARD_CODED_ALLOWED_UNARY: &[&str] = &["f32", "f64", "std::num::Saturating", "std::num::Wrapping"]; -const INTEGER_METHODS: &[Symbol] = &[ +const DISALLOWED_INT_METHODS: &[Symbol] = &[ sym::saturating_div, sym::wrapping_div, sym::wrapping_rem, @@ -27,8 +26,8 @@ pub struct ArithmeticSideEffects { allowed_unary: FxHashSet, // Used to check whether expressions are constants, such as in enum discriminants and consts const_span: Option, + disallowed_int_methods: FxHashSet, expr_span: Option, - integer_methods: FxHashSet, } impl_lint_pass!(ArithmeticSideEffects => [ARITHMETIC_SIDE_EFFECTS]); @@ -53,8 +52,8 @@ impl ArithmeticSideEffects { allowed_binary, allowed_unary, const_span: None, + disallowed_int_methods: DISALLOWED_INT_METHODS.iter().copied().collect(), expr_span: None, - integer_methods: INTEGER_METHODS.iter().copied().collect(), } } @@ -91,10 +90,10 @@ impl ArithmeticSideEffects { fn has_specific_allowed_type_and_operation<'tcx>( cx: &LateContext<'tcx>, lhs_ty: Ty<'tcx>, - op: &Spanned, + op: hir::BinOpKind, rhs_ty: Ty<'tcx>, ) -> bool { - let is_div_or_rem = matches!(op.node, hir::BinOpKind::Div | hir::BinOpKind::Rem); + let is_div_or_rem = matches!(op, hir::BinOpKind::Div | hir::BinOpKind::Rem); let is_non_zero_u = |cx: &LateContext<'tcx>, ty: Ty<'tcx>| { let tcx = cx.tcx; @@ -166,13 +165,35 @@ impl ArithmeticSideEffects { None } + /// Methods like `add_assign` are send to their `BinOps` references. + fn manage_sugar_methods<'tcx>( + &mut self, + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'_>, + lhs: &'tcx hir::Expr<'_>, + ps: &hir::PathSegment<'_>, + rhs: &'tcx hir::Expr<'_>, + ) { + if ps.ident.name == sym::add || ps.ident.name == sym::add_assign { + self.manage_bin_ops(cx, expr, hir::BinOpKind::Add, lhs, rhs); + } else if ps.ident.name == sym::div || ps.ident.name == sym::div_assign { + self.manage_bin_ops(cx, expr, hir::BinOpKind::Div, lhs, rhs); + } else if ps.ident.name == sym::mul || ps.ident.name == sym::mul_assign { + self.manage_bin_ops(cx, expr, hir::BinOpKind::Mul, lhs, rhs); + } else if ps.ident.name == sym::rem || ps.ident.name == sym::rem_assign { + self.manage_bin_ops(cx, expr, hir::BinOpKind::Rem, lhs, rhs); + } else if ps.ident.name == sym::sub || ps.ident.name == sym::sub_assign { + self.manage_bin_ops(cx, expr, hir::BinOpKind::Sub, lhs, rhs); + } + } + /// Manages when the lint should be triggered. Operations in constant environments, hard coded - /// types, custom allowed types and non-constant operations that won't overflow are ignored. + /// types, custom allowed types and non-constant operations that don't overflow are ignored. fn manage_bin_ops<'tcx>( &mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, - op: &Spanned, + op: hir::BinOpKind, lhs: &'tcx hir::Expr<'_>, rhs: &'tcx hir::Expr<'_>, ) { @@ -180,7 +201,7 @@ impl ArithmeticSideEffects { return; } if !matches!( - op.node, + op, hir::BinOpKind::Add | hir::BinOpKind::Div | hir::BinOpKind::Mul @@ -204,7 +225,7 @@ impl ArithmeticSideEffects { return; } let has_valid_op = if Self::is_integral(lhs_ty) && Self::is_integral(rhs_ty) { - if let hir::BinOpKind::Shl | hir::BinOpKind::Shr = op.node { + if let hir::BinOpKind::Shl | hir::BinOpKind::Shr = op { // At least for integers, shifts are already handled by the CTFE return; } @@ -213,7 +234,7 @@ impl ArithmeticSideEffects { Self::literal_integer(cx, actual_rhs), ) { (None, None) => false, - (None, Some(n)) => match (&op.node, n) { + (None, Some(n)) => match (&op, n) { // Division and module are always valid if applied to non-zero integers (hir::BinOpKind::Div | hir::BinOpKind::Rem, local_n) if local_n != 0 => true, // Adding or subtracting zeros is always a no-op @@ -223,7 +244,7 @@ impl ArithmeticSideEffects { => true, _ => false, }, - (Some(n), None) => match (&op.node, n) { + (Some(n), None) => match (&op, n) { // Adding or subtracting zeros is always a no-op (hir::BinOpKind::Add | hir::BinOpKind::Sub, 0) // Multiplication by 1 or 0 will never overflow @@ -249,6 +270,7 @@ impl ArithmeticSideEffects { &mut self, args: &'tcx [hir::Expr<'_>], cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'_>, ps: &'tcx hir::PathSegment<'_>, receiver: &'tcx hir::Expr<'_>, ) { @@ -262,7 +284,8 @@ impl ArithmeticSideEffects { if !Self::is_integral(instance_ty) { return; } - if !self.integer_methods.contains(&ps.ident.name) { + self.manage_sugar_methods(cx, expr, receiver, ps, arg); + if !self.disallowed_int_methods.contains(&ps.ident.name) { return; } let (actual_arg, _) = peel_hir_expr_refs(arg); @@ -310,10 +333,10 @@ impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects { } match &expr.kind { hir::ExprKind::AssignOp(op, lhs, rhs) | hir::ExprKind::Binary(op, lhs, rhs) => { - self.manage_bin_ops(cx, expr, op, lhs, rhs); + self.manage_bin_ops(cx, expr, op.node, lhs, rhs); }, hir::ExprKind::MethodCall(ps, receiver, args, _) => { - self.manage_method_call(args, cx, ps, receiver); + self.manage_method_call(args, cx, expr, ps, receiver); }, hir::ExprKind::Unary(un_op, un_expr) => { self.manage_unary_ops(cx, expr, un_expr, *un_op); diff --git a/tests/ui/arithmetic_side_effects.rs b/tests/ui/arithmetic_side_effects.rs index b454c29aef4d..e6951826b2f3 100644 --- a/tests/ui/arithmetic_side_effects.rs +++ b/tests/ui/arithmetic_side_effects.rs @@ -521,4 +521,14 @@ pub fn issue_11393() { example_rem(x, maybe_zero); } +pub fn issue_12318() { + use core::ops::{AddAssign, DivAssign, MulAssign, RemAssign, SubAssign}; + let mut one: i32 = 1; + one.add_assign(1); + one.div_assign(1); + one.mul_assign(1); + one.rem_assign(1); + one.sub_assign(1); +} + fn main() {} diff --git a/tests/ui/arithmetic_side_effects.stderr b/tests/ui/arithmetic_side_effects.stderr index 741c892a52cf..8039c0bfa248 100644 --- a/tests/ui/arithmetic_side_effects.stderr +++ b/tests/ui/arithmetic_side_effects.stderr @@ -715,5 +715,17 @@ error: arithmetic operation that can potentially result in unexpected side-effec LL | x % maybe_zero | ^^^^^^^^^^^^^^ -error: aborting due to 119 previous errors +error: arithmetic operation that can potentially result in unexpected side-effects + --> tests/ui/arithmetic_side_effects.rs:527:5 + | +LL | one.add_assign(1); + | ^^^^^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> tests/ui/arithmetic_side_effects.rs:531:5 + | +LL | one.sub_assign(1); + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 121 previous errors From 2f8b1e3eea2c513a14f9ce89118d94f5d534ea7b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 18 Apr 2024 22:20:42 +0200 Subject: [PATCH 14/47] needless_pass_by_ref_mut: Fix corner case in async functions --- clippy_lints/src/needless_pass_by_ref_mut.rs | 24 ++++++++++++++------ tests/ui/needless_pass_by_ref_mut2.fixed | 24 ++++++++++++++++++++ tests/ui/needless_pass_by_ref_mut2.rs | 24 ++++++++++++++++++++ tests/ui/needless_pass_by_ref_mut2.stderr | 20 ++++++++++++++++ 4 files changed, 85 insertions(+), 7 deletions(-) create mode 100644 tests/ui/needless_pass_by_ref_mut2.fixed create mode 100644 tests/ui/needless_pass_by_ref_mut2.rs create mode 100644 tests/ui/needless_pass_by_ref_mut2.stderr diff --git a/clippy_lints/src/needless_pass_by_ref_mut.rs b/clippy_lints/src/needless_pass_by_ref_mut.rs index 30d3e86dc4ed..c3ceb994f60b 100644 --- a/clippy_lints/src/needless_pass_by_ref_mut.rs +++ b/clippy_lints/src/needless_pass_by_ref_mut.rs @@ -185,7 +185,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> { } // Collect variables mutably used and spans which will need dereferencings from the // function body. - let MutablyUsedVariablesCtxt { mutably_used_vars, .. } = { + let mutably_used_vars = { let mut ctx = MutablyUsedVariablesCtxt { mutably_used_vars: HirIdSet::default(), prev_bind: None, @@ -217,7 +217,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> { check_closures(&mut ctx, cx, &infcx, &mut checked_closures, async_closures); } } - ctx + ctx.generate_mutably_used_ids_from_aliases() }; for ((&input, &_), arg) in it { // Only take `&mut` arguments. @@ -309,14 +309,24 @@ struct MutablyUsedVariablesCtxt<'tcx> { } impl<'tcx> MutablyUsedVariablesCtxt<'tcx> { - fn add_mutably_used_var(&mut self, mut used_id: HirId) { - while let Some(id) = self.aliases.get(&used_id) { - self.mutably_used_vars.insert(used_id); - used_id = *id; - } + fn add_mutably_used_var(&mut self, used_id: HirId) { self.mutably_used_vars.insert(used_id); } + // Because the alias may come after the mutable use of a variable, we need to fill the map at + // the end. + fn generate_mutably_used_ids_from_aliases(mut self) -> HirIdSet { + let all_ids = self.mutably_used_vars.iter().copied().collect::>(); + for mut used_id in all_ids { + while let Some(id) = self.aliases.get(&used_id) { + self.mutably_used_vars.insert(used_id); + used_id = *id; + } + self.mutably_used_vars.insert(used_id); + } + self.mutably_used_vars + } + fn would_be_alias_cycle(&self, alias: HirId, mut target: HirId) -> bool { while let Some(id) = self.aliases.get(&target) { if *id == alias { diff --git a/tests/ui/needless_pass_by_ref_mut2.fixed b/tests/ui/needless_pass_by_ref_mut2.fixed new file mode 100644 index 000000000000..3c2576213cd7 --- /dev/null +++ b/tests/ui/needless_pass_by_ref_mut2.fixed @@ -0,0 +1,24 @@ +// If both `inner_async3` and `inner_async4` are present, aliases are declared after +// they're used in `inner_async4` for some reasons... This test ensures that no +// only `v` is marked as not used mutably in `inner_async4`. + +#![allow(clippy::redundant_closure_call)] +#![warn(clippy::needless_pass_by_ref_mut)] + +pub async fn inner_async3(x: &i32, y: &mut u32) { + //~^ ERROR: this argument is a mutable reference, but not used mutably + async { + *y += 1; + } + .await; +} + +pub async fn inner_async4(u: &mut i32, v: &u32) { + //~^ ERROR: this argument is a mutable reference, but not used mutably + async { + *u += 1; + } + .await; +} + +fn main() {} diff --git a/tests/ui/needless_pass_by_ref_mut2.rs b/tests/ui/needless_pass_by_ref_mut2.rs new file mode 100644 index 000000000000..34b0b564deb8 --- /dev/null +++ b/tests/ui/needless_pass_by_ref_mut2.rs @@ -0,0 +1,24 @@ +// If both `inner_async3` and `inner_async4` are present, aliases are declared after +// they're used in `inner_async4` for some reasons... This test ensures that no +// only `v` is marked as not used mutably in `inner_async4`. + +#![allow(clippy::redundant_closure_call)] +#![warn(clippy::needless_pass_by_ref_mut)] + +pub async fn inner_async3(x: &mut i32, y: &mut u32) { + //~^ ERROR: this argument is a mutable reference, but not used mutably + async { + *y += 1; + } + .await; +} + +pub async fn inner_async4(u: &mut i32, v: &mut u32) { + //~^ ERROR: this argument is a mutable reference, but not used mutably + async { + *u += 1; + } + .await; +} + +fn main() {} diff --git a/tests/ui/needless_pass_by_ref_mut2.stderr b/tests/ui/needless_pass_by_ref_mut2.stderr new file mode 100644 index 000000000000..c87536032256 --- /dev/null +++ b/tests/ui/needless_pass_by_ref_mut2.stderr @@ -0,0 +1,20 @@ +error: this argument is a mutable reference, but not used mutably + --> tests/ui/needless_pass_by_ref_mut2.rs:8:30 + | +LL | pub async fn inner_async3(x: &mut i32, y: &mut u32) { + | ^^^^^^^^ help: consider changing to: `&i32` + | + = warning: changing this function will impact semver compatibility + = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]` + +error: this argument is a mutable reference, but not used mutably + --> tests/ui/needless_pass_by_ref_mut2.rs:16:43 + | +LL | pub async fn inner_async4(u: &mut i32, v: &mut u32) { + | ^^^^^^^^ help: consider changing to: `&u32` + | + = warning: changing this function will impact semver compatibility + +error: aborting due to 2 previous errors + From 0999867ec5036b55825c3bb94f0820dde1e61e6a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 18 Apr 2024 22:24:55 +0200 Subject: [PATCH 15/47] needless_pass_by_ref_mut: emit the lint on `self` as well --- clippy_lints/src/needless_pass_by_ref_mut.rs | 4 +- tests/ui/needless_pass_by_ref_mut.rs | 42 +++++++-- tests/ui/needless_pass_by_ref_mut.stderr | 98 ++++++++++++-------- 3 files changed, 96 insertions(+), 48 deletions(-) diff --git a/clippy_lints/src/needless_pass_by_ref_mut.rs b/clippy_lints/src/needless_pass_by_ref_mut.rs index c3ceb994f60b..9e47c3ad0b7f 100644 --- a/clippy_lints/src/needless_pass_by_ref_mut.rs +++ b/clippy_lints/src/needless_pass_by_ref_mut.rs @@ -83,7 +83,9 @@ fn should_skip<'tcx>( } if is_self(arg) { - return true; + // Interestingly enough, `self` arguments make `is_from_proc_macro` return `true`, hence why + // we return early here. + return false; } if let PatKind::Binding(.., name, _) = arg.pat.kind { diff --git a/tests/ui/needless_pass_by_ref_mut.rs b/tests/ui/needless_pass_by_ref_mut.rs index a92197fb0af5..3f5f55f40020 100644 --- a/tests/ui/needless_pass_by_ref_mut.rs +++ b/tests/ui/needless_pass_by_ref_mut.rs @@ -44,18 +44,13 @@ fn non_mut_ref(_: &Vec) {} struct Bar; impl Bar { - // Should not warn on `&mut self`. fn bar(&mut self) {} + //~^ ERROR: this argument is a mutable reference, but not used mutably fn mushroom(&self, vec: &mut Vec) -> usize { //~^ ERROR: this argument is a mutable reference, but not used mutably vec.len() } - - fn badger(&mut self, vec: &mut Vec) -> usize { - //~^ ERROR: this argument is a mutable reference, but not used mutably - vec.len() - } } trait Babar { @@ -307,6 +302,41 @@ fn filter_copy(predicate: &mut impl FnMut(T) -> bool) -> impl FnMut(&T) move |&item| predicate(item) } +trait MutSelfTrait { + // Should not warn since it's a trait method. + fn mut_self(&mut self); +} + +struct MutSelf { + a: u32, +} + +impl MutSelf { + fn bar(&mut self) {} + //~^ ERROR: this argument is a mutable reference, but not used mutably + async fn foo(&mut self, u: &mut i32, v: &mut u32) { + //~^ ERROR: this argument is a mutable reference, but not used mutably + //~| ERROR: this argument is a mutable reference, but not used mutably + async { + *u += 1; + } + .await; + } + async fn foo2(&mut self, u: &mut i32, v: &mut u32) { + //~^ ERROR: this argument is a mutable reference, but not used mutably + async { + self.a += 1; + *u += 1; + } + .await; + } +} + +impl MutSelfTrait for MutSelf { + // Should not warn since it's a trait method. + fn mut_self(&mut self) {} +} + // `is_from_proc_macro` stress tests fn _empty_tup(x: &mut (())) {} fn _single_tup(x: &mut ((i32,))) {} diff --git a/tests/ui/needless_pass_by_ref_mut.stderr b/tests/ui/needless_pass_by_ref_mut.stderr index 89dad3e60b14..21ca393dcb63 100644 --- a/tests/ui/needless_pass_by_ref_mut.stderr +++ b/tests/ui/needless_pass_by_ref_mut.stderr @@ -13,6 +13,12 @@ error: this argument is a mutable reference, but not used mutably LL | fn foo6(s: &mut Vec) { | ^^^^^^^^^^^^^ help: consider changing to: `&Vec` +error: this argument is a mutable reference, but not used mutably + --> tests/ui/needless_pass_by_ref_mut.rs:47:12 + | +LL | fn bar(&mut self) {} + | ^^^^^^^^^ help: consider changing to: `&self` + error: this argument is a mutable reference, but not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:50:29 | @@ -20,67 +26,61 @@ LL | fn mushroom(&self, vec: &mut Vec) -> usize { | ^^^^^^^^^^^^^ help: consider changing to: `&Vec` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:55:31 - | -LL | fn badger(&mut self, vec: &mut Vec) -> usize { - | ^^^^^^^^^^^^^ help: consider changing to: `&Vec` - -error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:132:16 + --> tests/ui/needless_pass_by_ref_mut.rs:127:16 | LL | async fn a1(x: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:136:16 + --> tests/ui/needless_pass_by_ref_mut.rs:131:16 | LL | async fn a2(x: &mut i32, y: String) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:140:16 + --> tests/ui/needless_pass_by_ref_mut.rs:135:16 | LL | async fn a3(x: &mut i32, y: String, z: String) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:144:16 + --> tests/ui/needless_pass_by_ref_mut.rs:139:16 | LL | async fn a4(x: &mut i32, y: i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:148:24 + --> tests/ui/needless_pass_by_ref_mut.rs:143:24 | LL | async fn a5(x: i32, y: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:152:24 + --> tests/ui/needless_pass_by_ref_mut.rs:147:24 | LL | async fn a6(x: i32, y: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:156:32 + --> tests/ui/needless_pass_by_ref_mut.rs:151:32 | LL | async fn a7(x: i32, y: i32, z: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:160:24 + --> tests/ui/needless_pass_by_ref_mut.rs:155:24 | LL | async fn a8(x: i32, a: &mut i32, y: i32, z: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:160:45 + --> tests/ui/needless_pass_by_ref_mut.rs:155:45 | LL | async fn a8(x: i32, a: &mut i32, y: i32, z: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:194:16 + --> tests/ui/needless_pass_by_ref_mut.rs:189:16 | LL | fn cfg_warn(s: &mut u32) {} | ^^^^^^^^ help: consider changing to: `&u32` @@ -88,7 +88,7 @@ LL | fn cfg_warn(s: &mut u32) {} = note: this is cfg-gated and may require further changes error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:200:20 + --> tests/ui/needless_pass_by_ref_mut.rs:195:20 | LL | fn cfg_warn(s: &mut u32) {} | ^^^^^^^^ help: consider changing to: `&u32` @@ -96,19 +96,19 @@ LL | fn cfg_warn(s: &mut u32) {} = note: this is cfg-gated and may require further changes error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:214:39 + --> tests/ui/needless_pass_by_ref_mut.rs:209:39 | LL | async fn inner_async2(x: &mut i32, y: &mut u32) { | ^^^^^^^^ help: consider changing to: `&u32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:222:26 + --> tests/ui/needless_pass_by_ref_mut.rs:217:26 | LL | async fn inner_async3(x: &mut i32, y: &mut u32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:241:34 + --> tests/ui/needless_pass_by_ref_mut.rs:236:34 | LL | pub async fn call_in_closure1(n: &mut str) { | ^^^^^^^^ help: consider changing to: `&str` @@ -116,15 +116,7 @@ LL | pub async fn call_in_closure1(n: &mut str) { = warning: changing this function will impact semver compatibility error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:253:25 - | -LL | pub async fn closure(n: &mut usize) -> impl '_ + FnMut() { - | ^^^^^^^^^^ help: consider changing to: `&usize` - | - = warning: changing this function will impact semver compatibility - -error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:260:20 + --> tests/ui/needless_pass_by_ref_mut.rs:255:20 | LL | pub fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize { | ^^^^^^^^^^ help: consider changing to: `&usize` @@ -132,7 +124,7 @@ LL | pub fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize { = warning: changing this function will impact semver compatibility error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:271:26 + --> tests/ui/needless_pass_by_ref_mut.rs:266:26 | LL | pub async fn closure4(n: &mut usize) { | ^^^^^^^^^^ help: consider changing to: `&usize` @@ -140,64 +132,88 @@ LL | pub async fn closure4(n: &mut usize) { = warning: changing this function will impact semver compatibility error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:311:18 + --> tests/ui/needless_pass_by_ref_mut.rs:315:12 + | +LL | fn bar(&mut self) {} + | ^^^^^^^^^ help: consider changing to: `&self` + +error: this argument is a mutable reference, but not used mutably + --> tests/ui/needless_pass_by_ref_mut.rs:317:18 + | +LL | async fn foo(&mut self, u: &mut i32, v: &mut u32) { + | ^^^^^^^^^ help: consider changing to: `&self` + +error: this argument is a mutable reference, but not used mutably + --> tests/ui/needless_pass_by_ref_mut.rs:317:45 + | +LL | async fn foo(&mut self, u: &mut i32, v: &mut u32) { + | ^^^^^^^^ help: consider changing to: `&u32` + +error: this argument is a mutable reference, but not used mutably + --> tests/ui/needless_pass_by_ref_mut.rs:325:46 + | +LL | async fn foo2(&mut self, u: &mut i32, v: &mut u32) { + | ^^^^^^^^ help: consider changing to: `&u32` + +error: this argument is a mutable reference, but not used mutably + --> tests/ui/needless_pass_by_ref_mut.rs:341:18 | LL | fn _empty_tup(x: &mut (())) {} | ^^^^^^^^^ help: consider changing to: `&()` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:312:19 + --> tests/ui/needless_pass_by_ref_mut.rs:342:19 | LL | fn _single_tup(x: &mut ((i32,))) {} | ^^^^^^^^^^^^^ help: consider changing to: `&(i32,)` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:313:18 + --> tests/ui/needless_pass_by_ref_mut.rs:343:18 | LL | fn _multi_tup(x: &mut ((i32, u32))) {} | ^^^^^^^^^^^^^^^^^ help: consider changing to: `&(i32, u32)` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:314:11 + --> tests/ui/needless_pass_by_ref_mut.rs:344:11 | LL | fn _fn(x: &mut (fn())) {} | ^^^^^^^^^^^ help: consider changing to: `&fn()` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:316:23 + --> tests/ui/needless_pass_by_ref_mut.rs:346:23 | LL | fn _extern_rust_fn(x: &mut extern "Rust" fn()) {} | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&extern "Rust" fn()` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:317:20 + --> tests/ui/needless_pass_by_ref_mut.rs:347:20 | LL | fn _extern_c_fn(x: &mut extern "C" fn()) {} | ^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&extern "C" fn()` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:318:18 + --> tests/ui/needless_pass_by_ref_mut.rs:348:18 | LL | fn _unsafe_fn(x: &mut unsafe fn()) {} | ^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe fn()` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:319:25 + --> tests/ui/needless_pass_by_ref_mut.rs:349:25 | LL | fn _unsafe_extern_fn(x: &mut unsafe extern "C" fn()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn()` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:320:20 + --> tests/ui/needless_pass_by_ref_mut.rs:350:20 | LL | fn _fn_with_arg(x: &mut unsafe extern "C" fn(i32)) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn(i32)` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:321:20 + --> tests/ui/needless_pass_by_ref_mut.rs:351:20 | LL | fn _fn_with_ret(x: &mut unsafe extern "C" fn() -> (i32)) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn() -> (i32)` -error: aborting due to 31 previous errors +error: aborting due to 34 previous errors From adab7d08d75f8e92c1202aff3f0abd797da1062b Mon Sep 17 00:00:00 2001 From: J-ZhengLi Date: Fri, 19 Apr 2024 15:55:20 +0800 Subject: [PATCH 16/47] [`collection_is_never_read`]: check clousure in method args --- clippy_lints/src/collection_is_never_read.rs | 27 +++++++++++++++++--- tests/ui/collection_is_never_read.rs | 14 ++++++++++ 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/collection_is_never_read.rs b/clippy_lints/src/collection_is_never_read.rs index 6942ca536404..70856b808810 100644 --- a/clippy_lints/src/collection_is_never_read.rs +++ b/clippy_lints/src/collection_is_never_read.rs @@ -1,9 +1,9 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; -use clippy_utils::visitors::for_each_expr_with_closures; +use clippy_utils::visitors::{for_each_expr_with_closures, Visitable}; use clippy_utils::{get_enclosing_block, path_to_local_id}; use core::ops::ControlFlow; -use rustc_hir::{Block, ExprKind, HirId, LangItem, LetStmt, Node, PatKind}; +use rustc_hir::{Body, ExprKind, HirId, LangItem, LetStmt, Node, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; @@ -77,7 +77,7 @@ fn match_acceptable_type(cx: &LateContext<'_>, local: &LetStmt<'_>, collections: || is_type_lang_item(cx, ty, LangItem::String) } -fn has_no_read_access<'tcx>(cx: &LateContext<'tcx>, id: HirId, block: &'tcx Block<'tcx>) -> bool { +fn has_no_read_access<'tcx, T: Visitable<'tcx>>(cx: &LateContext<'tcx>, id: HirId, block: T) -> bool { let mut has_access = false; let mut has_read_access = false; @@ -109,11 +109,30 @@ fn has_no_read_access<'tcx>(cx: &LateContext<'tcx>, id: HirId, block: &'tcx Bloc // traits (identified as local, based on the orphan rule), pessimistically assume that they might // have side effects, so consider them a read. if let Node::Expr(parent) = cx.tcx.parent_hir_node(expr.hir_id) - && let ExprKind::MethodCall(_, receiver, _, _) = parent.kind + && let ExprKind::MethodCall(_, receiver, args, _) = parent.kind && path_to_local_id(receiver, id) && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(parent.hir_id) && !method_def_id.is_local() { + // If this "official" method takes closures, + // it has read access if one of the closures has read access. + // + // items.retain(|item| send_item(item).is_ok()); + let is_read_in_closure_arg = args.iter().any(|arg| { + if let ExprKind::Closure(closure) = arg.kind + // To keep things simple, we only check the first param to see if its read. + && let Body { params: [param, ..], value } = cx.tcx.hir().body(closure.body) + { + !has_no_read_access(cx, param.hir_id, *value) + } else { + false + } + }); + if is_read_in_closure_arg { + has_read_access = true; + return ControlFlow::Break(()); + } + // The method call is a statement, so the return value is not used. That's not a read access: // // id.foo(args); diff --git a/tests/ui/collection_is_never_read.rs b/tests/ui/collection_is_never_read.rs index bd281f7870ce..eeb10da3402a 100644 --- a/tests/ui/collection_is_never_read.rs +++ b/tests/ui/collection_is_never_read.rs @@ -222,3 +222,17 @@ fn supported_types() { //~^ ERROR: collection is never read x.push_front(1); } + +fn issue11783() { + struct Sender; + impl Sender { + fn send(&self, msg: String) -> Result<(), ()> { + // pretend to send message + println!("{msg}"); + Ok(()) + } + } + + let mut users: Vec = vec![]; + users.retain(|user| user.send("hello".to_string()).is_ok()); +} From 206b1a1ac9df38ca5278a6db9954f9c62bd34b17 Mon Sep 17 00:00:00 2001 From: Quinn Sinclair Date: Wed, 17 Apr 2024 13:25:39 +0300 Subject: [PATCH 17/47] Threadlocal_initializer_can_be_made_const will not trigger for unreachable initializers This commit introduces a check to ensure that the lint won't trigger when the initializer is unreachable, such as: ``` thread_local! { static STATE: Cell = panic!(); } ``` This is achieved by looking at the unpeeled initializer expression and ensuring that the parent macro is not `panic!()`, `todo!()`, `unreachable!()`, `unimplemented!()`. fixes #12637 changelog: [`threadlocal_initializer_can_be_made_const`] will no longer trigger on `unreachable` macros. --- ...ead_local_initializer_can_be_made_const.rs | 36 ++++++++++++++++--- ..._local_initializer_can_be_made_const.fixed | 33 ++++++++++++++++- ...ead_local_initializer_can_be_made_const.rs | 33 ++++++++++++++++- 3 files changed, 95 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/thread_local_initializer_can_be_made_const.rs b/clippy_lints/src/thread_local_initializer_can_be_made_const.rs index c1e24674e3e8..4af3ee74d0ea 100644 --- a/clippy_lints/src/thread_local_initializer_can_be_made_const.rs +++ b/clippy_lints/src/thread_local_initializer_can_be_made_const.rs @@ -1,13 +1,14 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::macros::macro_backtrace; use clippy_utils::qualify_min_const_fn::is_min_const_fn; use clippy_utils::source::snippet; use clippy_utils::{fn_has_unsatisfiable_preds, peel_blocks}; use rustc_errors::Applicability; -use rustc_hir::{intravisit, ExprKind}; +use rustc_hir::{intravisit, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::sym::thread_local_macro; +use rustc_span::sym::{self, thread_local_macro}; declare_clippy_lint! { /// ### What it does @@ -69,6 +70,26 @@ fn is_thread_local_initializer( ) } +fn is_unreachable(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + if let Some(macro_call) = macro_backtrace(expr.span).next() + && let Some(diag_name) = cx.tcx.get_diagnostic_name(macro_call.def_id) + { + return (matches!( + diag_name, + sym::core_panic_macro + | sym::std_panic_macro + | sym::core_panic_2015_macro + | sym::std_panic_2015_macro + | sym::core_panic_2021_macro + ) && !cx.tcx.hir().is_inside_const_context(expr.hir_id)) + || matches!( + diag_name, + sym::unimplemented_macro | sym::todo_macro | sym::unreachable_macro | sym::unreachable_2015_macro + ); + } + false +} + #[inline] fn initializer_can_be_made_const(cx: &LateContext<'_>, defid: rustc_span::def_id::DefId, msrv: &Msrv) -> bool { // Building MIR for `fn`s with unsatisfiable preds results in ICE. @@ -102,12 +123,17 @@ impl<'tcx> LateLintPass<'tcx> for ThreadLocalInitializerCanBeMadeConst { // for details on this issue, see: // https://github.com/rust-lang/rust-clippy/pull/12276 && !cx.tcx.is_const_fn(defid) - && initializer_can_be_made_const(cx, defid, &self.msrv) - // we know that the function is const-qualifiable, so now - // we need only to get the initializer expression to span-lint it. && let ExprKind::Block(block, _) = body.value.kind && let Some(unpeeled) = block.expr && let ret_expr = peel_blocks(unpeeled) + // A common pattern around threadlocal! is to make the value unreachable + // to force an initialization before usage + // https://github.com/rust-lang/rust-clippy/issues/12637 + // we ensure that this is reachable before we check in mir + && !is_unreachable(cx, ret_expr) + && initializer_can_be_made_const(cx, defid, &self.msrv) + // we know that the function is const-qualifiable, so now + // we need only to get the initializer expression to span-lint it. && let initializer_snippet = snippet(cx, ret_expr.span, "thread_local! { ... }") && initializer_snippet != "thread_local! { ... }" { diff --git a/tests/ui/thread_local_initializer_can_be_made_const.fixed b/tests/ui/thread_local_initializer_can_be_made_const.fixed index a6ed59d49c54..4c9bd0bd8634 100644 --- a/tests/ui/thread_local_initializer_can_be_made_const.fixed +++ b/tests/ui/thread_local_initializer_can_be_made_const.fixed @@ -1,6 +1,6 @@ #![warn(clippy::thread_local_initializer_can_be_made_const)] -use std::cell::RefCell; +use std::cell::{Cell, RefCell}; fn main() { // lint and suggest const @@ -36,6 +36,37 @@ fn main() { } } +fn issue_12637() { + /// The set methods on LocalKey> and LocalKey> are + /// guaranteed to bypass the thread_local's initialization expression. + /// See rust-lang/rust#92122. Thus, = panic!() is a useful idiom for + /// forcing the use of set on each thread before it accesses the thread local in any other + /// manner. + thread_local! { + static STATE_12637_PANIC: Cell = panic!(); + } + STATE_12637_PANIC.set(9); + println!("{}", STATE_12637_PANIC.get()); + + thread_local! { + static STATE_12637_TODO: Cell = todo!(); + } + STATE_12637_TODO.set(9); + println!("{}", STATE_12637_TODO.get()); + + thread_local! { + static STATE_12637_UNIMPLEMENTED: Cell = unimplemented!(); + } + STATE_12637_UNIMPLEMENTED.set(9); + println!("{}", STATE_12637_UNIMPLEMENTED.get()); + + thread_local! { + static STATE_12637_UNREACHABLE: Cell = unreachable!(); + } + STATE_12637_UNREACHABLE.set(9); + println!("{}", STATE_12637_UNREACHABLE.get()); +} + #[clippy::msrv = "1.58"] fn f() { thread_local! { diff --git a/tests/ui/thread_local_initializer_can_be_made_const.rs b/tests/ui/thread_local_initializer_can_be_made_const.rs index 3f0159c58065..eb336f0dd191 100644 --- a/tests/ui/thread_local_initializer_can_be_made_const.rs +++ b/tests/ui/thread_local_initializer_can_be_made_const.rs @@ -1,6 +1,6 @@ #![warn(clippy::thread_local_initializer_can_be_made_const)] -use std::cell::RefCell; +use std::cell::{Cell, RefCell}; fn main() { // lint and suggest const @@ -36,6 +36,37 @@ fn main() { } } +fn issue_12637() { + /// The set methods on LocalKey> and LocalKey> are + /// guaranteed to bypass the thread_local's initialization expression. + /// See rust-lang/rust#92122. Thus, = panic!() is a useful idiom for + /// forcing the use of set on each thread before it accesses the thread local in any other + /// manner. + thread_local! { + static STATE_12637_PANIC: Cell = panic!(); + } + STATE_12637_PANIC.set(9); + println!("{}", STATE_12637_PANIC.get()); + + thread_local! { + static STATE_12637_TODO: Cell = todo!(); + } + STATE_12637_TODO.set(9); + println!("{}", STATE_12637_TODO.get()); + + thread_local! { + static STATE_12637_UNIMPLEMENTED: Cell = unimplemented!(); + } + STATE_12637_UNIMPLEMENTED.set(9); + println!("{}", STATE_12637_UNIMPLEMENTED.get()); + + thread_local! { + static STATE_12637_UNREACHABLE: Cell = unreachable!(); + } + STATE_12637_UNREACHABLE.set(9); + println!("{}", STATE_12637_UNREACHABLE.get()); +} + #[clippy::msrv = "1.58"] fn f() { thread_local! { From 898baf81cdaf1682c6cbf6e575fb546741bc73a0 Mon Sep 17 00:00:00 2001 From: Samuel Moelius Date: Sat, 20 Apr 2024 01:16:30 +0000 Subject: [PATCH 18/47] Add `test_with_disallowed_name` --- tests/ui/disallowed_names.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/ui/disallowed_names.rs b/tests/ui/disallowed_names.rs index 9a701a2cbcfb..13c883409bf6 100644 --- a/tests/ui/disallowed_names.rs +++ b/tests/ui/disallowed_names.rs @@ -71,3 +71,8 @@ mod tests { } } } + +#[test] +fn test_with_disallowed_name() { + let foo = 0; +} From de258cc6becde010381502ae0e80b4aca4064e3c Mon Sep 17 00:00:00 2001 From: Samuel Moelius Date: Sat, 20 Apr 2024 01:17:28 +0000 Subject: [PATCH 19/47] Fix `is_test_module_or_function` --- clippy_utils/src/lib.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index a13885b022f6..5ea9b375f5b9 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -2505,8 +2505,9 @@ fn with_test_item_names(tcx: TyCtxt<'_>, module: LocalModDefId, f: impl Fn(&[Sym /// Note: Add `//@compile-flags: --test` to UI tests with a `#[test]` function pub fn is_in_test_function(tcx: TyCtxt<'_>, id: HirId) -> bool { with_test_item_names(tcx, tcx.parent_module(id), |names| { - tcx.hir() - .parent_iter(id) + let node = tcx.hir_node(id); + once((id, node)) + .chain(tcx.hir().parent_iter(id)) // Since you can nest functions we need to collect all until we leave // function scope .any(|(_id, node)| { From d55e5b45007569c53bb86732d05ada08a1cd8ebd Mon Sep 17 00:00:00 2001 From: forcedebug Date: Tue, 23 Apr 2024 20:31:26 +0800 Subject: [PATCH 20/47] chore: fix some typos in comments Signed-off-by: forcedebug --- clippy_lints/src/implied_bounds_in_impls.rs | 2 +- clippy_lints/src/methods/unused_enumerate_index.rs | 2 +- clippy_lints/src/size_of_ref.rs | 2 +- tests/ui/mistyped_literal_suffix.fixed | 2 +- tests/ui/mistyped_literal_suffix.rs | 2 +- tests/ui/type_id_on_box_unfixable.rs | 2 +- util/gh-pages/script.js | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/implied_bounds_in_impls.rs b/clippy_lints/src/implied_bounds_in_impls.rs index 7b97fc15caaf..3bf8d6189558 100644 --- a/clippy_lints/src/implied_bounds_in_impls.rs +++ b/clippy_lints/src/implied_bounds_in_impls.rs @@ -24,7 +24,7 @@ declare_clippy_lint! { /// /// ### Limitations /// This lint does not check for implied bounds transitively. Meaning that - /// it does't check for implied bounds from supertraits of supertraits + /// it doesn't check for implied bounds from supertraits of supertraits /// (e.g. `trait A {} trait B: A {} trait C: B {}`, then having an `fn() -> impl A + C`) /// /// ### Example diff --git a/clippy_lints/src/methods/unused_enumerate_index.rs b/clippy_lints/src/methods/unused_enumerate_index.rs index e5cc898612e9..92f3ac5ff99b 100644 --- a/clippy_lints/src/methods/unused_enumerate_index.rs +++ b/clippy_lints/src/methods/unused_enumerate_index.rs @@ -78,7 +78,7 @@ pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>, && match_def_path(cx, enumerate_defid, &CORE_ITER_ENUMERATE_METHOD) { // Check if the tuple type was explicit. It may be the type system _needs_ the type of the element - // that would be explicited in the closure. + // that would be explicitly in the closure. let new_closure_param = match find_elem_explicit_type_span(closure.fn_decl) { // We have an explicit type. Get its snippet, that of the binding name, and do `binding: ty`. // Fallback to `..` if we fail getting either snippet. diff --git a/clippy_lints/src/size_of_ref.rs b/clippy_lints/src/size_of_ref.rs index 14ca7a3f0042..8d7f12af86e8 100644 --- a/clippy_lints/src/size_of_ref.rs +++ b/clippy_lints/src/size_of_ref.rs @@ -28,7 +28,7 @@ declare_clippy_lint! { /// fn size(&self) -> usize { /// // Note that `&self` as an argument is a `&&Foo`: Because `self` /// // is already a reference, `&self` is a double-reference. - /// // The return value of `size_of_val()` therefor is the + /// // The return value of `size_of_val()` therefore is the /// // size of the reference-type, not the size of `self`. /// std::mem::size_of_val(&self) /// } diff --git a/tests/ui/mistyped_literal_suffix.fixed b/tests/ui/mistyped_literal_suffix.fixed index 861764a2aeeb..b84b3dc349ec 100644 --- a/tests/ui/mistyped_literal_suffix.fixed +++ b/tests/ui/mistyped_literal_suffix.fixed @@ -32,7 +32,7 @@ fn main() { // testing that the suggestion actually fits in its type let fail30 = 127_i8; // should be i8 let fail31 = 240_u8; // should be u8 - let ok32 = 360_8; // doesnt fit in either, should be ignored + let ok32 = 360_8; // doesn't fit in either, should be ignored let fail33 = 0x1234_i16; let fail34 = 0xABCD_u16; let ok35 = 0x12345_16; diff --git a/tests/ui/mistyped_literal_suffix.rs b/tests/ui/mistyped_literal_suffix.rs index 4a15c335fd89..a47a736067a8 100644 --- a/tests/ui/mistyped_literal_suffix.rs +++ b/tests/ui/mistyped_literal_suffix.rs @@ -32,7 +32,7 @@ fn main() { // testing that the suggestion actually fits in its type let fail30 = 127_8; // should be i8 let fail31 = 240_8; // should be u8 - let ok32 = 360_8; // doesnt fit in either, should be ignored + let ok32 = 360_8; // doesn't fit in either, should be ignored let fail33 = 0x1234_16; let fail34 = 0xABCD_16; let ok35 = 0x12345_16; diff --git a/tests/ui/type_id_on_box_unfixable.rs b/tests/ui/type_id_on_box_unfixable.rs index f6d09834adb1..67e398e604b4 100644 --- a/tests/ui/type_id_on_box_unfixable.rs +++ b/tests/ui/type_id_on_box_unfixable.rs @@ -19,7 +19,7 @@ where impl NormalTrait for T {} fn main() { - // (currently we don't look deeper than one level into the supertrait hierachy, but we probably + // (currently we don't look deeper than one level into the supertrait hierarchy, but we probably // could) let b: Box = Box::new(1); let _ = b.type_id(); diff --git a/util/gh-pages/script.js b/util/gh-pages/script.js index f59245e556cd..c63edd5bf709 100644 --- a/util/gh-pages/script.js +++ b/util/gh-pages/script.js @@ -415,7 +415,7 @@ let terms = searchStr.split(" "); let docsLowerCase = lint.docs.toLowerCase(); for (index = 0; index < terms.length; index++) { - // This is more likely and will therefor be checked first + // This is more likely and will therefore be checked first if (docsLowerCase.indexOf(terms[index]) !== -1) { continue; } From 107e44b76ff76805bc9bea5dc2e4ba96354ab374 Mon Sep 17 00:00:00 2001 From: Luv-Ray Date: Wed, 24 Apr 2024 10:54:08 +0800 Subject: [PATCH 21/47] [`non_canonical_partial_ord_impl`]: Fix emitting warnings which conflict with `needless_return` --- clippy_lints/src/non_canonical_impls.rs | 46 ++++++++++++++----- tests/ui/non_canonical_partial_ord_impl.fixed | 18 ++++++++ tests/ui/non_canonical_partial_ord_impl.rs | 18 ++++++++ 3 files changed, 71 insertions(+), 11 deletions(-) diff --git a/clippy_lints/src/non_canonical_impls.rs b/clippy_lints/src/non_canonical_impls.rs index fd3985a5dafc..932d6fe54d66 100644 --- a/clippy_lints/src/non_canonical_impls.rs +++ b/clippy_lints/src/non_canonical_impls.rs @@ -182,17 +182,17 @@ impl LateLintPass<'_> for NonCanonicalImpls { if block.stmts.is_empty() && let Some(expr) = block.expr - && let ExprKind::Call( - Expr { - kind: ExprKind::Path(some_path), - hir_id: some_hir_id, - .. - }, - [cmp_expr], - ) = expr.kind - && is_res_lang_ctor(cx, cx.qpath_res(some_path, *some_hir_id), LangItem::OptionSome) - // Fix #11178, allow `Self::cmp(self, ..)` too - && self_cmp_call(cx, cmp_expr, impl_item.owner_id.def_id, &mut needs_fully_qualified) + && expr_is_cmp(cx, &expr.kind, impl_item, &mut needs_fully_qualified) + { + } + // Fix #12683, allow [`needless_return`] here + else if block.expr.is_none() + && let Some(stmt) = block.stmts.first() + && let rustc_hir::StmtKind::Semi(Expr { + kind: ExprKind::Ret(Some(Expr { kind: ret_kind, .. })), + .. + }) = stmt.kind + && expr_is_cmp(cx, ret_kind, impl_item, &mut needs_fully_qualified) { } else { // If `Self` and `Rhs` are not the same type, bail. This makes creating a valid @@ -245,6 +245,30 @@ impl LateLintPass<'_> for NonCanonicalImpls { } } +/// Return true if `expr_kind` is a `cmp` call. +fn expr_is_cmp<'tcx>( + cx: &LateContext<'tcx>, + expr_kind: &'tcx ExprKind<'tcx>, + impl_item: &ImplItem<'_>, + needs_fully_qualified: &mut bool, +) -> bool { + if let ExprKind::Call( + Expr { + kind: ExprKind::Path(some_path), + hir_id: some_hir_id, + .. + }, + [cmp_expr], + ) = expr_kind + { + is_res_lang_ctor(cx, cx.qpath_res(some_path, *some_hir_id), LangItem::OptionSome) + // Fix #11178, allow `Self::cmp(self, ..)` too + && self_cmp_call(cx, cmp_expr, impl_item.owner_id.def_id, needs_fully_qualified) + } else { + false + } +} + /// Returns whether this is any of `self.cmp(..)`, `Self::cmp(self, ..)` or `Ord::cmp(self, ..)`. fn self_cmp_call<'tcx>( cx: &LateContext<'tcx>, diff --git a/tests/ui/non_canonical_partial_ord_impl.fixed b/tests/ui/non_canonical_partial_ord_impl.fixed index db55cc094e3a..d444a753697f 100644 --- a/tests/ui/non_canonical_partial_ord_impl.fixed +++ b/tests/ui/non_canonical_partial_ord_impl.fixed @@ -142,3 +142,21 @@ impl PartialOrd for H { Some(Ord::cmp(self, other)) } } + +// #12683, do not lint + +#[derive(Eq, PartialEq)] +struct I(u32); + +impl Ord for I { + fn cmp(&self, other: &Self) -> Ordering { + todo!(); + } +} + +impl PartialOrd for I { + #[allow(clippy::needless_return)] + fn partial_cmp(&self, other: &Self) -> Option { + return Some(self.cmp(other)); + } +} diff --git a/tests/ui/non_canonical_partial_ord_impl.rs b/tests/ui/non_canonical_partial_ord_impl.rs index 52f4b85b9172..dc6c4354604d 100644 --- a/tests/ui/non_canonical_partial_ord_impl.rs +++ b/tests/ui/non_canonical_partial_ord_impl.rs @@ -146,3 +146,21 @@ impl PartialOrd for H { Some(Ord::cmp(self, other)) } } + +// #12683, do not lint + +#[derive(Eq, PartialEq)] +struct I(u32); + +impl Ord for I { + fn cmp(&self, other: &Self) -> Ordering { + todo!(); + } +} + +impl PartialOrd for I { + #[allow(clippy::needless_return)] + fn partial_cmp(&self, other: &Self) -> Option { + return Some(self.cmp(other)); + } +} From 3fc9537624b29ce8c635b4019c596f72e679cd49 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 11 Apr 2024 13:15:34 +0000 Subject: [PATCH 22/47] Error on using `yield` without also using `#[coroutine]` on the closure And suggest adding the `#[coroutine]` to the closure --- tests/ui/crashes/ice-5238.rs | 4 ++-- tests/ui/large_futures.fixed | 1 - tests/ui/large_futures.rs | 1 - tests/ui/large_futures.stderr | 16 ++++++++-------- tests/ui/redundant_locals.rs | 6 +++--- 5 files changed, 13 insertions(+), 15 deletions(-) diff --git a/tests/ui/crashes/ice-5238.rs b/tests/ui/crashes/ice-5238.rs index b1fc3fb9d251..fe03a39ad1ba 100644 --- a/tests/ui/crashes/ice-5238.rs +++ b/tests/ui/crashes/ice-5238.rs @@ -1,9 +1,9 @@ // Regression test for #5238 / https://github.com/rust-lang/rust/pull/69562 -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] fn main() { - let _ = || { + let _ = #[coroutine] || { yield; }; } diff --git a/tests/ui/large_futures.fixed b/tests/ui/large_futures.fixed index aa8c3021b970..1e87859f4526 100644 --- a/tests/ui/large_futures.fixed +++ b/tests/ui/large_futures.fixed @@ -1,4 +1,3 @@ -#![feature(coroutines)] #![warn(clippy::large_futures)] #![allow(clippy::never_loop)] #![allow(clippy::future_not_send)] diff --git a/tests/ui/large_futures.rs b/tests/ui/large_futures.rs index fc6ea458d3db..3f4ea2ebf8bb 100644 --- a/tests/ui/large_futures.rs +++ b/tests/ui/large_futures.rs @@ -1,4 +1,3 @@ -#![feature(coroutines)] #![warn(clippy::large_futures)] #![allow(clippy::never_loop)] #![allow(clippy::future_not_send)] diff --git a/tests/ui/large_futures.stderr b/tests/ui/large_futures.stderr index 5709c7b77a0a..00082e579c59 100644 --- a/tests/ui/large_futures.stderr +++ b/tests/ui/large_futures.stderr @@ -1,5 +1,5 @@ error: large future with a size of 16385 bytes - --> tests/ui/large_futures.rs:11:9 + --> tests/ui/large_futures.rs:10:9 | LL | big_fut([0u8; 1024 * 16]).await; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Box::pin` on it: `Box::pin(big_fut([0u8; 1024 * 16]))` @@ -8,37 +8,37 @@ LL | big_fut([0u8; 1024 * 16]).await; = help: to override `-D warnings` add `#[allow(clippy::large_futures)]` error: large future with a size of 16386 bytes - --> tests/ui/large_futures.rs:15:5 + --> tests/ui/large_futures.rs:14:5 | LL | f.await | ^ help: consider `Box::pin` on it: `Box::pin(f)` error: large future with a size of 16387 bytes - --> tests/ui/large_futures.rs:20:9 + --> tests/ui/large_futures.rs:19:9 | LL | wait().await; | ^^^^^^ help: consider `Box::pin` on it: `Box::pin(wait())` error: large future with a size of 16387 bytes - --> tests/ui/large_futures.rs:25:13 + --> tests/ui/large_futures.rs:24:13 | LL | wait().await; | ^^^^^^ help: consider `Box::pin` on it: `Box::pin(wait())` error: large future with a size of 65540 bytes - --> tests/ui/large_futures.rs:33:5 + --> tests/ui/large_futures.rs:32:5 | LL | foo().await; | ^^^^^ help: consider `Box::pin` on it: `Box::pin(foo())` error: large future with a size of 49159 bytes - --> tests/ui/large_futures.rs:35:5 + --> tests/ui/large_futures.rs:34:5 | LL | calls_fut(fut).await; | ^^^^^^^^^^^^^^ help: consider `Box::pin` on it: `Box::pin(calls_fut(fut))` error: large future with a size of 65540 bytes - --> tests/ui/large_futures.rs:48:5 + --> tests/ui/large_futures.rs:47:5 | LL | / async { LL | | @@ -59,7 +59,7 @@ LL + }) | error: large future with a size of 65540 bytes - --> tests/ui/large_futures.rs:60:13 + --> tests/ui/large_futures.rs:59:13 | LL | / async { LL | | let x = [0i32; 1024 * 16]; diff --git a/tests/ui/redundant_locals.rs b/tests/ui/redundant_locals.rs index f6909828aa9a..e9d77182a919 100644 --- a/tests/ui/redundant_locals.rs +++ b/tests/ui/redundant_locals.rs @@ -1,7 +1,7 @@ //@aux-build:proc_macros.rs #![allow(unused, clippy::no_effect, clippy::needless_pass_by_ref_mut)] #![warn(clippy::redundant_locals)] -#![feature(async_closure, coroutines)] +#![feature(async_closure, coroutines, stmt_expr_attributes)] extern crate proc_macros; use proc_macros::{external, with_span}; @@ -191,11 +191,11 @@ fn issue12225() { let v4 = v4; dbg!(&v4); }); - assert_static(static || { + assert_static(#[coroutine] static || { let v5 = v5; yield; }); - assert_static(|| { + assert_static(#[coroutine] || { let v6 = v6; yield; }); From 7d9f970d4eebd1b47a3c1e7bfb3045c6a3ee1283 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Fri, 19 Apr 2024 17:01:35 +0100 Subject: [PATCH 23/47] Fix and bless clippy tests --- tests/ui-toml/suppress_lint_in_const/test.rs | 1 - .../suppress_lint_in_const/test.stderr | 12 ++--- tests/ui/arithmetic_side_effects.rs | 2 +- tests/ui/bool_to_int_with_if.fixed | 2 +- tests/ui/bool_to_int_with_if.rs | 2 +- tests/ui/const_is_empty.rs | 1 - tests/ui/const_is_empty.stderr | 52 +++++++++---------- tests/ui/indexing_slicing_index.rs | 1 - tests/ui/indexing_slicing_index.stderr | 32 ++++++------ tests/ui/manual_float_methods.rs | 1 - tests/ui/manual_float_methods.stderr | 12 ++--- tests/ui/never_loop.rs | 2 +- tests/ui/panicking_macros.rs | 1 - tests/ui/panicking_macros.stderr | 32 ++++++------ 14 files changed, 74 insertions(+), 79 deletions(-) diff --git a/tests/ui-toml/suppress_lint_in_const/test.rs b/tests/ui-toml/suppress_lint_in_const/test.rs index 4ae75544c60c..232bccf6a154 100644 --- a/tests/ui-toml/suppress_lint_in_const/test.rs +++ b/tests/ui-toml/suppress_lint_in_const/test.rs @@ -1,4 +1,3 @@ -#![feature(inline_const)] #![warn(clippy::indexing_slicing)] // We also check the out_of_bounds_indexing lint here, because it lints similar things and // we want to avoid false positives. diff --git a/tests/ui-toml/suppress_lint_in_const/test.stderr b/tests/ui-toml/suppress_lint_in_const/test.stderr index 120f5c35cb03..5ce2ed2ffaee 100644 --- a/tests/ui-toml/suppress_lint_in_const/test.stderr +++ b/tests/ui-toml/suppress_lint_in_const/test.stderr @@ -1,5 +1,5 @@ error: indexing may panic - --> tests/ui-toml/suppress_lint_in_const/test.rs:27:5 + --> tests/ui-toml/suppress_lint_in_const/test.rs:26:5 | LL | x[index]; | ^^^^^^^^ @@ -9,7 +9,7 @@ LL | x[index]; = help: to override `-D warnings` add `#[allow(clippy::indexing_slicing)]` error: indexing may panic - --> tests/ui-toml/suppress_lint_in_const/test.rs:42:5 + --> tests/ui-toml/suppress_lint_in_const/test.rs:41:5 | LL | v[0]; | ^^^^ @@ -17,7 +17,7 @@ LL | v[0]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui-toml/suppress_lint_in_const/test.rs:43:5 + --> tests/ui-toml/suppress_lint_in_const/test.rs:42:5 | LL | v[10]; | ^^^^^ @@ -25,7 +25,7 @@ LL | v[10]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui-toml/suppress_lint_in_const/test.rs:44:5 + --> tests/ui-toml/suppress_lint_in_const/test.rs:43:5 | LL | v[1 << 3]; | ^^^^^^^^^ @@ -33,7 +33,7 @@ LL | v[1 << 3]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui-toml/suppress_lint_in_const/test.rs:50:5 + --> tests/ui-toml/suppress_lint_in_const/test.rs:49:5 | LL | v[N]; | ^^^^ @@ -41,7 +41,7 @@ LL | v[N]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui-toml/suppress_lint_in_const/test.rs:51:5 + --> tests/ui-toml/suppress_lint_in_const/test.rs:50:5 | LL | v[M]; | ^^^^ diff --git a/tests/ui/arithmetic_side_effects.rs b/tests/ui/arithmetic_side_effects.rs index b454c29aef4d..fdec14a1528f 100644 --- a/tests/ui/arithmetic_side_effects.rs +++ b/tests/ui/arithmetic_side_effects.rs @@ -10,7 +10,7 @@ arithmetic_overflow, unconditional_panic )] -#![feature(const_mut_refs, inline_const)] +#![feature(const_mut_refs)] #![warn(clippy::arithmetic_side_effects)] extern crate proc_macro_derive; diff --git a/tests/ui/bool_to_int_with_if.fixed b/tests/ui/bool_to_int_with_if.fixed index 167263d31df8..f7dad28b0369 100644 --- a/tests/ui/bool_to_int_with_if.fixed +++ b/tests/ui/bool_to_int_with_if.fixed @@ -1,4 +1,4 @@ -#![feature(let_chains, inline_const)] +#![feature(let_chains)] #![warn(clippy::bool_to_int_with_if)] #![allow(unused, dead_code, clippy::unnecessary_operation, clippy::no_effect)] diff --git a/tests/ui/bool_to_int_with_if.rs b/tests/ui/bool_to_int_with_if.rs index f3f055eb7f06..d22871d2c8f2 100644 --- a/tests/ui/bool_to_int_with_if.rs +++ b/tests/ui/bool_to_int_with_if.rs @@ -1,4 +1,4 @@ -#![feature(let_chains, inline_const)] +#![feature(let_chains)] #![warn(clippy::bool_to_int_with_if)] #![allow(unused, dead_code, clippy::unnecessary_operation, clippy::no_effect)] diff --git a/tests/ui/const_is_empty.rs b/tests/ui/const_is_empty.rs index ae37a82e4f93..04e0de91ecfb 100644 --- a/tests/ui/const_is_empty.rs +++ b/tests/ui/const_is_empty.rs @@ -1,4 +1,3 @@ -#![feature(inline_const)] #![warn(clippy::const_is_empty)] #![allow(clippy::needless_late_init, unused_must_use)] diff --git a/tests/ui/const_is_empty.stderr b/tests/ui/const_is_empty.stderr index 0e09da77bb46..7f80b520b1a4 100644 --- a/tests/ui/const_is_empty.stderr +++ b/tests/ui/const_is_empty.stderr @@ -1,5 +1,5 @@ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:6:8 + --> tests/ui/const_is_empty.rs:5:8 | LL | if "".is_empty() { | ^^^^^^^^^^^^^ @@ -8,151 +8,151 @@ LL | if "".is_empty() { = help: to override `-D warnings` add `#[allow(clippy::const_is_empty)]` error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:9:8 + --> tests/ui/const_is_empty.rs:8:8 | LL | if "foobar".is_empty() { | ^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:15:8 + --> tests/ui/const_is_empty.rs:14:8 | LL | if b"".is_empty() { | ^^^^^^^^^^^^^^ error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:18:8 + --> tests/ui/const_is_empty.rs:17:8 | LL | if b"foobar".is_empty() { | ^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:35:8 + --> tests/ui/const_is_empty.rs:34:8 | LL | if empty2.is_empty() { | ^^^^^^^^^^^^^^^^^ error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:38:8 + --> tests/ui/const_is_empty.rs:37:8 | LL | if non_empty2.is_empty() { | ^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:60:13 + --> tests/ui/const_is_empty.rs:59:13 | LL | let _ = EMPTY_STR.is_empty(); | ^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:62:13 + --> tests/ui/const_is_empty.rs:61:13 | LL | let _ = NON_EMPTY_STR.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:64:13 + --> tests/ui/const_is_empty.rs:63:13 | LL | let _ = EMPTY_BSTR.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:66:13 + --> tests/ui/const_is_empty.rs:65:13 | LL | let _ = NON_EMPTY_BSTR.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:68:13 + --> tests/ui/const_is_empty.rs:67:13 | LL | let _ = EMPTY_ARRAY.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:70:13 + --> tests/ui/const_is_empty.rs:69:13 | LL | let _ = EMPTY_ARRAY_REPEAT.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:72:13 + --> tests/ui/const_is_empty.rs:71:13 | LL | let _ = EMPTY_U8_SLICE.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:74:13 + --> tests/ui/const_is_empty.rs:73:13 | LL | let _ = NON_EMPTY_U8_SLICE.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:76:13 + --> tests/ui/const_is_empty.rs:75:13 | LL | let _ = NON_EMPTY_ARRAY.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:78:13 + --> tests/ui/const_is_empty.rs:77:13 | LL | let _ = NON_EMPTY_ARRAY_REPEAT.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:80:13 + --> tests/ui/const_is_empty.rs:79:13 | LL | let _ = EMPTY_REF_ARRAY.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:82:13 + --> tests/ui/const_is_empty.rs:81:13 | LL | let _ = NON_EMPTY_REF_ARRAY.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:84:13 + --> tests/ui/const_is_empty.rs:83:13 | LL | let _ = EMPTY_SLICE.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:86:13 + --> tests/ui/const_is_empty.rs:85:13 | LL | let _ = NON_EMPTY_SLICE.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:88:13 + --> tests/ui/const_is_empty.rs:87:13 | LL | let _ = NON_EMPTY_SLICE_REPEAT.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:94:13 + --> tests/ui/const_is_empty.rs:93:13 | LL | let _ = value.is_empty(); | ^^^^^^^^^^^^^^^^ error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:97:13 + --> tests/ui/const_is_empty.rs:96:13 | LL | let _ = x.is_empty(); | ^^^^^^^^^^^^ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:99:13 + --> tests/ui/const_is_empty.rs:98:13 | LL | let _ = "".is_empty(); | ^^^^^^^^^^^^^ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:101:13 + --> tests/ui/const_is_empty.rs:100:13 | LL | let _ = b"".is_empty(); | ^^^^^^^^^^^^^^ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:155:13 + --> tests/ui/const_is_empty.rs:154:13 | LL | let _ = val.is_empty(); | ^^^^^^^^^^^^^^ diff --git a/tests/ui/indexing_slicing_index.rs b/tests/ui/indexing_slicing_index.rs index 27ee2f91594b..2e726141649e 100644 --- a/tests/ui/indexing_slicing_index.rs +++ b/tests/ui/indexing_slicing_index.rs @@ -1,6 +1,5 @@ //@compile-flags: -Zdeduplicate-diagnostics=yes -#![feature(inline_const)] #![warn(clippy::indexing_slicing)] // We also check the out_of_bounds_indexing lint here, because it lints similar things and // we want to avoid false positives. diff --git a/tests/ui/indexing_slicing_index.stderr b/tests/ui/indexing_slicing_index.stderr index 5f62ec9b5565..386f91becf14 100644 --- a/tests/ui/indexing_slicing_index.stderr +++ b/tests/ui/indexing_slicing_index.stderr @@ -1,5 +1,5 @@ error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:16:20 + --> tests/ui/indexing_slicing_index.rs:15:20 | LL | const REF: &i32 = &ARR[idx()]; // This should be linted, since `suppress-restriction-lint-in-const` default is false. | ^^^^^^^^^^ @@ -10,19 +10,19 @@ LL | const REF: &i32 = &ARR[idx()]; // This should be linted, since `suppress-re = help: to override `-D warnings` add `#[allow(clippy::indexing_slicing)]` error[E0080]: evaluation of `main::{constant#3}` failed - --> tests/ui/indexing_slicing_index.rs:48:14 + --> tests/ui/indexing_slicing_index.rs:47:14 | LL | const { &ARR[idx4()] }; | ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4 note: erroneous constant encountered - --> tests/ui/indexing_slicing_index.rs:48:5 + --> tests/ui/indexing_slicing_index.rs:47:5 | LL | const { &ARR[idx4()] }; | ^^^^^^^^^^^^^^^^^^^^^^ error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:29:5 + --> tests/ui/indexing_slicing_index.rs:28:5 | LL | x[index]; | ^^^^^^^^ @@ -30,7 +30,7 @@ LL | x[index]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: index is out of bounds - --> tests/ui/indexing_slicing_index.rs:32:5 + --> tests/ui/indexing_slicing_index.rs:31:5 | LL | x[4]; | ^^^^ @@ -39,13 +39,13 @@ LL | x[4]; = help: to override `-D warnings` add `#[allow(clippy::out_of_bounds_indexing)]` error: index is out of bounds - --> tests/ui/indexing_slicing_index.rs:34:5 + --> tests/ui/indexing_slicing_index.rs:33:5 | LL | x[1 << 3]; | ^^^^^^^^^ error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:45:14 + --> tests/ui/indexing_slicing_index.rs:44:14 | LL | const { &ARR[idx()] }; | ^^^^^^^^^^ @@ -54,7 +54,7 @@ LL | const { &ARR[idx()] }; = note: the suggestion might not be applicable in constant blocks error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:48:14 + --> tests/ui/indexing_slicing_index.rs:47:14 | LL | const { &ARR[idx4()] }; | ^^^^^^^^^^^ @@ -63,13 +63,13 @@ LL | const { &ARR[idx4()] }; = note: the suggestion might not be applicable in constant blocks error: index is out of bounds - --> tests/ui/indexing_slicing_index.rs:55:5 + --> tests/ui/indexing_slicing_index.rs:54:5 | LL | y[4]; | ^^^^ error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:58:5 + --> tests/ui/indexing_slicing_index.rs:57:5 | LL | v[0]; | ^^^^ @@ -77,7 +77,7 @@ LL | v[0]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:60:5 + --> tests/ui/indexing_slicing_index.rs:59:5 | LL | v[10]; | ^^^^^ @@ -85,7 +85,7 @@ LL | v[10]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:62:5 + --> tests/ui/indexing_slicing_index.rs:61:5 | LL | v[1 << 3]; | ^^^^^^^^^ @@ -93,13 +93,13 @@ LL | v[1 << 3]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: index is out of bounds - --> tests/ui/indexing_slicing_index.rs:70:5 + --> tests/ui/indexing_slicing_index.rs:69:5 | LL | x[N]; | ^^^^ error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:73:5 + --> tests/ui/indexing_slicing_index.rs:72:5 | LL | v[N]; | ^^^^ @@ -107,7 +107,7 @@ LL | v[N]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:75:5 + --> tests/ui/indexing_slicing_index.rs:74:5 | LL | v[M]; | ^^^^ @@ -115,7 +115,7 @@ LL | v[M]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: index is out of bounds - --> tests/ui/indexing_slicing_index.rs:79:13 + --> tests/ui/indexing_slicing_index.rs:78:13 | LL | let _ = x[4]; | ^^^^ diff --git a/tests/ui/manual_float_methods.rs b/tests/ui/manual_float_methods.rs index f3e95d6807d3..80781ecda721 100644 --- a/tests/ui/manual_float_methods.rs +++ b/tests/ui/manual_float_methods.rs @@ -2,7 +2,6 @@ //@aux-build:proc_macros.rs #![allow(clippy::needless_if, unused)] #![warn(clippy::manual_is_infinite, clippy::manual_is_finite)] -#![feature(inline_const)] #[macro_use] extern crate proc_macros; diff --git a/tests/ui/manual_float_methods.stderr b/tests/ui/manual_float_methods.stderr index dae96839262d..930df0b97cb3 100644 --- a/tests/ui/manual_float_methods.stderr +++ b/tests/ui/manual_float_methods.stderr @@ -1,5 +1,5 @@ error: manually checking if a float is infinite - --> tests/ui/manual_float_methods.rs:23:8 + --> tests/ui/manual_float_methods.rs:22:8 | LL | if x == f32::INFINITY || x == f32::NEG_INFINITY {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the dedicated method instead: `x.is_infinite()` @@ -8,7 +8,7 @@ LL | if x == f32::INFINITY || x == f32::NEG_INFINITY {} = help: to override `-D warnings` add `#[allow(clippy::manual_is_infinite)]` error: manually checking if a float is finite - --> tests/ui/manual_float_methods.rs:24:8 + --> tests/ui/manual_float_methods.rs:23:8 | LL | if x != f32::INFINITY && x != f32::NEG_INFINITY {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -29,13 +29,13 @@ LL | if !x.is_infinite() {} | ~~~~~~~~~~~~~~~~ error: manually checking if a float is infinite - --> tests/ui/manual_float_methods.rs:25:8 + --> tests/ui/manual_float_methods.rs:24:8 | LL | if x == INFINITE || x == NEG_INFINITE {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the dedicated method instead: `x.is_infinite()` error: manually checking if a float is finite - --> tests/ui/manual_float_methods.rs:26:8 + --> tests/ui/manual_float_methods.rs:25:8 | LL | if x != INFINITE && x != NEG_INFINITE {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -54,13 +54,13 @@ LL | if !x.is_infinite() {} | ~~~~~~~~~~~~~~~~ error: manually checking if a float is infinite - --> tests/ui/manual_float_methods.rs:28:8 + --> tests/ui/manual_float_methods.rs:27:8 | LL | if x == f64::INFINITY || x == f64::NEG_INFINITY {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the dedicated method instead: `x.is_infinite()` error: manually checking if a float is finite - --> tests/ui/manual_float_methods.rs:29:8 + --> tests/ui/manual_float_methods.rs:28:8 | LL | if x != f64::INFINITY && x != f64::NEG_INFINITY {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/never_loop.rs b/tests/ui/never_loop.rs index 92f173d9db4a..93c69209c698 100644 --- a/tests/ui/never_loop.rs +++ b/tests/ui/never_loop.rs @@ -1,4 +1,4 @@ -#![feature(inline_const, try_blocks)] +#![feature(try_blocks)] #![allow( clippy::eq_op, clippy::single_match, diff --git a/tests/ui/panicking_macros.rs b/tests/ui/panicking_macros.rs index dccfbd409e50..2bbf5792ec4c 100644 --- a/tests/ui/panicking_macros.rs +++ b/tests/ui/panicking_macros.rs @@ -1,5 +1,4 @@ #![allow(clippy::assertions_on_constants, clippy::eq_op, clippy::let_unit_value)] -#![feature(inline_const)] #![warn(clippy::unimplemented, clippy::unreachable, clippy::todo, clippy::panic)] extern crate core; diff --git a/tests/ui/panicking_macros.stderr b/tests/ui/panicking_macros.stderr index 06025859c0c6..7c0f0a7d3764 100644 --- a/tests/ui/panicking_macros.stderr +++ b/tests/ui/panicking_macros.stderr @@ -1,5 +1,5 @@ error: `panic` should not be present in production code - --> tests/ui/panicking_macros.rs:23:5 + --> tests/ui/panicking_macros.rs:22:5 | LL | panic!(); | ^^^^^^^^ @@ -8,19 +8,19 @@ LL | panic!(); = help: to override `-D warnings` add `#[allow(clippy::panic)]` error: `panic` should not be present in production code - --> tests/ui/panicking_macros.rs:26:5 + --> tests/ui/panicking_macros.rs:25:5 | LL | panic!("message"); | ^^^^^^^^^^^^^^^^^ error: `panic` should not be present in production code - --> tests/ui/panicking_macros.rs:28:5 + --> tests/ui/panicking_macros.rs:27:5 | LL | panic!("{} {}", "panic with", "multiple arguments"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `todo` should not be present in production code - --> tests/ui/panicking_macros.rs:35:5 + --> tests/ui/panicking_macros.rs:34:5 | LL | todo!(); | ^^^^^^^ @@ -29,19 +29,19 @@ LL | todo!(); = help: to override `-D warnings` add `#[allow(clippy::todo)]` error: `todo` should not be present in production code - --> tests/ui/panicking_macros.rs:38:5 + --> tests/ui/panicking_macros.rs:37:5 | LL | todo!("message"); | ^^^^^^^^^^^^^^^^ error: `todo` should not be present in production code - --> tests/ui/panicking_macros.rs:40:5 + --> tests/ui/panicking_macros.rs:39:5 | LL | todo!("{} {}", "panic with", "multiple arguments"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `unimplemented` should not be present in production code - --> tests/ui/panicking_macros.rs:47:5 + --> tests/ui/panicking_macros.rs:46:5 | LL | unimplemented!(); | ^^^^^^^^^^^^^^^^ @@ -50,19 +50,19 @@ LL | unimplemented!(); = help: to override `-D warnings` add `#[allow(clippy::unimplemented)]` error: `unimplemented` should not be present in production code - --> tests/ui/panicking_macros.rs:50:5 + --> tests/ui/panicking_macros.rs:49:5 | LL | unimplemented!("message"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: `unimplemented` should not be present in production code - --> tests/ui/panicking_macros.rs:52:5 + --> tests/ui/panicking_macros.rs:51:5 | LL | unimplemented!("{} {}", "panic with", "multiple arguments"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: usage of the `unreachable!` macro - --> tests/ui/panicking_macros.rs:59:5 + --> tests/ui/panicking_macros.rs:58:5 | LL | unreachable!(); | ^^^^^^^^^^^^^^ @@ -71,37 +71,37 @@ LL | unreachable!(); = help: to override `-D warnings` add `#[allow(clippy::unreachable)]` error: usage of the `unreachable!` macro - --> tests/ui/panicking_macros.rs:62:5 + --> tests/ui/panicking_macros.rs:61:5 | LL | unreachable!("message"); | ^^^^^^^^^^^^^^^^^^^^^^^ error: usage of the `unreachable!` macro - --> tests/ui/panicking_macros.rs:64:5 + --> tests/ui/panicking_macros.rs:63:5 | LL | unreachable!("{} {}", "panic with", "multiple arguments"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `panic` should not be present in production code - --> tests/ui/panicking_macros.rs:71:5 + --> tests/ui/panicking_macros.rs:70:5 | LL | panic!(); | ^^^^^^^^ error: `todo` should not be present in production code - --> tests/ui/panicking_macros.rs:73:5 + --> tests/ui/panicking_macros.rs:72:5 | LL | todo!(); | ^^^^^^^ error: `unimplemented` should not be present in production code - --> tests/ui/panicking_macros.rs:75:5 + --> tests/ui/panicking_macros.rs:74:5 | LL | unimplemented!(); | ^^^^^^^^^^^^^^^^ error: usage of the `unreachable!` macro - --> tests/ui/panicking_macros.rs:77:5 + --> tests/ui/panicking_macros.rs:76:5 | LL | unreachable!(); | ^^^^^^^^^^^^^^ From 69a4a46631c084a2fa863f71447d0547339a4c0d Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Wed, 24 Apr 2024 19:02:43 +0000 Subject: [PATCH 24/47] Rename `msrvs::ASSIGNING_CLONES` to `msrvs::CLONE_INTO` --- clippy_config/src/msrvs.rs | 2 +- clippy_lints/src/assigning_clones.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_config/src/msrvs.rs b/clippy_config/src/msrvs.rs index 59dd5b334b84..14808440d48d 100644 --- a/clippy_config/src/msrvs.rs +++ b/clippy_config/src/msrvs.rs @@ -23,7 +23,7 @@ msrv_aliases! { 1,70,0 { OPTION_RESULT_IS_VARIANT_AND, BINARY_HEAP_RETAIN } 1,68,0 { PATH_MAIN_SEPARATOR_STR } 1,65,0 { LET_ELSE, POINTER_CAST_CONSTNESS } - 1,63,0 { ASSIGNING_CLONES } + 1,63,0 { CLONE_INTO } 1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE } 1,59,0 { THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST } 1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY } diff --git a/clippy_lints/src/assigning_clones.rs b/clippy_lints/src/assigning_clones.rs index dc7f44af2b74..d88ca84fb97d 100644 --- a/clippy_lints/src/assigning_clones.rs +++ b/clippy_lints/src/assigning_clones.rs @@ -153,7 +153,7 @@ fn extract_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option< fn is_ok_to_suggest<'tcx>(cx: &LateContext<'tcx>, lhs: &Expr<'tcx>, call: &CallCandidate<'tcx>, msrv: &Msrv) -> bool { // For calls to .to_owned we suggest using .clone_into(), which was only stablilized in 1.63. // If the current MSRV is below that, don't suggest the lint. - if !msrv.meets(msrvs::ASSIGNING_CLONES) && matches!(call.target, TargetTrait::ToOwned) { + if !msrv.meets(msrvs::CLONE_INTO) && matches!(call.target, TargetTrait::ToOwned) { return false; } From ec9ddc7b7af7f5b277cf06960bee9a20c3de8689 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 24 Apr 2024 20:31:51 +0300 Subject: [PATCH 25/47] ast: Generalize item kind visiting And avoid duplicating logic for visiting `Item`s with different kinds (regular, associated, foreign). --- tests/ui/tabs_in_doc_comments.stderr | 54 ++++++++++++++-------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/tests/ui/tabs_in_doc_comments.stderr b/tests/ui/tabs_in_doc_comments.stderr index 23d5dcd3a8da..aef6c3914526 100644 --- a/tests/ui/tabs_in_doc_comments.stderr +++ b/tests/ui/tabs_in_doc_comments.stderr @@ -1,35 +1,11 @@ -error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:10:9 - | -LL | /// - First String: - | ^^^^ help: consider using four spaces per tab - | - = note: `-D clippy::tabs-in-doc-comments` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::tabs_in_doc_comments)]` - -error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:11:9 - | -LL | /// - needs to be inside here - | ^^^^^^^^ help: consider using four spaces per tab - -error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:14:9 - | -LL | /// - Second String: - | ^^^^ help: consider using four spaces per tab - -error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:15:9 - | -LL | /// - needs to be inside here - | ^^^^^^^^ help: consider using four spaces per tab - error: using tabs in doc comments is not recommended --> tests/ui/tabs_in_doc_comments.rs:6:5 | LL | /// - first one | ^^^^ help: consider using four spaces per tab + | + = note: `-D clippy::tabs-in-doc-comments` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::tabs_in_doc_comments)]` error: using tabs in doc comments is not recommended --> tests/ui/tabs_in_doc_comments.rs:6:13 @@ -49,5 +25,29 @@ error: using tabs in doc comments is not recommended LL | /// - second one | ^^^^ help: consider using four spaces per tab +error: using tabs in doc comments is not recommended + --> tests/ui/tabs_in_doc_comments.rs:10:9 + | +LL | /// - First String: + | ^^^^ help: consider using four spaces per tab + +error: using tabs in doc comments is not recommended + --> tests/ui/tabs_in_doc_comments.rs:11:9 + | +LL | /// - needs to be inside here + | ^^^^^^^^ help: consider using four spaces per tab + +error: using tabs in doc comments is not recommended + --> tests/ui/tabs_in_doc_comments.rs:14:9 + | +LL | /// - Second String: + | ^^^^ help: consider using four spaces per tab + +error: using tabs in doc comments is not recommended + --> tests/ui/tabs_in_doc_comments.rs:15:9 + | +LL | /// - needs to be inside here + | ^^^^^^^^ help: consider using four spaces per tab + error: aborting due to 8 previous errors From a8e0bcb3365670a376ca6606b48c26e3d3a3a65d Mon Sep 17 00:00:00 2001 From: klensy Date: Fri, 26 Apr 2024 13:47:14 +0300 Subject: [PATCH 26/47] clippy: bless tests --- tests/ui/from_over_into.stderr | 2 +- tests/ui/let_and_return.stderr | 2 +- tests/ui/manual_strip.stderr | 4 ++-- tests/ui/result_map_unit_fn_unfixable.stderr | 2 +- tests/ui/suspicious_doc_comments.stderr | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/ui/from_over_into.stderr b/tests/ui/from_over_into.stderr index 0649a6cb0f3e..f913ae0bb506 100644 --- a/tests/ui/from_over_into.stderr +++ b/tests/ui/from_over_into.stderr @@ -54,7 +54,7 @@ help: replace the `Into` implementation with `From` LL ~ impl core::convert::From for bool { LL ~ fn from(mut val: crate::ExplicitPaths) -> Self { LL ~ let in_closure = || val.0; -LL | +LL | LL ~ val.0 = false; LL ~ val.0 | diff --git a/tests/ui/let_and_return.stderr b/tests/ui/let_and_return.stderr index f614a5739a86..ff5962ec196e 100644 --- a/tests/ui/let_and_return.stderr +++ b/tests/ui/let_and_return.stderr @@ -71,7 +71,7 @@ LL | result help: return the expression directly | LL ~ -LL | +LL | LL ~ (match self { LL + E::A(x) => x, LL + E::B(x) => x, diff --git a/tests/ui/manual_strip.stderr b/tests/ui/manual_strip.stderr index d2d4f765310b..a70c988a0549 100644 --- a/tests/ui/manual_strip.stderr +++ b/tests/ui/manual_strip.stderr @@ -17,7 +17,7 @@ LL ~ if let Some() = s.strip_prefix("ab") { LL ~ str::to_string(); LL | LL ~ .to_string(); -LL | +LL | LL ~ str::to_string(); LL ~ .to_string(); | @@ -39,7 +39,7 @@ LL ~ if let Some() = s.strip_suffix("bc") { LL ~ str::to_string(); LL | LL ~ .to_string(); -LL | +LL | LL ~ str::to_string(); LL ~ .to_string(); | diff --git a/tests/ui/result_map_unit_fn_unfixable.stderr b/tests/ui/result_map_unit_fn_unfixable.stderr index fa2ac7a1b37e..d69c86c70e29 100644 --- a/tests/ui/result_map_unit_fn_unfixable.stderr +++ b/tests/ui/result_map_unit_fn_unfixable.stderr @@ -27,7 +27,7 @@ LL | || do_nothing(value) LL | || }); | ||______^- help: try: `if let Ok(value) = x.field { ... }` | |______| - | + | error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> tests/ui/result_map_unit_fn_unfixable.rs:37:5 diff --git a/tests/ui/suspicious_doc_comments.stderr b/tests/ui/suspicious_doc_comments.stderr index b54309b44d5d..f12053b1595a 100644 --- a/tests/ui/suspicious_doc_comments.stderr +++ b/tests/ui/suspicious_doc_comments.stderr @@ -85,7 +85,7 @@ LL | | ///! b help: use an inner doc comment to document the parent module or crate | LL ~ //! a -LL | +LL | LL ~ //! b | From b700d9c9284a3a2423fb4cd26c31f86b6ca2f41d Mon Sep 17 00:00:00 2001 From: Kornel Date: Sun, 28 Apr 2024 00:15:56 +0100 Subject: [PATCH 27/47] clippy::single_match(_else) may be machine applicable --- clippy_lints/src/matches/single_match.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/matches/single_match.rs b/clippy_lints/src/matches/single_match.rs index a0db8e2db1f8..98dbe3c4f004 100644 --- a/clippy_lints/src/matches/single_match.rs +++ b/clippy_lints/src/matches/single_match.rs @@ -75,7 +75,7 @@ fn report_single_pattern( ) { let lint = if els.is_some() { SINGLE_MATCH_ELSE } else { SINGLE_MATCH }; let ctxt = expr.span.ctxt(); - let mut app = Applicability::HasPlaceholders; + let mut app = Applicability::MachineApplicable; let els_str = els.map_or(String::new(), |els| { format!(" else {}", expr_block(cx, els, ctxt, "..", Some(expr.span), &mut app)) }); From ef1b0210bd6210c3a5f68420ca69307c941ee2c1 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Sun, 28 Apr 2024 15:13:41 +0200 Subject: [PATCH 28/47] remove myself from vacation --- triagebot.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index 901977da25be..4d66b728b76d 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -20,7 +20,6 @@ new_pr = true [assign] contributing_url = "https://github.com/rust-lang/rust-clippy/blob/master/CONTRIBUTING.md" users_on_vacation = [ - "y21", "matthiaskrgr", "giraffate", "Centri3", From 0b1f09e6f7c8228b566f035d95b4f2b742e3d0cb Mon Sep 17 00:00:00 2001 From: Mats Macke <61540264+MATSMACKE@users.noreply.github.com> Date: Sat, 27 Apr 2024 19:54:24 +0200 Subject: [PATCH 29/47] Fixed reduction of & in cast_possible_truncation Fixed formatting Added tests for issue #12721 Checking for reduction on RHS --- .../src/casts/cast_possible_truncation.rs | 7 +- tests/ui/cast.rs | 21 +- tests/ui/cast.stderr | 206 ++++++++++-------- 3 files changed, 141 insertions(+), 93 deletions(-) diff --git a/clippy_lints/src/casts/cast_possible_truncation.rs b/clippy_lints/src/casts/cast_possible_truncation.rs index dbfa8e1ee91b..7c5acd1a678d 100644 --- a/clippy_lints/src/casts/cast_possible_truncation.rs +++ b/clippy_lints/src/casts/cast_possible_truncation.rs @@ -40,9 +40,14 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b get_constant_bits(cx, right).map_or(0, |b| b.saturating_sub(1)) }) }, - BinOpKind::Rem | BinOpKind::BitAnd => get_constant_bits(cx, right) + BinOpKind::Rem => get_constant_bits(cx, right) .unwrap_or(u64::MAX) .min(apply_reductions(cx, nbits, left, signed)), + BinOpKind::BitAnd => get_constant_bits(cx, right) + .unwrap_or(u64::MAX) + .min(get_constant_bits(cx, left).unwrap_or(u64::MAX)) + .min(apply_reductions(cx, nbits, right, signed)) + .min(apply_reductions(cx, nbits, left, signed)), BinOpKind::Shr => apply_reductions(cx, nbits, left, signed) .saturating_sub(constant_int(cx, right).map_or(0, |s| u64::try_from(s).unwrap_or_default())), _ => nbits, diff --git a/tests/ui/cast.rs b/tests/ui/cast.rs index 215c008902d2..453d62ce6075 100644 --- a/tests/ui/cast.rs +++ b/tests/ui/cast.rs @@ -13,7 +13,8 @@ clippy::cast_abs_to_unsigned, clippy::no_effect, clippy::unnecessary_operation, - clippy::unnecessary_literal_unwrap + clippy::unnecessary_literal_unwrap, + clippy::identity_op )] fn main() { @@ -479,3 +480,21 @@ fn issue12506() -> usize { let bar: Result, u32> = Ok(Some(10)); bar.unwrap().unwrap() as usize } + +fn issue12721() { + fn x() -> u64 { + u64::MAX + } + + // Don't lint. + (255 & 999999u64) as u8; + // Don't lint. + let _ = ((x() & 255) & 999999) as u8; + // Don't lint. + let _ = (999999 & (x() & 255)) as u8; + + (256 & 999999u64) as u8; + //~^ ERROR: casting `u64` to `u8` may truncate the value + (255 % 999999u64) as u8; + //~^ ERROR: casting `u64` to `u8` may truncate the value +} diff --git a/tests/ui/cast.stderr b/tests/ui/cast.stderr index 8b269c471765..43c0d8f4ed73 100644 --- a/tests/ui/cast.stderr +++ b/tests/ui/cast.stderr @@ -1,5 +1,5 @@ error: casting `i32` to `f32` causes a loss of precision (`i32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast.rs:22:5 + --> tests/ui/cast.rs:23:5 | LL | x0 as f32; | ^^^^^^^^^ @@ -8,37 +8,37 @@ LL | x0 as f32; = help: to override `-D warnings` add `#[allow(clippy::cast_precision_loss)]` error: casting `i64` to `f32` causes a loss of precision (`i64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast.rs:26:5 + --> tests/ui/cast.rs:27:5 | LL | x1 as f32; | ^^^^^^^^^ error: casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) - --> tests/ui/cast.rs:28:5 + --> tests/ui/cast.rs:29:5 | LL | x1 as f64; | ^^^^^^^^^ error: casting `u32` to `f32` causes a loss of precision (`u32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast.rs:31:5 + --> tests/ui/cast.rs:32:5 | LL | x2 as f32; | ^^^^^^^^^ error: casting `u64` to `f32` causes a loss of precision (`u64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast.rs:34:5 + --> tests/ui/cast.rs:35:5 | LL | x3 as f32; | ^^^^^^^^^ error: casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) - --> tests/ui/cast.rs:36:5 + --> tests/ui/cast.rs:37:5 | LL | x3 as f64; | ^^^^^^^^^ error: casting `f32` to `i32` may truncate the value - --> tests/ui/cast.rs:39:5 + --> tests/ui/cast.rs:40:5 | LL | 1f32 as i32; | ^^^^^^^^^^^ @@ -48,7 +48,7 @@ LL | 1f32 as i32; = help: to override `-D warnings` add `#[allow(clippy::cast_possible_truncation)]` error: casting `f32` to `u32` may truncate the value - --> tests/ui/cast.rs:41:5 + --> tests/ui/cast.rs:42:5 | LL | 1f32 as u32; | ^^^^^^^^^^^ @@ -56,7 +56,7 @@ LL | 1f32 as u32; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:41:5 + --> tests/ui/cast.rs:42:5 | LL | 1f32 as u32; | ^^^^^^^^^^^ @@ -65,7 +65,7 @@ LL | 1f32 as u32; = help: to override `-D warnings` add `#[allow(clippy::cast_sign_loss)]` error: casting `f64` to `f32` may truncate the value - --> tests/ui/cast.rs:45:5 + --> tests/ui/cast.rs:46:5 | LL | 1f64 as f32; | ^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL | 1f64 as f32; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `i32` to `i8` may truncate the value - --> tests/ui/cast.rs:47:5 + --> tests/ui/cast.rs:48:5 | LL | 1i32 as i8; | ^^^^^^^^^^ @@ -85,7 +85,7 @@ LL | i8::try_from(1i32); | ~~~~~~~~~~~~~~~~~~ error: casting `i32` to `u8` may truncate the value - --> tests/ui/cast.rs:49:5 + --> tests/ui/cast.rs:50:5 | LL | 1i32 as u8; | ^^^^^^^^^^ @@ -97,7 +97,7 @@ LL | u8::try_from(1i32); | ~~~~~~~~~~~~~~~~~~ error: casting `f64` to `isize` may truncate the value - --> tests/ui/cast.rs:51:5 + --> tests/ui/cast.rs:52:5 | LL | 1f64 as isize; | ^^^^^^^^^^^^^ @@ -105,7 +105,7 @@ LL | 1f64 as isize; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f64` to `usize` may truncate the value - --> tests/ui/cast.rs:53:5 + --> tests/ui/cast.rs:54:5 | LL | 1f64 as usize; | ^^^^^^^^^^^^^ @@ -113,13 +113,13 @@ LL | 1f64 as usize; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f64` to `usize` may lose the sign of the value - --> tests/ui/cast.rs:53:5 + --> tests/ui/cast.rs:54:5 | LL | 1f64 as usize; | ^^^^^^^^^^^^^ error: casting `u32` to `u16` may truncate the value - --> tests/ui/cast.rs:56:5 + --> tests/ui/cast.rs:57:5 | LL | 1f32 as u32 as u16; | ^^^^^^^^^^^^^^^^^^ @@ -131,7 +131,7 @@ LL | u16::try_from(1f32 as u32); | ~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `f32` to `u32` may truncate the value - --> tests/ui/cast.rs:56:5 + --> tests/ui/cast.rs:57:5 | LL | 1f32 as u32 as u16; | ^^^^^^^^^^^ @@ -139,13 +139,13 @@ LL | 1f32 as u32 as u16; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:56:5 + --> tests/ui/cast.rs:57:5 | LL | 1f32 as u32 as u16; | ^^^^^^^^^^^ error: casting `i32` to `i8` may truncate the value - --> tests/ui/cast.rs:61:22 + --> tests/ui/cast.rs:62:22 | LL | let _x: i8 = 1i32 as _; | ^^^^^^^^^ @@ -157,7 +157,7 @@ LL | let _x: i8 = 1i32.try_into(); | ~~~~~~~~~~~~~~~ error: casting `f32` to `i32` may truncate the value - --> tests/ui/cast.rs:63:9 + --> tests/ui/cast.rs:64:9 | LL | 1f32 as i32; | ^^^^^^^^^^^ @@ -165,7 +165,7 @@ LL | 1f32 as i32; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f64` to `i32` may truncate the value - --> tests/ui/cast.rs:65:9 + --> tests/ui/cast.rs:66:9 | LL | 1f64 as i32; | ^^^^^^^^^^^ @@ -173,7 +173,7 @@ LL | 1f64 as i32; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f32` to `u8` may truncate the value - --> tests/ui/cast.rs:67:9 + --> tests/ui/cast.rs:68:9 | LL | 1f32 as u8; | ^^^^^^^^^^ @@ -181,13 +181,13 @@ LL | 1f32 as u8; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f32` to `u8` may lose the sign of the value - --> tests/ui/cast.rs:67:9 + --> tests/ui/cast.rs:68:9 | LL | 1f32 as u8; | ^^^^^^^^^^ error: casting `u8` to `i8` may wrap around the value - --> tests/ui/cast.rs:72:5 + --> tests/ui/cast.rs:73:5 | LL | 1u8 as i8; | ^^^^^^^^^ @@ -196,31 +196,31 @@ LL | 1u8 as i8; = help: to override `-D warnings` add `#[allow(clippy::cast_possible_wrap)]` error: casting `u16` to `i16` may wrap around the value - --> tests/ui/cast.rs:75:5 + --> tests/ui/cast.rs:76:5 | LL | 1u16 as i16; | ^^^^^^^^^^^ error: casting `u32` to `i32` may wrap around the value - --> tests/ui/cast.rs:77:5 + --> tests/ui/cast.rs:78:5 | LL | 1u32 as i32; | ^^^^^^^^^^^ error: casting `u64` to `i64` may wrap around the value - --> tests/ui/cast.rs:79:5 + --> tests/ui/cast.rs:80:5 | LL | 1u64 as i64; | ^^^^^^^^^^^ error: casting `usize` to `isize` may wrap around the value - --> tests/ui/cast.rs:81:5 + --> tests/ui/cast.rs:82:5 | LL | 1usize as isize; | ^^^^^^^^^^^^^^^ error: casting `usize` to `i8` may truncate the value - --> tests/ui/cast.rs:84:5 + --> tests/ui/cast.rs:85:5 | LL | 1usize as i8; | ^^^^^^^^^^^^ @@ -232,7 +232,7 @@ LL | i8::try_from(1usize); | ~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `i16` may truncate the value - --> tests/ui/cast.rs:87:5 + --> tests/ui/cast.rs:88:5 | LL | 1usize as i16; | ^^^^^^^^^^^^^ @@ -244,7 +244,7 @@ LL | i16::try_from(1usize); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `i16` may wrap around the value on targets with 16-bit wide pointers - --> tests/ui/cast.rs:87:5 + --> tests/ui/cast.rs:88:5 | LL | 1usize as i16; | ^^^^^^^^^^^^^ @@ -253,7 +253,7 @@ LL | 1usize as i16; = note: for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types error: casting `usize` to `i32` may truncate the value on targets with 64-bit wide pointers - --> tests/ui/cast.rs:92:5 + --> tests/ui/cast.rs:93:5 | LL | 1usize as i32; | ^^^^^^^^^^^^^ @@ -265,19 +265,19 @@ LL | i32::try_from(1usize); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `i32` may wrap around the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:92:5 + --> tests/ui/cast.rs:93:5 | LL | 1usize as i32; | ^^^^^^^^^^^^^ error: casting `usize` to `i64` may wrap around the value on targets with 64-bit wide pointers - --> tests/ui/cast.rs:96:5 + --> tests/ui/cast.rs:97:5 | LL | 1usize as i64; | ^^^^^^^^^^^^^ error: casting `u16` to `isize` may wrap around the value on targets with 16-bit wide pointers - --> tests/ui/cast.rs:101:5 + --> tests/ui/cast.rs:102:5 | LL | 1u16 as isize; | ^^^^^^^^^^^^^ @@ -286,13 +286,13 @@ LL | 1u16 as isize; = note: for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types error: casting `u32` to `isize` may wrap around the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:105:5 + --> tests/ui/cast.rs:106:5 | LL | 1u32 as isize; | ^^^^^^^^^^^^^ error: casting `u64` to `isize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:108:5 + --> tests/ui/cast.rs:109:5 | LL | 1u64 as isize; | ^^^^^^^^^^^^^ @@ -304,55 +304,55 @@ LL | isize::try_from(1u64); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `u64` to `isize` may wrap around the value on targets with 64-bit wide pointers - --> tests/ui/cast.rs:108:5 + --> tests/ui/cast.rs:109:5 | LL | 1u64 as isize; | ^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:113:5 + --> tests/ui/cast.rs:114:5 | LL | -1i32 as u32; | ^^^^^^^^^^^^ error: casting `isize` to `usize` may lose the sign of the value - --> tests/ui/cast.rs:116:5 + --> tests/ui/cast.rs:117:5 | LL | -1isize as usize; | ^^^^^^^^^^^^^^^^ error: casting `i8` to `u8` may lose the sign of the value - --> tests/ui/cast.rs:127:5 + --> tests/ui/cast.rs:128:5 | LL | (i8::MIN).abs() as u8; | ^^^^^^^^^^^^^^^^^^^^^ error: casting `i64` to `u64` may lose the sign of the value - --> tests/ui/cast.rs:131:5 + --> tests/ui/cast.rs:132:5 | LL | (-1i64).abs() as u64; | ^^^^^^^^^^^^^^^^^^^^ error: casting `isize` to `usize` may lose the sign of the value - --> tests/ui/cast.rs:132:5 + --> tests/ui/cast.rs:133:5 | LL | (-1isize).abs() as usize; | ^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i64` to `u64` may lose the sign of the value - --> tests/ui/cast.rs:139:5 + --> tests/ui/cast.rs:140:5 | LL | (unsafe { (-1i64).checked_abs().unwrap_unchecked() }) as u64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i64` to `u64` may lose the sign of the value - --> tests/ui/cast.rs:154:5 + --> tests/ui/cast.rs:155:5 | LL | (unsafe { (-1i64).checked_isqrt().unwrap_unchecked() }) as u64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i64` to `i8` may truncate the value - --> tests/ui/cast.rs:205:5 + --> tests/ui/cast.rs:206:5 | LL | (-99999999999i64).min(1) as i8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -364,7 +364,7 @@ LL | i8::try_from((-99999999999i64).min(1)); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `u64` to `u8` may truncate the value - --> tests/ui/cast.rs:219:5 + --> tests/ui/cast.rs:220:5 | LL | 999999u64.clamp(0, 256) as u8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -376,7 +376,7 @@ LL | u8::try_from(999999u64.clamp(0, 256)); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `main::E2` to `u8` may truncate the value - --> tests/ui/cast.rs:242:21 + --> tests/ui/cast.rs:243:21 | LL | let _ = self as u8; | ^^^^^^^^^^ @@ -388,7 +388,7 @@ LL | let _ = u8::try_from(self); | ~~~~~~~~~~~~~~~~~~ error: casting `main::E2::B` to `u8` will truncate the value - --> tests/ui/cast.rs:244:21 + --> tests/ui/cast.rs:245:21 | LL | let _ = Self::B as u8; | ^^^^^^^^^^^^^ @@ -397,7 +397,7 @@ LL | let _ = Self::B as u8; = help: to override `-D warnings` add `#[allow(clippy::cast_enum_truncation)]` error: casting `main::E5` to `i8` may truncate the value - --> tests/ui/cast.rs:286:21 + --> tests/ui/cast.rs:287:21 | LL | let _ = self as i8; | ^^^^^^^^^^ @@ -409,13 +409,13 @@ LL | let _ = i8::try_from(self); | ~~~~~~~~~~~~~~~~~~ error: casting `main::E5::A` to `i8` will truncate the value - --> tests/ui/cast.rs:288:21 + --> tests/ui/cast.rs:289:21 | LL | let _ = Self::A as i8; | ^^^^^^^^^^^^^ error: casting `main::E6` to `i16` may truncate the value - --> tests/ui/cast.rs:305:21 + --> tests/ui/cast.rs:306:21 | LL | let _ = self as i16; | ^^^^^^^^^^^ @@ -427,7 +427,7 @@ LL | let _ = i16::try_from(self); | ~~~~~~~~~~~~~~~~~~~ error: casting `main::E7` to `usize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:324:21 + --> tests/ui/cast.rs:325:21 | LL | let _ = self as usize; | ^^^^^^^^^^^^^ @@ -439,7 +439,7 @@ LL | let _ = usize::try_from(self); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `main::E10` to `u16` may truncate the value - --> tests/ui/cast.rs:371:21 + --> tests/ui/cast.rs:372:21 | LL | let _ = self as u16; | ^^^^^^^^^^^ @@ -451,7 +451,7 @@ LL | let _ = u16::try_from(self); | ~~~~~~~~~~~~~~~~~~~ error: casting `u32` to `u8` may truncate the value - --> tests/ui/cast.rs:382:13 + --> tests/ui/cast.rs:383:13 | LL | let c = (q >> 16) as u8; | ^^^^^^^^^^^^^^^ @@ -463,7 +463,7 @@ LL | let c = u8::try_from(q >> 16); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `u32` to `u8` may truncate the value - --> tests/ui/cast.rs:386:13 + --> tests/ui/cast.rs:387:13 | LL | let c = (q / 1000) as u8; | ^^^^^^^^^^^^^^^^ @@ -475,85 +475,85 @@ LL | let c = u8::try_from(q / 1000); | ~~~~~~~~~~~~~~~~~~~~~~ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:398:9 + --> tests/ui/cast.rs:399:9 | LL | (x * x) as u32; | ^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:403:32 + --> tests/ui/cast.rs:404:32 | LL | let _a = |x: i32| -> u32 { (x * x * x * x) as u32 }; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:405:5 + --> tests/ui/cast.rs:406:5 | LL | (2_i32).checked_pow(3).unwrap() as u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:406:5 + --> tests/ui/cast.rs:407:5 | LL | (-2_i32).pow(3) as u32; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:411:5 + --> tests/ui/cast.rs:412:5 | LL | (-5_i32 % 2) as u32; | ^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:413:5 + --> tests/ui/cast.rs:414:5 | LL | (-5_i32 % -2) as u32; | ^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:416:5 + --> tests/ui/cast.rs:417:5 | LL | (-2_i32 >> 1) as u32; | ^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:420:5 + --> tests/ui/cast.rs:421:5 | LL | (x * x) as u32; | ^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:421:5 + --> tests/ui/cast.rs:422:5 | LL | (x * x * x) as u32; | ^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:425:5 + --> tests/ui/cast.rs:426:5 | LL | (y * y * y * y * -2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:427:5 + --> tests/ui/cast.rs:428:5 | LL | (y * y * y / y * 2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:428:5 + --> tests/ui/cast.rs:429:5 | LL | (y * y / y * 2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:430:5 + --> tests/ui/cast.rs:431:5 | LL | (y / y * y * -2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^^ error: equal expressions as operands to `/` - --> tests/ui/cast.rs:430:6 + --> tests/ui/cast.rs:431:6 | LL | (y / y * y * -2) as u16; | ^^^^^ @@ -561,97 +561,97 @@ LL | (y / y * y * -2) as u16; = note: `#[deny(clippy::eq_op)]` on by default error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:433:5 + --> tests/ui/cast.rs:434:5 | LL | (y + y + y + -2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:435:5 + --> tests/ui/cast.rs:436:5 | LL | (y + y + y + 2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:439:5 + --> tests/ui/cast.rs:440:5 | LL | (z + -2) as u16; | ^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:441:5 + --> tests/ui/cast.rs:442:5 | LL | (z + z + 2) as u16; | ^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:444:9 + --> tests/ui/cast.rs:445:9 | LL | (a * a * b * b * c * c) as u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:445:9 + --> tests/ui/cast.rs:446:9 | LL | (a * b * c) as u32; | ^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:447:9 + --> tests/ui/cast.rs:448:9 | LL | (a * -b * c) as u32; | ^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:449:9 + --> tests/ui/cast.rs:450:9 | LL | (a * b * c * c) as u32; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:450:9 + --> tests/ui/cast.rs:451:9 | LL | (a * -2) as u32; | ^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:452:9 + --> tests/ui/cast.rs:453:9 | LL | (a * b * c * -2) as u32; | ^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:454:9 + --> tests/ui/cast.rs:455:9 | LL | (a / b) as u32; | ^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:455:9 + --> tests/ui/cast.rs:456:9 | LL | (a / b * c) as u32; | ^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:457:9 + --> tests/ui/cast.rs:458:9 | LL | (a / b + b * c) as u32; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:459:9 + --> tests/ui/cast.rs:460:9 | LL | a.saturating_pow(3) as u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:461:9 + --> tests/ui/cast.rs:462:9 | LL | (a.abs() * b.pow(2) / c.abs()) as u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:469:21 + --> tests/ui/cast.rs:470:21 | LL | let _ = i32::MIN as u32; // cast_sign_loss | ^^^^^^^^^^^^^^^ @@ -662,7 +662,7 @@ LL | m!(); = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) error: casting `u32` to `u8` may truncate the value - --> tests/ui/cast.rs:470:21 + --> tests/ui/cast.rs:471:21 | LL | let _ = u32::MAX as u8; // cast_possible_truncation | ^^^^^^^^^^^^^^ @@ -678,7 +678,7 @@ LL | let _ = u8::try_from(u32::MAX); // cast_possible_truncation | ~~~~~~~~~~~~~~~~~~~~~~ error: casting `f64` to `f32` may truncate the value - --> tests/ui/cast.rs:471:21 + --> tests/ui/cast.rs:472:21 | LL | let _ = std::f64::consts::PI as f32; // cast_possible_truncation | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -690,7 +690,7 @@ LL | m!(); = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) error: casting `i64` to `usize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:480:5 + --> tests/ui/cast.rs:481:5 | LL | bar.unwrap().unwrap() as usize | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -702,10 +702,34 @@ LL | usize::try_from(bar.unwrap().unwrap()) | error: casting `i64` to `usize` may lose the sign of the value - --> tests/ui/cast.rs:480:5 + --> tests/ui/cast.rs:481:5 | LL | bar.unwrap().unwrap() as usize | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 90 previous errors +error: casting `u64` to `u8` may truncate the value + --> tests/ui/cast.rs:496:5 + | +LL | (256 & 999999u64) as u8; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | u8::try_from(256 & 999999u64); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: casting `u64` to `u8` may truncate the value + --> tests/ui/cast.rs:498:5 + | +LL | (255 % 999999u64) as u8; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | u8::try_from(255 % 999999u64); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to 92 previous errors From e2861d56522591758b54200d75d7220c519fcf62 Mon Sep 17 00:00:00 2001 From: Aneesh Kadiyala <143342960+ARandomDev99@users.noreply.github.com> Date: Sat, 30 Mar 2024 11:11:16 +0530 Subject: [PATCH 30/47] Encourage using `LateLintPass` --- book/src/development/adding_lints.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/book/src/development/adding_lints.md b/book/src/development/adding_lints.md index e30a5f9fe10b..9fc286e9e685 100644 --- a/book/src/development/adding_lints.md +++ b/book/src/development/adding_lints.md @@ -297,10 +297,10 @@ This is good, because it makes writing this particular lint less complicated. We have to make this decision with every new Clippy lint. It boils down to using either [`EarlyLintPass`][early_lint_pass] or [`LateLintPass`][late_lint_pass]. -In short, the `LateLintPass` has access to type information while the -`EarlyLintPass` doesn't. If you don't need access to type information, use the -`EarlyLintPass`. The `EarlyLintPass` is also faster. However, linting speed -hasn't really been a concern with Clippy so far. +In short, the `EarlyLintPass` runs before type checking and +[HIR](https://rustc-dev-guide.rust-lang.org/hir.html) lowering and the `LateLintPass` +has access to type information. Consider using the `LateLintPass` unless you need +something specific from the `EarlyLintPass`. Since we don't need type information for checking the function name, we used `--pass=early` when running the new lint automation and all the imports were From 87efce4fa22f51075e1fd25904f757f783eebfdc Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Sun, 28 Apr 2024 00:01:14 +0200 Subject: [PATCH 31/47] configurably allow `useless_vec` in tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds a `àllow-useless-vec-in-test` configuration which, when set to `true` will allow the `useless_vec` lint in `#[test]` functions and code within `#[cfg(test)]`. It also moves a `is_in_test` helper to `clippy_utils`. --- CHANGELOG.md | 1 + book/src/lint_configuration.md | 10 +++++++ clippy_config/src/conf.rs | 4 +++ clippy_lints/src/dbg_macro.rs | 10 +++---- clippy_lints/src/lib.rs | 2 ++ clippy_lints/src/vec.rs | 6 ++++- clippy_utils/src/lib.rs | 5 ++++ .../toml_unknown_key/conf_unknown_key.stderr | 3 +++ tests/ui-toml/useless_vec/clippy.toml | 1 + tests/ui-toml/useless_vec/useless_vec.fixed | 26 +++++++++++++++++++ tests/ui-toml/useless_vec/useless_vec.rs | 26 +++++++++++++++++++ tests/ui-toml/useless_vec/useless_vec.stderr | 11 ++++++++ 12 files changed, 97 insertions(+), 8 deletions(-) create mode 100644 tests/ui-toml/useless_vec/clippy.toml create mode 100644 tests/ui-toml/useless_vec/useless_vec.fixed create mode 100644 tests/ui-toml/useless_vec/useless_vec.rs create mode 100644 tests/ui-toml/useless_vec/useless_vec.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index bd3a04e34ae3..12d4918ca55e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5891,6 +5891,7 @@ Released 2018-09-13 [`allow-print-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-print-in-tests [`allow-private-module-inception`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-private-module-inception [`allow-unwrap-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-unwrap-in-tests +[`allow-useless-vec-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-useless-vec-in-tests [`allowed-dotfiles`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-dotfiles [`allowed-duplicate-crates`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-duplicate-crates [`allowed-idents-below-min-chars`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-idents-below-min-chars diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index fe0e9b80b11e..f6af9810ca16 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -132,6 +132,16 @@ Whether `unwrap` should be allowed in test functions or `#[cfg(test)]` * [`unwrap_used`](https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_used) +## `allow-useless-vec-in-tests` +Whether `useless_vec` should ignore test functions or `#[cfg(test)]` + +**Default Value:** `false` + +--- +**Affected lints:** +* [`useless_vec`](https://rust-lang.github.io/rust-clippy/master/index.html#useless_vec) + + ## `allowed-dotfiles` Additional dotfiles (files or directories starting with a dot) to allow diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index bbce4180dc4d..5cfcbdb57d73 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -463,6 +463,10 @@ define_Conf! { /// /// Whether print macros (ex. `println!`) should be allowed in test functions or `#[cfg(test)]` (allow_print_in_tests: bool = false), + /// Lint: USELESS_VEC. + /// + /// Whether `useless_vec` should ignore test functions or `#[cfg(test)]` + (allow_useless_vec_in_tests: bool = false), /// Lint: RESULT_LARGE_ERR. /// /// The maximum size of the `Err`-variant in a `Result` returned from a function diff --git a/clippy_lints/src/dbg_macro.rs b/clippy_lints/src/dbg_macro.rs index e22967674319..db5937266047 100644 --- a/clippy_lints/src/dbg_macro.rs +++ b/clippy_lints/src/dbg_macro.rs @@ -1,10 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_in_test; use clippy_utils::macros::{macro_backtrace, MacroCall}; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{is_in_cfg_test, is_in_test_function}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, HirId, Node}; +use rustc_hir::{Expr, ExprKind, Node}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; @@ -63,7 +63,7 @@ impl LateLintPass<'_> for DbgMacro { !in_external_macro(cx.sess(), macro_call.span) && self.checked_dbg_call_site.insert(macro_call.span) && // allows `dbg!` in test code if allow-dbg-in-test is set to true in clippy.toml - !(self.allow_dbg_in_tests && is_in_test(cx, expr.hir_id)) + !(self.allow_dbg_in_tests && is_in_test(cx.tcx, expr.hir_id)) { let mut applicability = Applicability::MachineApplicable; @@ -129,10 +129,6 @@ impl LateLintPass<'_> for DbgMacro { } } -fn is_in_test(cx: &LateContext<'_>, hir_id: HirId) -> bool { - is_in_test_function(cx.tcx, hir_id) || is_in_cfg_test(cx.tcx, hir_id) -} - fn first_dbg_macro_in_expansion(cx: &LateContext<'_>, span: Span) -> Option { macro_backtrace(span).find(|mc| cx.tcx.is_diagnostic_item(sym::dbg_macro, mc.def_id)) } diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index e2aac58bf979..2c44c3881aa7 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -535,6 +535,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { allow_print_in_tests, allow_private_module_inception, allow_unwrap_in_tests, + allow_useless_vec_in_tests, ref allowed_dotfiles, ref allowed_idents_below_min_chars, ref allowed_scripts, @@ -754,6 +755,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { too_large_for_stack, msrv: msrv(), span_to_lint_map: BTreeMap::new(), + allow_in_test: allow_useless_vec_in_tests, }) }); store.register_late_pass(|_| Box::new(panic_unimplemented::PanicUnimplemented)); diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index 27ead55bf39c..9edf7579d482 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -7,7 +7,7 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::source::snippet_opt; use clippy_utils::ty::is_copy; use clippy_utils::visitors::for_each_local_use_after_expr; -use clippy_utils::{get_parent_expr, higher, is_trait_method}; +use clippy_utils::{get_parent_expr, higher, is_in_test, is_trait_method}; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, LetStmt, Mutability, Node, Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -22,6 +22,7 @@ pub struct UselessVec { pub too_large_for_stack: u64, pub msrv: Msrv, pub span_to_lint_map: BTreeMap>, + pub allow_in_test: bool, } declare_clippy_lint! { @@ -57,6 +58,9 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec { let Some(vec_args) = higher::VecArgs::hir(cx, expr.peel_borrows()) else { return; }; + if self.allow_in_test && is_in_test(cx.tcx, expr.hir_id) { + return; + }; // the parent callsite of this `vec!` expression, or span to the borrowed one such as `&vec!` let callsite = expr.span.parent_callsite().unwrap_or(expr.span); diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index fccd75d81533..26ee5225f999 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -2548,6 +2548,11 @@ pub fn is_in_cfg_test(tcx: TyCtxt<'_>, id: HirId) -> bool { .any(|parent_id| is_cfg_test(tcx, parent_id)) } +/// Checks if the node is in a `#[test]` function or has any parent node marked `#[cfg(test)]` +pub fn is_in_test(tcx: TyCtxt<'_>, hir_id: HirId) -> bool { + is_in_test_function(tcx, hir_id) || is_in_cfg_test(tcx, hir_id) +} + /// Checks if the item of any of its parents has `#[cfg(...)]` attribute applied. pub fn inherits_cfg(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { let hir = tcx.hir(); diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index 24645b61fdb0..722e9b3bc8d4 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -11,6 +11,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect allow-print-in-tests allow-private-module-inception allow-unwrap-in-tests + allow-useless-vec-in-tests allowed-dotfiles allowed-duplicate-crates allowed-idents-below-min-chars @@ -91,6 +92,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect allow-print-in-tests allow-private-module-inception allow-unwrap-in-tests + allow-useless-vec-in-tests allowed-dotfiles allowed-duplicate-crates allowed-idents-below-min-chars @@ -171,6 +173,7 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni allow-print-in-tests allow-private-module-inception allow-unwrap-in-tests + allow-useless-vec-in-tests allowed-dotfiles allowed-duplicate-crates allowed-idents-below-min-chars diff --git a/tests/ui-toml/useless_vec/clippy.toml b/tests/ui-toml/useless_vec/clippy.toml new file mode 100644 index 000000000000..230ca2d0ab72 --- /dev/null +++ b/tests/ui-toml/useless_vec/clippy.toml @@ -0,0 +1 @@ +allow-useless-vec-in-tests = true diff --git a/tests/ui-toml/useless_vec/useless_vec.fixed b/tests/ui-toml/useless_vec/useless_vec.fixed new file mode 100644 index 000000000000..08323a0dcc90 --- /dev/null +++ b/tests/ui-toml/useless_vec/useless_vec.fixed @@ -0,0 +1,26 @@ +//@compile-flags: --test +#![warn(clippy::useless_vec)] +#![allow(clippy::unnecessary_operation, clippy::no_effect)] + +fn foo(_: &[u32]) {} + +fn main() { + foo(&[1_u32]); +} + +#[test] +pub fn in_test() { + foo(&vec![2_u32]); +} + +#[cfg(test)] +fn in_cfg_test() { + foo(&vec![3_u32]); +} + +#[cfg(test)] +mod mod1 { + fn in_cfg_test_mod() { + super::foo(&vec![4_u32]); + } +} diff --git a/tests/ui-toml/useless_vec/useless_vec.rs b/tests/ui-toml/useless_vec/useless_vec.rs new file mode 100644 index 000000000000..1f4b27c53429 --- /dev/null +++ b/tests/ui-toml/useless_vec/useless_vec.rs @@ -0,0 +1,26 @@ +//@compile-flags: --test +#![warn(clippy::useless_vec)] +#![allow(clippy::unnecessary_operation, clippy::no_effect)] + +fn foo(_: &[u32]) {} + +fn main() { + foo(&vec![1_u32]); +} + +#[test] +pub fn in_test() { + foo(&vec![2_u32]); +} + +#[cfg(test)] +fn in_cfg_test() { + foo(&vec![3_u32]); +} + +#[cfg(test)] +mod mod1 { + fn in_cfg_test_mod() { + super::foo(&vec![4_u32]); + } +} diff --git a/tests/ui-toml/useless_vec/useless_vec.stderr b/tests/ui-toml/useless_vec/useless_vec.stderr new file mode 100644 index 000000000000..633110c3c8d9 --- /dev/null +++ b/tests/ui-toml/useless_vec/useless_vec.stderr @@ -0,0 +1,11 @@ +error: useless use of `vec!` + --> tests/ui-toml/useless_vec/useless_vec.rs:8:9 + | +LL | foo(&vec![1_u32]); + | ^^^^^^^^^^^^ help: you can use a slice directly: `&[1_u32]` + | + = note: `-D clippy::useless-vec` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::useless_vec)]` + +error: aborting due to 1 previous error + From cbdc36aa091d4d99a4848155a74a770d3793219b Mon Sep 17 00:00:00 2001 From: J-ZhengLi Date: Mon, 29 Apr 2024 13:38:45 +0800 Subject: [PATCH 32/47] skip warning when generic evolved; suggest explicit type when its inferred in closure --- clippy_lints/src/manual_is_ascii_check.rs | 88 +++++++++++++++-------- tests/ui/manual_is_ascii_check.fixed | 27 +++++++ tests/ui/manual_is_ascii_check.rs | 27 +++++++ tests/ui/manual_is_ascii_check.stderr | 42 ++++++++++- 4 files changed, 152 insertions(+), 32 deletions(-) diff --git a/clippy_lints/src/manual_is_ascii_check.rs b/clippy_lints/src/manual_is_ascii_check.rs index ed7eabd9b994..6f6ba1852a68 100644 --- a/clippy_lints/src/manual_is_ascii_check.rs +++ b/clippy_lints/src/manual_is_ascii_check.rs @@ -1,13 +1,14 @@ use clippy_config::msrvs::{self, Msrv}; -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::matching_root_macro_call; use clippy_utils::sugg::Sugg; -use clippy_utils::{higher, in_constant}; +use clippy_utils::{higher, in_constant, path_to_local, peel_ref_operators}; use rustc_ast::ast::RangeLimits; use rustc_ast::LitKind::{Byte, Char}; use rustc_errors::Applicability; -use rustc_hir::{BorrowKind, Expr, ExprKind, PatKind, RangeEnd}; +use rustc_hir::{Expr, ExprKind, Node, Param, PatKind, RangeEnd}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; use rustc_session::impl_lint_pass; use rustc_span::{sym, Span}; @@ -99,7 +100,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck { if let Some(macro_call) = matching_root_macro_call(cx, expr.span, sym::matches_macro) { if let ExprKind::Match(recv, [arm, ..], _) = expr.kind { let range = check_pat(&arm.pat.kind); - check_is_ascii(cx, macro_call.span, recv, &range); + check_is_ascii(cx, macro_call.span, recv, &range, None); } } else if let ExprKind::MethodCall(path, receiver, [arg], ..) = expr.kind && path.ident.name == sym!(contains) @@ -108,42 +109,67 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck { end: Some(end), limits: RangeLimits::Closed, }) = higher::Range::hir(receiver) + && !matches!(cx.typeck_results().expr_ty(arg).peel_refs().kind(), ty::Param(_)) { + let arg = peel_ref_operators(cx, arg); + let ty_sugg = get_ty_sugg(cx, arg, start); let range = check_range(start, end); - if let ExprKind::AddrOf(BorrowKind::Ref, _, e) = arg.kind { - check_is_ascii(cx, expr.span, e, &range); - } else { - check_is_ascii(cx, expr.span, arg, &range); - } + check_is_ascii(cx, expr.span, arg, &range, ty_sugg); } } extract_msrv_attr!(LateContext); } -fn check_is_ascii(cx: &LateContext<'_>, span: Span, recv: &Expr<'_>, range: &CharRange) { - 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::HexDigit => Some("is_ascii_hexdigit"), - CharRange::Otherwise | CharRange::LowerHexLetter | CharRange::UpperHexLetter => None, - } { - let default_snip = ".."; - let mut app = Applicability::MachineApplicable; - let recv = Sugg::hir_with_context(cx, recv, span.ctxt(), default_snip, &mut app).maybe_par(); - - span_lint_and_sugg( - cx, - MANUAL_IS_ASCII_CHECK, - span, - "manual check for common ascii range", - "try", - format!("{recv}.{sugg}()"), - app, - ); +fn get_ty_sugg(cx: &LateContext<'_>, arg: &Expr<'_>, bound_expr: &Expr<'_>) -> Option<(Span, &'static str)> { + if let ExprKind::Lit(lit) = bound_expr.kind + && let local_hid = path_to_local(arg)? + && let Node::Param(Param { ty_span, span, .. }) = cx.tcx.parent_hir_node(local_hid) + // `ty_span` and `span` are the same for inferred type, thus a type suggestion must be given + && ty_span == span + { + let ty_str = match lit.node { + Char(_) => "char", + Byte(_) => "u8", + _ => return None, + }; + return Some((*ty_span, ty_str)); } + None +} + +fn check_is_ascii( + cx: &LateContext<'_>, + span: Span, + recv: &Expr<'_>, + range: &CharRange, + ty_sugg: Option<(Span, &'_ str)>, +) { + let sugg = match range { + CharRange::UpperChar => "is_ascii_uppercase", + CharRange::LowerChar => "is_ascii_lowercase", + CharRange::FullChar => "is_ascii_alphabetic", + CharRange::Digit => "is_ascii_digit", + CharRange::HexDigit => "is_ascii_hexdigit", + CharRange::Otherwise | CharRange::LowerHexLetter | CharRange::UpperHexLetter => return, + }; + let default_snip = ".."; + let mut app = Applicability::MachineApplicable; + let recv = Sugg::hir_with_context(cx, recv, span.ctxt(), default_snip, &mut app).maybe_par(); + let mut suggestion = vec![(span, format!("{recv}.{sugg}()"))]; + if let Some((ty_span, ty_str)) = ty_sugg { + suggestion.push((ty_span, format!("{recv}: {ty_str}"))); + } + + span_lint_and_then( + cx, + MANUAL_IS_ASCII_CHECK, + span, + "manual check for common ascii range", + |diag| { + diag.multipart_suggestion("try", suggestion, app); + }, + ); } fn check_pat(pat_kind: &PatKind<'_>) -> CharRange { diff --git a/tests/ui/manual_is_ascii_check.fixed b/tests/ui/manual_is_ascii_check.fixed index 9c4bd335ad8b..a72caa3a37ee 100644 --- a/tests/ui/manual_is_ascii_check.fixed +++ b/tests/ui/manual_is_ascii_check.fixed @@ -55,3 +55,30 @@ fn msrv_1_47() { const FOO: bool = 'x'.is_ascii_digit(); const BAR: bool = 'x'.is_ascii_hexdigit(); } + +#[allow(clippy::deref_addrof, clippy::needless_borrow)] +fn with_refs() { + let cool_letter = &&'g'; + cool_letter.is_ascii_digit(); + cool_letter.is_ascii_lowercase(); +} + +fn generics() { + fn a(u: &U) -> bool + where + char: PartialOrd, + U: PartialOrd + ?Sized, + { + ('A'..='Z').contains(u) + } + + fn take_while(cond: F) + where + Item: Sized, + F: Fn(Item) -> bool, + { + } + take_while(|c: char| c.is_ascii_uppercase()); + take_while(|c: u8| c.is_ascii_uppercase()); + take_while(|c: char| c.is_ascii_uppercase()); +} diff --git a/tests/ui/manual_is_ascii_check.rs b/tests/ui/manual_is_ascii_check.rs index 785943cd24d2..bb6e2a317da1 100644 --- a/tests/ui/manual_is_ascii_check.rs +++ b/tests/ui/manual_is_ascii_check.rs @@ -55,3 +55,30 @@ fn msrv_1_47() { const FOO: bool = matches!('x', '0'..='9'); const BAR: bool = matches!('x', '0'..='9' | 'a'..='f' | 'A'..='F'); } + +#[allow(clippy::deref_addrof, clippy::needless_borrow)] +fn with_refs() { + let cool_letter = &&'g'; + ('0'..='9').contains(&&cool_letter); + ('a'..='z').contains(*cool_letter); +} + +fn generics() { + fn a(u: &U) -> bool + where + char: PartialOrd, + U: PartialOrd + ?Sized, + { + ('A'..='Z').contains(u) + } + + fn take_while(cond: F) + where + Item: Sized, + F: Fn(Item) -> bool, + { + } + take_while(|c| ('A'..='Z').contains(&c)); + take_while(|c| (b'A'..=b'Z').contains(&c)); + take_while(|c: char| ('A'..='Z').contains(&c)); +} diff --git a/tests/ui/manual_is_ascii_check.stderr b/tests/ui/manual_is_ascii_check.stderr index 3632077ec808..a93ccace28a6 100644 --- a/tests/ui/manual_is_ascii_check.stderr +++ b/tests/ui/manual_is_ascii_check.stderr @@ -133,5 +133,45 @@ error: manual check for common ascii range LL | const BAR: bool = matches!('x', '0'..='9' | 'a'..='f' | 'A'..='F'); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'x'.is_ascii_hexdigit()` -error: aborting due to 22 previous errors +error: manual check for common ascii range + --> tests/ui/manual_is_ascii_check.rs:62:5 + | +LL | ('0'..='9').contains(&&cool_letter); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cool_letter.is_ascii_digit()` + +error: manual check for common ascii range + --> tests/ui/manual_is_ascii_check.rs:63:5 + | +LL | ('a'..='z').contains(*cool_letter); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cool_letter.is_ascii_lowercase()` + +error: manual check for common ascii range + --> tests/ui/manual_is_ascii_check.rs:81:20 + | +LL | take_while(|c| ('A'..='Z').contains(&c)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL | take_while(|c: char| c.is_ascii_uppercase()); + | ~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~ + +error: manual check for common ascii range + --> tests/ui/manual_is_ascii_check.rs:82:20 + | +LL | take_while(|c| (b'A'..=b'Z').contains(&c)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL | take_while(|c: u8| c.is_ascii_uppercase()); + | ~~~~~ ~~~~~~~~~~~~~~~~~~~~~~ + +error: manual check for common ascii range + --> tests/ui/manual_is_ascii_check.rs:83:26 + | +LL | take_while(|c: char| ('A'..='Z').contains(&c)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `c.is_ascii_uppercase()` + +error: aborting due to 27 previous errors From f0beaedf832c574042bb8ec1957e462b97373758 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Mon, 29 Apr 2024 17:27:40 +0200 Subject: [PATCH 33/47] suppress `readonly_write_lock` for underscore-prefixed bindings --- clippy_lints/src/methods/readonly_write_lock.rs | 7 ++++++- tests/ui/readonly_write_lock.fixed | 4 ++++ tests/ui/readonly_write_lock.rs | 4 ++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/methods/readonly_write_lock.rs b/clippy_lints/src/methods/readonly_write_lock.rs index 9b0180d93699..774aaec1afda 100644 --- a/clippy_lints/src/methods/readonly_write_lock.rs +++ b/clippy_lints/src/methods/readonly_write_lock.rs @@ -4,7 +4,7 @@ use clippy_utils::mir::{enclosing_mir, visit_local_usage}; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, Node}; +use rustc_hir::{Expr, ExprKind, Node, PatKind}; use rustc_lint::LateContext; use rustc_middle::mir::{Location, START_BLOCK}; use rustc_span::sym; @@ -25,6 +25,11 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, receiver && is_unwrap_call(cx, unwrap_call_expr) && let parent = cx.tcx.parent_hir_node(unwrap_call_expr.hir_id) && let Node::LetStmt(local) = parent + && let PatKind::Binding(.., ident, _) = local.pat.kind + // if the binding is prefixed with `_`, it typically means + // that this guard only exists to protect a section of code + // rather than the contained data + && !ident.as_str().starts_with('_') && let Some(mir) = enclosing_mir(cx.tcx, expr.hir_id) && let Some((local, _)) = mir .local_decls diff --git a/tests/ui/readonly_write_lock.fixed b/tests/ui/readonly_write_lock.fixed index 76f4a43ae530..4db13482ac78 100644 --- a/tests/ui/readonly_write_lock.fixed +++ b/tests/ui/readonly_write_lock.fixed @@ -43,3 +43,7 @@ fn main() { *writer1 = *writer2; } } + +fn issue12733(rw: &RwLock<()>) { + let _write_guard = rw.write().unwrap(); +} diff --git a/tests/ui/readonly_write_lock.rs b/tests/ui/readonly_write_lock.rs index 3d1d3855fe12..66ba1b2d6969 100644 --- a/tests/ui/readonly_write_lock.rs +++ b/tests/ui/readonly_write_lock.rs @@ -43,3 +43,7 @@ fn main() { *writer1 = *writer2; } } + +fn issue12733(rw: &RwLock<()>) { + let _write_guard = rw.write().unwrap(); +} From 9276ce1cf3db6045678fa04e9dc3f58bec923c4d Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Mon, 29 Apr 2024 11:27:14 -0300 Subject: [PATCH 34/47] Add StaticForeignItem and use it on ForeignItemKind --- clippy_utils/src/ast_utils.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/clippy_utils/src/ast_utils.rs b/clippy_utils/src/ast_utils.rs index 0395eb1449b4..529d20126b22 100644 --- a/clippy_utils/src/ast_utils.rs +++ b/clippy_utils/src/ast_utils.rs @@ -446,7 +446,18 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool { use ForeignItemKind::*; match (l, r) { - (Static(lt, lm, le), Static(rt, rm, re)) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re), + ( + Static(box StaticForeignItem { + ty: lt, + mutability: lm, + expr: le, + }), + Static(box StaticForeignItem { + ty: rt, + mutability: rm, + expr: re, + }), + ) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re), ( Fn(box ast::Fn { defaultness: ld, From b1fa2842b10308b1ac3d482cef2f6ec316b2e98f Mon Sep 17 00:00:00 2001 From: xFrednet Date: Mon, 29 Apr 2024 21:26:14 +0200 Subject: [PATCH 35/47] Update version attribute for 1.78 lints --- clippy_lints/src/assigning_clones.rs | 2 +- clippy_lints/src/cargo/mod.rs | 2 +- clippy_lints/src/casts/mod.rs | 2 +- clippy_lints/src/methods/mod.rs | 4 ++-- clippy_lints/src/multiple_bound_locations.rs | 2 +- clippy_lints/src/to_string_trait_impl.rs | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/assigning_clones.rs b/clippy_lints/src/assigning_clones.rs index d88ca84fb97d..f0dafb1ae0d5 100644 --- a/clippy_lints/src/assigning_clones.rs +++ b/clippy_lints/src/assigning_clones.rs @@ -45,7 +45,7 @@ declare_clippy_lint! { /// a.clone_from(&b); /// } /// ``` - #[clippy::version = "1.77.0"] + #[clippy::version = "1.78.0"] pub ASSIGNING_CLONES, perf, "assigning the result of cloning may be inefficient" diff --git a/clippy_lints/src/cargo/mod.rs b/clippy_lints/src/cargo/mod.rs index ca7fa4e5a410..593bc6c81ee8 100644 --- a/clippy_lints/src/cargo/mod.rs +++ b/clippy_lints/src/cargo/mod.rs @@ -197,7 +197,7 @@ declare_clippy_lint! { /// pedantic = { level = "warn", priority = -1 } /// similar_names = "allow" /// ``` - #[clippy::version = "1.76.0"] + #[clippy::version = "1.78.0"] pub LINT_GROUPS_PRIORITY, correctness, "a lint group in `Cargo.toml` at the same priority as a lint" diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index d14898a8196c..bd2c96f01f6f 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -708,7 +708,7 @@ declare_clippy_lint! { /// let a_ref = &1; /// let a_ptr = std::ptr::from_ref(a_ref); /// ``` - #[clippy::version = "1.77.0"] + #[clippy::version = "1.78.0"] pub REF_AS_PTR, pedantic, "using `as` to cast a reference to pointer" diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 16e508bf4e1d..63545d6c5035 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3993,7 +3993,7 @@ declare_clippy_lint! { /// let x: Result = Ok(0); /// let y = x.unwrap_or_else(|err| handle_error(err)); /// ``` - #[clippy::version = "1.77.0"] + #[clippy::version = "1.78.0"] pub UNNECESSARY_RESULT_MAP_OR_ELSE, suspicious, "making no use of the \"map closure\" when calling `.map_or_else(|err| handle_error(err), |n| n)`" @@ -4027,7 +4027,7 @@ declare_clippy_lint! { /// needs_cstr(c"Hello"); /// unsafe { libc::puts(c"World".as_ptr()) } /// ``` - #[clippy::version = "1.76.0"] + #[clippy::version = "1.78.0"] pub MANUAL_C_STR_LITERALS, pedantic, r#"creating a `CStr` through functions when `c""` literals can be used"# diff --git a/clippy_lints/src/multiple_bound_locations.rs b/clippy_lints/src/multiple_bound_locations.rs index 191b32408efe..d608f3bf7b4d 100644 --- a/clippy_lints/src/multiple_bound_locations.rs +++ b/clippy_lints/src/multiple_bound_locations.rs @@ -29,7 +29,7 @@ declare_clippy_lint! { /// F: Sized + std::fmt::Debug, /// {} /// ``` - #[clippy::version = "1.77.0"] + #[clippy::version = "1.78.0"] pub MULTIPLE_BOUND_LOCATIONS, suspicious, "defining generic bounds in multiple locations" diff --git a/clippy_lints/src/to_string_trait_impl.rs b/clippy_lints/src/to_string_trait_impl.rs index 59ae185c9de7..0361836cdec7 100644 --- a/clippy_lints/src/to_string_trait_impl.rs +++ b/clippy_lints/src/to_string_trait_impl.rs @@ -38,7 +38,7 @@ declare_clippy_lint! { /// } /// } /// ``` - #[clippy::version = "1.77.0"] + #[clippy::version = "1.78.0"] pub TO_STRING_TRAIT_IMPL, style, "check for direct implementations of `ToString`" From 7ac1529ff630eeefb96888d734ae26bb6e84e335 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Mon, 29 Apr 2024 21:44:16 +0200 Subject: [PATCH 36/47] Changelog for Clippy 1.78 :magic_wand: --- CHANGELOG.md | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 66 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 12d4918ca55e..d908ed43cfae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,11 +6,75 @@ document. ## Unreleased / Beta / In Rust Nightly -[66c29b97...master](https://github.com/rust-lang/rust-clippy/compare/66c29b97...master) +[93f0a9a9...master](https://github.com/rust-lang/rust-clippy/compare/93f0a9a9...master) + +## Rust 1.78 + +Current stable, released 2024-05-02 + +[View all 112 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2024-01-26T05%3A46%3A23Z..2024-03-07T16%3A25%3A52Z+base%3Amaster) + +### Important Changes + +* In a few versions, `cargo-clippy` will now no longer ignore the first argument. + Passing in `clippy` as the first argument like cargo does will continue to work. + However, arguments like `--fix` will soon issue a warning and will no longer be. + `cargo clippy` (without `-`!) is unaffected by this change. + [#9461](https://github.com/rust-lang/rust-clippy/pull/9461) + +### New Lints + +* [`assigning_clones`] + [#12077](https://github.com/rust-lang/rust-clippy/pull/12077) +* [`mixed_attributes_style`] + [#12354](https://github.com/rust-lang/rust-clippy/pull/12354) +* [`empty_docs`] + [#12342](https://github.com/rust-lang/rust-clippy/pull/12342) +* [`unnecessary_get_then_check`] + [#12339](https://github.com/rust-lang/rust-clippy/pull/12339) +* [`multiple_bound_locations`] + [#12259](https://github.com/rust-lang/rust-clippy/pull/12259) +* [`unnecessary_clippy_cfg`] + [#12303](https://github.com/rust-lang/rust-clippy/pull/12303) +* [`deprecated_clippy_cfg_attr`] + [#12292](https://github.com/rust-lang/rust-clippy/pull/12292) +* [`manual_c_str_literals`] + [#11919](https://github.com/rust-lang/rust-clippy/pull/11919) +* [`ref_as_ptr`] + [#12087](https://github.com/rust-lang/rust-clippy/pull/12087) +* [`lint_groups_priority`] + [#11832](https://github.com/rust-lang/rust-clippy/pull/11832) +* [`unnecessary_result_map_or_else`] + [#12169](https://github.com/rust-lang/rust-clippy/pull/12169) +* [`to_string_trait_impl`] + [#12122](https://github.com/rust-lang/rust-clippy/pull/12122) +* [`incompatible_msrv`] + [#12160](https://github.com/rust-lang/rust-clippy/pull/12160) + +### Moves and Deprecations + +* Moved [`mixed_attributes_style`] to `style` (Remains warn-by-default) + [#12572](https://github.com/rust-lang/rust-clippy/pull/12572) + +### Enhancements + +* [`thread_local_initializer_can_be_made_const`]: Now checks the [`msrv`] configuration + [#12405](https://github.com/rust-lang/rust-clippy/pull/12405) +* [`disallowed_macros`]: Code generated by derive macros can no longer allow this lint + [#12267](https://github.com/rust-lang/rust-clippy/pull/12267) +* [`wildcard_imports`]: Add configuration [`allowed-wildcard-imports`] to allow preconfigured wildcards + [#11979](https://github.com/rust-lang/rust-clippy/pull/11979) + +### ICE Fixes + +* [`ptr_as_ptr`]: No longer ICEs on types from other crates + [#12617](https://github.com/rust-lang/rust-clippy/pull/12617) +* [`cast_sign_loss`]: Avoids an infinit loop when casting two changed `.unwrap()` calls + [#12508](https://github.com/rust-lang/rust-clippy/pull/12508) ## Rust 1.77 -Current stable, released 2024-03-18 +Released 2024-03-18 [View all 93 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2023-12-16T18%3A20%3A00Z..2024-01-25T18%3A15%3A56Z+base%3Amaster) From 71db2d14510d82c2499cf0621279389c7e0f92ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ul=C4=85=C5=BCka=20Mateusz?= Date: Mon, 29 Apr 2024 22:32:36 +0200 Subject: [PATCH 37/47] [type_complexity]: Fix duplicate errors --- clippy_lints/src/types/mod.rs | 12 +++++++++--- tests/ui/type_complexity.rs | 2 -- tests/ui/type_complexity.stderr | 30 +++++++++++++++--------------- 3 files changed, 24 insertions(+), 20 deletions(-) diff --git a/clippy_lints/src/types/mod.rs b/clippy_lints/src/types/mod.rs index 0802cb2b7c75..5e45ab211efd 100644 --- a/clippy_lints/src/types/mod.rs +++ b/clippy_lints/src/types/mod.rs @@ -12,8 +12,8 @@ mod vec_box; use rustc_hir as hir; use rustc_hir::intravisit::FnKind; use rustc_hir::{ - Body, FnDecl, FnRetTy, GenericArg, ImplItem, ImplItemKind, Item, ItemKind, LetStmt, MutTy, QPath, TraitItem, - TraitItemKind, TyKind, + Body, FnDecl, FnRetTy, GenericArg, ImplItem, ImplItemKind, Item, ItemKind, LetStmt, MutTy, QPath, TraitFn, + TraitItem, TraitItemKind, TyKind, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; @@ -420,7 +420,13 @@ impl<'tcx> LateLintPass<'tcx> for Types { TraitItemKind::Const(ty, _) | TraitItemKind::Type(_, Some(ty)) => { self.check_ty(cx, ty, context); }, - TraitItemKind::Fn(ref sig, _) => self.check_fn_decl(cx, sig.decl, context), + TraitItemKind::Fn(ref sig, trait_method) => { + // Check only methods without body + // Methods with body are covered by check_fn. + if let TraitFn::Required(_) = trait_method { + self.check_fn_decl(cx, sig.decl, context); + } + }, TraitItemKind::Type(..) => (), } } diff --git a/tests/ui/type_complexity.rs b/tests/ui/type_complexity.rs index b057dc4e89f2..be28ee2da0cd 100644 --- a/tests/ui/type_complexity.rs +++ b/tests/ui/type_complexity.rs @@ -1,5 +1,3 @@ -//@compile-flags: -Zdeduplicate-diagnostics=yes - #![warn(clippy::all)] #![allow(unused, clippy::needless_pass_by_value, clippy::vec_box, clippy::useless_vec)] #![feature(associated_type_defaults)] diff --git a/tests/ui/type_complexity.stderr b/tests/ui/type_complexity.stderr index bfbab8647e85..9e27899e4f90 100644 --- a/tests/ui/type_complexity.stderr +++ b/tests/ui/type_complexity.stderr @@ -1,5 +1,5 @@ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:9:12 + --> tests/ui/type_complexity.rs:7:12 | LL | const CST: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0)))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,85 +8,85 @@ LL | const CST: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0)))); = help: to override `-D warnings` add `#[allow(clippy::type_complexity)]` error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:12:12 + --> tests/ui/type_complexity.rs:10:12 | LL | static ST: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0)))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:16:8 + --> tests/ui/type_complexity.rs:14:8 | LL | f: Vec>>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:20:11 + --> tests/ui/type_complexity.rs:18:11 | LL | struct Ts(Vec>>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:24:11 + --> tests/ui/type_complexity.rs:22:11 | LL | Tuple(Vec>>), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:26:17 + --> tests/ui/type_complexity.rs:24:17 | LL | Struct { f: Vec>> }, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:31:14 + --> tests/ui/type_complexity.rs:29:14 | LL | const A: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0)))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:33:30 + --> tests/ui/type_complexity.rs:31:30 | LL | fn impl_method(&self, p: Vec>>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:38:14 + --> tests/ui/type_complexity.rs:36:14 | LL | const A: Vec>>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:40:14 + --> tests/ui/type_complexity.rs:38:14 | LL | type B = Vec>>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:42:25 + --> tests/ui/type_complexity.rs:40:25 | LL | fn method(&self, p: Vec>>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:44:29 + --> tests/ui/type_complexity.rs:42:29 | LL | fn def_method(&self, p: Vec>>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:57:15 + --> tests/ui/type_complexity.rs:55:15 | LL | fn test1() -> Vec>> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:62:14 + --> tests/ui/type_complexity.rs:60:14 | LL | fn test2(_x: Vec>>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:66:13 + --> tests/ui/type_complexity.rs:64:13 | LL | let _y: Vec>> = vec![]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From a3ef100fa6fdb7d07c52b35d2462fa74cbf7ccd3 Mon Sep 17 00:00:00 2001 From: bendn Date: Wed, 1 May 2024 07:45:15 +0700 Subject: [PATCH 38/47] warning --- clippy_lints/src/needless_for_each.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/clippy_lints/src/needless_for_each.rs b/clippy_lints/src/needless_for_each.rs index 3fe3d50197d2..630018238f4c 100644 --- a/clippy_lints/src/needless_for_each.rs +++ b/clippy_lints/src/needless_for_each.rs @@ -35,6 +35,16 @@ declare_clippy_lint! { /// println!("{}", elem); /// } /// ``` + /// + /// ### Known Problems + /// When doing things such as: + /// ```ignore + /// let v = vec![0, 1, 2]; + /// v.iter().for_each(|elem| unsafe { + /// libc::printf(c"%d\n".as_ptr(), elem); + /// }); + /// ``` + /// This lint will not trigger. #[clippy::version = "1.53.0"] pub NEEDLESS_FOR_EACH, pedantic, From fed9940e57949b4e2153a465d22a51a2bc975b6d Mon Sep 17 00:00:00 2001 From: "Christopher B. Speir" Date: Tue, 30 Apr 2024 20:02:32 -0500 Subject: [PATCH 39/47] Remove clippy_utils::paths::VEC_RESIZE This path is no longer used and can be removed. --- clippy_utils/src/paths.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 456b8019e95c..0e26b3bfd624 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -108,7 +108,6 @@ pub const VEC_DEQUE_ITER: [&str; 5] = ["alloc", "collections", "vec_deque", "Vec pub const VEC_FROM_ELEM: [&str; 3] = ["alloc", "vec", "from_elem"]; pub const VEC_NEW: [&str; 4] = ["alloc", "vec", "Vec", "new"]; pub const VEC_WITH_CAPACITY: [&str; 4] = ["alloc", "vec", "Vec", "with_capacity"]; -pub const VEC_RESIZE: [&str; 4] = ["alloc", "vec", "Vec", "resize"]; pub const INSTANT_NOW: [&str; 4] = ["std", "time", "Instant", "now"]; pub const VEC_IS_EMPTY: [&str; 4] = ["alloc", "vec", "Vec", "is_empty"]; pub const VEC_POP: [&str; 4] = ["alloc", "vec", "Vec", "pop"]; From 272413f458151978d7e2185e20d7d23ce81bf6e6 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Thu, 2 May 2024 04:45:45 +0200 Subject: [PATCH 40/47] allow or patterns for a high enough MSRV in `collapsible_match` --- clippy_lints/src/matches/collapsible_match.rs | 23 +++---- clippy_lints/src/matches/mod.rs | 23 +++++-- clippy_lints/src/matches/redundant_guards.rs | 7 +- tests/ui/collapsible_match.rs | 16 ++++- tests/ui/collapsible_match.stderr | 68 ++++++++++++------- 5 files changed, 88 insertions(+), 49 deletions(-) diff --git a/clippy_lints/src/matches/collapsible_match.rs b/clippy_lints/src/matches/collapsible_match.rs index 6746920edc51..90cfdecc1993 100644 --- a/clippy_lints/src/matches/collapsible_match.rs +++ b/clippy_lints/src/matches/collapsible_match.rs @@ -1,3 +1,4 @@ +use clippy_config::msrvs::Msrv; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::IfLetOrMatch; use clippy_utils::source::snippet; @@ -11,12 +12,12 @@ use rustc_hir::{Arm, Expr, HirId, Pat, PatKind}; use rustc_lint::LateContext; use rustc_span::Span; -use super::COLLAPSIBLE_MATCH; +use super::{pat_contains_disallowed_or, COLLAPSIBLE_MATCH}; -pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) { +pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], msrv: &Msrv) { if let Some(els_arm) = arms.iter().rfind(|arm| arm_is_wild_like(cx, arm)) { for arm in arms { - check_arm(cx, true, arm.pat, arm.body, arm.guard, Some(els_arm.body)); + check_arm(cx, true, arm.pat, arm.body, arm.guard, Some(els_arm.body), msrv); } } } @@ -26,8 +27,9 @@ pub(super) fn check_if_let<'tcx>( pat: &'tcx Pat<'_>, body: &'tcx Expr<'_>, else_expr: Option<&'tcx Expr<'_>>, + msrv: &Msrv, ) { - check_arm(cx, false, pat, body, None, else_expr); + check_arm(cx, false, pat, body, None, else_expr, msrv); } fn check_arm<'tcx>( @@ -37,6 +39,7 @@ fn check_arm<'tcx>( outer_then_body: &'tcx Expr<'tcx>, outer_guard: Option<&'tcx Expr<'tcx>>, outer_else_body: Option<&'tcx Expr<'tcx>>, + msrv: &Msrv, ) { let inner_expr = peel_blocks_with_stmt(outer_then_body); if let Some(inner) = IfLetOrMatch::parse(cx, inner_expr) @@ -57,7 +60,7 @@ fn check_arm<'tcx>( // match expression must be a local binding // match { .. } && let Some(binding_id) = path_to_local(peel_ref_operators(cx, inner_scrutinee)) - && !pat_contains_or(inner_then_pat) + && !pat_contains_disallowed_or(inner_then_pat, msrv) // the binding must come from the pattern of the containing match arm // .... => match { .. } && let (Some(binding_span), is_innermost_parent_pat_struct) @@ -142,13 +145,3 @@ fn find_pat_binding_and_is_innermost_parent_pat_struct(pat: &Pat<'_>, hir_id: Hi }); (span, is_innermost_parent_pat_struct) } - -fn pat_contains_or(pat: &Pat<'_>) -> bool { - let mut result = false; - pat.walk(|p| { - let is_or = matches!(p.kind, PatKind::Or(_)); - result |= is_or; - !is_or - }); - result -} diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs index fae2c4e4af92..ee9f48d71ad8 100644 --- a/clippy_lints/src/matches/mod.rs +++ b/clippy_lints/src/matches/mod.rs @@ -27,7 +27,7 @@ mod wild_in_or_pats; use clippy_config::msrvs::{self, Msrv}; use clippy_utils::source::walk_span_to_context; use clippy_utils::{higher, in_constant, is_direct_expn_of, is_span_match, span_contains_cfg}; -use rustc_hir::{Arm, Expr, ExprKind, LetStmt, MatchSource, Pat}; +use rustc_hir::{Arm, Expr, ExprKind, LetStmt, MatchSource, Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; @@ -1040,7 +1040,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches { significant_drop_in_scrutinee::check(cx, expr, ex, arms, source); } - collapsible_match::check_match(cx, arms); + collapsible_match::check_match(cx, arms, &self.msrv); if !from_expansion { // These don't depend on a relationship between multiple arms match_wild_err_arm::check(cx, ex, arms); @@ -1066,7 +1066,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches { needless_match::check_match(cx, ex, arms, expr); match_on_vec_items::check(cx, ex); match_str_case_mismatch::check(cx, ex, arms); - redundant_guards::check(cx, arms); + redundant_guards::check(cx, arms, &self.msrv); if !in_constant(cx, expr.hir_id) { manual_unwrap_or::check(cx, expr, ex, arms); @@ -1083,7 +1083,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches { match_ref_pats::check(cx, ex, arms.iter().map(|el| el.pat), expr); } } else if let Some(if_let) = higher::IfLet::hir(cx, expr) { - collapsible_match::check_if_let(cx, if_let.let_pat, if_let.if_then, if_let.if_else); + collapsible_match::check_if_let(cx, if_let.let_pat, if_let.if_then, if_let.if_else, &self.msrv); if !from_expansion { if let Some(else_expr) = if_let.if_else { if self.msrv.meets(msrvs::MATCHES_MACRO) { @@ -1195,3 +1195,18 @@ fn contains_cfg_arm(cx: &LateContext<'_>, e: &Expr<'_>, scrutinee: &Expr<'_>, ar Err(()) => true, } } + +/// Checks if `pat` contains OR patterns that cannot be nested due to a too low MSRV. +fn pat_contains_disallowed_or(pat: &Pat<'_>, msrv: &Msrv) -> bool { + if msrv.meets(msrvs::OR_PATTERNS) { + return false; + } + + let mut result = false; + pat.walk(|p| { + let is_or = matches!(p.kind, PatKind::Or(_)); + result |= is_or; + !is_or + }); + result +} diff --git a/clippy_lints/src/matches/redundant_guards.rs b/clippy_lints/src/matches/redundant_guards.rs index 50cbccc39683..984aa3d73708 100644 --- a/clippy_lints/src/matches/redundant_guards.rs +++ b/clippy_lints/src/matches/redundant_guards.rs @@ -1,3 +1,4 @@ +use clippy_config::msrvs::Msrv; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; use clippy_utils::visitors::{for_each_expr, is_local_used}; @@ -12,9 +13,9 @@ use rustc_span::{Span, Symbol}; use std::borrow::Cow; use std::ops::ControlFlow; -use super::REDUNDANT_GUARDS; +use super::{pat_contains_disallowed_or, REDUNDANT_GUARDS}; -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) { +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>], msrv: &Msrv) { for outer_arm in arms { let Some(guard) = outer_arm.guard else { continue; @@ -35,6 +36,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) { MatchSource::Normal, ) = guard.kind && let Some(binding) = get_pat_binding(cx, scrutinee, outer_arm) + && !pat_contains_disallowed_or(&arm.pat, msrv) { let pat_span = match (arm.pat.kind, binding.byref_ident) { (PatKind::Ref(pat, _), Some(_)) => pat.span, @@ -53,6 +55,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) { // `Some(x) if let Some(2) = x` else if let ExprKind::Let(let_expr) = guard.kind && let Some(binding) = get_pat_binding(cx, let_expr.init, outer_arm) + && !pat_contains_disallowed_or(&let_expr.pat, msrv) { let pat_span = match (let_expr.pat.kind, binding.byref_ident) { (PatKind::Ref(pat, _), Some(_)) => pat.span, diff --git a/tests/ui/collapsible_match.rs b/tests/ui/collapsible_match.rs index 7501fd2b0bd9..2264b560791a 100644 --- a/tests/ui/collapsible_match.rs +++ b/tests/ui/collapsible_match.rs @@ -4,7 +4,8 @@ clippy::needless_return, clippy::no_effect, clippy::single_match, - clippy::uninlined_format_args + clippy::uninlined_format_args, + clippy::let_unit_value )] fn lint_cases(opt_opt: Option>, res_opt: Result, String>) { @@ -238,13 +239,22 @@ fn negative_cases(res_opt: Result, String>, res_res: Result return, } - match make::>>() { + #[clippy::msrv = "1.52.0"] + let _ = match make::>>() { Some(val) => match val { E::A(val) | E::B(val) => foo(val), _ => return, }, _ => return, - } + }; + #[clippy::msrv = "1.53.0"] + let _ = match make::>>() { + Some(val) => match val { + E::A(val) | E::B(val) => foo(val), + _ => return, + }, + _ => return, + }; if let Ok(val) = res_opt { if let Some(n) = val { let _ = || { diff --git a/tests/ui/collapsible_match.stderr b/tests/ui/collapsible_match.stderr index 46b484ab05c4..01944baee79a 100644 --- a/tests/ui/collapsible_match.stderr +++ b/tests/ui/collapsible_match.stderr @@ -1,5 +1,5 @@ error: this `match` can be collapsed into the outer `match` - --> tests/ui/collapsible_match.rs:13:20 + --> tests/ui/collapsible_match.rs:14:20 | LL | Ok(val) => match val { | ____________________^ @@ -10,7 +10,7 @@ LL | | }, | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match.rs:13:12 + --> tests/ui/collapsible_match.rs:14:12 | LL | Ok(val) => match val { | ^^^ replace this binding @@ -21,7 +21,7 @@ LL | Some(n) => foo(n), = help: to override `-D warnings` add `#[allow(clippy::collapsible_match)]` error: this `match` can be collapsed into the outer `match` - --> tests/ui/collapsible_match.rs:23:20 + --> tests/ui/collapsible_match.rs:24:20 | LL | Ok(val) => match val { | ____________________^ @@ -32,7 +32,7 @@ LL | | }, | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match.rs:23:12 + --> tests/ui/collapsible_match.rs:24:12 | LL | Ok(val) => match val { | ^^^ replace this binding @@ -41,7 +41,7 @@ LL | Some(n) => foo(n), | ^^^^^^^ with this pattern error: this `if let` can be collapsed into the outer `if let` - --> tests/ui/collapsible_match.rs:33:9 + --> tests/ui/collapsible_match.rs:34:9 | LL | / if let Some(n) = val { LL | | @@ -50,7 +50,7 @@ LL | | } | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match.rs:32:15 + --> tests/ui/collapsible_match.rs:33:15 | LL | if let Ok(val) = res_opt { | ^^^ replace this binding @@ -58,7 +58,7 @@ LL | if let Some(n) = val { | ^^^^^^^ with this pattern error: this `if let` can be collapsed into the outer `if let` - --> tests/ui/collapsible_match.rs:41:9 + --> tests/ui/collapsible_match.rs:42:9 | LL | / if let Some(n) = val { LL | | @@ -69,7 +69,7 @@ LL | | } | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match.rs:40:15 + --> tests/ui/collapsible_match.rs:41:15 | LL | if let Ok(val) = res_opt { | ^^^ replace this binding @@ -77,7 +77,7 @@ LL | if let Some(n) = val { | ^^^^^^^ with this pattern error: this `match` can be collapsed into the outer `if let` - --> tests/ui/collapsible_match.rs:53:9 + --> tests/ui/collapsible_match.rs:54:9 | LL | / match val { LL | | @@ -87,7 +87,7 @@ LL | | } | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match.rs:52:15 + --> tests/ui/collapsible_match.rs:53:15 | LL | if let Ok(val) = res_opt { | ^^^ replace this binding @@ -96,7 +96,7 @@ LL | Some(n) => foo(n), | ^^^^^^^ with this pattern error: this `if let` can be collapsed into the outer `match` - --> tests/ui/collapsible_match.rs:63:13 + --> tests/ui/collapsible_match.rs:64:13 | LL | / if let Some(n) = val { LL | | @@ -105,7 +105,7 @@ LL | | } | |_____________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match.rs:62:12 + --> tests/ui/collapsible_match.rs:63:12 | LL | Ok(val) => { | ^^^ replace this binding @@ -113,7 +113,7 @@ LL | if let Some(n) = val { | ^^^^^^^ with this pattern error: this `match` can be collapsed into the outer `if let` - --> tests/ui/collapsible_match.rs:73:9 + --> tests/ui/collapsible_match.rs:74:9 | LL | / match val { LL | | @@ -123,7 +123,7 @@ LL | | } | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match.rs:72:15 + --> tests/ui/collapsible_match.rs:73:15 | LL | if let Ok(val) = res_opt { | ^^^ replace this binding @@ -132,7 +132,7 @@ LL | Some(n) => foo(n), | ^^^^^^^ with this pattern error: this `if let` can be collapsed into the outer `match` - --> tests/ui/collapsible_match.rs:85:13 + --> tests/ui/collapsible_match.rs:86:13 | LL | / if let Some(n) = val { LL | | @@ -143,7 +143,7 @@ LL | | } | |_____________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match.rs:84:12 + --> tests/ui/collapsible_match.rs:85:12 | LL | Ok(val) => { | ^^^ replace this binding @@ -151,7 +151,7 @@ LL | if let Some(n) = val { | ^^^^^^^ with this pattern error: this `match` can be collapsed into the outer `match` - --> tests/ui/collapsible_match.rs:97:20 + --> tests/ui/collapsible_match.rs:98:20 | LL | Ok(val) => match val { | ____________________^ @@ -162,7 +162,7 @@ LL | | }, | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match.rs:97:12 + --> tests/ui/collapsible_match.rs:98:12 | LL | Ok(val) => match val { | ^^^ replace this binding @@ -171,7 +171,7 @@ LL | Some(n) => foo(n), | ^^^^^^^ with this pattern error: this `match` can be collapsed into the outer `match` - --> tests/ui/collapsible_match.rs:107:22 + --> tests/ui/collapsible_match.rs:108:22 | LL | Some(val) => match val { | ______________________^ @@ -182,7 +182,7 @@ LL | | }, | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match.rs:107:14 + --> tests/ui/collapsible_match.rs:108:14 | LL | Some(val) => match val { | ^^^ replace this binding @@ -190,8 +190,26 @@ LL | LL | Some(n) => foo(n), | ^^^^^^^ with this pattern +error: this `match` can be collapsed into the outer `match` + --> tests/ui/collapsible_match.rs:252:22 + | +LL | Some(val) => match val { + | ______________________^ +LL | | E::A(val) | E::B(val) => foo(val), +LL | | _ => return, +LL | | }, + | |_________^ + | +help: the outer pattern can be modified to include the inner pattern + --> tests/ui/collapsible_match.rs:252:14 + | +LL | Some(val) => match val { + | ^^^ replace this binding +LL | E::A(val) | E::B(val) => foo(val), + | ^^^^^^^^^^^^^^^^^^^^^ with this pattern + error: this `if let` can be collapsed into the outer `if let` - --> tests/ui/collapsible_match.rs:273:9 + --> tests/ui/collapsible_match.rs:283:9 | LL | / if let Some(u) = a { LL | | @@ -200,7 +218,7 @@ LL | | } | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match.rs:272:27 + --> tests/ui/collapsible_match.rs:282:27 | LL | if let Issue9647::A { a, .. } = x { | ^ replace this binding @@ -208,7 +226,7 @@ LL | if let Some(u) = a { | ^^^^^^^ with this pattern, prefixed by a: error: this `if let` can be collapsed into the outer `if let` - --> tests/ui/collapsible_match.rs:282:9 + --> tests/ui/collapsible_match.rs:292:9 | LL | / if let Some(u) = a { LL | | @@ -217,12 +235,12 @@ LL | | } | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match.rs:281:35 + --> tests/ui/collapsible_match.rs:291:35 | LL | if let Issue9647::A { a: Some(a), .. } = x { | ^ replace this binding LL | if let Some(u) = a { | ^^^^^^^ with this pattern -error: aborting due to 12 previous errors +error: aborting due to 13 previous errors From 790fb9396a14e4686ff4b5ab88d91577cffe1d44 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Thu, 2 May 2024 04:58:28 +0200 Subject: [PATCH 41/47] check for `matches!` macro directly in `redundant_guards` --- clippy_lints/src/matches/redundant_guards.rs | 24 ++++---------- tests/ui/redundant_guards.fixed | 12 +++++++ tests/ui/redundant_guards.rs | 12 +++++++ tests/ui/redundant_guards.stderr | 34 ++++++++++---------- 4 files changed, 48 insertions(+), 34 deletions(-) diff --git a/clippy_lints/src/matches/redundant_guards.rs b/clippy_lints/src/matches/redundant_guards.rs index 984aa3d73708..a75cf37945f7 100644 --- a/clippy_lints/src/matches/redundant_guards.rs +++ b/clippy_lints/src/matches/redundant_guards.rs @@ -1,15 +1,16 @@ use clippy_config::msrvs::Msrv; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::macros::matching_root_macro_call; use clippy_utils::source::snippet; use clippy_utils::visitors::{for_each_expr, is_local_used}; use clippy_utils::{in_constant, path_to_local}; use rustc_ast::{BorrowKind, LitKind}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{Arm, BinOpKind, Expr, ExprKind, MatchSource, Node, Pat, PatKind, UnOp}; +use rustc_hir::{Arm, BinOpKind, Expr, ExprKind, MatchSource, Node, PatKind, UnOp}; use rustc_lint::LateContext; use rustc_span::symbol::Ident; -use rustc_span::{Span, Symbol}; +use rustc_span::{sym, Span, Symbol}; use std::borrow::Cow; use std::ops::ControlFlow; @@ -22,21 +23,10 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>], msrv: }; // `Some(x) if matches!(x, y)` - if let ExprKind::Match( - scrutinee, - [ - arm, - Arm { - pat: Pat { - kind: PatKind::Wild, .. - }, - .. - }, - ], - MatchSource::Normal, - ) = guard.kind + if let ExprKind::Match(scrutinee, [arm, _], MatchSource::Normal) = guard.kind + && matching_root_macro_call(cx, guard.span, sym::matches_macro).is_some() && let Some(binding) = get_pat_binding(cx, scrutinee, outer_arm) - && !pat_contains_disallowed_or(&arm.pat, msrv) + && !pat_contains_disallowed_or(arm.pat, msrv) { let pat_span = match (arm.pat.kind, binding.byref_ident) { (PatKind::Ref(pat, _), Some(_)) => pat.span, @@ -55,7 +45,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>], msrv: // `Some(x) if let Some(2) = x` else if let ExprKind::Let(let_expr) = guard.kind && let Some(binding) = get_pat_binding(cx, let_expr.init, outer_arm) - && !pat_contains_disallowed_or(&let_expr.pat, msrv) + && !pat_contains_disallowed_or(let_expr.pat, msrv) { let pat_span = match (let_expr.pat.kind, binding.byref_ident) { (PatKind::Ref(pat, _), Some(_)) => pat.span, diff --git a/tests/ui/redundant_guards.fixed b/tests/ui/redundant_guards.fixed index ded91e083769..ed4b1c219150 100644 --- a/tests/ui/redundant_guards.fixed +++ b/tests/ui/redundant_guards.fixed @@ -136,6 +136,18 @@ fn f(s: Option) { } } +fn not_matches() { + match Some(42) { + // The pattern + guard is not equivalent to `Some(42)` because of the `panic!` + Some(v) + if match v { + 42 => true, + _ => panic!(), + } => {}, + _ => {}, + } +} + struct S { a: usize, } diff --git a/tests/ui/redundant_guards.rs b/tests/ui/redundant_guards.rs index 2aaa2ace3982..adbc4ed16cd7 100644 --- a/tests/ui/redundant_guards.rs +++ b/tests/ui/redundant_guards.rs @@ -136,6 +136,18 @@ fn f(s: Option) { } } +fn not_matches() { + match Some(42) { + // The pattern + guard is not equivalent to `Some(42)` because of the `panic!` + Some(v) + if match v { + 42 => true, + _ => panic!(), + } => {}, + _ => {}, + } +} + struct S { a: usize, } diff --git a/tests/ui/redundant_guards.stderr b/tests/ui/redundant_guards.stderr index 01ca91fcd09e..fd12e0832823 100644 --- a/tests/ui/redundant_guards.stderr +++ b/tests/ui/redundant_guards.stderr @@ -132,7 +132,7 @@ LL + 1 => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:174:28 + --> tests/ui/redundant_guards.rs:186:28 | LL | Some(ref x) if x == &1 => {}, | ^^^^^^^ @@ -144,7 +144,7 @@ LL + Some(1) => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:175:28 + --> tests/ui/redundant_guards.rs:187:28 | LL | Some(ref x) if &1 == x => {}, | ^^^^^^^ @@ -156,7 +156,7 @@ LL + Some(1) => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:176:28 + --> tests/ui/redundant_guards.rs:188:28 | LL | Some(ref x) if let &2 = x => {}, | ^^^^^^^^^^ @@ -168,7 +168,7 @@ LL + Some(2) => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:177:28 + --> tests/ui/redundant_guards.rs:189:28 | LL | Some(ref x) if matches!(x, &3) => {}, | ^^^^^^^^^^^^^^^ @@ -180,7 +180,7 @@ LL + Some(3) => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:197:32 + --> tests/ui/redundant_guards.rs:209:32 | LL | B { ref c, .. } if c == &1 => {}, | ^^^^^^^ @@ -192,7 +192,7 @@ LL + B { c: 1, .. } => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:198:32 + --> tests/ui/redundant_guards.rs:210:32 | LL | B { ref c, .. } if &1 == c => {}, | ^^^^^^^ @@ -204,7 +204,7 @@ LL + B { c: 1, .. } => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:199:32 + --> tests/ui/redundant_guards.rs:211:32 | LL | B { ref c, .. } if let &1 = c => {}, | ^^^^^^^^^^ @@ -216,7 +216,7 @@ LL + B { c: 1, .. } => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:200:32 + --> tests/ui/redundant_guards.rs:212:32 | LL | B { ref c, .. } if matches!(c, &1) => {}, | ^^^^^^^^^^^^^^^ @@ -228,7 +228,7 @@ LL + B { c: 1, .. } => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:210:26 + --> tests/ui/redundant_guards.rs:222:26 | LL | Some(Some(x)) if x.is_empty() => {}, | ^^^^^^^^^^^^ @@ -240,7 +240,7 @@ LL + Some(Some("")) => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:221:26 + --> tests/ui/redundant_guards.rs:233:26 | LL | Some(Some(x)) if x.is_empty() => {}, | ^^^^^^^^^^^^ @@ -252,7 +252,7 @@ LL + Some(Some([])) => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:226:26 + --> tests/ui/redundant_guards.rs:238:26 | LL | Some(Some(x)) if x.is_empty() => {}, | ^^^^^^^^^^^^ @@ -264,7 +264,7 @@ LL + Some(Some([])) => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:237:26 + --> tests/ui/redundant_guards.rs:249:26 | LL | Some(Some(x)) if x.starts_with(&[]) => {}, | ^^^^^^^^^^^^^^^^^^ @@ -276,7 +276,7 @@ LL + Some(Some([..])) => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:242:26 + --> tests/ui/redundant_guards.rs:254:26 | LL | Some(Some(x)) if x.starts_with(&[1]) => {}, | ^^^^^^^^^^^^^^^^^^^ @@ -288,7 +288,7 @@ LL + Some(Some([1, ..])) => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:247:26 + --> tests/ui/redundant_guards.rs:259:26 | LL | Some(Some(x)) if x.starts_with(&[1, 2]) => {}, | ^^^^^^^^^^^^^^^^^^^^^^ @@ -300,7 +300,7 @@ LL + Some(Some([1, 2, ..])) => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:252:26 + --> tests/ui/redundant_guards.rs:264:26 | LL | Some(Some(x)) if x.ends_with(&[1, 2]) => {}, | ^^^^^^^^^^^^^^^^^^^^ @@ -312,7 +312,7 @@ LL + Some(Some([.., 1, 2])) => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:274:18 + --> tests/ui/redundant_guards.rs:286:18 | LL | y if y.is_empty() => {}, | ^^^^^^^^^^^^ @@ -324,7 +324,7 @@ LL + "" => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:293:22 + --> tests/ui/redundant_guards.rs:305:22 | LL | y if y.is_empty() => {}, | ^^^^^^^^^^^^ From 5e05821af33d98d06242940417de6c915950c391 Mon Sep 17 00:00:00 2001 From: "Christopher B. Speir" Date: Wed, 1 May 2024 22:23:31 -0500 Subject: [PATCH 42/47] Remove clippy_utils::paths::{SLICE_GET, STR_BYTES} Both clippy_utils::paths::SLICE_GET and clippy_utils::paths::STR_BYTES are dead_code and can therefore be removed. --- clippy_utils/src/paths.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 0e26b3bfd624..2836df0926d4 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -73,7 +73,6 @@ pub const REGEX_NEW: [&str; 3] = ["regex", "Regex", "new"]; pub const REGEX_SET_NEW: [&str; 3] = ["regex", "RegexSet", "new"]; pub const SERDE_DESERIALIZE: [&str; 3] = ["serde", "de", "Deserialize"]; pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"]; -pub const SLICE_GET: [&str; 4] = ["core", "slice", "", "get"]; pub const SLICE_INTO_VEC: [&str; 4] = ["alloc", "slice", "", "into_vec"]; pub const SLICE_INTO: [&str; 4] = ["core", "slice", "", "iter"]; pub const STD_IO_SEEK_FROM_CURRENT: [&str; 4] = ["std", "io", "SeekFrom", "Current"]; @@ -81,7 +80,6 @@ pub const STD_IO_SEEKFROM_START: [&str; 4] = ["std", "io", "SeekFrom", "Start"]; pub const STRING_AS_MUT_STR: [&str; 4] = ["alloc", "string", "String", "as_mut_str"]; pub const STRING_AS_STR: [&str; 4] = ["alloc", "string", "String", "as_str"]; pub const STRING_NEW: [&str; 4] = ["alloc", "string", "String", "new"]; -pub const STR_BYTES: [&str; 4] = ["core", "str", "", "bytes"]; pub const STR_CHARS: [&str; 4] = ["core", "str", "", "chars"]; pub const STR_ENDS_WITH: [&str; 4] = ["core", "str", "", "ends_with"]; pub const STR_LEN: [&str; 4] = ["core", "str", "", "len"]; From 5c23f138dd5217e9b7cef3717540f05d76d7ce3d Mon Sep 17 00:00:00 2001 From: Fridtjof Stoldt Date: Mon, 29 Apr 2024 22:15:05 +0200 Subject: [PATCH 43/47] Apply suggestions from code review <3 Co-authored-by: Timo <30553356+y21@users.noreply.github.com> --- CHANGELOG.md | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d908ed43cfae..9c9ea1140814 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,14 +14,6 @@ Current stable, released 2024-05-02 [View all 112 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2024-01-26T05%3A46%3A23Z..2024-03-07T16%3A25%3A52Z+base%3Amaster) -### Important Changes - -* In a few versions, `cargo-clippy` will now no longer ignore the first argument. - Passing in `clippy` as the first argument like cargo does will continue to work. - However, arguments like `--fix` will soon issue a warning and will no longer be. - `cargo clippy` (without `-`!) is unaffected by this change. - [#9461](https://github.com/rust-lang/rust-clippy/pull/9461) - ### New Lints * [`assigning_clones`] @@ -51,11 +43,6 @@ Current stable, released 2024-05-02 * [`incompatible_msrv`] [#12160](https://github.com/rust-lang/rust-clippy/pull/12160) -### Moves and Deprecations - -* Moved [`mixed_attributes_style`] to `style` (Remains warn-by-default) - [#12572](https://github.com/rust-lang/rust-clippy/pull/12572) - ### Enhancements * [`thread_local_initializer_can_be_made_const`]: Now checks the [`msrv`] configuration @@ -67,9 +54,9 @@ Current stable, released 2024-05-02 ### ICE Fixes -* [`ptr_as_ptr`]: No longer ICEs on types from other crates +* [`ptr_as_ptr`]: No longer ICEs when the cast source is a function call to a local variable [#12617](https://github.com/rust-lang/rust-clippy/pull/12617) -* [`cast_sign_loss`]: Avoids an infinit loop when casting two changed `.unwrap()` calls +* [`cast_sign_loss`]: Avoids an infinite loop when casting two chained `.unwrap()` calls [#12508](https://github.com/rust-lang/rust-clippy/pull/12508) ## Rust 1.77 From dcfc3b5de1375c6984e8d3f829d50b940e5bab07 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 2 May 2024 12:44:40 +0200 Subject: [PATCH 44/47] Bump ui_test to 0.23 --- Cargo.toml | 2 +- tests/compile-test.rs | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 43f20ecedc21..bbd8ccb88b4f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,7 +30,7 @@ color-print = "0.3.4" anstream = "0.6.0" [dev-dependencies] -ui_test = "0.22.2" +ui_test = "0.23" regex = "1.5.5" toml = "0.7.3" walkdir = "2.3" diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 32a31f5e0823..b06a11702ec8 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -4,6 +4,7 @@ #![warn(rust_2018_idioms, unused_lifetimes)] #![allow(unused_extern_crates)] +use ui_test::custom_flags::rustfix::RustfixMode; use ui_test::spanned::Spanned; use ui_test::{status_emitter, Args, CommandBuilder, Config, Match, Mode, OutputConflictHandling}; @@ -122,10 +123,11 @@ fn base_config(test_dir: &str) -> (Config, Args) { out_dir: target_dir.join("ui_test"), ..Config::rustc(Path::new("tests").join(test_dir)) }; - config.comment_defaults.base().mode = Some(Spanned::dummy(Mode::Yolo { - rustfix: ui_test::RustfixMode::Everything, - })) - .into(); + config.comment_defaults.base().mode = Some(Spanned::dummy(Mode::Yolo)).into(); + config + .comment_defaults + .base() + .set_custom("rustfix", RustfixMode::Everything); config.comment_defaults.base().diagnostic_code_prefix = Some(Spanned::dummy("clippy::".into())).into(); config.with_args(&args); let current_exe_path = env::current_exe().unwrap(); @@ -235,13 +237,12 @@ fn run_ui_cargo() { .push(("RUSTFLAGS".into(), Some("-Dwarnings".into()))); // We need to do this while we still have a rustc in the `program` field. config.fill_host_and_target().unwrap(); - config.dependencies_crate_manifest_path = None; config.program.program.set_file_name(if cfg!(windows) { "cargo-clippy.exe" } else { "cargo-clippy" }); - config.comment_defaults.base().edition = Default::default(); + config.comment_defaults.base().custom.clear(); config .comment_defaults From 76b95fd2492389714e132dbd6b20142128cbe747 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 2 May 2024 14:21:19 +0200 Subject: [PATCH 45/47] Bump Clippy version -> 0.1.80 --- Cargo.toml | 2 +- clippy_config/Cargo.toml | 2 +- clippy_lints/Cargo.toml | 2 +- clippy_utils/Cargo.toml | 2 +- declare_clippy_lint/Cargo.toml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 43f20ecedc21..a932cc6e5e4b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.1.79" +version = "0.1.80" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" diff --git a/clippy_config/Cargo.toml b/clippy_config/Cargo.toml index 8ba2ab566256..7f7dc9d6cfb0 100644 --- a/clippy_config/Cargo.toml +++ b/clippy_config/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_config" -version = "0.1.79" +version = "0.1.80" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index 1d954607eee8..5e3a119337cc 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_lints" -version = "0.1.79" +version = "0.1.80" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" diff --git a/clippy_utils/Cargo.toml b/clippy_utils/Cargo.toml index d2bb719a517f..ab883c25338b 100644 --- a/clippy_utils/Cargo.toml +++ b/clippy_utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_utils" -version = "0.1.79" +version = "0.1.80" edition = "2021" publish = false diff --git a/declare_clippy_lint/Cargo.toml b/declare_clippy_lint/Cargo.toml index 9a3a41e1d1ea..c8c734c3a7c9 100644 --- a/declare_clippy_lint/Cargo.toml +++ b/declare_clippy_lint/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "declare_clippy_lint" -version = "0.1.79" +version = "0.1.80" edition = "2021" publish = false From d878e0e8eedd18b03339435d983f04f202e83949 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 2 May 2024 14:21:32 +0200 Subject: [PATCH 46/47] Bump nightly version -> 2024-05-02 --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 521c0d12983d..055f305eb8e1 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2024-04-18" +channel = "nightly-2024-05-02" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] From e395dc9000b6f19aae52584c97b83b40e7e3a556 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 2 May 2024 17:27:08 +0200 Subject: [PATCH 47/47] Update Cargo.lock --- Cargo.lock | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ca69536855ec..7e4db4fdd53e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -120,6 +120,16 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "annotate-snippets" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5a59f105fb9635e9eebdc1e29d53e764fa5795b9cf899a638a53e61567ef61" +dependencies = [ + "anstyle", + "unicode-width", +] + [[package]] name = "ansi_term" version = "0.12.1" @@ -574,7 +584,7 @@ checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" [[package]] name = "clippy" -version = "0.1.79" +version = "0.1.80" dependencies = [ "anstream", "clippy_config", @@ -595,13 +605,13 @@ dependencies = [ "termize", "tokio", "toml 0.7.8", - "ui_test 0.22.3", + "ui_test 0.23.0", "walkdir", ] [[package]] name = "clippy_config" -version = "0.1.79" +version = "0.1.80" dependencies = [ "rustc-semver", "serde", @@ -624,7 +634,7 @@ dependencies = [ [[package]] name = "clippy_lints" -version = "0.1.79" +version = "0.1.80" dependencies = [ "arrayvec", "cargo_metadata 0.18.1", @@ -649,7 +659,7 @@ dependencies = [ [[package]] name = "clippy_utils" -version = "0.1.79" +version = "0.1.80" dependencies = [ "arrayvec", "clippy_config", @@ -968,7 +978,7 @@ checksum = "a0afaad2b26fa326569eb264b1363e8ae3357618c43982b3f285f0774ce76b69" [[package]] name = "declare_clippy_lint" -version = "0.1.79" +version = "0.1.80" dependencies = [ "itertools 0.12.1", "quote", @@ -5160,9 +5170,9 @@ dependencies = [ [[package]] name = "spanned" -version = "0.1.6" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad48ded9f0734eca7058107cc170767b8758e41e4088fb0020e7ff7ec6b0d92d" +checksum = "ccdf4f5590b7e6fbd4f2e80d442789079a6fff7c12ef921a9de358b7b353098e" dependencies = [ "bstr", "color-eyre", @@ -5900,11 +5910,11 @@ dependencies = [ [[package]] name = "ui_test" -version = "0.22.3" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa577a42db0e211a73c069d7dbcae54bc7473a7c5535a564842cbd8a13c0441e" +checksum = "29e5f4ffcbab82453958fbf59990e981b8e8a177dcd60c2bd8f9b52c3036a6e1" dependencies = [ - "annotate-snippets 0.10.2", + "annotate-snippets 0.11.2", "anyhow", "bstr", "cargo-platform", @@ -5919,7 +5929,7 @@ dependencies = [ "prettydiff", "regex", "rustc_version", - "rustfix 0.6.1", + "rustfix 0.8.1", "serde", "serde_json", "spanned",