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/80] 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 daf166bad90d8..71073716cf8ba 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 5478372cbe00f..593649b60bc71 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 2643815d939b5..0c9b98d739d38 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/80] 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 2d5b351f8da3e..0df6a0a202ae7 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/80] 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 f9ce1defda17c..6c582190b4424 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 01a1bf8940a12..4aa84eca26120 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/80] 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 ff83725da6913..37f5dd5583bfb 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 cc87de0d90f18..c25c2062aceba 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 00c18d92b5fb6..dc242ecf4c72e 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 47e61326219d9..8057c25a5e499 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 288541362cddb..c43e50761bd52 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 eef3a42e35149..4a5ca231315eb 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/80] 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 927eccf2d54c5..841ec6b5d5c77 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/80] 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 aae4f8ac47f82..f149bfb77740c 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/80] 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 253f9959e13e7..d0cb24884686a 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 99fdbcff890b4..d4330400cd0e5 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 c510cd915d0c9..519091406ccf3 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 5d899415d7728..fed2b128dcf30 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 82f22ad693d78..97b2f99299a73 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 8d7f12af86e8a..b3d32a6d7d84c 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 fc02b974ee12a..29ea03f7bb180 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/80] 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 82f22ad693d78..7470ff754b5a8 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 a3c2e84566681..87b33b1f881d8 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 5b4a73712ee6e..8d8882a1781e8 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 17b00610899d6..ceb9ab6db73dc 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/80] 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 e6d52bcef717c..3b4cc1134802d 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 72fa05be3cc60..0b7279f2b360d 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 d425b505a760c..cbeb48b6cc376 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 28068c6347325..7384e534ed7d7 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 0ecfa7baa72d4..837e8b9028de2 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 801e886261993..89ba33583d6cd 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/80] 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 0db1456d40bfc..69a8eb7d94e74 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 2261fcdbdabc9..2998c6f8ae0a4 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 c67da689aaee0..f2f841dcec33d 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 8fa63f3e8fde0..b522c22a44d70 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 631d10f4a72e9..76eba7327cff6 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 6d8e166a649d8..81e4fb6765d0b 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 b5a07418734c9..3026854e317ae 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/80] 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 4a6ffcd9a7888..c7dd7292a14be 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 2998c6f8ae0a4..39cddece75daa 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 95ae591884bc4..186bf4035f0c6 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 fbb83c8ce5635..ee34891ad8af0 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 935ed48dacc50..a9ea11f4c2b06 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 85029a5e6a0d4..59c8c7f38e4e4 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 9c5a8a0cfcdfa..6964d8c8dbb33 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 305499f9da43c..e9c5f64a2550d 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/80] 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 194dd4752f91b..c171fa1c622af 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 277ba8427e054..7ce9bde1a7339 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 59b5c858d0460..b8087c6e000f5 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 559513d56946d..8e02f59b51265 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 8ff1f23644b16..d96b26acf345d 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/80] 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 593649b60bc71..c1dc8b5e8d09c 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 0c9b98d739d38..c7f66824d5818 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/80] 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 7066c9ad2b96b..2a5d3536ff6b7 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/80] 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 | 103 ++- 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 | 187 ++++-- clippy_lints/src/unnecessary_wraps.rs | 5 +- clippy_lints/src/unnested_or_patterns.rs | 8 +- clippy_lints/src/unused_peekable.rs | 61 +- 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 | 216 +++++-- 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 | 523 +++++++++++++--- 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 | 60 +- 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 | 186 +++--- 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, 4846 insertions(+), 5161 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 48a63e4856815..7afdd068a9905 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 f016a77005920..6a5139b6dc0bb 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 55281f3cbec0b..60c03b03d9be3 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 4378849905514..bb4dc97e748e3 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 48c00bcbf3413..a71d94daca74c 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 ad29339a84ad6..fb717a2c166d4 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 319b72e8c5d50..a7b0cc56ea127 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 be0b048ac0c76..e1b2edc8a6ff9 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 7f53aad679330..63140a36875da 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 435aa9244c522..d47e34bb5bce5 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 d762e30ef02e1..de91233d196c8 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 5708ffba08fd5..eb04c006f89fd 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 461117cf965dc..c0a9d888e0b0b 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 96e9c949b7500..451bae959874f 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 ec28fd4611184..e6d52bcef717c 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 d57ab539fff42..4eafa330fafab 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 0de0031ed24ff..03f777600f084 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 8ec60314cc9a0..8f430ae601a85 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 d4a1e2780d083..d5f017b26509b 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 0ca4a0e067d36..bd123a725a736 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() - { - 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; + && 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, } - - // 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; - } - + }) + && !is_from_proc_macro(cx, e) + { 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 593bc6c81ee8e..312ad4c299007 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 d52ad1c6f23f5..ff460a3fd8e39 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 54f0c7c468719..c31716fbcee1d 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 921693567fcd4..7513e18d408b1 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 92810ea2aa0ff..0b1ab5411bf18 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) - && !in_external_macro(cx.sess(), item.span) - && let ExprKind::Binary(op, left, right) = &item.kind - { - match op.node { - BinOpKind::Ge | BinOpKind::Le => single_check(item), - BinOpKind::And => double_check(cx, left, right), - _ => None, + 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, } - } 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, - ); + && !in_external_macro(cx.sess(), item.span) + && !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 + { + 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 60815f4f2afbb..5fa0522e4e5f9 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 07b02c98df151..f311c052ad6ee 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 28d9f68d504cc..eebda3ff76fd9 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 d896452be9209..86e0368c4e423 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 adf6f7c473757..678bdbc0ffb8a 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 b0590b0a71cb2..788c6f3ada297 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 eabc67601a2f1..69f9eb6842bcd 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 0c9ad5e8d0015..f27f68e2cbc5f 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 871f529da6c40..b51d343132b26 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 38fe687f7ccfe..5a01d76a2a621 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 58809604c373e..f55b0cf1c5034 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 5ce11900adf8f..f79264e6b04a1 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