From c6cc160ec695b23f17df2a3840141093ae0c466b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maja=20K=C4=85dzio=C5=82ka?= Date: Wed, 5 Jun 2024 23:29:37 +0200 Subject: [PATCH 01/73] needless_borrows_for_generic_args: Fix for &mut MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit fixes a bug introduced in #12706, where the behavior of the lint has been changed, to avoid suggestions that introduce a move. The motivation in the commit message is quite poor (if the detection for significant drops is not sufficient because it's not transitive, the proper fix would be to make it transitive). However, #12454, the linked issue, provides a good reason for the change — if the value being borrowed is bound to a variable, then moving it will only introduce friction into future refactorings. Thus #12706 changes the logic so that the lint triggers if the value being borrowed is Copy, or is the result of a function call, simplifying the logic to the point where analysing "is this the only use of this value" isn't necessary. However, said PR also introduces an undocumented carveout, where referents that themselves are mutable references are treated as Copy, to catch some cases that we do want to lint against. However, that is not sound — it's possible to consume a mutable reference by moving it. To avoid emitting false suggestions, this PR reintroduces the referent_used_exactly_once logic and runs that check for referents that are themselves mutable references. Thinking about the code shape of &mut x, where x: &mut T, raises the point that while removing the &mut outright won't work, the extra indirection is still undesirable, and perhaps instead we should suggest reborrowing: &mut *x. That, however, is left as possible future work. Fixes #12856 --- .../src/needless_borrows_for_generic_args.rs | 48 +++++++++++++++++-- .../needless_borrows_for_generic_args.fixed | 8 ++++ tests/ui/needless_borrows_for_generic_args.rs | 8 ++++ 3 files changed, 59 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/needless_borrows_for_generic_args.rs b/clippy_lints/src/needless_borrows_for_generic_args.rs index daf166bad90d..71073716cf8b 100644 --- a/clippy_lints/src/needless_borrows_for_generic_args.rs +++ b/clippy_lints/src/needless_borrows_for_generic_args.rs @@ -1,6 +1,6 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::mir::PossibleBorrowerMap; +use clippy_utils::mir::{enclosing_mir, expr_local, local_assignments, used_exactly_once, PossibleBorrowerMap}; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{implements_trait, is_copy}; use clippy_utils::{expr_use_ctxt, peel_n_hir_expr_refs, DefinedTy, ExprUseNode}; @@ -11,6 +11,7 @@ use rustc_hir::{Body, Expr, ExprKind, Mutability, Path, QPath}; use rustc_index::bit_set::BitSet; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::mir::{Rvalue, StatementKind}; use rustc_middle::ty::{ self, ClauseKind, EarlyBinder, FnSig, GenericArg, GenericArgKind, ParamTy, ProjectionPredicate, Ty, }; @@ -105,6 +106,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowsForGenericArgs<'tcx> { } && let count = needless_borrow_count( cx, + &mut self.possible_borrowers, fn_id, cx.typeck_results().node_args(hir_id), i, @@ -153,9 +155,14 @@ fn path_has_args(p: &QPath<'_>) -> bool { /// The following constraints will be checked: /// * The borrowed expression meets all the generic type's constraints. /// * The generic type appears only once in the functions signature. -/// * The borrowed value is Copy itself OR not a variable (created by a function call) +/// * The borrowed value is: +/// - `Copy` itself, or +/// - the only use of a mutable reference, or +/// - not a variable (created by a function call) +#[expect(clippy::too_many_arguments)] fn needless_borrow_count<'tcx>( cx: &LateContext<'tcx>, + possible_borrowers: &mut Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>, fn_id: DefId, callee_args: ty::GenericArgsRef<'tcx>, arg_index: usize, @@ -230,9 +237,9 @@ fn needless_borrow_count<'tcx>( let referent_ty = cx.typeck_results().expr_ty(referent); - if (!is_copy(cx, referent_ty) && !referent_ty.is_ref()) - && let ExprKind::AddrOf(_, _, inner) = reference.kind - && !matches!(inner.kind, ExprKind::Call(..) | ExprKind::MethodCall(..)) + if !(is_copy(cx, referent_ty) + || referent_ty.is_ref() && referent_used_exactly_once(cx, possible_borrowers, reference) + || matches!(referent.kind, ExprKind::Call(..) | ExprKind::MethodCall(..))) { return false; } @@ -335,6 +342,37 @@ fn is_mixed_projection_predicate<'tcx>( } } +fn referent_used_exactly_once<'tcx>( + cx: &LateContext<'tcx>, + possible_borrowers: &mut Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>, + reference: &Expr<'tcx>, +) -> bool { + if let Some(mir) = enclosing_mir(cx.tcx, reference.hir_id) + && let Some(local) = expr_local(cx.tcx, reference) + && let [location] = *local_assignments(mir, local).as_slice() + && let block_data = &mir.basic_blocks[location.block] + && let Some(statement) = block_data.statements.get(location.statement_index) + && let StatementKind::Assign(box (_, Rvalue::Ref(_, _, place))) = statement.kind + && !place.is_indirect_first_projection() + { + let body_owner_local_def_id = cx.tcx.hir().enclosing_body_owner(reference.hir_id); + if possible_borrowers + .last() + .map_or(true, |&(local_def_id, _)| local_def_id != body_owner_local_def_id) + { + possible_borrowers.push((body_owner_local_def_id, PossibleBorrowerMap::new(cx, mir))); + } + let possible_borrower = &mut possible_borrowers.last_mut().unwrap().1; + // If `only_borrowers` were used here, the `copyable_iterator::warn` test would fail. The reason is + // that `PossibleBorrowerVisitor::visit_terminator` considers `place.local` a possible borrower of + // itself. See the comment in that method for an explanation as to why. + possible_borrower.bounded_borrowers(&[local], &[local, place.local], place.local, location) + && used_exactly_once(mir, place.local).unwrap_or(false) + } else { + false + } +} + // Iteratively replaces `param_ty` with `new_ty` in `args`, and similarly for each resulting // projected type that is a type parameter. Returns `false` if replacing the types would have an // effect on the function signature beyond substituting `new_ty` for `param_ty`. diff --git a/tests/ui/needless_borrows_for_generic_args.fixed b/tests/ui/needless_borrows_for_generic_args.fixed index 5478372cbe00..593649b60bc7 100644 --- a/tests/ui/needless_borrows_for_generic_args.fixed +++ b/tests/ui/needless_borrows_for_generic_args.fixed @@ -333,4 +333,12 @@ fn main() { f(&y); // Don't lint f("".to_owned()); // Lint } + { + fn takes_writer(_: T) {} + + fn f(mut buffer: &mut Vec) { + takes_writer(&mut buffer); // Don't lint, would make buffer unavailable later + buffer.extend(b"\n"); + } + } } diff --git a/tests/ui/needless_borrows_for_generic_args.rs b/tests/ui/needless_borrows_for_generic_args.rs index 2643815d939b..0c9b98d739d3 100644 --- a/tests/ui/needless_borrows_for_generic_args.rs +++ b/tests/ui/needless_borrows_for_generic_args.rs @@ -333,4 +333,12 @@ fn main() { f(&y); // Don't lint f(&"".to_owned()); // Lint } + { + fn takes_writer(_: T) {} + + fn f(mut buffer: &mut Vec) { + takes_writer(&mut buffer); // Don't lint, would make buffer unavailable later + buffer.extend(b"\n"); + } + } } From 37d8462bd92e0648e65aebc4cecd54e9840e3fe6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Thu, 4 Jul 2024 21:23:55 +0200 Subject: [PATCH 02/73] fix tests after rebase --- tests/ui/from_str_radix_10.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ui/from_str_radix_10.rs b/tests/ui/from_str_radix_10.rs index 2d5b351f8da3..0df6a0a202ae 100644 --- a/tests/ui/from_str_radix_10.rs +++ b/tests/ui/from_str_radix_10.rs @@ -1,4 +1,3 @@ -#![feature(const_int_from_str)] #![warn(clippy::from_str_radix_10)] mod some_mod { @@ -61,7 +60,8 @@ fn main() -> Result<(), Box> { Ok(()) } -fn issue_12732() { +// https://github.com/rust-lang/rust-clippy/issues/12731 +fn issue_12731() { const A: Result = u32::from_str_radix("123", 10); const B: () = { let _ = u32::from_str_radix("123", 10); From 26cdeed27e2304b6820016ee7fbcdb2331f9b113 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Thu, 4 Jul 2024 22:31:53 +0200 Subject: [PATCH 03/73] bless tests --- tests/ui/from_str_radix_10.fixed | 4 ++-- tests/ui/from_str_radix_10.stderr | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/ui/from_str_radix_10.fixed b/tests/ui/from_str_radix_10.fixed index f9ce1defda17..6c582190b442 100644 --- a/tests/ui/from_str_radix_10.fixed +++ b/tests/ui/from_str_radix_10.fixed @@ -1,4 +1,3 @@ -#![feature(const_int_from_str)] #![warn(clippy::from_str_radix_10)] mod some_mod { @@ -61,7 +60,8 @@ fn main() -> Result<(), Box> { Ok(()) } -fn issue_12732() { +// https://github.com/rust-lang/rust-clippy/issues/12731 +fn issue_12731() { const A: Result = u32::from_str_radix("123", 10); const B: () = { let _ = u32::from_str_radix("123", 10); diff --git a/tests/ui/from_str_radix_10.stderr b/tests/ui/from_str_radix_10.stderr index 01a1bf8940a1..4aa84eca2612 100644 --- a/tests/ui/from_str_radix_10.stderr +++ b/tests/ui/from_str_radix_10.stderr @@ -1,5 +1,5 @@ error: this call to `from_str_radix` can be replaced with a call to `str::parse` - --> tests/ui/from_str_radix_10.rs:29:5 + --> tests/ui/from_str_radix_10.rs:28:5 | LL | u32::from_str_radix("30", 10)?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"30".parse::()` @@ -8,43 +8,43 @@ LL | u32::from_str_radix("30", 10)?; = help: to override `-D warnings` add `#[allow(clippy::from_str_radix_10)]` error: this call to `from_str_radix` can be replaced with a call to `str::parse` - --> tests/ui/from_str_radix_10.rs:32:5 + --> tests/ui/from_str_radix_10.rs:31:5 | LL | i64::from_str_radix("24", 10)?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"24".parse::()` error: this call to `from_str_radix` can be replaced with a call to `str::parse` - --> tests/ui/from_str_radix_10.rs:34:5 + --> tests/ui/from_str_radix_10.rs:33:5 | LL | isize::from_str_radix("100", 10)?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"100".parse::()` error: this call to `from_str_radix` can be replaced with a call to `str::parse` - --> tests/ui/from_str_radix_10.rs:36:5 + --> tests/ui/from_str_radix_10.rs:35:5 | LL | u8::from_str_radix("7", 10)?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"7".parse::()` error: this call to `from_str_radix` can be replaced with a call to `str::parse` - --> tests/ui/from_str_radix_10.rs:38:5 + --> tests/ui/from_str_radix_10.rs:37:5 | LL | u16::from_str_radix(&("10".to_owned() + "5"), 10)?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `("10".to_owned() + "5").parse::()` error: this call to `from_str_radix` can be replaced with a call to `str::parse` - --> tests/ui/from_str_radix_10.rs:40:5 + --> tests/ui/from_str_radix_10.rs:39:5 | LL | i128::from_str_radix(Test + Test, 10)?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(Test + Test).parse::()` error: this call to `from_str_radix` can be replaced with a call to `str::parse` - --> tests/ui/from_str_radix_10.rs:44:5 + --> tests/ui/from_str_radix_10.rs:43:5 | LL | i32::from_str_radix(string, 10)?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `string.parse::()` error: this call to `from_str_radix` can be replaced with a call to `str::parse` - --> tests/ui/from_str_radix_10.rs:48:5 + --> tests/ui/from_str_radix_10.rs:47:5 | LL | i32::from_str_radix(&stringier, 10)?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `stringier.parse::()` From 5f3a6e1805dc59417fbc79734b97f4dc532d4484 Mon Sep 17 00:00:00 2001 From: Urgau Date: Tue, 20 Feb 2024 22:19:26 +0100 Subject: [PATCH 04/73] Remove unary neg from `clippy::precedence` lint --- clippy_lints/src/precedence.rs | 56 +-------------------------------- tests/ui/precedence.fixed | 34 -------------------- tests/ui/precedence.rs | 34 -------------------- tests/ui/precedence.stderr | 32 +------------------ tests/ui/unnecessary_cast.fixed | 2 +- tests/ui/unnecessary_cast.rs | 2 +- 6 files changed, 4 insertions(+), 156 deletions(-) diff --git a/clippy_lints/src/precedence.rs b/clippy_lints/src/precedence.rs index ff83725da691..37f5dd5583bf 100644 --- a/clippy_lints/src/precedence.rs +++ b/clippy_lints/src/precedence.rs @@ -1,38 +1,17 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; -use rustc_ast::ast::{BinOpKind, Expr, ExprKind, MethodCall, UnOp}; -use rustc_ast::token; +use rustc_ast::ast::{BinOpKind, Expr, ExprKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::declare_lint_pass; use rustc_span::source_map::Spanned; -const ALLOWED_ODD_FUNCTIONS: [&str; 14] = [ - "asin", - "asinh", - "atan", - "atanh", - "cbrt", - "fract", - "round", - "signum", - "sin", - "sinh", - "tan", - "tanh", - "to_degrees", - "to_radians", -]; - declare_clippy_lint! { /// ### What it does /// Checks for operations where precedence may be unclear /// and suggests to add parentheses. Currently it catches the following: /// * mixed usage of arithmetic and bit shifting/combining operators without /// parentheses - /// * a "negative" numeric literal (which is really a unary `-` followed by a - /// numeric literal) - /// followed by a method call /// /// ### Why is this bad? /// Not everyone knows the precedence of those operators by @@ -41,7 +20,6 @@ declare_clippy_lint! { /// /// ### Example /// * `1 << 2 + 3` equals 32, while `(1 << 2) + 3` equals 7 - /// * `-1i32.abs()` equals -1, while `(-1i32).abs()` equals 1 #[clippy::version = "pre 1.29.0"] pub PRECEDENCE, complexity, @@ -104,38 +82,6 @@ impl EarlyLintPass for Precedence { (false, false) => (), } } - - if let ExprKind::Unary(UnOp::Neg, operand) = &expr.kind { - let mut arg = operand; - - let mut all_odd = true; - while let ExprKind::MethodCall(box MethodCall { seg, receiver, .. }) = &arg.kind { - let seg_str = seg.ident.name.as_str(); - all_odd &= ALLOWED_ODD_FUNCTIONS - .iter() - .any(|odd_function| **odd_function == *seg_str); - arg = receiver; - } - - if !all_odd - && let ExprKind::Lit(lit) = &arg.kind - && let token::LitKind::Integer | token::LitKind::Float = &lit.kind - { - let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - PRECEDENCE, - expr.span, - "unary minus has lower precedence than method call", - "consider adding parentheses to clarify your intent", - format!( - "-({})", - snippet_with_applicability(cx, operand.span, "..", &mut applicability) - ), - applicability, - ); - } - } } } diff --git a/tests/ui/precedence.fixed b/tests/ui/precedence.fixed index cc87de0d90f1..c25c2062aceb 100644 --- a/tests/ui/precedence.fixed +++ b/tests/ui/precedence.fixed @@ -20,40 +20,6 @@ fn main() { 1 ^ (1 - 1); 3 | (2 - 1); 3 & (5 - 2); - -(1i32.abs()); - -(1f32.abs()); - - // These should not trigger an error - let _ = (-1i32).abs(); - let _ = (-1f32).abs(); - let _ = -(1i32).abs(); - let _ = -(1f32).abs(); - let _ = -(1i32.abs()); - let _ = -(1f32.abs()); - - // Odd functions should not trigger an error - let _ = -1f64.asin(); - let _ = -1f64.asinh(); - let _ = -1f64.atan(); - let _ = -1f64.atanh(); - let _ = -1f64.cbrt(); - let _ = -1f64.fract(); - let _ = -1f64.round(); - let _ = -1f64.signum(); - let _ = -1f64.sin(); - let _ = -1f64.sinh(); - let _ = -1f64.tan(); - let _ = -1f64.tanh(); - let _ = -1f64.to_degrees(); - let _ = -1f64.to_radians(); - - // Chains containing any non-odd function should trigger (issue #5924) - let _ = -(1.0_f64.cos().cos()); - let _ = -(1.0_f64.cos().sin()); - let _ = -(1.0_f64.sin().cos()); - - // Chains of odd functions shouldn't trigger - let _ = -1f64.sin().sin(); let b = 3; trip!(b * 8); diff --git a/tests/ui/precedence.rs b/tests/ui/precedence.rs index 00c18d92b5fb..dc242ecf4c72 100644 --- a/tests/ui/precedence.rs +++ b/tests/ui/precedence.rs @@ -20,40 +20,6 @@ fn main() { 1 ^ 1 - 1; 3 | 2 - 1; 3 & 5 - 2; - -1i32.abs(); - -1f32.abs(); - - // These should not trigger an error - let _ = (-1i32).abs(); - let _ = (-1f32).abs(); - let _ = -(1i32).abs(); - let _ = -(1f32).abs(); - let _ = -(1i32.abs()); - let _ = -(1f32.abs()); - - // Odd functions should not trigger an error - let _ = -1f64.asin(); - let _ = -1f64.asinh(); - let _ = -1f64.atan(); - let _ = -1f64.atanh(); - let _ = -1f64.cbrt(); - let _ = -1f64.fract(); - let _ = -1f64.round(); - let _ = -1f64.signum(); - let _ = -1f64.sin(); - let _ = -1f64.sinh(); - let _ = -1f64.tan(); - let _ = -1f64.tanh(); - let _ = -1f64.to_degrees(); - let _ = -1f64.to_radians(); - - // Chains containing any non-odd function should trigger (issue #5924) - let _ = -1.0_f64.cos().cos(); - let _ = -1.0_f64.cos().sin(); - let _ = -1.0_f64.sin().cos(); - - // Chains of odd functions shouldn't trigger - let _ = -1f64.sin().sin(); let b = 3; trip!(b * 8); diff --git a/tests/ui/precedence.stderr b/tests/ui/precedence.stderr index 47e61326219d..8057c25a5e49 100644 --- a/tests/ui/precedence.stderr +++ b/tests/ui/precedence.stderr @@ -43,35 +43,5 @@ error: operator precedence can trip the unwary LL | 3 & 5 - 2; | ^^^^^^^^^ help: consider parenthesizing your expression: `3 & (5 - 2)` -error: unary minus has lower precedence than method call - --> tests/ui/precedence.rs:23:5 - | -LL | -1i32.abs(); - | ^^^^^^^^^^^ help: consider adding parentheses to clarify your intent: `-(1i32.abs())` - -error: unary minus has lower precedence than method call - --> tests/ui/precedence.rs:24:5 - | -LL | -1f32.abs(); - | ^^^^^^^^^^^ help: consider adding parentheses to clarify your intent: `-(1f32.abs())` - -error: unary minus has lower precedence than method call - --> tests/ui/precedence.rs:51:13 - | -LL | let _ = -1.0_f64.cos().cos(); - | ^^^^^^^^^^^^^^^^^^^^ help: consider adding parentheses to clarify your intent: `-(1.0_f64.cos().cos())` - -error: unary minus has lower precedence than method call - --> tests/ui/precedence.rs:52:13 - | -LL | let _ = -1.0_f64.cos().sin(); - | ^^^^^^^^^^^^^^^^^^^^ help: consider adding parentheses to clarify your intent: `-(1.0_f64.cos().sin())` - -error: unary minus has lower precedence than method call - --> tests/ui/precedence.rs:53:13 - | -LL | let _ = -1.0_f64.sin().cos(); - | ^^^^^^^^^^^^^^^^^^^^ help: consider adding parentheses to clarify your intent: `-(1.0_f64.sin().cos())` - -error: aborting due to 12 previous errors +error: aborting due to 7 previous errors diff --git a/tests/ui/unnecessary_cast.fixed b/tests/ui/unnecessary_cast.fixed index 288541362cdd..c43e50761bd5 100644 --- a/tests/ui/unnecessary_cast.fixed +++ b/tests/ui/unnecessary_cast.fixed @@ -206,7 +206,7 @@ mod fixable { fn issue_9563() { let _: f64 = (-8.0_f64).exp(); - #[allow(clippy::precedence)] + #[allow(ambiguous_negative_literals)] let _: f64 = -8.0_f64.exp(); // should suggest `-8.0_f64.exp()` here not to change code behavior } diff --git a/tests/ui/unnecessary_cast.rs b/tests/ui/unnecessary_cast.rs index eef3a42e3514..4a5ca231315e 100644 --- a/tests/ui/unnecessary_cast.rs +++ b/tests/ui/unnecessary_cast.rs @@ -206,7 +206,7 @@ mod fixable { fn issue_9563() { let _: f64 = (-8.0 as f64).exp(); - #[allow(clippy::precedence)] + #[allow(ambiguous_negative_literals)] let _: f64 = -(8.0 as f64).exp(); // should suggest `-8.0_f64.exp()` here not to change code behavior } From fceeb133995b50bddc3df6cf58c4ce684a64fcf3 Mon Sep 17 00:00:00 2001 From: yaxum62 Date: Mon, 15 Jul 2024 21:21:52 -0700 Subject: [PATCH 05/73] Add test for `try_err` lint within try blocks. --- tests/ui/try_err.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tests/ui/try_err.rs b/tests/ui/try_err.rs index 927eccf2d54c..841ec6b5d5c7 100644 --- a/tests/ui/try_err.rs +++ b/tests/ui/try_err.rs @@ -1,5 +1,5 @@ //@aux-build:proc_macros.rs - +#![feature(try_blocks)] #![deny(clippy::try_err)] #![allow( clippy::unnecessary_wraps, @@ -152,3 +152,11 @@ pub fn try_return(x: bool) -> Result { } Ok(0) } + +// Test that the lint is suppressed in try block. +pub fn try_block() -> Result<(), i32> { + let _: Result<_, i32> = try { + Err(1)?; + }; + Ok(()) +} From 1821defc39d410b3f761dbc0bae45e7ac1e6d585 Mon Sep 17 00:00:00 2001 From: yaxum62 Date: Mon, 15 Jul 2024 21:54:15 -0700 Subject: [PATCH 06/73] add expected output for try_err test --- tests/ui/try_err.fixed | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tests/ui/try_err.fixed b/tests/ui/try_err.fixed index aae4f8ac47f8..f149bfb77740 100644 --- a/tests/ui/try_err.fixed +++ b/tests/ui/try_err.fixed @@ -1,5 +1,5 @@ //@aux-build:proc_macros.rs - +#![feature(try_blocks)] #![deny(clippy::try_err)] #![allow( clippy::unnecessary_wraps, @@ -152,3 +152,11 @@ pub fn try_return(x: bool) -> Result { } Ok(0) } + +// Test that the lint is suppressed in try block. +pub fn try_block() -> Result<(), i32> { + let _: Result<_, i32> = try { + Err(1)?; + }; + Ok(()) +} From a5fd2c98bdf1881e553500cad4d8ce3b970a0a97 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Wed, 17 Jul 2024 12:51:08 +0700 Subject: [PATCH 07/73] Remove duplicated peel_middle_ty_refs TODO: Should we move `ty::peel_mid_ty_refs_is_mutable` to super module too? --- clippy_lints/src/dereference.rs | 4 ++-- clippy_lints/src/matches/single_match.rs | 8 +++++--- clippy_lints/src/methods/implicit_clone.rs | 6 +++--- clippy_lints/src/methods/unnecessary_to_owned.rs | 13 ++++++------- clippy_lints/src/redundant_slicing.rs | 8 ++++---- clippy_lints/src/size_of_ref.rs | 5 ++--- clippy_utils/src/ty.rs | 13 ------------- 7 files changed, 22 insertions(+), 35 deletions(-) diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 253f9959e13e..d0cb24884686 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::sugg::has_enclosing_paren; -use clippy_utils::ty::{implements_trait, is_manually_drop, peel_mid_ty_refs}; +use clippy_utils::ty::{implements_trait, is_manually_drop}; use clippy_utils::{ expr_use_ctxt, get_parent_expr, is_block_like, is_lint_allowed, path_to_local, peel_middle_ty_refs, DefinedTy, ExprUseNode, @@ -947,7 +947,7 @@ fn report<'tcx>( let (expr_str, _expr_is_macro_call) = snippet_with_context(cx, expr.span, data.first_expr.span.ctxt(), "..", &mut app); let ty = typeck.expr_ty(expr); - let (_, ref_count) = peel_mid_ty_refs(ty); + let (_, ref_count) = peel_middle_ty_refs(ty); let deref_str = if ty_changed_count >= ref_count && ref_count != 0 { // a deref call changing &T -> &U requires two deref operators the first time // this occurs. One to remove the reference, a second to call the deref impl. diff --git a/clippy_lints/src/matches/single_match.rs b/clippy_lints/src/matches/single_match.rs index 99fdbcff890b..d4330400cd0e 100644 --- a/clippy_lints/src/matches/single_match.rs +++ b/clippy_lints/src/matches/single_match.rs @@ -1,7 +1,9 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{expr_block, snippet, SpanRangeExt}; -use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, peel_mid_ty_refs}; -use clippy_utils::{is_lint_allowed, is_unit_expr, is_wild, peel_blocks, peel_hir_pat_refs, peel_n_hir_expr_refs}; +use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; +use clippy_utils::{ + is_lint_allowed, is_unit_expr, is_wild, peel_blocks, peel_hir_pat_refs, peel_middle_ty_refs, peel_n_hir_expr_refs, +}; use core::cmp::max; use rustc_errors::Applicability; use rustc_hir::{Arm, BindingMode, Block, Expr, ExprKind, Pat, PatKind}; @@ -82,7 +84,7 @@ fn report_single_pattern( let (pat, pat_ref_count) = peel_hir_pat_refs(arms[0].pat); let (msg, sugg) = if let PatKind::Path(_) | PatKind::Lit(_) = pat.kind - && let (ty, ty_ref_count) = peel_mid_ty_refs(cx.typeck_results().expr_ty(ex)) + && let (ty, ty_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(ex)) && let Some(spe_trait_id) = cx.tcx.lang_items().structural_peq_trait() && let Some(pe_trait_id) = cx.tcx.lang_items().eq_trait() && (ty.is_integral() diff --git a/clippy_lints/src/methods/implicit_clone.rs b/clippy_lints/src/methods/implicit_clone.rs index c510cd915d0c..519091406ccf 100644 --- a/clippy_lints/src/methods/implicit_clone.rs +++ b/clippy_lints/src/methods/implicit_clone.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_context; -use clippy_utils::ty::{implements_trait, peel_mid_ty_refs}; -use clippy_utils::{is_diag_item_method, is_diag_trait_item}; +use clippy_utils::ty::implements_trait; +use clippy_utils::{is_diag_item_method, is_diag_trait_item, peel_middle_ty_refs}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -14,7 +14,7 @@ pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv && is_clone_like(cx, method_name, method_def_id) && let return_type = cx.typeck_results().expr_ty(expr) && let input_type = cx.typeck_results().expr_ty(recv) - && let (input_type, ref_count) = peel_mid_ty_refs(input_type) + && let (input_type, ref_count) = peel_middle_ty_refs(input_type) && !(ref_count > 0 && is_diag_trait_item(cx, method_def_id, sym::ToOwned)) && let Some(ty_name) = input_type.ty_adt_def().map(|adt_def| cx.tcx.item_name(adt_def.did())) && return_type == input_type diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index 5d899415d772..fed2b128dcf3 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -3,12 +3,11 @@ use super::unnecessary_iter_cloned::{self, is_into_iter}; use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::{snippet, snippet_opt}; -use clippy_utils::ty::{ - get_iterator_item_ty, implements_trait, is_copy, is_type_diagnostic_item, is_type_lang_item, peel_mid_ty_refs, -}; +use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy, is_type_diagnostic_item, is_type_lang_item}; use clippy_utils::visitors::find_all_ret_expressions; use clippy_utils::{ - fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, match_def_path, paths, return_ty, + fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, match_def_path, paths, peel_middle_ty_refs, + return_ty, }; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; @@ -120,8 +119,8 @@ fn check_addr_of_expr( }, ] = adjustments[..] && let receiver_ty = cx.typeck_results().expr_ty(receiver) - && let (target_ty, n_target_refs) = peel_mid_ty_refs(*target_ty) - && let (receiver_ty, n_receiver_refs) = peel_mid_ty_refs(receiver_ty) + && let (target_ty, n_target_refs) = peel_middle_ty_refs(*target_ty) + && let (receiver_ty, n_receiver_refs) = peel_middle_ty_refs(receiver_ty) // Only flag cases satisfying at least one of the following three conditions: // * the referent and receiver types are distinct // * the referent/receiver type is a copyable array @@ -382,7 +381,7 @@ fn check_other_call_arg<'tcx>( && let fn_sig = cx.tcx.fn_sig(callee_def_id).instantiate_identity().skip_binder() && let Some(i) = recv.into_iter().chain(call_args).position(|arg| arg.hir_id == maybe_arg.hir_id) && let Some(input) = fn_sig.inputs().get(i) - && let (input, n_refs) = peel_mid_ty_refs(*input) + && let (input, n_refs) = peel_middle_ty_refs(*input) && let (trait_predicates, _) = get_input_traits_and_projections(cx, callee_def_id, input) && let Some(sized_def_id) = cx.tcx.lang_items().sized_trait() && let [trait_predicate] = trait_predicates diff --git a/clippy_lints/src/redundant_slicing.rs b/clippy_lints/src/redundant_slicing.rs index 82f22ad693d7..97b2f99299a7 100644 --- a/clippy_lints/src/redundant_slicing.rs +++ b/clippy_lints/src/redundant_slicing.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::get_parent_expr; use clippy_utils::source::snippet_with_context; -use clippy_utils::ty::{is_type_lang_item, peel_mid_ty_refs}; +use clippy_utils::ty::is_type_lang_item; +use clippy_utils::{get_parent_expr, peel_middle_ty_refs}; use rustc_ast::util::parser::PREC_PREFIX; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, LangItem, Mutability}; @@ -82,8 +82,8 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing { && let ExprKind::Index(indexed, range, _) = addressee.kind && is_type_lang_item(cx, cx.typeck_results().expr_ty_adjusted(range), LangItem::RangeFull) { - let (expr_ty, expr_ref_count) = peel_mid_ty_refs(cx.typeck_results().expr_ty(expr)); - let (indexed_ty, indexed_ref_count) = peel_mid_ty_refs(cx.typeck_results().expr_ty(indexed)); + let (expr_ty, expr_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(expr)); + let (indexed_ty, indexed_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(indexed)); let parent_expr = get_parent_expr(cx, expr); let needs_parens_for_prefix = parent_expr.map_or(false, |parent| parent.precedence().order() > PREC_PREFIX); let mut app = Applicability::MachineApplicable; diff --git a/clippy_lints/src/size_of_ref.rs b/clippy_lints/src/size_of_ref.rs index 8d7f12af86e8..b3d32a6d7d84 100644 --- a/clippy_lints/src/size_of_ref.rs +++ b/clippy_lints/src/size_of_ref.rs @@ -1,6 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::path_def_id; -use clippy_utils::ty::peel_mid_ty_refs; +use clippy_utils::{path_def_id, peel_middle_ty_refs}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -60,7 +59,7 @@ impl LateLintPass<'_> for SizeOfRef { && let Some(def_id) = path_def_id(cx, path) && cx.tcx.is_diagnostic_item(sym::mem_size_of_val, def_id) && let arg_ty = cx.typeck_results().expr_ty(arg) - && peel_mid_ty_refs(arg_ty).1 > 1 + && peel_middle_ty_refs(arg_ty).1 > 1 { span_lint_and_help( cx, diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index fc02b974ee12..29ea03f7bb18 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -525,19 +525,6 @@ pub fn needs_ordered_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { needs_ordered_drop_inner(cx, ty, &mut FxHashSet::default()) } -/// Peels off all references on the type. Returns the underlying type and the number of references -/// removed. -pub fn peel_mid_ty_refs(ty: Ty<'_>) -> (Ty<'_>, usize) { - fn peel(ty: Ty<'_>, count: usize) -> (Ty<'_>, usize) { - if let ty::Ref(_, ty, _) = ty.kind() { - peel(*ty, count + 1) - } else { - (ty, count) - } - } - peel(ty, 0) -} - /// Peels off all references on the type. Returns the underlying type, the number of references /// removed, and whether the pointer is ultimately mutable or not. pub fn peel_mid_ty_refs_is_mutable(ty: Ty<'_>) -> (Ty<'_>, usize, Mutability) { From 58027e265793d632597330ae2209c11b98bd9ed5 Mon Sep 17 00:00:00 2001 From: apoisternex Date: Thu, 18 Jul 2024 15:23:04 -0300 Subject: [PATCH 08/73] Fix [`redundant_slicing`] when the slice is behind a mutable reference Fixes #12751 changelog: Fix [`redundant_slicing`] when the slice is behind a mutable reference --- clippy_lints/src/redundant_slicing.rs | 7 +++++-- tests/ui/deref_by_slicing.fixed | 4 ++++ tests/ui/deref_by_slicing.rs | 4 ++++ tests/ui/deref_by_slicing.stderr | 8 +++++++- 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/redundant_slicing.rs b/clippy_lints/src/redundant_slicing.rs index 82f22ad693d7..7470ff754b5a 100644 --- a/clippy_lints/src/redundant_slicing.rs +++ b/clippy_lints/src/redundant_slicing.rs @@ -113,8 +113,11 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing { a.kind, Adjust::Borrow(AutoBorrow::Ref(_, AutoBorrowMutability::Mut { .. })) ) - }) { - // The slice was used to make a temporary reference. + }) || (matches!( + cx.typeck_results().expr_ty(indexed).ref_mutability(), + Some(Mutability::Mut) + ) && mutability == Mutability::Not) + { (DEREF_BY_SLICING_LINT, "&*", "reborrow the original value instead") } else if deref_count != 0 { (DEREF_BY_SLICING_LINT, "", "dereference the original value instead") diff --git a/tests/ui/deref_by_slicing.fixed b/tests/ui/deref_by_slicing.fixed index a3c2e8456668..87b33b1f881d 100644 --- a/tests/ui/deref_by_slicing.fixed +++ b/tests/ui/deref_by_slicing.fixed @@ -25,4 +25,8 @@ fn main() { let bytes: &[u8] = &[]; let _ = (&*bytes).read_to_end(&mut vec![]).unwrap(); // Err, re-borrows slice + + // issue 12751 + let a = &mut [1, 2, 3][..]; + let _ = &*a; } diff --git a/tests/ui/deref_by_slicing.rs b/tests/ui/deref_by_slicing.rs index 5b4a73712ee6..8d8882a1781e 100644 --- a/tests/ui/deref_by_slicing.rs +++ b/tests/ui/deref_by_slicing.rs @@ -25,4 +25,8 @@ fn main() { let bytes: &[u8] = &[]; let _ = (&bytes[..]).read_to_end(&mut vec![]).unwrap(); // Err, re-borrows slice + + // issue 12751 + let a = &mut [1, 2, 3][..]; + let _ = &a[..]; } diff --git a/tests/ui/deref_by_slicing.stderr b/tests/ui/deref_by_slicing.stderr index 17b00610899d..ceb9ab6db73d 100644 --- a/tests/ui/deref_by_slicing.stderr +++ b/tests/ui/deref_by_slicing.stderr @@ -55,5 +55,11 @@ error: slicing when dereferencing would work LL | let _ = (&bytes[..]).read_to_end(&mut vec![]).unwrap(); // Err, re-borrows slice | ^^^^^^^^^^^^ help: reborrow the original value instead: `(&*bytes)` -error: aborting due to 9 previous errors +error: slicing when dereferencing would work + --> tests/ui/deref_by_slicing.rs:31:13 + | +LL | let _ = &a[..]; + | ^^^^^^ help: reborrow the original value instead: `&*a` + +error: aborting due to 10 previous errors From 266abf3c08203d0ae7bf6d0ba18db5a6df2fd1c2 Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Fri, 19 Jul 2024 16:10:24 -0400 Subject: [PATCH 09/73] Avoid ref when using format! Clean up a few minor refs in `format!` macro, as it has a performance cost. Apparently the compiler is unable to inline `format!("{}", &variable)`, and does a run-time double-reference instead (format macro already does one level referencing). Inlining format args prevents accidental `&` misuse. --- clippy_lints/src/approx_const.rs | 2 +- clippy_lints/src/default.rs | 2 +- clippy_lints/src/methods/open_options.rs | 2 +- clippy_lints/src/methods/wrong_self_convention.rs | 2 +- clippy_lints/src/no_effect.rs | 2 +- clippy_lints/src/types/borrowed_box.rs | 6 +++--- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/approx_const.rs b/clippy_lints/src/approx_const.rs index e6d52bcef717..3b4cc1134802 100644 --- a/clippy_lints/src/approx_const.rs +++ b/clippy_lints/src/approx_const.rs @@ -97,7 +97,7 @@ impl ApproxConstant { cx, APPROX_CONSTANT, e.span, - format!("approximate value of `{module}::consts::{}` found", &name), + format!("approximate value of `{module}::consts::{name}` found"), None, "consider using the constant directly", ); diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs index 72fa05be3cc6..0b7279f2b360 100644 --- a/clippy_lints/src/default.rs +++ b/clippy_lints/src/default.rs @@ -221,7 +221,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { .map(ToString::to_string) .collect::>() .join(", "); - format!("{adt_def_ty_name}::<{}>", &tys_str) + format!("{adt_def_ty_name}::<{tys_str}>") } else { binding_type.to_string() }; diff --git a/clippy_lints/src/methods/open_options.rs b/clippy_lints/src/methods/open_options.rs index d425b505a760..cbeb48b6cc37 100644 --- a/clippy_lints/src/methods/open_options.rs +++ b/clippy_lints/src/methods/open_options.rs @@ -151,7 +151,7 @@ fn check_open_options(cx: &LateContext<'_>, settings: &[(OpenOption, Argument, S cx, NONSENSICAL_OPEN_OPTIONS, prev_span, - format!("the method `{}` is called more than once", &option), + format!("the method `{option}` is called more than once"), ); } } diff --git a/clippy_lints/src/methods/wrong_self_convention.rs b/clippy_lints/src/methods/wrong_self_convention.rs index 28068c634732..7384e534ed7d 100644 --- a/clippy_lints/src/methods/wrong_self_convention.rs +++ b/clippy_lints/src/methods/wrong_self_convention.rs @@ -127,7 +127,7 @@ pub(super) fn check<'tcx>( .collect::>() .join(" and "); - format!("methods with the following characteristics: ({})", &s) + format!("methods with the following characteristics: ({s})") } else { format!("methods called {}", &conventions[0]) } diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index 0ecfa7baa72d..837e8b9028de 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -272,7 +272,7 @@ fn check_unnecessary_operation(cx: &LateContext<'_>, stmt: &Stmt<'_>) { } let snippet = if let (Some(arr), Some(func)) = (snippet_opt(cx, reduced[0].span), snippet_opt(cx, reduced[1].span)) { - format!("assert!({}.len() > {});", &arr, &func) + format!("assert!({arr}.len() > {func});") } else { return; }; diff --git a/clippy_lints/src/types/borrowed_box.rs b/clippy_lints/src/types/borrowed_box.rs index 801e88626199..89ba33583d6c 100644 --- a/clippy_lints/src/types/borrowed_box.rs +++ b/clippy_lints/src/types/borrowed_box.rs @@ -48,15 +48,15 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, m let inner_snippet = snippet(cx, inner.span, ".."); let suggestion = match &inner.kind { TyKind::TraitObject(bounds, lt_bound, _) if bounds.len() > 1 || !lt_bound.is_elided() => { - format!("&{ltopt}({})", &inner_snippet) + format!("&{ltopt}({inner_snippet})") }, TyKind::Path(qpath) if get_bounds_if_impl_trait(cx, qpath, inner.hir_id) .map_or(false, |bounds| bounds.len() > 1) => { - format!("&{ltopt}({})", &inner_snippet) + format!("&{ltopt}({inner_snippet})") }, - _ => format!("&{ltopt}{}", &inner_snippet), + _ => format!("&{ltopt}{inner_snippet}"), }; span_lint_and_sugg( cx, From bc8fc6b1d8abc1c1265da805534a4f172b1fe5d9 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Sun, 21 Jul 2024 19:26:53 +0200 Subject: [PATCH 10/73] Make restriction lint's use `span_lint_and_then` (i -> l) --- clippy_lints/src/asm_syntax.rs | 22 ++-- clippy_lints/src/float_literal.rs | 40 ++++--- clippy_lints/src/large_include_file.rs | 16 +-- clippy_lints/src/let_underscore.rs | 58 +++++---- .../src/operators/integer_division.rs | 14 +-- tests/ui/excessive_precision.stderr | 111 +++++++++++++++--- tests/ui/lossy_float_literal.stderr | 76 ++++++++++-- 7 files changed, 245 insertions(+), 92 deletions(-) diff --git a/clippy_lints/src/asm_syntax.rs b/clippy_lints/src/asm_syntax.rs index 0db1456d40bf..69a8eb7d94e7 100644 --- a/clippy_lints/src/asm_syntax.rs +++ b/clippy_lints/src/asm_syntax.rs @@ -1,6 +1,6 @@ use std::fmt; -use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_and_then; use rustc_ast::ast::{Expr, ExprKind, InlineAsmOptions}; use rustc_ast::{InlineAsm, Item, ItemKind}; use rustc_lint::{EarlyContext, EarlyLintPass, Lint, LintContext}; @@ -49,14 +49,10 @@ fn check_asm_syntax( }; if style == check_for { - span_lint_and_help( - cx, - lint, - span, - format!("{style} x86 assembly syntax used"), - None, - format!("use {} x86 assembly syntax", !style), - ); + #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] + span_lint_and_then(cx, lint, span, format!("{style} x86 assembly syntax used"), |diag| { + diag.help(format!("use {} x86 assembly syntax", !style)); + }); } } } @@ -98,13 +94,13 @@ declare_lint_pass!(InlineAsmX86IntelSyntax => [INLINE_ASM_X86_INTEL_SYNTAX]); impl EarlyLintPass for InlineAsmX86IntelSyntax { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { if let ExprKind::InlineAsm(inline_asm) = &expr.kind { - check_asm_syntax(Self::get_lints()[0], cx, inline_asm, expr.span, AsmStyle::Intel); + check_asm_syntax(INLINE_ASM_X86_INTEL_SYNTAX, cx, inline_asm, expr.span, AsmStyle::Intel); } } fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { if let ItemKind::GlobalAsm(inline_asm) = &item.kind { - check_asm_syntax(Self::get_lints()[0], cx, inline_asm, item.span, AsmStyle::Intel); + check_asm_syntax(INLINE_ASM_X86_INTEL_SYNTAX, cx, inline_asm, item.span, AsmStyle::Intel); } } } @@ -146,13 +142,13 @@ declare_lint_pass!(InlineAsmX86AttSyntax => [INLINE_ASM_X86_ATT_SYNTAX]); impl EarlyLintPass for InlineAsmX86AttSyntax { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { if let ExprKind::InlineAsm(inline_asm) = &expr.kind { - check_asm_syntax(Self::get_lints()[0], cx, inline_asm, expr.span, AsmStyle::Att); + check_asm_syntax(INLINE_ASM_X86_ATT_SYNTAX, cx, inline_asm, expr.span, AsmStyle::Att); } } fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { if let ItemKind::GlobalAsm(inline_asm) = &item.kind { - check_asm_syntax(Self::get_lints()[0], cx, inline_asm, item.span, AsmStyle::Att); + check_asm_syntax(INLINE_ASM_X86_ATT_SYNTAX, cx, inline_asm, item.span, AsmStyle::Att); } } } diff --git a/clippy_lints/src/float_literal.rs b/clippy_lints/src/float_literal.rs index 2261fcdbdabc..2998c6f8ae0a 100644 --- a/clippy_lints/src/float_literal.rs +++ b/clippy_lints/src/float_literal.rs @@ -1,7 +1,7 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::numeric_literal; use rustc_ast::ast::{self, LitFloatType, LitKind}; -use rustc_errors::Applicability; +use rustc_errors::{Applicability, SuggestionStyle}; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, FloatTy}; @@ -109,29 +109,41 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral { // If the type suffix is missing the suggestion would be // incorrectly interpreted as an integer so adding a `.0` // suffix to prevent that. - if type_suffix.is_none() { - float_str.push_str(".0"); - } - - span_lint_and_sugg( + + span_lint_and_then( cx, LOSSY_FLOAT_LITERAL, expr.span, "literal cannot be represented as the underlying type without loss of precision", - "consider changing the type or replacing it with", - numeric_literal::format(&float_str, type_suffix, true), - Applicability::MachineApplicable, + |diag| { + if type_suffix.is_none() { + float_str.push_str(".0"); + } + diag.span_suggestion_with_style( + expr.span, + "consider changing the type or replacing it with", + numeric_literal::format(&float_str, type_suffix, true), + Applicability::MachineApplicable, + SuggestionStyle::ShowAlways, + ); + }, ); } } else if digits > max as usize && float_str.len() < sym_str.len() { - span_lint_and_sugg( + span_lint_and_then( cx, EXCESSIVE_PRECISION, expr.span, "float has excessive precision", - "consider changing the type or truncating it to", - numeric_literal::format(&float_str, type_suffix, true), - Applicability::MachineApplicable, + |diag| { + diag.span_suggestion_with_style( + expr.span, + "consider changing the type or truncating it to", + numeric_literal::format(&float_str, type_suffix, true), + Applicability::MachineApplicable, + SuggestionStyle::ShowAlways, + ); + }, ); } } diff --git a/clippy_lints/src/large_include_file.rs b/clippy_lints/src/large_include_file.rs index c67da689aaee..f2f841dcec33 100644 --- a/clippy_lints/src/large_include_file.rs +++ b/clippy_lints/src/large_include_file.rs @@ -1,5 +1,5 @@ use clippy_config::Conf; -use clippy_utils::diagnostics::span_lint_and_note; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::root_macro_call_first_node; use rustc_ast::LitKind; use rustc_hir::{Expr, ExprKind}; @@ -66,16 +66,18 @@ impl LateLintPass<'_> for LargeIncludeFile { && (cx.tcx.is_diagnostic_item(sym::include_bytes_macro, macro_call.def_id) || cx.tcx.is_diagnostic_item(sym::include_str_macro, macro_call.def_id)) { - span_lint_and_note( + #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] + span_lint_and_then( cx, LARGE_INCLUDE_FILE, expr.span.source_callsite(), "attempted to include a large file", - None, - format!( - "the configuration allows a maximum size of {} bytes", - self.max_file_size - ), + |diag| { + diag.note(format!( + "the configuration allows a maximum size of {} bytes", + self.max_file_size + )); + }, ); } } diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs index 8fa63f3e8fde..b522c22a44d7 100644 --- a/clippy_lints/src/let_underscore.rs +++ b/clippy_lints/src/let_underscore.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::{implements_trait, is_must_use_ty, match_type}; use clippy_utils::{is_from_proc_macro, is_must_use_func_call, paths}; use rustc_hir::{LetStmt, LocalSource, PatKind}; @@ -149,43 +149,53 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false, }); if contains_sync_guard { - span_lint_and_help( + #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] + span_lint_and_then( cx, LET_UNDERSCORE_LOCK, local.span, "non-binding `let` on a synchronization lock", - None, - "consider using an underscore-prefixed named \ - binding or dropping explicitly with `std::mem::drop`", + |diag| { + diag.help( + "consider using an underscore-prefixed named \ + binding or dropping explicitly with `std::mem::drop`", + ); + }, ); } else if let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() && implements_trait(cx, cx.typeck_results().expr_ty(init), future_trait_def_id, &[]) { - span_lint_and_help( + #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] + span_lint_and_then( cx, LET_UNDERSCORE_FUTURE, local.span, "non-binding `let` on a future", - None, - "consider awaiting the future or dropping explicitly with `std::mem::drop`", + |diag| { + diag.help("consider awaiting the future or dropping explicitly with `std::mem::drop`"); + }, ); } else if is_must_use_ty(cx, cx.typeck_results().expr_ty(init)) { - span_lint_and_help( + #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] + span_lint_and_then( cx, LET_UNDERSCORE_MUST_USE, local.span, "non-binding `let` on an expression with `#[must_use]` type", - None, - "consider explicitly using expression value", + |diag| { + diag.help("consider explicitly using expression value"); + }, ); } else if is_must_use_func_call(cx, init) { - span_lint_and_help( + #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] + span_lint_and_then( cx, LET_UNDERSCORE_MUST_USE, local.span, "non-binding `let` on a result of a `#[must_use]` function", - None, - "consider explicitly using function result", + |diag| { + diag.help("consider explicitly using function result"); + }, ); } @@ -204,18 +214,22 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { return; } - span_lint_and_help( + span_lint_and_then( cx, LET_UNDERSCORE_UNTYPED, local.span, "non-binding `let` without a type annotation", - Some(Span::new( - local.pat.span.hi(), - local.pat.span.hi() + BytePos(1), - local.pat.span.ctxt(), - local.pat.span.parent(), - )), - "consider adding a type annotation", + |diag| { + diag.span_help( + Span::new( + local.pat.span.hi(), + local.pat.span.hi() + BytePos(1), + local.pat.span.ctxt(), + local.pat.span.parent(), + ), + "consider adding a type annotation", + ); + }, ); } } diff --git a/clippy_lints/src/operators/integer_division.rs b/clippy_lints/src/operators/integer_division.rs index 631d10f4a72e..76eba7327cff 100644 --- a/clippy_lints/src/operators/integer_division.rs +++ b/clippy_lints/src/operators/integer_division.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_and_then; use rustc_hir as hir; use rustc_lint::LateContext; @@ -15,13 +15,9 @@ pub(crate) fn check<'tcx>( && cx.typeck_results().expr_ty(left).is_integral() && cx.typeck_results().expr_ty(right).is_integral() { - span_lint_and_help( - cx, - INTEGER_DIVISION, - expr.span, - "integer division", - None, - "division of integers may cause loss of precision. consider using floats", - ); + #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] + span_lint_and_then(cx, INTEGER_DIVISION, expr.span, "integer division", |diag| { + diag.help("division of integers may cause loss of precision. consider using floats"); + }); } } diff --git a/tests/ui/excessive_precision.stderr b/tests/ui/excessive_precision.stderr index 6d8e166a649d..81e4fb6765d0 100644 --- a/tests/ui/excessive_precision.stderr +++ b/tests/ui/excessive_precision.stderr @@ -2,100 +2,179 @@ error: float has excessive precision --> tests/ui/excessive_precision.rs:20:26 | LL | const BAD32_1: f32 = 0.123_456_789_f32; - | ^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_79_f32` + | ^^^^^^^^^^^^^^^^^ | = note: `-D clippy::excessive-precision` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::excessive_precision)]` +help: consider changing the type or truncating it to + | +LL | const BAD32_1: f32 = 0.123_456_79_f32; + | ~~~~~~~~~~~~~~~~ error: float has excessive precision --> tests/ui/excessive_precision.rs:21:26 | LL | const BAD32_2: f32 = 0.123_456_789; - | ^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_79` + | ^^^^^^^^^^^^^ + | +help: consider changing the type or truncating it to + | +LL | const BAD32_2: f32 = 0.123_456_79; + | ~~~~~~~~~~~~ error: float has excessive precision --> tests/ui/excessive_precision.rs:22:26 | LL | const BAD32_3: f32 = 0.100_000_000_000_1; - | ^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.1` + | ^^^^^^^^^^^^^^^^^^^ + | +help: consider changing the type or truncating it to + | +LL | const BAD32_3: f32 = 0.1; + | ~~~ error: float has excessive precision --> tests/ui/excessive_precision.rs:23:29 | LL | const BAD32_EDGE: f32 = 1.000_000_9; - | ^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.000_001` + | ^^^^^^^^^^^ + | +help: consider changing the type or truncating it to + | +LL | const BAD32_EDGE: f32 = 1.000_001; + | ~~~~~~~~~ error: float has excessive precision --> tests/ui/excessive_precision.rs:27:26 | LL | const BAD64_3: f64 = 0.100_000_000_000_000_000_1; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.1` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider changing the type or truncating it to + | +LL | const BAD64_3: f64 = 0.1; + | ~~~ error: float has excessive precision --> tests/ui/excessive_precision.rs:30:22 | LL | println!("{:?}", 8.888_888_888_888_888_888_888); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `8.888_888_888_888_89` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider changing the type or truncating it to + | +LL | println!("{:?}", 8.888_888_888_888_89); + | ~~~~~~~~~~~~~~~~~~~~ error: float has excessive precision --> tests/ui/excessive_precision.rs:41:22 | LL | let bad32: f32 = 1.123_456_789; - | ^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8` + | ^^^^^^^^^^^^^ + | +help: consider changing the type or truncating it to + | +LL | let bad32: f32 = 1.123_456_8; + | ~~~~~~~~~~~ error: float has excessive precision --> tests/ui/excessive_precision.rs:42:26 | LL | let bad32_suf: f32 = 1.123_456_789_f32; - | ^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8_f32` + | ^^^^^^^^^^^^^^^^^ + | +help: consider changing the type or truncating it to + | +LL | let bad32_suf: f32 = 1.123_456_8_f32; + | ~~~~~~~~~~~~~~~ error: float has excessive precision --> tests/ui/excessive_precision.rs:43:21 | LL | let bad32_inf = 1.123_456_789_f32; - | ^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8_f32` + | ^^^^^^^^^^^^^^^^^ + | +help: consider changing the type or truncating it to + | +LL | let bad32_inf = 1.123_456_8_f32; + | ~~~~~~~~~~~~~~~ error: float has excessive precision --> tests/ui/excessive_precision.rs:53:36 | LL | let bad_vec32: Vec = vec![0.123_456_789]; - | ^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_79` + | ^^^^^^^^^^^^^ + | +help: consider changing the type or truncating it to + | +LL | let bad_vec32: Vec = vec![0.123_456_79]; + | ~~~~~~~~~~~~ error: float has excessive precision --> tests/ui/excessive_precision.rs:54:36 | LL | let bad_vec64: Vec = vec![0.123_456_789_123_456_789]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_789_123_456_78` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider changing the type or truncating it to + | +LL | let bad_vec64: Vec = vec![0.123_456_789_123_456_78]; + | ~~~~~~~~~~~~~~~~~~~~~~~~ error: float has excessive precision --> tests/ui/excessive_precision.rs:58:24 | LL | let bad_e32: f32 = 1.123_456_788_888e-10; - | ^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8e-10` + | ^^^^^^^^^^^^^^^^^^^^^ + | +help: consider changing the type or truncating it to + | +LL | let bad_e32: f32 = 1.123_456_8e-10; + | ~~~~~~~~~~~~~~~ error: float has excessive precision --> tests/ui/excessive_precision.rs:61:27 | LL | let bad_bige32: f32 = 1.123_456_788_888E-10; - | ^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8E-10` + | ^^^^^^^^^^^^^^^^^^^^^ + | +help: consider changing the type or truncating it to + | +LL | let bad_bige32: f32 = 1.123_456_8E-10; + | ~~~~~~~~~~~~~~~ error: float has excessive precision --> tests/ui/excessive_precision.rs:70:13 | LL | let _ = 2.225_073_858_507_201_1e-308_f64; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `2.225_073_858_507_201e-308_f64` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider changing the type or truncating it to + | +LL | let _ = 2.225_073_858_507_201e-308_f64; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: float has excessive precision --> tests/ui/excessive_precision.rs:73:13 | LL | let _ = 1.000_000_000_000_001e-324_f64; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0_f64` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider changing the type or truncating it to + | +LL | let _ = 0_f64; + | ~~~~~ error: float has excessive precision --> tests/ui/excessive_precision.rs:83:20 | LL | const _: f64 = 3.0000000000000000e+00; - | ^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `3.0` + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider changing the type or truncating it to + | +LL | const _: f64 = 3.0; + | ~~~ error: aborting due to 16 previous errors diff --git a/tests/ui/lossy_float_literal.stderr b/tests/ui/lossy_float_literal.stderr index b5a07418734c..3026854e317a 100644 --- a/tests/ui/lossy_float_literal.stderr +++ b/tests/ui/lossy_float_literal.stderr @@ -2,70 +2,124 @@ error: literal cannot be represented as the underlying type without loss of prec --> tests/ui/lossy_float_literal.rs:14:18 | LL | let _: f32 = 16_777_217.0; - | ^^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_216.0` + | ^^^^^^^^^^^^ | = note: `-D clippy::lossy-float-literal` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::lossy_float_literal)]` +help: consider changing the type or replacing it with + | +LL | let _: f32 = 16_777_216.0; + | ~~~~~~~~~~~~ error: literal cannot be represented as the underlying type without loss of precision --> tests/ui/lossy_float_literal.rs:15:18 | LL | let _: f32 = 16_777_219.0; - | ^^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_220.0` + | ^^^^^^^^^^^^ + | +help: consider changing the type or replacing it with + | +LL | let _: f32 = 16_777_220.0; + | ~~~~~~~~~~~~ error: literal cannot be represented as the underlying type without loss of precision --> tests/ui/lossy_float_literal.rs:16:18 | LL | let _: f32 = 16_777_219.; - | ^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_220.0` + | ^^^^^^^^^^^ + | +help: consider changing the type or replacing it with + | +LL | let _: f32 = 16_777_220.0; + | ~~~~~~~~~~~~ error: literal cannot be represented as the underlying type without loss of precision --> tests/ui/lossy_float_literal.rs:17:18 | LL | let _: f32 = 16_777_219.000; - | ^^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_220.0` + | ^^^^^^^^^^^^^^ + | +help: consider changing the type or replacing it with + | +LL | let _: f32 = 16_777_220.0; + | ~~~~~~~~~~~~ error: literal cannot be represented as the underlying type without loss of precision --> tests/ui/lossy_float_literal.rs:18:13 | LL | let _ = 16_777_219f32; - | ^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_220_f32` + | ^^^^^^^^^^^^^ + | +help: consider changing the type or replacing it with + | +LL | let _ = 16_777_220_f32; + | ~~~~~~~~~~~~~~ error: literal cannot be represented as the underlying type without loss of precision --> tests/ui/lossy_float_literal.rs:19:19 | LL | let _: f32 = -16_777_219.0; - | ^^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_220.0` + | ^^^^^^^^^^^^ + | +help: consider changing the type or replacing it with + | +LL | let _: f32 = -16_777_220.0; + | ~~~~~~~~~~~~ error: literal cannot be represented as the underlying type without loss of precision --> tests/ui/lossy_float_literal.rs:21:18 | LL | let _: f64 = 9_007_199_254_740_993.0; - | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `9_007_199_254_740_992.0` + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider changing the type or replacing it with + | +LL | let _: f64 = 9_007_199_254_740_992.0; + | ~~~~~~~~~~~~~~~~~~~~~~~ error: literal cannot be represented as the underlying type without loss of precision --> tests/ui/lossy_float_literal.rs:22:18 | LL | let _: f64 = 9_007_199_254_740_993.; - | ^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `9_007_199_254_740_992.0` + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider changing the type or replacing it with + | +LL | let _: f64 = 9_007_199_254_740_992.0; + | ~~~~~~~~~~~~~~~~~~~~~~~ error: literal cannot be represented as the underlying type without loss of precision --> tests/ui/lossy_float_literal.rs:23:18 | LL | let _: f64 = 9_007_199_254_740_993.00; - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `9_007_199_254_740_992.0` + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider changing the type or replacing it with + | +LL | let _: f64 = 9_007_199_254_740_992.0; + | ~~~~~~~~~~~~~~~~~~~~~~~ error: literal cannot be represented as the underlying type without loss of precision --> tests/ui/lossy_float_literal.rs:24:13 | LL | let _ = 9_007_199_254_740_993f64; - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `9_007_199_254_740_992_f64` + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider changing the type or replacing it with + | +LL | let _ = 9_007_199_254_740_992_f64; + | ~~~~~~~~~~~~~~~~~~~~~~~~~ error: literal cannot be represented as the underlying type without loss of precision --> tests/ui/lossy_float_literal.rs:25:19 | LL | let _: f64 = -9_007_199_254_740_993.0; - | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `9_007_199_254_740_992.0` + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider changing the type or replacing it with + | +LL | let _: f64 = -9_007_199_254_740_992.0; + | ~~~~~~~~~~~~~~~~~~~~~~~ error: aborting due to 11 previous errors From d17f113474fc18284bc7ab0d67a815a220244a3e Mon Sep 17 00:00:00 2001 From: xFrednet Date: Sun, 21 Jul 2024 19:53:22 +0200 Subject: [PATCH 11/73] Make restriction lint's use `span_lint_and_then` (m -> m) --- clippy_lints/src/drop_forget_ref.rs | 18 +++++------ clippy_lints/src/float_literal.rs | 2 +- clippy_lints/src/inherent_impl.rs | 9 +++--- clippy_lints/src/methods/map_err_ignore.rs | 13 +++++--- clippy_lints/src/missing_assert_message.rs | 10 +++--- clippy_lints/src/missing_trait_methods.rs | 12 +++---- .../src/mixed_read_write_in_expression.rs | 12 ++++--- clippy_lints/src/module_style.rs | 32 ++++++++++--------- 8 files changed, 61 insertions(+), 47 deletions(-) diff --git a/clippy_lints/src/drop_forget_ref.rs b/clippy_lints/src/drop_forget_ref.rs index 4a6ffcd9a788..c7dd7292a14b 100644 --- a/clippy_lints/src/drop_forget_ref.rs +++ b/clippy_lints/src/drop_forget_ref.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::span_lint_and_note; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_must_use_func_call; use clippy_utils::ty::{is_copy, is_must_use_ty, is_type_lang_item}; use rustc_hir::{Arm, Expr, ExprKind, LangItem, Node}; @@ -126,14 +126,14 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef { }, _ => return, }; - span_lint_and_note( - cx, - lint, - expr.span, - msg, - note_span, - format!("argument has type `{arg_ty}`"), - ); + span_lint_and_then(cx, lint, expr.span, msg, |diag| { + let note = format!("argument has type `{arg_ty}`"); + if let Some(span) = note_span { + diag.span_note(span, note); + } else { + diag.note(note); + } + }); } } } diff --git a/clippy_lints/src/float_literal.rs b/clippy_lints/src/float_literal.rs index 2998c6f8ae0a..39cddece75da 100644 --- a/clippy_lints/src/float_literal.rs +++ b/clippy_lints/src/float_literal.rs @@ -109,7 +109,7 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral { // If the type suffix is missing the suggestion would be // incorrectly interpreted as an integer so adding a `.0` // suffix to prevent that. - + span_lint_and_then( cx, LOSSY_FLOAT_LITERAL, diff --git a/clippy_lints/src/inherent_impl.rs b/clippy_lints/src/inherent_impl.rs index 95ae591884bc..186bf4035f0c 100644 --- a/clippy_lints/src/inherent_impl.rs +++ b/clippy_lints/src/inherent_impl.rs @@ -1,6 +1,6 @@ //! lint on inherent implementations -use clippy_utils::diagnostics::span_lint_and_note; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_lint_allowed; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::LocalDefId; @@ -106,13 +106,14 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl { // `TyCtxt::crate_inherent_impls` doesn't have a defined order. Sort the lint output first. lint_spans.sort_by_key(|x| x.0.lo()); for (span, first_span) in lint_spans { - span_lint_and_note( + span_lint_and_then( cx, MULTIPLE_INHERENT_IMPL, span, "multiple implementations of this structure", - Some(first_span), - "first implementation here", + |diag| { + diag.span_note(first_span, "first implementation here"); + }, ); } } diff --git a/clippy_lints/src/methods/map_err_ignore.rs b/clippy_lints/src/methods/map_err_ignore.rs index fbb83c8ce563..ee34891ad8af 100644 --- a/clippy_lints/src/methods/map_err_ignore.rs +++ b/clippy_lints/src/methods/map_err_ignore.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::is_type_diagnostic_item; use rustc_hir::{CaptureBy, Closure, Expr, ExprKind, PatKind}; use rustc_lint::LateContext; @@ -22,13 +22,18 @@ pub(super) fn check(cx: &LateContext<'_>, e: &Expr<'_>, arg: &Expr<'_>) { { // span the area of the closure capture and warn that the // original error will be thrown away - span_lint_and_help( + #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] + span_lint_and_then( cx, MAP_ERR_IGNORE, fn_decl_span, "`map_err(|_|...` wildcard pattern discards the original error", - None, - "consider storing the original error as a source in the new error, or silence this warning using an ignored identifier (`.map_err(|_foo| ...`)", + |diag| { + diag.help( + + "consider storing the original error as a source in the new error, or silence this warning using an ignored identifier (`.map_err(|_foo| ...`)", + ); + }, ); } } diff --git a/clippy_lints/src/missing_assert_message.rs b/clippy_lints/src/missing_assert_message.rs index 935ed48dacc5..a9ea11f4c2b0 100644 --- a/clippy_lints/src/missing_assert_message.rs +++ b/clippy_lints/src/missing_assert_message.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_in_test; use clippy_utils::macros::{find_assert_args, find_assert_eq_args, root_macro_call_first_node, PanicExpn}; use rustc_hir::Expr; @@ -79,13 +79,15 @@ impl<'tcx> LateLintPass<'tcx> for MissingAssertMessage { }; if let PanicExpn::Empty = panic_expn { - span_lint_and_help( + #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] + span_lint_and_then( cx, MISSING_ASSERT_MESSAGE, macro_call.span, "assert without any message", - None, - "consider describing why the failing assert is problematic", + |diag| { + diag.help("consider describing why the failing assert is problematic"); + }, ); } } diff --git a/clippy_lints/src/missing_trait_methods.rs b/clippy_lints/src/missing_trait_methods.rs index 85029a5e6a0d..59c8c7f38e4e 100644 --- a/clippy_lints/src/missing_trait_methods.rs +++ b/clippy_lints/src/missing_trait_methods.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_lint_allowed; use clippy_utils::macros::span_is_local; use rustc_hir::def_id::DefIdMap; @@ -83,15 +83,15 @@ impl<'tcx> LateLintPass<'tcx> for MissingTraitMethods { cx.tcx.with_stable_hashing_context(|hcx| { for assoc in provided.values_sorted(&hcx, true) { let source_map = cx.tcx.sess.source_map(); - let definition_span = source_map.guess_head_span(cx.tcx.def_span(assoc.def_id)); - - span_lint_and_help( + span_lint_and_then( cx, MISSING_TRAIT_METHODS, source_map.guess_head_span(item.span), format!("missing trait method provided by default: `{}`", assoc.name), - Some(definition_span), - "implement the method", + |diag| { + let definition_span = source_map.guess_head_span(cx.tcx.def_span(assoc.def_id)); + diag.span_help(definition_span, "implement the method"); + }, ); } }); diff --git a/clippy_lints/src/mixed_read_write_in_expression.rs b/clippy_lints/src/mixed_read_write_in_expression.rs index 9c5a8a0cfcdf..6964d8c8dbb3 100644 --- a/clippy_lints/src/mixed_read_write_in_expression.rs +++ b/clippy_lints/src/mixed_read_write_in_expression.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::{span_lint, span_lint_and_note}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::{get_parent_expr, path_to_local, path_to_local_id}; use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, LetStmt, Node, Stmt, StmtKind}; @@ -324,13 +324,17 @@ impl<'a, 'tcx> Visitor<'tcx> for ReadVisitor<'a, 'tcx> { if path_to_local_id(expr, self.var) { // Check that this is a read, not a write. if !is_in_assignment_position(self.cx, expr) { - span_lint_and_note( + span_lint_and_then( self.cx, MIXED_READ_WRITE_IN_EXPRESSION, expr.span, format!("unsequenced read of `{}`", self.cx.tcx.hir().name(self.var)), - Some(self.write_expr.span), - "whether read occurs before this write depends on evaluation order", + |diag| { + diag.span_note( + self.write_expr.span, + "whether read occurs before this write depends on evaluation order", + ); + }, ); } } diff --git a/clippy_lints/src/module_style.rs b/clippy_lints/src/module_style.rs index 305499f9da43..e9c5f64a2550 100644 --- a/clippy_lints/src/module_style.rs +++ b/clippy_lints/src/module_style.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_and_then; use rustc_ast::ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_lint::{EarlyContext, EarlyLintPass, Level, LintContext}; @@ -121,17 +121,18 @@ impl EarlyLintPass for ModStyle { for folder in &folder_segments { if !mod_folders.contains(folder) { if let Some((file, path)) = file_map.get(folder) { - let mut correct = path.to_path_buf(); - correct.pop(); - correct.push(folder); - correct.push("mod.rs"); - span_lint_and_help( + span_lint_and_then( cx, SELF_NAMED_MODULE_FILES, Span::new(file.start_pos, file.start_pos, SyntaxContext::root(), None), format!("`mod.rs` files are required, found `{}`", path.display()), - None, - format!("move `{}` to `{}`", path.display(), correct.display(),), + |diag| { + let mut correct = path.to_path_buf(); + correct.pop(); + correct.push(folder); + correct.push("mod.rs"); + diag.help(format!("move `{}` to `{}`", path.display(), correct.display(),)); + }, ); } } @@ -161,17 +162,18 @@ fn process_paths_for_mod_files<'a>( /// for code-sharing between tests. fn check_self_named_mod_exists(cx: &EarlyContext<'_>, path: &Path, file: &SourceFile) { if path.ends_with("mod.rs") && !path.starts_with("tests") { - let mut mod_file = path.to_path_buf(); - mod_file.pop(); - mod_file.set_extension("rs"); - - span_lint_and_help( + span_lint_and_then( cx, MOD_MODULE_FILES, Span::new(file.start_pos, file.start_pos, SyntaxContext::root(), None), format!("`mod.rs` files are not allowed, found `{}`", path.display()), - None, - format!("move `{}` to `{}`", path.display(), mod_file.display()), + |diag| { + let mut mod_file = path.to_path_buf(); + mod_file.pop(); + mod_file.set_extension("rs"); + + diag.help(format!("move `{}` to `{}`", path.display(), mod_file.display())); + }, ); } } From 0cdf6e172cb861387d41ad01540a321a1e09c1b4 Mon Sep 17 00:00:00 2001 From: jusexton Date: Tue, 23 Jul 2024 02:55:58 -0500 Subject: [PATCH 12/73] Fix while_let_on_iterator dropping loop label when applying fix. --- clippy_lints/src/loops/while_let_on_iterator.rs | 7 +++++-- clippy_utils/src/higher.rs | 4 +++- tests/ui/while_let_on_iterator.fixed | 9 +++++++++ tests/ui/while_let_on_iterator.rs | 9 +++++++++ tests/ui/while_let_on_iterator.stderr | 8 +++++++- 5 files changed, 33 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/loops/while_let_on_iterator.rs b/clippy_lints/src/loops/while_let_on_iterator.rs index 194dd4752f91..c171fa1c622a 100644 --- a/clippy_lints/src/loops/while_let_on_iterator.rs +++ b/clippy_lints/src/loops/while_let_on_iterator.rs @@ -14,7 +14,7 @@ use rustc_span::symbol::sym; use rustc_span::Symbol; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let Some(higher::WhileLet { if_then, let_pat, let_expr, .. }) = higher::WhileLet::hir(expr) + if let Some(higher::WhileLet { if_then, let_pat, let_expr, label, .. }) = higher::WhileLet::hir(expr) // check for `Some(..)` pattern && let PatKind::TupleStruct(ref pat_path, some_pat, _) = let_pat.kind && is_res_lang_ctor(cx, cx.qpath_res(pat_path, let_pat.hir_id), LangItem::OptionSome) @@ -27,6 +27,9 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { && !uses_iter(cx, &iter_expr_struct, if_then) { let mut applicability = Applicability::MachineApplicable; + + let loop_label = label.map_or(String::new(), |l| format!("{}: ", l.ident.name)); + let loop_var = if let Some(some_pat) = some_pat.first() { if is_refutable(cx, some_pat) { // Refutable patterns don't work with for loops. @@ -57,7 +60,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { expr.span.with_hi(let_expr.span.hi()), "this loop could be written as a `for` loop", "try", - format!("for {loop_var} in {iterator}{by_ref}"), + format!("{loop_label}for {loop_var} in {iterator}{by_ref}"), applicability, ); } diff --git a/clippy_utils/src/higher.rs b/clippy_utils/src/higher.rs index 277ba8427e05..7ce9bde1a733 100644 --- a/clippy_utils/src/higher.rs +++ b/clippy_utils/src/higher.rs @@ -367,6 +367,7 @@ pub struct WhileLet<'hir> { pub let_expr: &'hir Expr<'hir>, /// `while let` loop body pub if_then: &'hir Expr<'hir>, + pub label: Option, /// `while let PAT = EXPR` /// ^^^^^^^^^^^^^^ pub let_span: Span, @@ -399,7 +400,7 @@ impl<'hir> WhileLet<'hir> { }), .. }, - _, + label, LoopSource::While, _, ) = expr.kind @@ -408,6 +409,7 @@ impl<'hir> WhileLet<'hir> { let_pat, let_expr, if_then, + label, let_span, }); } diff --git a/tests/ui/while_let_on_iterator.fixed b/tests/ui/while_let_on_iterator.fixed index 59b5c858d046..b8087c6e000f 100644 --- a/tests/ui/while_let_on_iterator.fixed +++ b/tests/ui/while_let_on_iterator.fixed @@ -456,6 +456,15 @@ fn fn_once_closure() { }); } +fn issue13123() { + let mut it = 0..20; + 'label: for n in it { + if n % 25 == 0 { + break 'label; + } + } +} + fn main() { let mut it = 0..20; for _ in it { diff --git a/tests/ui/while_let_on_iterator.rs b/tests/ui/while_let_on_iterator.rs index 559513d56946..8e02f59b5126 100644 --- a/tests/ui/while_let_on_iterator.rs +++ b/tests/ui/while_let_on_iterator.rs @@ -456,6 +456,15 @@ fn fn_once_closure() { }); } +fn issue13123() { + let mut it = 0..20; + 'label: while let Some(n) = it.next() { + if n % 25 == 0 { + break 'label; + } + } +} + fn main() { let mut it = 0..20; while let Some(..) = it.next() { diff --git a/tests/ui/while_let_on_iterator.stderr b/tests/ui/while_let_on_iterator.stderr index 8ff1f23644b1..d96b26acf345 100644 --- a/tests/ui/while_let_on_iterator.stderr +++ b/tests/ui/while_let_on_iterator.stderr @@ -160,8 +160,14 @@ LL | while let Some(x) = it.next() { error: this loop could be written as a `for` loop --> tests/ui/while_let_on_iterator.rs:461:5 | +LL | 'label: while let Some(n) = it.next() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'label: for n in it` + +error: this loop could be written as a `for` loop + --> tests/ui/while_let_on_iterator.rs:470:5 + | LL | while let Some(..) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in it` -error: aborting due to 27 previous errors +error: aborting due to 28 previous errors From e63061d75bd11ad7020cd4366c385a0ad713408f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maja=20K=C4=85dzio=C5=82ka?= Date: Wed, 24 Jul 2024 22:24:12 +0200 Subject: [PATCH 13/73] Apply review suggestion Co-authored-by: Fridtjof Stoldt --- tests/ui/needless_borrows_for_generic_args.fixed | 2 +- tests/ui/needless_borrows_for_generic_args.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ui/needless_borrows_for_generic_args.fixed b/tests/ui/needless_borrows_for_generic_args.fixed index 593649b60bc7..c1dc8b5e8d09 100644 --- a/tests/ui/needless_borrows_for_generic_args.fixed +++ b/tests/ui/needless_borrows_for_generic_args.fixed @@ -336,7 +336,7 @@ fn main() { { fn takes_writer(_: T) {} - fn f(mut buffer: &mut Vec) { + fn issue_12856(mut buffer: &mut Vec) { takes_writer(&mut buffer); // Don't lint, would make buffer unavailable later buffer.extend(b"\n"); } diff --git a/tests/ui/needless_borrows_for_generic_args.rs b/tests/ui/needless_borrows_for_generic_args.rs index 0c9b98d739d3..c7f66824d581 100644 --- a/tests/ui/needless_borrows_for_generic_args.rs +++ b/tests/ui/needless_borrows_for_generic_args.rs @@ -336,7 +336,7 @@ fn main() { { fn takes_writer(_: T) {} - fn f(mut buffer: &mut Vec) { + fn issue_12856(mut buffer: &mut Vec) { takes_writer(&mut buffer); // Don't lint, would make buffer unavailable later buffer.extend(b"\n"); } From de1e1637795cae6bb19191f1afb1ab847ed10240 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Thu, 25 Jul 2024 15:02:31 +0200 Subject: [PATCH 14/73] get rid of unnecessary `res` field in `for_each_expr` visitors --- clippy_utils/src/visitors.rs | 98 ++++++++++++++++++------------------ 1 file changed, 48 insertions(+), 50 deletions(-) diff --git a/clippy_utils/src/visitors.rs b/clippy_utils/src/visitors.rs index 7066c9ad2b96..2a5d3536ff6b 100644 --- a/clippy_utils/src/visitors.rs +++ b/clippy_utils/src/visitors.rs @@ -1,6 +1,7 @@ use crate::ty::needs_ordered_drop; use crate::{get_enclosing_block, path_to_local_id}; use core::ops::ControlFlow; +use rustc_ast::visit::{try_visit, VisitorResult}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::intravisit::{self, walk_block, walk_expr, Visitor}; @@ -50,16 +51,17 @@ impl Continue for Descend { /// A type which can be visited. pub trait Visitable<'tcx> { /// Calls the corresponding `visit_*` function on the visitor. - fn visit>(self, visitor: &mut V); + fn visit>(self, visitor: &mut V) -> V::Result; } impl<'tcx, T> Visitable<'tcx> for &'tcx [T] where &'tcx T: Visitable<'tcx>, { - fn visit>(self, visitor: &mut V) { + fn visit>(self, visitor: &mut V) -> V::Result { for x in self { - x.visit(visitor); + try_visit!(x.visit(visitor)); } + V::Result::output() } } impl<'tcx, A, B> Visitable<'tcx> for (A, B) @@ -67,27 +69,28 @@ where A: Visitable<'tcx>, B: Visitable<'tcx>, { - fn visit>(self, visitor: &mut V) { + fn visit>(self, visitor: &mut V) -> V::Result { let (a, b) = self; - a.visit(visitor); - b.visit(visitor); + try_visit!(a.visit(visitor)); + b.visit(visitor) } } impl<'tcx, T> Visitable<'tcx> for Option where T: Visitable<'tcx>, { - fn visit>(self, visitor: &mut V) { + fn visit>(self, visitor: &mut V) -> V::Result { if let Some(x) = self { - x.visit(visitor); + try_visit!(x.visit(visitor)); } + V::Result::output() } } macro_rules! visitable_ref { ($t:ident, $f:ident) => { impl<'tcx> Visitable<'tcx> for &'tcx $t<'tcx> { - fn visit>(self, visitor: &mut V) { - visitor.$f(self); + fn visit>(self, visitor: &mut V) -> V::Result { + visitor.$f(self) } } }; @@ -104,45 +107,37 @@ pub fn for_each_expr_without_closures<'tcx, B, C: Continue>( node: impl Visitable<'tcx>, f: impl FnMut(&'tcx Expr<'tcx>) -> ControlFlow, ) -> Option { - struct V { + struct V { f: F, - res: Option, } - impl<'tcx, B, C: Continue, F: FnMut(&'tcx Expr<'tcx>) -> ControlFlow> Visitor<'tcx> for V { - type Result = ControlFlow<()>; + impl<'tcx, B, C: Continue, F: FnMut(&'tcx Expr<'tcx>) -> ControlFlow> Visitor<'tcx> for V { + type Result = ControlFlow; - fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) -> ControlFlow<()> { - if self.res.is_some() { - return ControlFlow::Break(()); - } + fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) -> Self::Result { match (self.f)(e) { ControlFlow::Continue(c) if c.descend() => walk_expr(self, e), - ControlFlow::Break(b) => { - self.res = Some(b); - ControlFlow::Break(()) - }, + ControlFlow::Break(b) => ControlFlow::Break(b), ControlFlow::Continue(_) => ControlFlow::Continue(()), } } // Avoid unnecessary `walk_*` calls. - fn visit_ty(&mut self, _: &'tcx hir::Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, _: &'tcx hir::Ty<'tcx>) -> Self::Result { ControlFlow::Continue(()) } - fn visit_pat(&mut self, _: &'tcx Pat<'tcx>) -> ControlFlow<()> { + fn visit_pat(&mut self, _: &'tcx Pat<'tcx>) -> Self::Result { ControlFlow::Continue(()) } - fn visit_qpath(&mut self, _: &'tcx QPath<'tcx>, _: HirId, _: Span) -> ControlFlow<()> { + fn visit_qpath(&mut self, _: &'tcx QPath<'tcx>, _: HirId, _: Span) -> Self::Result { ControlFlow::Continue(()) } // Avoid monomorphising all `visit_*` functions. - fn visit_nested_item(&mut self, _: ItemId) -> ControlFlow<()> { + fn visit_nested_item(&mut self, _: ItemId) -> Self::Result { ControlFlow::Continue(()) } } - let mut v = V { f, res: None }; - node.visit(&mut v); - v.res + let mut v = V { f }; + node.visit(&mut v).break_value() } /// Calls the given function once for each expression contained. This will enter bodies, but not @@ -152,44 +147,47 @@ pub fn for_each_expr<'tcx, B, C: Continue>( node: impl Visitable<'tcx>, f: impl FnMut(&'tcx Expr<'tcx>) -> ControlFlow, ) -> Option { - struct V<'tcx, B, F> { + struct V<'tcx, F> { tcx: TyCtxt<'tcx>, f: F, - res: Option, } - impl<'tcx, B, C: Continue, F: FnMut(&'tcx Expr<'tcx>) -> ControlFlow> Visitor<'tcx> for V<'tcx, B, F> { + impl<'tcx, B, C: Continue, F: FnMut(&'tcx Expr<'tcx>) -> ControlFlow> Visitor<'tcx> for V<'tcx, F> { type NestedFilter = nested_filter::OnlyBodies; + type Result = ControlFlow; + fn nested_visit_map(&mut self) -> Self::Map { self.tcx.hir() } - fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) { - if self.res.is_some() { - return; - } + fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) -> Self::Result { match (self.f)(e) { ControlFlow::Continue(c) if c.descend() => walk_expr(self, e), - ControlFlow::Break(b) => self.res = Some(b), - ControlFlow::Continue(_) => (), + ControlFlow::Break(b) => ControlFlow::Break(b), + ControlFlow::Continue(_) => ControlFlow::Continue(()), } } // Only walk closures - fn visit_anon_const(&mut self, _: &'tcx AnonConst) {} + fn visit_anon_const(&mut self, _: &'tcx AnonConst) -> Self::Result { + ControlFlow::Continue(()) + } // Avoid unnecessary `walk_*` calls. - fn visit_ty(&mut self, _: &'tcx hir::Ty<'tcx>) {} - fn visit_pat(&mut self, _: &'tcx Pat<'tcx>) {} - fn visit_qpath(&mut self, _: &'tcx QPath<'tcx>, _: HirId, _: Span) {} + fn visit_ty(&mut self, _: &'tcx hir::Ty<'tcx>) -> Self::Result { + ControlFlow::Continue(()) + } + fn visit_pat(&mut self, _: &'tcx Pat<'tcx>) -> Self::Result { + ControlFlow::Continue(()) + } + fn visit_qpath(&mut self, _: &'tcx QPath<'tcx>, _: HirId, _: Span) -> Self::Result { + ControlFlow::Continue(()) + } // Avoid monomorphising all `visit_*` functions. - fn visit_nested_item(&mut self, _: ItemId) {} + fn visit_nested_item(&mut self, _: ItemId) -> Self::Result { + ControlFlow::Continue(()) + } } - let mut v = V { - tcx: cx.tcx, - f, - res: None, - }; - node.visit(&mut v); - v.res + let mut v = V { tcx: cx.tcx, f }; + node.visit(&mut v).break_value() } /// returns `true` if expr contains match expr desugared from try From 4e6851e50bde42cef280076aa48035871bfe9520 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 25 Jul 2024 18:29:17 +0200 Subject: [PATCH 15/73] Merge commit '37f4fbb92913586b73a35772efd00eccd1cbbe13' into clippy-subtree-update --- .cargo/config.toml | 2 +- .github/workflows/lintcheck.yml | 28 +- CHANGELOG.md | 47 +- Cargo.toml | 9 +- book/src/development/adding_lints.md | 14 +- book/src/lint_configuration.md | 3 +- clippy.toml | 1 - clippy_config/Cargo.toml | 2 +- clippy_config/src/conf.rs | 29 +- clippy_config/src/types.rs | 14 +- clippy_dev/src/new_lint.rs | 8 +- clippy_lints/Cargo.toml | 2 +- clippy_lints/src/absolute_paths.rs | 12 +- clippy_lints/src/almost_complete_range.rs | 7 +- clippy_lints/src/approx_const.rs | 8 +- clippy_lints/src/arc_with_non_send_sync.rs | 15 +- clippy_lints/src/assigning_clones.rs | 8 +- clippy_lints/src/attrs/mod.rs | 19 +- clippy_lints/src/await_holding_invalid.rs | 39 +- clippy_lints/src/borrow_deref_ref.rs | 44 +- clippy_lints/src/cargo/mod.rs | 16 +- clippy_lints/src/casts/cast_lossless.rs | 111 ++-- clippy_lints/src/casts/mod.rs | 48 +- clippy_lints/src/casts/ptr_cast_constness.rs | 3 +- clippy_lints/src/checked_conversions.rs | 141 ++--- clippy_lints/src/cognitive_complexity.rs | 6 +- clippy_lints/src/collapsible_if.rs | 33 +- clippy_lints/src/collection_is_never_read.rs | 6 +- clippy_lints/src/copies.rs | 14 +- clippy_lints/src/crate_in_macro_def.rs | 7 +- clippy_lints/src/dbg_macro.rs | 6 +- clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/derivable_impls.rs | 8 +- clippy_lints/src/disallowed_macros.rs | 31 +- clippy_lints/src/disallowed_methods.rs | 42 +- clippy_lints/src/disallowed_names.rs | 11 +- clippy_lints/src/disallowed_script_idents.rs | 18 +- clippy_lints/src/disallowed_types.rs | 91 ++- clippy_lints/src/doc/mod.rs | 12 +- clippy_lints/src/double_parens.rs | 48 +- clippy_lints/src/else_if_without_else.rs | 5 +- clippy_lints/src/empty_enum.rs | 34 +- clippy_lints/src/endian_bytes.rs | 39 +- clippy_lints/src/equatable_if_let.rs | 4 +- clippy_lints/src/error_impl_error.rs | 9 +- clippy_lints/src/escape.rs | 12 +- clippy_lints/src/excessive_bools.rs | 105 ++-- clippy_lints/src/excessive_nesting.rs | 9 +- clippy_lints/src/exhaustive_items.rs | 26 +- clippy_lints/src/exit.rs | 6 +- .../src/extra_unused_type_parameters.rs | 35 +- clippy_lints/src/float_literal.rs | 5 +- clippy_lints/src/format_args.rs | 8 +- clippy_lints/src/format_impl.rs | 1 - clippy_lints/src/from_over_into.rs | 14 +- clippy_lints/src/from_str_radix_10.rs | 19 +- clippy_lints/src/functions/mod.rs | 37 +- clippy_lints/src/future_not_send.rs | 14 +- clippy_lints/src/if_let_mutex.rs | 65 +- clippy_lints/src/if_not_else.rs | 63 +- clippy_lints/src/if_then_some_else_none.rs | 33 +- clippy_lints/src/ignored_unit_patterns.rs | 31 +- clippy_lints/src/incompatible_msrv.rs | 5 +- .../src/inconsistent_struct_constructor.rs | 6 +- clippy_lints/src/index_refutable_slice.rs | 11 +- clippy_lints/src/indexing_slicing.rs | 14 +- clippy_lints/src/infinite_iter.rs | 5 +- clippy_lints/src/instant_subtraction.rs | 8 +- clippy_lints/src/item_name_repetitions.rs | 20 +- clippy_lints/src/large_const_arrays.rs | 12 +- clippy_lints/src/large_enum_variant.rs | 7 +- clippy_lints/src/large_futures.rs | 8 +- clippy_lints/src/large_include_file.rs | 8 +- clippy_lints/src/large_stack_arrays.rs | 12 +- clippy_lints/src/large_stack_frames.rs | 6 +- clippy_lints/src/legacy_numeric_constants.rs | 8 +- clippy_lints/src/lib.rs | 463 +++----------- clippy_lints/src/lifetimes.rs | 18 +- clippy_lints/src/literal_representation.rs | 18 +- clippy_lints/src/loops/mod.rs | 7 +- clippy_lints/src/loops/mut_range_bound.rs | 15 +- clippy_lints/src/loops/single_element_loop.rs | 7 +- .../src/loops/while_immutable_condition.rs | 24 +- clippy_lints/src/macro_metavars_in_unsafe.rs | 20 +- clippy_lints/src/manual_bits.rs | 9 +- clippy_lints/src/manual_clamp.rs | 7 +- clippy_lints/src/manual_hash_one.rs | 8 +- clippy_lints/src/manual_is_ascii_check.rs | 8 +- clippy_lints/src/manual_main_separator_str.rs | 8 +- clippy_lints/src/manual_non_exhaustive.rs | 13 +- clippy_lints/src/manual_rem_euclid.rs | 8 +- clippy_lints/src/manual_retain.rs | 8 +- clippy_lints/src/manual_strip.rs | 8 +- clippy_lints/src/matches/manual_unwrap_or.rs | 11 + clippy_lints/src/matches/mod.rs | 6 +- .../matches/significant_drop_in_scrutinee.rs | 6 +- clippy_lints/src/mem_replace.rs | 8 +- .../src/methods/bind_instead_of_map.rs | 109 ++-- clippy_lints/src/methods/mod.rs | 31 +- .../src/methods/option_map_unwrap_or.rs | 32 +- clippy_lints/src/methods/or_fun_call.rs | 133 ++-- .../src/methods/path_ends_with_ext.rs | 2 +- clippy_lints/src/min_ident_chars.rs | 19 +- clippy_lints/src/misc.rs | 43 +- .../src/mismatching_type_param_order.rs | 6 +- clippy_lints/src/missing_const_for_fn.rs | 8 +- .../src/missing_const_for_thread_local.rs | 8 +- clippy_lints/src/missing_doc.rs | 13 +- .../src/missing_enforced_import_rename.rs | 29 +- clippy_lints/src/mut_key.rs | 13 +- clippy_lints/src/mut_mut.rs | 37 +- clippy_lints/src/needless_borrowed_ref.rs | 142 ++--- .../src/needless_borrows_for_generic_args.rs | 6 +- clippy_lints/src/needless_for_each.rs | 16 +- clippy_lints/src/needless_pass_by_ref_mut.rs | 9 +- clippy_lints/src/neg_cmp_op_on_partial_ord.rs | 4 +- clippy_lints/src/non_copy_const.rs | 11 +- clippy_lints/src/non_expressive_names.rs | 23 +- .../src/non_send_fields_in_send_ty.rs | 6 +- clippy_lints/src/nonstandard_macro_braces.rs | 7 +- .../src/operators/arithmetic_side_effects.rs | 55 +- clippy_lints/src/operators/mod.rs | 21 +- clippy_lints/src/option_env_unwrap.rs | 24 +- clippy_lints/src/panic_unimplemented.rs | 12 +- clippy_lints/src/pass_by_ref_or_value.rs | 19 +- clippy_lints/src/pathbuf_init_then_push.rs | 193 ++++++ .../src/permissions_set_readonly_false.rs | 4 +- clippy_lints/src/pub_underscore_fields.rs | 11 +- clippy_lints/src/question_mark.rs | 8 +- clippy_lints/src/ranges.rs | 8 +- clippy_lints/src/raw_strings.rs | 45 +- clippy_lints/src/redundant_closure_call.rs | 25 +- clippy_lints/src/redundant_field_names.rs | 8 +- .../src/redundant_static_lifetimes.rs | 8 +- clippy_lints/src/regex.rs | 2 +- clippy_lints/src/semicolon_block.rs | 12 +- clippy_lints/src/serde_api.rs | 2 +- clippy_lints/src/single_call_fn.rs | 13 +- clippy_lints/src/single_range_in_vec_init.rs | 2 +- clippy_lints/src/string_patterns.rs | 8 +- clippy_lints/src/trait_bounds.rs | 10 +- clippy_lints/src/transmute/mod.rs | 10 +- .../src/transmute/transmute_ptr_to_ptr.rs | 43 +- clippy_lints/src/tuple_array_conversions.rs | 11 +- clippy_lints/src/types/mod.rs | 9 +- clippy_lints/src/unconditional_recursion.rs | 14 +- .../src/undocumented_unsafe_blocks.rs | 8 +- clippy_lints/src/unnecessary_box_returns.rs | 7 +- .../src/unnecessary_struct_initialization.rs | 189 ++++-- clippy_lints/src/unnecessary_wraps.rs | 5 +- clippy_lints/src/unnested_or_patterns.rs | 8 +- clippy_lints/src/unused_peekable.rs | 63 +- clippy_lints/src/unused_self.rs | 5 +- clippy_lints/src/upper_case_acronyms.rs | 8 +- clippy_lints/src/use_self.rs | 6 +- .../interning_defined_symbol.rs | 2 +- .../src/utils/internal_lints/invalid_paths.rs | 2 +- .../internal_lints/unnecessary_def_path.rs | 4 +- clippy_lints/src/vec.rs | 20 +- clippy_lints/src/wildcard_imports.rs | 12 +- clippy_lints/src/write.rs | 8 +- clippy_lints/src/zero_repeat_side_effects.rs | 28 +- clippy_utils/Cargo.toml | 2 +- clippy_utils/src/hir_utils.rs | 2 +- clippy_utils/src/lib.rs | 29 +- clippy_utils/src/numeric_literal.rs | 2 + clippy_utils/src/sugg.rs | 9 +- clippy_utils/src/ty.rs | 8 +- clippy_utils/src/ty/type_certainty/mod.rs | 2 +- clippy_utils/src/visitors.rs | 29 +- declare_clippy_lint/Cargo.toml | 2 +- lintcheck/Cargo.toml | 2 +- lintcheck/ci_crates.toml | 208 +++++++ lintcheck/lintcheck_crates.toml | 74 ++- lintcheck/src/config.rs | 8 +- lintcheck/src/driver.rs | 1 + lintcheck/src/input.rs | 128 ++-- lintcheck/src/json.rs | 218 +++++-- lintcheck/src/main.rs | 63 +- lintcheck/src/output.rs | 33 +- lintcheck/src/recursive.rs | 10 +- rust-toolchain | 2 +- tests/compile-test.rs | 14 +- tests/dogfood.rs | 47 +- tests/integration.rs | 6 +- tests/ui-internal/disallow_span_lint.stderr | 4 +- .../await_holding_invalid_type.stderr | 10 +- .../disallowed_macros.stderr | 2 +- .../index_refutable_slice.fixed | 24 - .../index_refutable_slice.rs | 2 + .../index_refutable_slice.stderr | 2 +- .../conf_disallowed_methods.stderr | 2 +- .../conf_disallowed_types.stderr | 44 +- tests/ui/cast_lossless_bool.stderr | 149 ++++- tests/ui/cast_lossless_float.stderr | 129 +++- tests/ui/cast_lossless_integer.fixed | 129 +++- tests/ui/cast_lossless_integer.rs | 129 +++- tests/ui/cast_lossless_integer.stderr | 547 +++++++++++++--- tests/ui/crashes/ice-3717.fixed | 11 - tests/ui/crashes/ice-3717.rs | 2 + tests/ui/crashes/ice-3717.stderr | 2 +- tests/ui/deref_addrof.fixed | 2 +- tests/ui/deref_addrof.rs | 2 +- tests/ui/derivable_impls.fixed | 295 --------- tests/ui/derivable_impls.rs | 2 + tests/ui/derivable_impls.stderr | 16 +- tests/ui/doc/doc-fixable.fixed | 13 +- tests/ui/doc/doc-fixable.rs | 13 +- tests/ui/doc/doc-fixable.stderr | 44 +- tests/ui/excessive_precision.fixed | 4 + tests/ui/excessive_precision.rs | 4 + tests/ui/excessive_precision.stderr | 8 +- tests/ui/floating_point_powf.fixed | 8 + tests/ui/floating_point_powf.rs | 8 + tests/ui/floating_point_powf.stderr | 32 +- .../if_let_slice_binding.fixed | 177 ------ .../if_let_slice_binding.rs | 2 + .../if_let_slice_binding.stderr | 20 +- .../slice_indexing_in_macro.fixed | 29 - .../slice_indexing_in_macro.rs | 2 + .../slice_indexing_in_macro.stderr | 2 +- tests/ui/let_unit.fixed | 196 ------ tests/ui/let_unit.rs | 2 + tests/ui/let_unit.stderr | 8 +- tests/ui/manual_assert.edition2018.fixed | 76 --- tests/ui/manual_assert.edition2018.stderr | 20 +- tests/ui/manual_assert.edition2021.fixed | 76 --- tests/ui/manual_assert.edition2021.stderr | 20 +- tests/ui/manual_assert.rs | 2 + tests/ui/manual_async_fn.fixed | 115 ---- tests/ui/manual_async_fn.rs | 2 + tests/ui/manual_async_fn.stderr | 26 +- tests/ui/manual_split_once.fixed | 144 ----- tests/ui/manual_split_once.rs | 2 + tests/ui/manual_split_once.stderr | 38 +- tests/ui/manual_unwrap_or.fixed | 16 + tests/ui/manual_unwrap_or.rs | 16 + tests/ui/match_same_arms2.fixed | 258 -------- tests/ui/match_same_arms2.rs | 3 + tests/ui/match_same_arms2.stderr | 30 +- tests/ui/min_ident_chars.stderr | 8 +- .../missing_const_for_fn/could_be_const.fixed | 2 +- .../ui/missing_const_for_fn/could_be_const.rs | 2 +- tests/ui/needless_option_as_deref.fixed | 18 + tests/ui/needless_option_as_deref.rs | 18 + tests/ui/or_fun_call.fixed | 47 ++ tests/ui/or_fun_call.rs | 47 ++ tests/ui/or_fun_call.stderr | 50 +- tests/ui/path_buf_push_overwrite.fixed | 3 +- tests/ui/path_buf_push_overwrite.rs | 3 +- tests/ui/path_buf_push_overwrite.stderr | 2 +- tests/ui/pathbuf_init_then_push.fixed | 22 + tests/ui/pathbuf_init_then_push.rs | 26 + tests/ui/pathbuf_init_then_push.stderr | 33 + tests/ui/ptr_cast_constness.fixed | 4 + tests/ui/ptr_cast_constness.rs | 4 + tests/ui/ptr_cast_constness.stderr | 4 +- tests/ui/redundant_clone.fixed | 1 + tests/ui/redundant_clone.rs | 1 + tests/ui/redundant_clone.stderr | 78 +-- tests/ui/significant_drop_tightening.fixed | 144 ----- tests/ui/significant_drop_tightening.rs | 2 + tests/ui/significant_drop_tightening.stderr | 8 +- tests/ui/single_element_loop.fixed | 8 + tests/ui/single_element_loop.rs | 7 + tests/ui/single_element_loop.stderr | 18 +- tests/ui/toplevel_ref_arg.fixed | 2 + tests/ui/toplevel_ref_arg.rs | 2 + tests/ui/transmute_ptr_to_ptr.fixed | 79 ++- tests/ui/transmute_ptr_to_ptr.rs | 87 ++- tests/ui/transmute_ptr_to_ptr.stderr | 152 ++++- .../transmutes_expressible_as_ptr_casts.fixed | 2 +- ...transmutes_expressible_as_ptr_casts.stderr | 13 +- tests/ui/types.fixed | 13 - tests/ui/types.rs | 13 - tests/ui/types.stderr | 11 - tests/ui/unnecessary_iter_cloned.fixed | 201 ------ tests/ui/unnecessary_iter_cloned.rs | 2 + tests/ui/unnecessary_iter_cloned.stderr | 10 +- .../unnecessary_struct_initialization.fixed | 70 +++ tests/ui/unnecessary_struct_initialization.rs | 70 +++ .../unnecessary_struct_initialization.stderr | 44 +- tests/ui/unnecessary_to_owned.fixed | 587 ------------------ tests/ui/unnecessary_to_owned.rs | 2 + tests/ui/unnecessary_to_owned.stderr | 224 +++---- tests/ui/zero_repeat_side_effects.fixed | 20 +- tests/ui/zero_repeat_side_effects.rs | 20 +- tests/ui/zero_repeat_side_effects.stderr | 36 +- triagebot.toml | 2 +- util/gh-pages/index.html | 40 +- util/gh-pages/script.js | 6 + 291 files changed, 4890 insertions(+), 5205 deletions(-) create mode 100644 clippy_lints/src/pathbuf_init_then_push.rs create mode 100644 lintcheck/ci_crates.toml delete mode 100644 tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.fixed delete mode 100644 tests/ui/crashes/ice-3717.fixed delete mode 100644 tests/ui/derivable_impls.fixed delete mode 100644 tests/ui/index_refutable_slice/if_let_slice_binding.fixed delete mode 100644 tests/ui/index_refutable_slice/slice_indexing_in_macro.fixed delete mode 100644 tests/ui/let_unit.fixed delete mode 100644 tests/ui/manual_assert.edition2018.fixed delete mode 100644 tests/ui/manual_assert.edition2021.fixed delete mode 100644 tests/ui/manual_async_fn.fixed delete mode 100644 tests/ui/manual_split_once.fixed delete mode 100644 tests/ui/match_same_arms2.fixed create mode 100644 tests/ui/pathbuf_init_then_push.fixed create mode 100644 tests/ui/pathbuf_init_then_push.rs create mode 100644 tests/ui/pathbuf_init_then_push.stderr delete mode 100644 tests/ui/significant_drop_tightening.fixed delete mode 100644 tests/ui/types.fixed delete mode 100644 tests/ui/types.rs delete mode 100644 tests/ui/types.stderr delete mode 100644 tests/ui/unnecessary_iter_cloned.fixed delete mode 100644 tests/ui/unnecessary_to_owned.fixed diff --git a/.cargo/config.toml b/.cargo/config.toml index 48a63e485681..7afdd068a990 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -4,7 +4,7 @@ uibless = "test --test compile-test -- -- --bless" bless = "test -- -- --bless" dev = "run --package clippy_dev --bin clippy_dev --manifest-path clippy_dev/Cargo.toml --" lintcheck = "run --package lintcheck --bin lintcheck --manifest-path lintcheck/Cargo.toml -- " -collect-metadata = "test --test dogfood --features internal -- run_metadata_collection_lint --ignored" +collect-metadata = "test --test dogfood --features internal -- collect_metadata" [build] # -Zbinary-dep-depinfo allows us to track which rlib files to use for compiling UI tests diff --git a/.github/workflows/lintcheck.yml b/.github/workflows/lintcheck.yml index f016a7700592..6a5139b6dc0b 100644 --- a/.github/workflows/lintcheck.yml +++ b/.github/workflows/lintcheck.yml @@ -53,18 +53,18 @@ jobs: id: cache-json uses: actions/cache@v4 with: - path: lintcheck-logs/lintcheck_crates_logs.json + path: lintcheck-logs/ci_crates_logs.json key: ${{ steps.key.outputs.key }} - name: Run lintcheck if: steps.cache-json.outputs.cache-hit != 'true' - run: ./target/debug/lintcheck --format json --warn-all + run: ./target/debug/lintcheck --format json --warn-all --crates-toml ./lintcheck/ci_crates.toml - name: Upload base JSON uses: actions/upload-artifact@v4 with: name: base - path: lintcheck-logs/lintcheck_crates_logs.json + path: lintcheck-logs/ci_crates_logs.json # Runs lintcheck on the PR and stores the results as an artifact head: @@ -86,13 +86,13 @@ jobs: run: cargo build --manifest-path=lintcheck/Cargo.toml - name: Run lintcheck - run: ./target/debug/lintcheck --format json --warn-all + run: ./target/debug/lintcheck --format json --warn-all --crates-toml ./lintcheck/ci_crates.toml - name: Upload head JSON uses: actions/upload-artifact@v4 with: name: head - path: lintcheck-logs/lintcheck_crates_logs.json + path: lintcheck-logs/ci_crates_logs.json # Retrieves the head and base JSON results and prints the diff to the GH actions step summary diff: @@ -115,4 +115,20 @@ jobs: uses: actions/download-artifact@v4 - name: Diff results - run: ./target/debug/lintcheck diff {base,head}/lintcheck_crates_logs.json >> $GITHUB_STEP_SUMMARY + # GH's summery has a maximum size of 1024k: + # https://docs.github.com/actions/using-workflows/workflow-commands-for-github-actions#adding-a-markdown-summary + # That's why we first log to file and then to the summary and logs + run: | + ./target/debug/lintcheck diff {base,head}/ci_crates_logs.json --truncate >> truncated_diff.md + head -c 1024000 truncated_diff.md >> $GITHUB_STEP_SUMMARY + cat truncated_diff.md + ./target/debug/lintcheck diff {base,head}/ci_crates_logs.json >> full_diff.md + + - name: Upload full diff + uses: actions/upload-artifact@v4 + with: + name: diff + if-no-files-found: ignore + path: | + full_diff.md + truncated_diff.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 55281f3cbec0..60c03b03d9be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,11 +6,53 @@ document. ## Unreleased / Beta / In Rust Nightly -[ca3b3937...master](https://github.com/rust-lang/rust-clippy/compare/ca3b3937...master) +[c9139bd5...master](https://github.com/rust-lang/rust-clippy/compare/c9139bd5...master) + +## Rust 1.80 + +Current stable, released 2024-07-25 + +[View all 68 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2024-04-18T22%3A50%3A22Z..2024-05-30T08%3A26%3A18Z+base%3Amaster) + +### New Lints + +* Added [`while_float`] to `nursery` + [#12765](https://github.com/rust-lang/rust-clippy/pull/12765) +* Added [`macro_metavars_in_unsafe`] to `suspicious` + [#12107](https://github.com/rust-lang/rust-clippy/pull/12107) +* Added [`renamed_function_params`] to `restriction` + [#11540](https://github.com/rust-lang/rust-clippy/pull/11540) +* Added [`doc_lazy_continuation`] to `style` + [#12770](https://github.com/rust-lang/rust-clippy/pull/12770) + +### Moves and Deprecations + +* Moved [`assigning_clones`] to `pedantic` (From `perf` now allow-by-default) + [#12779](https://github.com/rust-lang/rust-clippy/pull/12779) +* Moved [`single_char_pattern`] to `pedantic` (From `perf` now allow-by-default) + [#11852](https://github.com/rust-lang/rust-clippy/pull/11852) + +### Enhancements + +* [`panic`]: Added [`allow-panic-in-tests`] configuration to allow the lint in tests + [#12803](https://github.com/rust-lang/rust-clippy/pull/12803) +* [`missing_const_for_fn`]: Now respects the [`msrv`] configuration + [#12713](https://github.com/rust-lang/rust-clippy/pull/12713) +* [`missing_panics_doc`]: No longer lints on compile-time panics + [#12790](https://github.com/rust-lang/rust-clippy/pull/12790) +* [`collapsible_match`]: Now considers the [`msrv`] configuration for the suggestion + [#12745](https://github.com/rust-lang/rust-clippy/pull/12745) +* [`useless_vec`]: Added [`allow-useless-vec-in-tests`] configuration to allow the lint in tests + [#12725](https://github.com/rust-lang/rust-clippy/pull/12725) + +### Suggestion Fixes/Improvements + +* [`single_match`], [`single_match_else`]: Suggestions are now machine-applicable + [#12726](https://github.com/rust-lang/rust-clippy/pull/12726) ## Rust 1.79 -Current stable, released 2024-06-13 +Released 2024-06-13 [View all 102 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2024-03-08T11%3A13%3A58Z..2024-04-18T15%3A50%3A50Z+base%3Amaster) @@ -5712,6 +5754,7 @@ Released 2018-09-13 [`partialeq_to_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_to_none [`path_buf_push_overwrite`]: https://rust-lang.github.io/rust-clippy/master/index.html#path_buf_push_overwrite [`path_ends_with_ext`]: https://rust-lang.github.io/rust-clippy/master/index.html#path_ends_with_ext +[`pathbuf_init_then_push`]: https://rust-lang.github.io/rust-clippy/master/index.html#pathbuf_init_then_push [`pattern_type_mismatch`]: https://rust-lang.github.io/rust-clippy/master/index.html#pattern_type_mismatch [`permissions_set_readonly_false`]: https://rust-lang.github.io/rust-clippy/master/index.html#permissions_set_readonly_false [`positional_named_format_parameters`]: https://rust-lang.github.io/rust-clippy/master/index.html#positional_named_format_parameters diff --git a/Cargo.toml b/Cargo.toml index 437884990551..bb4dc97e748e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.1.81" +version = "0.1.82" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" @@ -30,11 +30,10 @@ color-print = "0.3.4" anstream = "0.6.0" [dev-dependencies] -ui_test = "0.23" +ui_test = "0.24" regex = "1.5.5" toml = "0.7.3" walkdir = "2.3" -# This is used by the `collect-metadata` alias. filetime = "0.2.9" itertools = "0.12" @@ -63,3 +62,7 @@ rustc_private = true [[test]] name = "compile-test" harness = false + +[[test]] +name = "dogfood" +harness = false diff --git a/book/src/development/adding_lints.md b/book/src/development/adding_lints.md index 48c00bcbf341..a71d94daca74 100644 --- a/book/src/development/adding_lints.md +++ b/book/src/development/adding_lints.md @@ -458,9 +458,8 @@ pub struct ManualStrip { } impl ManualStrip { - #[must_use] - pub fn new(msrv: Msrv) -> Self { - Self { msrv } + pub fn new(conf: &'static Conf) -> Self { + Self { msrv: conf.msrv.clone() } } } ``` @@ -689,7 +688,6 @@ for some users. Adding a configuration is done in the following steps: ]); // New manual definition struct - #[derive(Copy, Clone)] pub struct StructName {} impl_lint_pass!(StructName => [ @@ -700,7 +698,6 @@ for some users. Adding a configuration is done in the following steps: 2. Next add the configuration value and a corresponding creation method like this: ```rust - #[derive(Copy, Clone)] pub struct StructName { configuration_ident: Type, } @@ -708,9 +705,9 @@ for some users. Adding a configuration is done in the following steps: // ... impl StructName { - pub fn new(configuration_ident: Type) -> Self { + pub fn new(conf: &'static Conf) -> Self { Self { - configuration_ident, + configuration_ident: conf.configuration_ident, } } } @@ -726,8 +723,7 @@ for some users. Adding a configuration is done in the following steps: store.register_*_pass(|| box module::StructName); // New registration with configuration value - let configuration_ident = conf.configuration_ident.clone(); - store.register_*_pass(move || box module::StructName::new(configuration_ident)); + store.register_*_pass(move || box module::StructName::new(conf)); ``` Congratulations the work is almost done. The configuration value can now be diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index ad29339a84ad..fb717a2c166d 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -455,7 +455,7 @@ default configuration of Clippy. By default, any configuration will replace the * `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`. * `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list. -**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DevOps", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "WebGL", "WebGL2", "WebGPU", "WebP", "OpenExr", "YCbCr", "sRGB", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` +**Default Value:** `["TiB", "CoreGraphics", "CoffeeScript", "TeX", "Direct2D", "PiB", "DirectX", "NetBSD", "OAuth", "NaN", "OpenType", "WebGL2", "WebTransport", "JavaScript", "OpenSSL", "OpenSSH", "EiB", "PureScript", "OpenAL", "MiB", "WebAssembly", "MinGW", "CoreFoundation", "WebGPU", "ClojureScript", "CamelCase", "OpenDNS", "NaNs", "OpenMP", "GitLab", "KiB", "sRGB", "CoreText", "macOS", "TypeScript", "GiB", "OpenExr", "YCbCr", "OpenTelemetry", "OpenBSD", "FreeBSD", "GPLv2", "PostScript", "WebP", "LaTeX", "TensorFlow", "AccessKit", "TrueType", "OpenStreetMap", "OpenGL", "DevOps", "OCaml", "WebRTC", "WebGL", "BibLaTeX", "GitHub", "GraphQL", "iOS", "Direct3D", "BibTeX", "DirectWrite", "GPLv3", "IPv6", "WebSocket", "IPv4", "ECMAScript"]` --- **Affected lints:** @@ -679,6 +679,7 @@ The minimum rust version that the project supports. Defaults to the `rust-versio * [`cast_abs_to_unsigned`](https://rust-lang.github.io/rust-clippy/master/index.html#cast_abs_to_unsigned) * [`checked_conversions`](https://rust-lang.github.io/rust-clippy/master/index.html#checked_conversions) * [`cloned_instead_of_copied`](https://rust-lang.github.io/rust-clippy/master/index.html#cloned_instead_of_copied) +* [`collapsible_match`](https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_match) * [`collapsible_str_replace`](https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_str_replace) * [`deprecated_cfg_attr`](https://rust-lang.github.io/rust-clippy/master/index.html#deprecated_cfg_attr) * [`derivable_impls`](https://rust-lang.github.io/rust-clippy/master/index.html#derivable_impls) diff --git a/clippy.toml b/clippy.toml index 319b72e8c5d5..a7b0cc56ea12 100644 --- a/clippy.toml +++ b/clippy.toml @@ -8,7 +8,6 @@ reason = "this function does not add a link to our documentation, please use the path = "rustc_lint::context::LintContext::span_lint" reason = "this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint*` functions instead" - [[disallowed-methods]] path = "rustc_middle::ty::context::TyCtxt::node_span_lint" reason = "this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint_hir*` functions instead" diff --git a/clippy_config/Cargo.toml b/clippy_config/Cargo.toml index be0b048ac0c7..e1b2edc8a6ff 100644 --- a/clippy_config/Cargo.toml +++ b/clippy_config/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_config" -version = "0.1.81" +version = "0.1.82" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index 7f53aad67933..63140a36875d 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -18,23 +18,26 @@ use std::{cmp, env, fmt, fs, io}; #[rustfmt::skip] const DEFAULT_DOC_VALID_IDENTS: &[&str] = &[ "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", + "AccessKit", + "CoreFoundation", "CoreGraphics", "CoreText", "DevOps", - "DirectX", + "Direct2D", "Direct3D", "DirectWrite", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", - "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", + "ClojureScript", "CoffeeScript", "JavaScript", "PostScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", - "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", - "WebGL", "WebGL2", "WebGPU", + "OpenAL", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", + "OpenType", + "WebGL", "WebGL2", "WebGPU", "WebRTC", "WebSocket", "WebTransport", "WebP", "OpenExr", "YCbCr", "sRGB", "TensorFlow", "TrueType", - "iOS", "macOS", "FreeBSD", + "iOS", "macOS", "FreeBSD", "NetBSD", "OpenBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase", @@ -235,7 +238,7 @@ define_Conf! { /// /// A type, say `SomeType`, listed in this configuration has the same behavior of /// `["SomeType" , "*"], ["*", "SomeType"]` in `arithmetic_side_effects_allowed_binary`. - (arithmetic_side_effects_allowed: FxHashSet = <_>::default()), + (arithmetic_side_effects_allowed: Vec = <_>::default()), /// Lint: ARITHMETIC_SIDE_EFFECTS. /// /// Suppress checking of the passed type pair names in binary operations like addition or @@ -262,12 +265,12 @@ define_Conf! { /// ```toml /// arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"] /// ``` - (arithmetic_side_effects_allowed_unary: FxHashSet = <_>::default()), + (arithmetic_side_effects_allowed_unary: Vec = <_>::default()), /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UNUSED_SELF, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX, UNNECESSARY_BOX_RETURNS, SINGLE_CALL_FN, NEEDLESS_PASS_BY_REF_MUT. /// /// Suppress lints whenever the suggested change would cause breakage for other crates. (avoid_breaking_exported_api: bool = true), - /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD, MANUAL_HASH_ONE, ITER_KV_MAP, MANUAL_C_STR_LITERALS, ASSIGNING_CLONES, LEGACY_NUMERIC_CONSTANTS, MANUAL_PATTERN_CHAR_COMPARISON, ALLOW_ATTRIBUTES, ALLOW_ATTRIBUTES_WITHOUT_REASON. + /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD, MANUAL_HASH_ONE, ITER_KV_MAP, MANUAL_C_STR_LITERALS, ASSIGNING_CLONES, LEGACY_NUMERIC_CONSTANTS, MANUAL_PATTERN_CHAR_COMPARISON, ALLOW_ATTRIBUTES, ALLOW_ATTRIBUTES_WITHOUT_REASON, COLLAPSIBLE_MATCH. /// /// The minimum rust version that the project supports. Defaults to the `rust-version` field in `Cargo.toml` #[default_text = ""] @@ -311,7 +314,7 @@ define_Conf! { /// default configuration of Clippy. By default, any configuration will replace the default value. For example: /// * `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`. /// * `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list. - (doc_valid_idents: Vec = DEFAULT_DOC_VALID_IDENTS.iter().map(ToString::to_string).collect()), + (doc_valid_idents: FxHashSet = DEFAULT_DOC_VALID_IDENTS.iter().map(ToString::to_string).collect()), /// Lint: TOO_MANY_ARGUMENTS. /// /// The maximum number of argument a function or method can have @@ -547,7 +550,7 @@ define_Conf! { /// Lint: PATH_ENDS_WITH_EXT. /// /// Additional dotfiles (files or directories starting with a dot) to allow - (allowed_dotfiles: FxHashSet = FxHashSet::default()), + (allowed_dotfiles: Vec = Vec::default()), /// Lint: MULTIPLE_CRATE_VERSIONS. /// /// A list of crate names to allow duplicates of @@ -700,7 +703,6 @@ pub fn lookup_conf_file() -> io::Result<(Option, Vec)> { fn deserialize(file: &SourceFile) -> TryConf { match toml::de::Deserializer::new(file.src.as_ref().unwrap()).deserialize_map(ConfVisitor(file)) { 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); extend_vec_if_indicator_present( @@ -713,6 +715,11 @@ fn deserialize(file: &SourceFile) -> TryConf { .allowed_idents_below_min_chars .extend(DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS.iter().map(ToString::to_string)); } + if conf.conf.doc_valid_idents.contains("..") { + conf.conf + .doc_valid_idents + .extend(DEFAULT_DOC_VALID_IDENTS.iter().map(ToString::to_string)); + } conf }, diff --git a/clippy_config/src/types.rs b/clippy_config/src/types.rs index 435aa9244c52..d47e34bb5bce 100644 --- a/clippy_config/src/types.rs +++ b/clippy_config/src/types.rs @@ -2,13 +2,13 @@ use serde::de::{self, Deserializer, Visitor}; use serde::{ser, Deserialize, Serialize}; use std::fmt; -#[derive(Clone, Debug, Deserialize)] +#[derive(Debug, Deserialize)] pub struct Rename { pub path: String, pub rename: String, } -#[derive(Clone, Debug, Deserialize)] +#[derive(Debug, Deserialize)] #[serde(untagged)] pub enum DisallowedPath { Simple(String), @@ -22,12 +22,10 @@ impl DisallowedPath { path } - pub fn reason(&self) -> Option { - match self { - Self::WithReason { - reason: Some(reason), .. - } => Some(format!("{reason} (from clippy.toml)")), - _ => None, + pub fn reason(&self) -> Option<&str> { + match &self { + Self::WithReason { reason, .. } => reason.as_deref(), + Self::Simple(_) => None, } } } diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index d762e30ef02e..de91233d196c 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -140,7 +140,7 @@ fn add_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> { let new_lint = if enable_msrv { format!( - "store.register_{lint_pass}_pass(move |{ctor_arg}| Box::new({module_name}::{camel_name}::new(msrv())));\n ", + "store.register_{lint_pass}_pass(move |{ctor_arg}| Box::new({module_name}::{camel_name}::new(conf)));\n ", lint_pass = lint.pass, ctor_arg = if lint.pass == "late" { "_" } else { "" }, module_name = lint.name, @@ -274,6 +274,7 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { formatdoc!( r#" use clippy_config::msrvs::{{self, Msrv}}; + use clippy_config::Conf; {pass_import} use rustc_lint::{{{context_import}, {pass_type}, LintContext}}; use rustc_session::impl_lint_pass; @@ -301,9 +302,8 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { }} impl {name_camel} {{ - #[must_use] - pub fn new(msrv: Msrv) -> Self {{ - Self {{ msrv }} + pub fn new(conf: &'static Conf) -> Self {{ + Self {{ msrv: conf.msrv.clone() }} }} }} diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index 5708ffba08fd..eb04c006f89f 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_lints" -version = "0.1.81" +version = "0.1.82" 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_lints/src/absolute_paths.rs b/clippy_lints/src/absolute_paths.rs index 461117cf965d..c0a9d888e0b0 100644 --- a/clippy_lints/src/absolute_paths.rs +++ b/clippy_lints/src/absolute_paths.rs @@ -1,3 +1,4 @@ +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint; use clippy_utils::source::snippet_opt; use rustc_data_structures::fx::FxHashSet; @@ -47,7 +48,16 @@ impl_lint_pass!(AbsolutePaths => [ABSOLUTE_PATHS]); pub struct AbsolutePaths { pub absolute_paths_max_segments: u64, - pub absolute_paths_allowed_crates: FxHashSet, + pub absolute_paths_allowed_crates: &'static FxHashSet, +} + +impl AbsolutePaths { + pub fn new(conf: &'static Conf) -> Self { + Self { + absolute_paths_max_segments: conf.absolute_paths_max_segments, + absolute_paths_allowed_crates: &conf.absolute_paths_allowed_crates, + } + } } impl LateLintPass<'_> for AbsolutePaths { diff --git a/clippy_lints/src/almost_complete_range.rs b/clippy_lints/src/almost_complete_range.rs index 96e9c949b750..451bae959874 100644 --- a/clippy_lints/src/almost_complete_range.rs +++ b/clippy_lints/src/almost_complete_range.rs @@ -1,4 +1,5 @@ use clippy_config::msrvs::{self, Msrv}; +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{trim_span, walk_span_to_context}; use rustc_ast::ast::{Expr, ExprKind, LitKind, Pat, PatKind, RangeEnd, RangeLimits}; @@ -34,8 +35,10 @@ pub struct AlmostCompleteRange { msrv: Msrv, } impl AlmostCompleteRange { - pub fn new(msrv: Msrv) -> Self { - Self { msrv } + pub fn new(conf: &'static Conf) -> Self { + Self { + msrv: conf.msrv.clone(), + } } } impl EarlyLintPass for AlmostCompleteRange { diff --git a/clippy_lints/src/approx_const.rs b/clippy_lints/src/approx_const.rs index ec28fd461118..e6d52bcef717 100644 --- a/clippy_lints/src/approx_const.rs +++ b/clippy_lints/src/approx_const.rs @@ -1,4 +1,5 @@ use clippy_config::msrvs::{self, Msrv}; +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{FloatTy, LitFloatType, LitKind}; use rustc_hir::{Expr, ExprKind}; @@ -67,9 +68,10 @@ pub struct ApproxConstant { } impl ApproxConstant { - #[must_use] - pub fn new(msrv: Msrv) -> Self { - Self { msrv } + pub fn new(conf: &'static Conf) -> Self { + Self { + msrv: conf.msrv.clone(), + } } fn check_lit(&self, cx: &LateContext<'_>, lit: &LitKind, e: &Expr<'_>) { diff --git a/clippy_lints/src/arc_with_non_send_sync.rs b/clippy_lints/src/arc_with_non_send_sync.rs index d57ab539fff4..4eafa330fafa 100644 --- a/clippy_lints/src/arc_with_non_send_sync.rs +++ b/clippy_lints/src/arc_with_non_send_sync.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::is_from_proc_macro; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; -use clippy_utils::{is_from_proc_macro, last_path_segment}; -use rustc_hir::{Expr, ExprKind}; +use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_middle::ty::print::with_forced_trimmed_paths; @@ -42,12 +42,11 @@ declare_lint_pass!(ArcWithNonSendSync => [ARC_WITH_NON_SEND_SYNC]); impl<'tcx> LateLintPass<'tcx> for ArcWithNonSendSync { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if !expr.span.from_expansion() - && let ty = cx.typeck_results().expr_ty(expr) - && is_type_diagnostic_item(cx, ty, sym::Arc) - && let ExprKind::Call(func, [arg]) = expr.kind - && let ExprKind::Path(func_path) = func.kind - && last_path_segment(&func_path).ident.name == sym::new + if let ExprKind::Call(func, [arg]) = expr.kind + && let ExprKind::Path(QPath::TypeRelative(func_ty, func_name)) = func.kind + && func_name.ident.name == sym::new + && !expr.span.from_expansion() + && is_type_diagnostic_item(cx, cx.typeck_results().node_type(func_ty.hir_id), sym::Arc) && let arg_ty = cx.typeck_results().expr_ty(arg) // make sure that the type is not and does not contain any type parameters && arg_ty.walk().all(|arg| { diff --git a/clippy_lints/src/assigning_clones.rs b/clippy_lints/src/assigning_clones.rs index 0de0031ed24f..03f777600f08 100644 --- a/clippy_lints/src/assigning_clones.rs +++ b/clippy_lints/src/assigning_clones.rs @@ -1,4 +1,5 @@ use clippy_config::msrvs::{self, Msrv}; +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::mir::{enclosing_mir, PossibleBorrowerMap}; use clippy_utils::sugg::Sugg; @@ -57,9 +58,10 @@ pub struct AssigningClones { } impl AssigningClones { - #[must_use] - pub fn new(msrv: Msrv) -> Self { - Self { msrv } + pub fn new(conf: &'static Conf) -> Self { + Self { + msrv: conf.msrv.clone(), + } } } diff --git a/clippy_lints/src/attrs/mod.rs b/clippy_lints/src/attrs/mod.rs index 8ec60314cc9a..8f430ae601a8 100644 --- a/clippy_lints/src/attrs/mod.rs +++ b/clippy_lints/src/attrs/mod.rs @@ -16,6 +16,7 @@ mod useless_attribute; mod utils; use clippy_config::msrvs::{self, Msrv}; +use clippy_config::Conf; use rustc_ast::{Attribute, MetaItemKind, NestedMetaItem}; use rustc_hir::{ImplItem, Item, ItemKind, TraitItem}; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; @@ -499,7 +500,6 @@ declare_clippy_lint! { "duplicated attribute" } -#[derive(Clone)] pub struct Attributes { msrv: Msrv, } @@ -517,9 +517,10 @@ impl_lint_pass!(Attributes => [ ]); impl Attributes { - #[must_use] - pub fn new(msrv: Msrv) -> Self { - Self { msrv } + pub fn new(conf: &'static Conf) -> Self { + Self { + msrv: conf.msrv.clone(), + } } } @@ -589,7 +590,15 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { } pub struct EarlyAttributes { - pub msrv: Msrv, + msrv: Msrv, +} + +impl EarlyAttributes { + pub fn new(conf: &'static Conf) -> Self { + Self { + msrv: conf.msrv.clone(), + } + } } impl_lint_pass!(EarlyAttributes => [ diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs index d4a1e2780d08..d5f017b26509 100644 --- a/clippy_lints/src/await_holding_invalid.rs +++ b/clippy_lints/src/await_holding_invalid.rs @@ -1,11 +1,11 @@ -use clippy_config::types::DisallowedPath; +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::{match_def_path, paths}; -use rustc_data_structures::fx::FxHashMap; +use clippy_utils::{create_disallowed_map, match_def_path, paths}; use rustc_hir as hir; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, DefIdMap}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::CoroutineLayout; +use rustc_middle::ty::TyCtxt; use rustc_session::impl_lint_pass; use rustc_span::{sym, Span}; @@ -172,31 +172,19 @@ declare_clippy_lint! { impl_lint_pass!(AwaitHolding => [AWAIT_HOLDING_LOCK, AWAIT_HOLDING_REFCELL_REF, AWAIT_HOLDING_INVALID_TYPE]); -#[derive(Debug)] pub struct AwaitHolding { - conf_invalid_types: Vec, - def_ids: FxHashMap, + def_ids: DefIdMap<(&'static str, Option<&'static str>)>, } impl AwaitHolding { - pub(crate) fn new(conf_invalid_types: Vec) -> Self { + pub(crate) fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self { Self { - conf_invalid_types, - def_ids: FxHashMap::default(), + def_ids: create_disallowed_map(tcx, &conf.await_holding_invalid_types), } } } impl<'tcx> LateLintPass<'tcx> for AwaitHolding { - fn check_crate(&mut self, cx: &LateContext<'tcx>) { - for conf in &self.conf_invalid_types { - let segs: Vec<_> = conf.path().split("::").collect(); - for id in clippy_utils::def_path_def_ids(cx, &segs) { - self.def_ids.insert(id, conf.clone()); - } - } - } - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { if let hir::ExprKind::Closure(hir::Closure { kind: hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)), @@ -258,25 +246,22 @@ impl AwaitHolding { ); }, ); - } else if let Some(disallowed) = self.def_ids.get(&adt.did()) { - emit_invalid_type(cx, ty_cause.source_info.span, disallowed); + } else if let Some(&(path, reason)) = self.def_ids.get(&adt.did()) { + emit_invalid_type(cx, ty_cause.source_info.span, path, reason); } } } } } -fn emit_invalid_type(cx: &LateContext<'_>, span: Span, disallowed: &DisallowedPath) { +fn emit_invalid_type(cx: &LateContext<'_>, span: Span, path: &'static str, reason: Option<&'static str>) { span_lint_and_then( cx, AWAIT_HOLDING_INVALID_TYPE, span, - format!( - "`{}` may not be held across an await point per `clippy.toml`", - disallowed.path() - ), + format!("holding a disallowed type across an await point `{path}`"), |diag| { - if let Some(reason) = disallowed.reason() { + if let Some(reason) = reason { diag.note(reason); } }, diff --git a/clippy_lints/src/borrow_deref_ref.rs b/clippy_lints/src/borrow_deref_ref.rs index 0ca4a0e067d3..bd123a725a73 100644 --- a/clippy_lints/src/borrow_deref_ref.rs +++ b/clippy_lints/src/borrow_deref_ref.rs @@ -49,35 +49,31 @@ declare_lint_pass!(BorrowDerefRef => [BORROW_DEREF_REF]); impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &rustc_hir::Expr<'tcx>) { - if !e.span.from_expansion() - && let ExprKind::AddrOf(_, Mutability::Not, addrof_target) = e.kind - && !addrof_target.span.from_expansion() + if let ExprKind::AddrOf(_, Mutability::Not, addrof_target) = e.kind && let ExprKind::Unary(UnOp::Deref, deref_target) = addrof_target.kind - && !deref_target.span.from_expansion() && !matches!(deref_target.kind, ExprKind::Unary(UnOp::Deref, ..)) + && !e.span.from_expansion() + && !deref_target.span.from_expansion() + && !addrof_target.span.from_expansion() && let ref_ty = cx.typeck_results().expr_ty(deref_target) && let ty::Ref(_, inner_ty, Mutability::Not) = ref_ty.kind() + && get_parent_expr(cx, e).map_or(true, |parent| { + match parent.kind { + // `*&*foo` should lint `deref_addrof` instead. + ExprKind::Unary(UnOp::Deref, _) => is_lint_allowed(cx, DEREF_ADDROF, parent.hir_id), + // `&*foo` creates a distinct temporary from `foo` + ExprKind::AddrOf(_, Mutability::Mut, _) => !matches!( + deref_target.kind, + ExprKind::Path(..) + | ExprKind::Field(..) + | ExprKind::Index(..) + | ExprKind::Unary(UnOp::Deref, ..) + ), + _ => true, + } + }) + && !is_from_proc_macro(cx, e) { - if let Some(parent_expr) = get_parent_expr(cx, e) { - if matches!(parent_expr.kind, ExprKind::Unary(UnOp::Deref, ..)) - && !is_lint_allowed(cx, DEREF_ADDROF, parent_expr.hir_id) - { - return; - } - - // modification to `&mut &*x` is different from `&mut x` - if matches!( - deref_target.kind, - ExprKind::Path(..) | ExprKind::Field(..) | ExprKind::Index(..) | ExprKind::Unary(UnOp::Deref, ..) - ) && matches!(parent_expr.kind, ExprKind::AddrOf(_, Mutability::Mut, _)) - { - return; - } - } - if is_from_proc_macro(cx, e) { - return; - } - span_lint_and_then( cx, BORROW_DEREF_REF, diff --git a/clippy_lints/src/cargo/mod.rs b/clippy_lints/src/cargo/mod.rs index 593bc6c81ee8..312ad4c29900 100644 --- a/clippy_lints/src/cargo/mod.rs +++ b/clippy_lints/src/cargo/mod.rs @@ -5,6 +5,7 @@ mod multiple_crate_versions; mod wildcard_dependencies; use cargo_metadata::MetadataCommand; +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint; use clippy_utils::is_lint_allowed; use rustc_data_structures::fx::FxHashSet; @@ -204,8 +205,8 @@ declare_clippy_lint! { } pub struct Cargo { - pub allowed_duplicate_crates: FxHashSet, - pub ignore_publish: bool, + allowed_duplicate_crates: &'static FxHashSet, + ignore_publish: bool, } impl_lint_pass!(Cargo => [ @@ -217,6 +218,15 @@ impl_lint_pass!(Cargo => [ LINT_GROUPS_PRIORITY, ]); +impl Cargo { + pub fn new(conf: &'static Conf) -> Self { + Self { + allowed_duplicate_crates: &conf.allowed_duplicate_crates, + ignore_publish: conf.cargo_ignore_publish, + } + } +} + impl LateLintPass<'_> for Cargo { fn check_crate(&mut self, cx: &LateContext<'_>) { static NO_DEPS_LINTS: &[&Lint] = &[ @@ -253,7 +263,7 @@ impl LateLintPass<'_> for Cargo { { match MetadataCommand::new().exec() { Ok(metadata) => { - multiple_crate_versions::check(cx, &metadata, &self.allowed_duplicate_crates); + multiple_crate_versions::check(cx, &metadata, self.allowed_duplicate_crates); }, Err(e) => { for lint in WITH_DEPS_LINTS { diff --git a/clippy_lints/src/casts/cast_lossless.rs b/clippy_lints/src/casts/cast_lossless.rs index d52ad1c6f23f..ff460a3fd8e3 100644 --- a/clippy_lints/src/casts/cast_lossless.rs +++ b/clippy_lints/src/casts/cast_lossless.rs @@ -1,19 +1,21 @@ 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::in_constant; -use clippy_utils::source::{snippet_opt, snippet_with_applicability}; +use clippy_utils::source::snippet_opt; +use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_isize_or_usize; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, QPath, TyKind}; +use rustc_hir::{Expr, QPath, TyKind}; use rustc_lint::LateContext; -use rustc_middle::ty::{self, FloatTy, Ty, UintTy}; +use rustc_middle::ty::{self, FloatTy, Ty}; +use rustc_span::hygiene; use super::{utils, CAST_LOSSLESS}; pub(super) fn check( cx: &LateContext<'_>, expr: &Expr<'_>, - cast_op: &Expr<'_>, + cast_from_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>, cast_to_hir: &rustc_hir::Ty<'_>, @@ -23,64 +25,54 @@ pub(super) fn check( return; } - // The suggestion is to use a function call, so if the original expression - // has parens on the outside, they are no longer needed. - let mut app = Applicability::MachineApplicable; - let opt = snippet_opt(cx, cast_op.span.source_callsite()); - let sugg = opt.as_ref().map_or_else( - || { - app = Applicability::HasPlaceholders; - ".." - }, - |snip| { - if should_strip_parens(cast_op, snip) { - &snip[1..snip.len() - 1] - } else { - snip.as_str() - } - }, - ); - - // Display the type alias instead of the aliased type. Fixes #11285 - // - // FIXME: Once `lazy_type_alias` is stabilized(?) we should use `rustc_middle` types instead, - // this will allow us to display the right type with `cast_from` as well. - let cast_to_fmt = if let TyKind::Path(QPath::Resolved(None, path)) = cast_to_hir.kind - // It's a bit annoying but the turbofish is optional for types. A type in an `as` cast - // shouldn't have these if they're primitives, which are the only things we deal with. - // - // This could be removed for performance if this check is determined to have a pretty major - // effect. - && path.segments.iter().all(|segment| segment.args.is_none()) - { - snippet_with_applicability(cx, cast_to_hir.span, "..", &mut app) - } else { - cast_to.to_string().into() - }; - - let message = if cast_from.is_bool() { - format!("casting `{cast_from}` to `{cast_to_fmt}` is more cleanly stated with `{cast_to_fmt}::from(_)`") - } else { - format!("casting `{cast_from}` to `{cast_to_fmt}` may become silently lossy if you later change the type") - }; - - span_lint_and_sugg( + span_lint_and_then( cx, CAST_LOSSLESS, expr.span, - message, - "try", - format!("{cast_to_fmt}::from({sugg})"), - app, + format!("casts from `{cast_from}` to `{cast_to}` can be expressed infallibly using `From`"), + |diag| { + diag.help("an `as` cast can become silently lossy if the types change in the future"); + let mut applicability = Applicability::MachineApplicable; + let from_sugg = Sugg::hir_with_context(cx, cast_from_expr, expr.span.ctxt(), "", &mut applicability); + let Some(ty) = snippet_opt(cx, hygiene::walk_chain(cast_to_hir.span, expr.span.ctxt())) else { + return; + }; + match cast_to_hir.kind { + TyKind::Infer => { + diag.span_suggestion_verbose( + expr.span, + "use `Into::into` instead", + format!("{}.into()", from_sugg.maybe_par()), + applicability, + ); + }, + // Don't suggest `A<_>::B::From(x)` or `macro!()::from(x)` + kind if matches!(kind, TyKind::Path(QPath::Resolved(_, path)) if path.segments.iter().any(|s| s.args.is_some())) + || !cast_to_hir.span.eq_ctxt(expr.span) => + { + diag.span_suggestion_verbose( + expr.span, + format!("use `<{ty}>::from` instead"), + format!("<{ty}>::from({from_sugg})"), + applicability, + ); + }, + _ => { + diag.span_suggestion_verbose( + expr.span, + format!("use `{ty}::from` instead"), + format!("{ty}::from({from_sugg})"), + applicability, + ); + }, + } + }, ); } fn should_lint(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>, msrv: &Msrv) -> bool { // Do not suggest using From in consts/statics until it is valid to do so (see #2267). - // - // If destination is u128, do not lint because source type cannot be larger - // If source is bool, still lint due to the lint message differing (refers to style) - if in_constant(cx, expr.hir_id) || (!cast_from.is_bool() && matches!(cast_to.kind(), ty::Uint(UintTy::U128))) { + if in_constant(cx, expr.hir_id) { return false; } @@ -110,12 +102,3 @@ fn should_lint(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to }, } } - -fn should_strip_parens(cast_expr: &Expr<'_>, snip: &str) -> bool { - if let ExprKind::Binary(_, _, _) = cast_expr.kind { - if snip.starts_with('(') && snip.ends_with(')') { - return true; - } - } - false -} diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index 54f0c7c46871..c31716fbcee1 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -24,6 +24,7 @@ mod utils; mod zero_ptr; use clippy_config::msrvs::{self, Msrv}; +use clippy_config::Conf; use clippy_utils::is_hir_ty_cfg_dependant; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -658,11 +659,11 @@ declare_clippy_lint! { /// /// ### Example /// ```rust,ignore - /// let _: (0.0_f32 / 0.0) as u64; + /// let _ = (0.0_f32 / 0.0) as u64; /// ``` /// Use instead: /// ```rust,ignore - /// let _: = 0_u64; + /// let _ = 0_u64; /// ``` #[clippy::version = "1.66.0"] pub CAST_NAN_TO_INT, @@ -722,9 +723,10 @@ pub struct Casts { } impl Casts { - #[must_use] - pub fn new(msrv: Msrv) -> Self { - Self { msrv } + pub fn new(conf: &'static Conf) -> Self { + Self { + msrv: conf.msrv.clone(), + } } } @@ -761,45 +763,45 @@ impl<'tcx> LateLintPass<'tcx> for Casts { return; } - if let ExprKind::Cast(cast_expr, cast_to_hir) = expr.kind { + if let ExprKind::Cast(cast_from_expr, cast_to_hir) = expr.kind { if is_hir_ty_cfg_dependant(cx, cast_to_hir) { return; } let (cast_from, cast_to) = ( - cx.typeck_results().expr_ty(cast_expr), + cx.typeck_results().expr_ty(cast_from_expr), cx.typeck_results().expr_ty(expr), ); - if !expr.span.from_expansion() && unnecessary_cast::check(cx, expr, cast_expr, cast_from, cast_to) { + if !expr.span.from_expansion() && unnecessary_cast::check(cx, expr, cast_from_expr, cast_from, cast_to) { return; } - cast_slice_from_raw_parts::check(cx, expr, cast_expr, cast_to, &self.msrv); - ptr_cast_constness::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv); - as_ptr_cast_mut::check(cx, expr, cast_expr, cast_to); - fn_to_numeric_cast_any::check(cx, expr, cast_expr, cast_from, cast_to); - fn_to_numeric_cast::check(cx, expr, cast_expr, cast_from, cast_to); - 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); + cast_slice_from_raw_parts::check(cx, expr, cast_from_expr, cast_to, &self.msrv); + ptr_cast_constness::check(cx, expr, cast_from_expr, cast_from, cast_to, &self.msrv); + as_ptr_cast_mut::check(cx, expr, cast_from_expr, cast_to); + fn_to_numeric_cast_any::check(cx, expr, cast_from_expr, cast_from, cast_to); + fn_to_numeric_cast::check(cx, expr, cast_from_expr, cast_from, cast_to); + fn_to_numeric_cast_with_truncation::check(cx, expr, cast_from_expr, cast_from, cast_to); + zero_ptr::check(cx, expr, cast_from_expr, cast_to_hir); if cast_to.is_numeric() { - cast_possible_truncation::check(cx, expr, cast_expr, cast_from, cast_to, cast_to_hir.span); + cast_possible_truncation::check(cx, expr, cast_from_expr, cast_from, cast_to, cast_to_hir.span); if cast_from.is_numeric() { cast_possible_wrap::check(cx, expr, cast_from, cast_to); cast_precision_loss::check(cx, expr, cast_from, cast_to); - cast_sign_loss::check(cx, expr, cast_expr, cast_from, cast_to); - cast_abs_to_unsigned::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv); - cast_nan_to_int::check(cx, expr, cast_expr, cast_from, cast_to); + cast_sign_loss::check(cx, expr, cast_from_expr, cast_from, cast_to); + cast_abs_to_unsigned::check(cx, expr, cast_from_expr, cast_from, cast_to, &self.msrv); + cast_nan_to_int::check(cx, expr, cast_from_expr, cast_from, cast_to); } - cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to, cast_to_hir, &self.msrv); - cast_enum_constructor::check(cx, expr, cast_expr, cast_from); + cast_lossless::check(cx, expr, cast_from_expr, cast_from, cast_to, cast_to_hir, &self.msrv); + cast_enum_constructor::check(cx, expr, cast_from_expr, cast_from); } as_underscore::check(cx, expr, cast_to_hir); if self.msrv.meets(msrvs::PTR_FROM_REF) { - ref_as_ptr::check(cx, expr, cast_expr, cast_to_hir); + ref_as_ptr::check(cx, expr, cast_from_expr, cast_to_hir); } else if self.msrv.meets(msrvs::BORROW_AS_PTR) { - borrow_as_ptr::check(cx, expr, cast_expr, cast_to_hir); + borrow_as_ptr::check(cx, expr, cast_from_expr, cast_to_hir); } } diff --git a/clippy_lints/src/casts/ptr_cast_constness.rs b/clippy_lints/src/casts/ptr_cast_constness.rs index 921693567fcd..7513e18d408b 100644 --- a/clippy_lints/src/casts/ptr_cast_constness.rs +++ b/clippy_lints/src/casts/ptr_cast_constness.rs @@ -4,7 +4,7 @@ use clippy_utils::sugg::Sugg; use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability}; use rustc_lint::LateContext; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use super::PTR_CAST_CONSTNESS; @@ -24,6 +24,7 @@ pub(super) fn check<'tcx>( (Mutability::Not, Mutability::Mut) | (Mutability::Mut, Mutability::Not) ) && from_ty == to_ty + && !from_ty.has_erased_regions() { let sugg = Sugg::hir(cx, cast_expr, "_"); let constness = match *to_mutbl { diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs index 92810ea2aa0f..0b1ab5411bf1 100644 --- a/clippy_lints/src/checked_conversions.rs +++ b/clippy_lints/src/checked_conversions.rs @@ -1,11 +1,12 @@ //! lint on manually implemented checked conversions that could be transformed into `try_from` use clippy_config::msrvs::{self, Msrv}; +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::{in_constant, is_integer_literal, SpanlessEq}; use rustc_errors::Applicability; -use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind, QPath, TyKind}; +use rustc_hir::{BinOpKind, Expr, ExprKind, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; @@ -40,9 +41,10 @@ pub struct CheckedConversions { } impl CheckedConversions { - #[must_use] - pub fn new(msrv: Msrv) -> Self { - Self { msrv } + pub fn new(conf: &'static Conf) -> Self { + Self { + msrv: conf.msrv.clone(), + } } } @@ -50,61 +52,54 @@ impl_lint_pass!(CheckedConversions => [CHECKED_CONVERSIONS]); impl<'tcx> LateLintPass<'tcx> for CheckedConversions { fn check_expr(&mut self, cx: &LateContext<'_>, item: &Expr<'_>) { - if !self.msrv.meets(msrvs::TRY_FROM) { - return; - } - - let result = if !in_constant(cx, item.hir_id) + if let ExprKind::Binary(op, lhs, rhs) = item.kind + && let (lt1, gt1, op2) = match op.node { + BinOpKind::Le => (lhs, rhs, None), + BinOpKind::Ge => (rhs, lhs, None), + BinOpKind::And + if let ExprKind::Binary(op1, lhs1, rhs1) = lhs.kind + && let ExprKind::Binary(op2, lhs2, rhs2) = rhs.kind + && let Some((lt1, gt1)) = read_le_ge(op1.node, lhs1, rhs1) + && let Some((lt2, gt2)) = read_le_ge(op2.node, lhs2, rhs2) => + { + (lt1, gt1, Some((lt2, gt2))) + }, + _ => return, + } && !in_external_macro(cx.sess(), item.span) - && let ExprKind::Binary(op, left, right) = &item.kind + && !in_constant(cx, item.hir_id) + && self.msrv.meets(msrvs::TRY_FROM) + && let Some(cv) = match op2 { + // todo: check for case signed -> larger unsigned == only x >= 0 + None => check_upper_bound(lt1, gt1).filter(|cv| cv.cvt == ConversionType::FromUnsigned), + Some((lt2, gt2)) => { + let upper_lower = |lt1, gt1, lt2, gt2| { + check_upper_bound(lt1, gt1) + .zip(check_lower_bound(lt2, gt2)) + .and_then(|(l, r)| l.combine(r, cx)) + }; + upper_lower(lt1, gt1, lt2, gt2).or_else(|| upper_lower(lt2, gt2, lt1, gt1)) + }, + } + && let Some(to_type) = cv.to_type { - match op.node { - BinOpKind::Ge | BinOpKind::Le => single_check(item), - BinOpKind::And => double_check(cx, left, right), - _ => None, - } - } else { - None - }; - - if let Some(cv) = result { - if let Some(to_type) = cv.to_type { - let mut applicability = Applicability::MachineApplicable; - let snippet = snippet_with_applicability(cx, cv.expr_to_cast.span, "_", &mut applicability); - span_lint_and_sugg( - cx, - CHECKED_CONVERSIONS, - item.span, - "checked cast can be simplified", - "try", - format!("{to_type}::try_from({snippet}).is_ok()"), - applicability, - ); - } + let mut applicability = Applicability::MachineApplicable; + let snippet = snippet_with_applicability(cx, cv.expr_to_cast.span, "_", &mut applicability); + span_lint_and_sugg( + cx, + CHECKED_CONVERSIONS, + item.span, + "checked cast can be simplified", + "try", + format!("{to_type}::try_from({snippet}).is_ok()"), + applicability, + ); } } extract_msrv_attr!(LateContext); } -/// Searches for a single check from unsigned to _ is done -/// todo: check for case signed -> larger unsigned == only x >= 0 -fn single_check<'tcx>(expr: &'tcx Expr<'tcx>) -> Option> { - check_upper_bound(expr).filter(|cv| cv.cvt == ConversionType::FromUnsigned) -} - -/// Searches for a combination of upper & lower bound checks -fn double_check<'a>(cx: &LateContext<'_>, left: &'a Expr<'_>, right: &'a Expr<'_>) -> Option> { - let upper_lower = |l, r| { - let upper = check_upper_bound(l); - let lower = check_lower_bound(r); - - upper.zip(lower).and_then(|(l, r)| l.combine(r, cx)) - }; - - upper_lower(left, right).or_else(|| upper_lower(right, left)) -} - /// Contains the result of a tried conversion check #[derive(Clone, Debug)] struct Conversion<'a> { @@ -121,6 +116,19 @@ enum ConversionType { FromUnsigned, } +/// Attempts to read either `<=` or `>=` with a normalized operand order. +fn read_le_ge<'tcx>( + op: BinOpKind, + lhs: &'tcx Expr<'tcx>, + rhs: &'tcx Expr<'tcx>, +) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>)> { + match op { + BinOpKind::Le => Some((lhs, rhs)), + BinOpKind::Ge => Some((rhs, lhs)), + _ => None, + } +} + impl<'a> Conversion<'a> { /// Combine multiple conversions if the are compatible pub fn combine(self, other: Self, cx: &LateContext<'_>) -> Option> { @@ -188,29 +196,17 @@ impl ConversionType { } /// Check for `expr <= (to_type::MAX as from_type)` -fn check_upper_bound<'tcx>(expr: &'tcx Expr<'tcx>) -> Option> { - if let ExprKind::Binary(ref op, left, right) = &expr.kind - && let Some((candidate, check)) = normalize_le_ge(op, left, right) - && let Some((from, to)) = get_types_from_cast(check, INTS, "max_value", "MAX") - { - Conversion::try_new(candidate, from, to) +fn check_upper_bound<'tcx>(lt: &'tcx Expr<'tcx>, gt: &'tcx Expr<'tcx>) -> Option> { + if let Some((from, to)) = get_types_from_cast(gt, INTS, "max_value", "MAX") { + Conversion::try_new(lt, from, to) } else { None } } /// Check for `expr >= 0|(to_type::MIN as from_type)` -fn check_lower_bound<'tcx>(expr: &'tcx Expr<'tcx>) -> Option> { - fn check_function<'a>(candidate: &'a Expr<'a>, check: &'a Expr<'a>) -> Option> { - (check_lower_bound_zero(candidate, check)).or_else(|| (check_lower_bound_min(candidate, check))) - } - - // First of we need a binary containing the expression & the cast - if let ExprKind::Binary(ref op, left, right) = &expr.kind { - normalize_le_ge(op, right, left).and_then(|(l, r)| check_function(l, r)) - } else { - None - } +fn check_lower_bound<'tcx>(lt: &'tcx Expr<'tcx>, gt: &'tcx Expr<'tcx>) -> Option> { + check_lower_bound_zero(gt, lt).or_else(|| check_lower_bound_min(gt, lt)) } /// Check for `expr >= 0` @@ -309,15 +305,6 @@ fn int_ty_to_sym<'tcx>(path: &QPath<'_>) -> Option<&'tcx str> { } } -/// Will return the expressions as if they were expr1 <= expr2 -fn normalize_le_ge<'a>(op: &BinOp, left: &'a Expr<'a>, right: &'a Expr<'a>) -> Option<(&'a Expr<'a>, &'a Expr<'a>)> { - match op.node { - BinOpKind::Le => Some((left, right)), - BinOpKind::Ge => Some((right, left)), - _ => None, - } -} - // Constants const UINTS: &[&str] = &["u8", "u16", "u32", "u64", "usize"]; const SINTS: &[&str] = &["i8", "i16", "i32", "i64", "isize"]; diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs index 60815f4f2afb..5fa0522e4e5f 100644 --- a/clippy_lints/src/cognitive_complexity.rs +++ b/clippy_lints/src/cognitive_complexity.rs @@ -1,5 +1,6 @@ //! calculate cognitive complexity and warn about overly complex functions +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::{IntoSpan, SpanRangeExt}; use clippy_utils::ty::is_type_diagnostic_item; @@ -39,10 +40,9 @@ pub struct CognitiveComplexity { } impl CognitiveComplexity { - #[must_use] - pub fn new(limit: u64) -> Self { + pub fn new(conf: &'static Conf) -> Self { Self { - limit: LimitStack::new(limit), + limit: LimitStack::new(conf.cognitive_complexity_threshold), } } } diff --git a/clippy_lints/src/collapsible_if.rs b/clippy_lints/src/collapsible_if.rs index 07b02c98df15..f311c052ad6e 100644 --- a/clippy_lints/src/collapsible_if.rs +++ b/clippy_lints/src/collapsible_if.rs @@ -93,20 +93,14 @@ declare_lint_pass!(CollapsibleIf => [COLLAPSIBLE_IF, COLLAPSIBLE_ELSE_IF]); impl EarlyLintPass for CollapsibleIf { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) { - if !expr.span.from_expansion() { - check_if(cx, expr); - } - } -} - -fn check_if(cx: &EarlyContext<'_>, expr: &ast::Expr) { - if let ast::ExprKind::If(check, then, else_) = &expr.kind { - if let Some(else_) = else_ { - check_collapsible_maybe_if_let(cx, then.span, else_); - } else if let ast::ExprKind::Let(..) = check.kind { - // Prevent triggering on `if let a = b { if c { .. } }`. - } else { - check_collapsible_no_if_let(cx, expr, check, then); + if let ast::ExprKind::If(cond, then, else_) = &expr.kind + && !expr.span.from_expansion() + { + if let Some(else_) = else_ { + check_collapsible_maybe_if_let(cx, then.span, else_); + } else if !matches!(cond.kind, ast::ExprKind::Let(..)) { + check_collapsible_no_if_let(cx, expr, cond, then); + } } } } @@ -189,13 +183,10 @@ fn check_collapsible_no_if_let(cx: &EarlyContext<'_>, expr: &ast::Expr, check: & /// If the block contains only one expression, return it. fn expr_block(block: &ast::Block) -> Option<&ast::Expr> { - let mut it = block.stmts.iter(); - - if let (Some(stmt), None) = (it.next(), it.next()) { - match stmt.kind { - ast::StmtKind::Expr(ref expr) | ast::StmtKind::Semi(ref expr) => Some(expr), - _ => None, - } + if let [stmt] = &*block.stmts + && let ast::StmtKind::Expr(expr) | ast::StmtKind::Semi(expr) = &stmt.kind + { + Some(expr) } else { None } diff --git a/clippy_lints/src/collection_is_never_read.rs b/clippy_lints/src/collection_is_never_read.rs index 28d9f68d504c..eebda3ff76fd 100644 --- a/clippy_lints/src/collection_is_never_read.rs +++ b/clippy_lints/src/collection_is_never_read.rs @@ -59,9 +59,9 @@ static COLLECTIONS: [Symbol; 9] = [ impl<'tcx> LateLintPass<'tcx> for CollectionIsNeverRead { fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) { - // Look for local variables whose type is a container. Search surrounding bock for read access. - if match_acceptable_type(cx, local, &COLLECTIONS) - && let PatKind::Binding(_, local_id, _, _) = local.pat.kind + // Look for local variables whose type is a container. Search surrounding block for read access. + if let PatKind::Binding(_, local_id, _, _) = local.pat.kind + && match_acceptable_type(cx, local, &COLLECTIONS) && let Some(enclosing_block) = get_enclosing_block(cx, local.hir_id) && has_no_read_access(cx, local_id, enclosing_block) { diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index d896452be920..86e0368c4e42 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -1,3 +1,4 @@ +use clippy_config::Conf; 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, IntoSpan, SpanRangeExt}; use clippy_utils::ty::{needs_ordered_drop, InteriorMut}; @@ -11,6 +12,7 @@ use core::ops::ControlFlow; use rustc_errors::Applicability; use rustc_hir::{intravisit, BinOpKind, Block, Expr, ExprKind, HirId, HirIdSet, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::TyCtxt; use rustc_session::impl_lint_pass; use rustc_span::hygiene::walk_chain; use rustc_span::source_map::SourceMap; @@ -159,15 +161,13 @@ declare_clippy_lint! { } pub struct CopyAndPaste<'tcx> { - ignore_interior_mutability: Vec, interior_mut: InteriorMut<'tcx>, } -impl CopyAndPaste<'_> { - pub fn new(ignore_interior_mutability: Vec) -> Self { +impl<'tcx> CopyAndPaste<'tcx> { + pub fn new(tcx: TyCtxt<'tcx>, conf: &'static Conf) -> Self { Self { - ignore_interior_mutability, - interior_mut: InteriorMut::default(), + interior_mut: InteriorMut::new(tcx, &conf.ignore_interior_mutability), } } } @@ -180,10 +180,6 @@ impl_lint_pass!(CopyAndPaste<'_> => [ ]); impl<'tcx> LateLintPass<'tcx> for CopyAndPaste<'tcx> { - fn check_crate(&mut self, cx: &LateContext<'tcx>) { - 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); diff --git a/clippy_lints/src/crate_in_macro_def.rs b/clippy_lints/src/crate_in_macro_def.rs index adf6f7c47375..678bdbc0ffb8 100644 --- a/clippy_lints/src/crate_in_macro_def.rs +++ b/clippy_lints/src/crate_in_macro_def.rs @@ -53,10 +53,9 @@ declare_lint_pass!(CrateInMacroDef => [CRATE_IN_MACRO_DEF]); impl EarlyLintPass for CrateInMacroDef { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { - if item.attrs.iter().any(is_macro_export) - && let ItemKind::MacroDef(macro_def) = &item.kind - && let tts = macro_def.body.tokens.clone() - && let Some(span) = contains_unhygienic_crate_reference(&tts) + if let ItemKind::MacroDef(macro_def) = &item.kind + && item.attrs.iter().any(is_macro_export) + && let Some(span) = contains_unhygienic_crate_reference(¯o_def.body.tokens) { span_lint_and_sugg( cx, diff --git a/clippy_lints/src/dbg_macro.rs b/clippy_lints/src/dbg_macro.rs index b0590b0a71cb..788c6f3ada29 100644 --- a/clippy_lints/src/dbg_macro.rs +++ b/clippy_lints/src/dbg_macro.rs @@ -1,3 +1,4 @@ +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_in_test; use clippy_utils::macros::{macro_backtrace, MacroCall}; @@ -33,7 +34,6 @@ declare_clippy_lint! { "`dbg!` macro is intended as a debugging tool" } -#[derive(Clone)] pub struct DbgMacro { allow_dbg_in_tests: bool, /// Tracks the `dbg!` macro callsites that are already checked. @@ -45,9 +45,9 @@ pub struct DbgMacro { impl_lint_pass!(DbgMacro => [DBG_MACRO]); impl DbgMacro { - pub fn new(allow_dbg_in_tests: bool) -> Self { + pub fn new(conf: &'static Conf) -> Self { DbgMacro { - allow_dbg_in_tests, + allow_dbg_in_tests: conf.allow_dbg_in_tests, checked_dbg_call_site: FxHashSet::default(), prev_ctxt: SyntaxContext::root(), } diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index eabc67601a2f..69f9eb6842bc 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -598,6 +598,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::partialeq_to_none::PARTIALEQ_TO_NONE_INFO, crate::pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE_INFO, crate::pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF_INFO, + crate::pathbuf_init_then_push::PATHBUF_INIT_THEN_PUSH_INFO, crate::pattern_type_mismatch::PATTERN_TYPE_MISMATCH_INFO, crate::permissions_set_readonly_false::PERMISSIONS_SET_READONLY_FALSE_INFO, crate::precedence::PRECEDENCE_INFO, diff --git a/clippy_lints/src/derivable_impls.rs b/clippy_lints/src/derivable_impls.rs index 0c9ad5e8d001..f27f68e2cbc5 100644 --- a/clippy_lints/src/derivable_impls.rs +++ b/clippy_lints/src/derivable_impls.rs @@ -1,4 +1,5 @@ use clippy_config::msrvs::{self, Msrv}; +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::indent_of; use clippy_utils::{is_default_equivalent, peel_blocks}; @@ -60,9 +61,10 @@ pub struct DerivableImpls { } impl DerivableImpls { - #[must_use] - pub fn new(msrv: Msrv) -> Self { - DerivableImpls { msrv } + pub fn new(conf: &'static Conf) -> Self { + DerivableImpls { + msrv: conf.msrv.clone(), + } } } diff --git a/clippy_lints/src/disallowed_macros.rs b/clippy_lints/src/disallowed_macros.rs index 871f529da6c4..b51d343132b2 100644 --- a/clippy_lints/src/disallowed_macros.rs +++ b/clippy_lints/src/disallowed_macros.rs @@ -1,4 +1,5 @@ -use clippy_config::types::DisallowedPath; +use clippy_config::Conf; +use clippy_utils::create_disallowed_map; use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::macros::macro_backtrace; use rustc_ast::Attribute; @@ -9,6 +10,7 @@ use rustc_hir::{ Expr, ExprKind, ForeignItem, HirId, ImplItem, Item, ItemKind, OwnerId, Pat, Path, Stmt, TraitItem, Ty, }; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::TyCtxt; use rustc_session::impl_lint_pass; use rustc_span::{ExpnId, MacroKind, Span}; @@ -57,27 +59,24 @@ declare_clippy_lint! { } pub struct DisallowedMacros { - conf_disallowed: Vec, - disallowed: DefIdMap, + disallowed: DefIdMap<(&'static str, Option<&'static str>)>, seen: FxHashSet, - // Track the most recently seen node that can have a `derive` attribute. // Needed to use the correct lint level. derive_src: Option, } impl DisallowedMacros { - pub fn new(conf_disallowed: Vec) -> Self { + pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self { Self { - conf_disallowed, - disallowed: DefIdMap::default(), + disallowed: create_disallowed_map(tcx, &conf.disallowed_macros), seen: FxHashSet::default(), derive_src: None, } } fn check(&mut self, cx: &LateContext<'_>, span: Span, derive_src: Option) { - if self.conf_disallowed.is_empty() { + if self.disallowed.is_empty() { return; } @@ -86,11 +85,10 @@ impl DisallowedMacros { return; } - if let Some(&index) = self.disallowed.get(&mac.def_id) { - let conf = &self.conf_disallowed[index]; - let msg = format!("use of a disallowed macro `{}`", conf.path()); + if let Some(&(path, reason)) = self.disallowed.get(&mac.def_id) { + let msg = format!("use of a disallowed macro `{path}`"); let add_note = |diag: &mut Diag<'_, _>| { - if let Some(reason) = conf.reason() { + if let Some(reason) = reason { diag.note(reason); } }; @@ -116,15 +114,6 @@ impl DisallowedMacros { impl_lint_pass!(DisallowedMacros => [DISALLOWED_MACROS]); impl LateLintPass<'_> for DisallowedMacros { - fn check_crate(&mut self, cx: &LateContext<'_>) { - for (index, conf) in self.conf_disallowed.iter().enumerate() { - let segs: Vec<_> = conf.path().split("::").collect(); - for id in clippy_utils::def_path_def_ids(cx, &segs) { - self.disallowed.insert(id, index); - } - } - } - fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { self.check(cx, expr.span, None); // `$t + $t` can have the context of $t, check also the span of the binary operator diff --git a/clippy_lints/src/disallowed_methods.rs b/clippy_lints/src/disallowed_methods.rs index 38fe687f7ccf..5a01d76a2a62 100644 --- a/clippy_lints/src/disallowed_methods.rs +++ b/clippy_lints/src/disallowed_methods.rs @@ -1,9 +1,11 @@ -use clippy_config::types::DisallowedPath; +use clippy_config::Conf; +use clippy_utils::create_disallowed_map; use clippy_utils::diagnostics::span_lint_and_then; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefIdMap; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::TyCtxt; use rustc_session::impl_lint_pass; declare_clippy_lint! { @@ -55,17 +57,14 @@ declare_clippy_lint! { "use of a disallowed method call" } -#[derive(Clone, Debug)] pub struct DisallowedMethods { - conf_disallowed: Vec, - disallowed: DefIdMap, + disallowed: DefIdMap<(&'static str, Option<&'static str>)>, } impl DisallowedMethods { - pub fn new(conf_disallowed: Vec) -> Self { + pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self { Self { - conf_disallowed, - disallowed: DefIdMap::default(), + disallowed: create_disallowed_map(tcx, &conf.disallowed_methods), } } } @@ -73,15 +72,6 @@ impl DisallowedMethods { impl_lint_pass!(DisallowedMethods => [DISALLOWED_METHODS]); impl<'tcx> LateLintPass<'tcx> for DisallowedMethods { - fn check_crate(&mut self, cx: &LateContext<'_>) { - for (index, conf) in self.conf_disallowed.iter().enumerate() { - let segs: Vec<_> = conf.path().split("::").collect(); - for id in clippy_utils::def_path_def_ids(cx, &segs) { - self.disallowed.insert(id, index); - } - } - } - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { let (id, span) = match &expr.kind { ExprKind::Path(path) @@ -95,14 +85,18 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods { }, _ => return, }; - if let Some(&index) = self.disallowed.get(&id) { - let conf = &self.conf_disallowed[index]; - let msg = format!("use of a disallowed method `{}`", conf.path()); - span_lint_and_then(cx, DISALLOWED_METHODS, span, msg, |diag| { - if let Some(reason) = conf.reason() { - diag.note(reason); - } - }); + if let Some(&(path, reason)) = self.disallowed.get(&id) { + span_lint_and_then( + cx, + DISALLOWED_METHODS, + span, + format!("use of a disallowed method `{path}`"), + |diag| { + if let Some(reason) = reason { + diag.note(reason); + } + }, + ); } } } diff --git a/clippy_lints/src/disallowed_names.rs b/clippy_lints/src/disallowed_names.rs index 58809604c373..f55b0cf1c503 100644 --- a/clippy_lints/src/disallowed_names.rs +++ b/clippy_lints/src/disallowed_names.rs @@ -1,9 +1,11 @@ +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint; use clippy_utils::is_in_test; use rustc_data_structures::fx::FxHashSet; use rustc_hir::{Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; +use rustc_span::Symbol; declare_clippy_lint! { /// ### What it does @@ -24,15 +26,14 @@ declare_clippy_lint! { "usage of a disallowed/placeholder name" } -#[derive(Clone, Debug)] pub struct DisallowedNames { - disallow: FxHashSet, + disallow: FxHashSet, } impl DisallowedNames { - pub fn new(disallowed_names: &[String]) -> Self { + pub fn new(conf: &'static Conf) -> Self { Self { - disallow: disallowed_names.iter().cloned().collect(), + disallow: conf.disallowed_names.iter().map(|x| Symbol::intern(x)).collect(), } } } @@ -42,7 +43,7 @@ impl_lint_pass!(DisallowedNames => [DISALLOWED_NAMES]); impl<'tcx> LateLintPass<'tcx> for DisallowedNames { fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) { if let PatKind::Binding(.., ident, _) = pat.kind - && self.disallow.contains(&ident.name.to_string()) + && self.disallow.contains(&ident.name) && !is_in_test(cx.tcx, pat.hir_id) { span_lint( diff --git a/clippy_lints/src/disallowed_script_idents.rs b/clippy_lints/src/disallowed_script_idents.rs index 5ce11900adf8..f79264e6b04a 100644 --- a/clippy_lints/src/disallowed_script_idents.rs +++ b/clippy_lints/src/disallowed_script_idents.rs @@ -1,3 +1,4 @@ +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint; use rustc_ast::ast; use rustc_data_structures::fx::FxHashSet; @@ -44,19 +45,20 @@ declare_clippy_lint! { "usage of non-allowed Unicode scripts" } -#[derive(Clone, Debug)] pub struct DisallowedScriptIdents { whitelist: FxHashSet