From 4c43aa7053a38ea7e0bb3aca2ffec4e734f7164f Mon Sep 17 00:00:00 2001 From: Aaron Christiansen Date: Sat, 25 Jun 2022 23:15:44 +0100 Subject: [PATCH 01/62] Fix suggestion for `async` in redundant_closure_call Fix redundant_closure_call for single-expression async closures Add Sugg::asyncify Use Sugg for redundant_closure_call implementation --- clippy_lints/src/redundant_closure_call.rs | 21 +++++--- clippy_utils/src/sugg.rs | 6 +++ tests/ui/redundant_closure_call_fixable.fixed | 20 ++++++++ tests/ui/redundant_closure_call_fixable.rs | 20 ++++++++ .../ui/redundant_closure_call_fixable.stderr | 50 ++++++++++++++++++- 5 files changed, 109 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/redundant_closure_call.rs b/clippy_lints/src/redundant_closure_call.rs index f5a93cebab8ca..74eea6de4bbef 100644 --- a/clippy_lints/src/redundant_closure_call.rs +++ b/clippy_lints/src/redundant_closure_call.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::sugg::Sugg; use if_chain::if_chain; use rustc_ast::ast; use rustc_ast::visit as ast_visit; @@ -69,7 +69,7 @@ impl EarlyLintPass for RedundantClosureCall { if_chain! { if let ast::ExprKind::Call(ref paren, _) = expr.kind; if let ast::ExprKind::Paren(ref closure) = paren.kind; - if let ast::ExprKind::Closure(_, _, _, _, ref decl, ref block, _) = closure.kind; + if let ast::ExprKind::Closure(_, _, ref r#async, _, ref decl, ref block, _) = closure.kind; then { let mut visitor = ReturnVisitor::new(); visitor.visit_expr(block); @@ -81,10 +81,19 @@ impl EarlyLintPass for RedundantClosureCall { "try not to call a closure in the expression where it is declared", |diag| { if decl.inputs.is_empty() { - let mut app = Applicability::MachineApplicable; - let hint = - snippet_with_applicability(cx, block.span, "..", &mut app).into_owned(); - diag.span_suggestion(expr.span, "try doing something like", hint, app); + let app = Applicability::MachineApplicable; + let mut hint = Sugg::ast(cx, block, ".."); + + if r#async.is_async() { + // `async x` is a syntax error, so it becomes `async { x }` + if !matches!(block.kind, ast::ExprKind::Block(_, _)) { + hint = hint.blockify(); + } + + hint = hint.asyncify(); + } + + diag.span_suggestion(expr.span, "try doing something like", hint.to_string(), app); } }, ); diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index bad291dfc2513..081c98e2f3ce7 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -315,6 +315,12 @@ impl<'a> Sugg<'a> { Sugg::NonParen(Cow::Owned(format!("{{ {} }}", self))) } + /// Convenience method to prefix the expression with the `async` keyword. + /// Can be used after `blockify` to create an async block. + pub fn asyncify(self) -> Sugg<'static> { + Sugg::NonParen(Cow::Owned(format!("async {}", self))) + } + /// Convenience method to create the `..` or `...` /// suggestion. pub fn range(self, end: &Self, limit: ast::RangeLimits) -> Sugg<'static> { diff --git a/tests/ui/redundant_closure_call_fixable.fixed b/tests/ui/redundant_closure_call_fixable.fixed index 0abca6fca0613..7cd687c95a003 100644 --- a/tests/ui/redundant_closure_call_fixable.fixed +++ b/tests/ui/redundant_closure_call_fixable.fixed @@ -1,8 +1,28 @@ // run-rustfix +#![feature(async_closure)] #![warn(clippy::redundant_closure_call)] #![allow(unused)] +async fn something() -> u32 { + 21 +} + +async fn something_else() -> u32 { + 2 +} + fn main() { let a = 42; + let b = async { + let x = something().await; + let y = something_else().await; + x * y + }; + let c = { + let x = 21; + let y = 2; + x * y + }; + let d = async { something().await }; } diff --git a/tests/ui/redundant_closure_call_fixable.rs b/tests/ui/redundant_closure_call_fixable.rs index f8b9d37a5cc4e..37e4d22386415 100644 --- a/tests/ui/redundant_closure_call_fixable.rs +++ b/tests/ui/redundant_closure_call_fixable.rs @@ -1,8 +1,28 @@ // run-rustfix +#![feature(async_closure)] #![warn(clippy::redundant_closure_call)] #![allow(unused)] +async fn something() -> u32 { + 21 +} + +async fn something_else() -> u32 { + 2 +} + fn main() { let a = (|| 42)(); + let b = (async || { + let x = something().await; + let y = something_else().await; + x * y + })(); + let c = (|| { + let x = 21; + let y = 2; + x * y + })(); + let d = (async || something().await)(); } diff --git a/tests/ui/redundant_closure_call_fixable.stderr b/tests/ui/redundant_closure_call_fixable.stderr index afd704ef12a93..56a8e57c0c362 100644 --- a/tests/ui/redundant_closure_call_fixable.stderr +++ b/tests/ui/redundant_closure_call_fixable.stderr @@ -1,10 +1,56 @@ error: try not to call a closure in the expression where it is declared - --> $DIR/redundant_closure_call_fixable.rs:7:13 + --> $DIR/redundant_closure_call_fixable.rs:16:13 | LL | let a = (|| 42)(); | ^^^^^^^^^ help: try doing something like: `42` | = note: `-D clippy::redundant-closure-call` implied by `-D warnings` -error: aborting due to previous error +error: try not to call a closure in the expression where it is declared + --> $DIR/redundant_closure_call_fixable.rs:17:13 + | +LL | let b = (async || { + | _____________^ +LL | | let x = something().await; +LL | | let y = something_else().await; +LL | | x * y +LL | | })(); + | |________^ + | +help: try doing something like + | +LL ~ let b = async { +LL + let x = something().await; +LL + let y = something_else().await; +LL + x * y +LL ~ }; + | + +error: try not to call a closure in the expression where it is declared + --> $DIR/redundant_closure_call_fixable.rs:22:13 + | +LL | let c = (|| { + | _____________^ +LL | | let x = 21; +LL | | let y = 2; +LL | | x * y +LL | | })(); + | |________^ + | +help: try doing something like + | +LL ~ let c = { +LL + let x = 21; +LL + let y = 2; +LL + x * y +LL ~ }; + | + +error: try not to call a closure in the expression where it is declared + --> $DIR/redundant_closure_call_fixable.rs:27:13 + | +LL | let d = (async || something().await)(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `async { something().await }` + +error: aborting due to 4 previous errors From c990e2922ac7ff27e9a7516e9ac92cac5989c9e0 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Tue, 5 Jul 2022 16:03:51 -0400 Subject: [PATCH 02/62] Don't suggest using auto deref for block expressions --- clippy_lints/src/dereference.rs | 127 ++++++++++++++++++++-------- tests/ui/explicit_auto_deref.fixed | 17 ++++ tests/ui/explicit_auto_deref.rs | 17 ++++ tests/ui/explicit_auto_deref.stderr | 72 ++++++++-------- 4 files changed, 167 insertions(+), 66 deletions(-) diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 8c7cf7748be13..b87d41455d9b6 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -17,7 +17,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable, TypeckResults}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::{symbol::sym, Span, Symbol}; +use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP}; use rustc_trait_selection::infer::InferCtxtExt; declare_clippy_lint! { @@ -609,18 +609,21 @@ enum Position { Postfix, Deref, /// Any other location which will trigger auto-deref to a specific time. - DerefStable(i8), + /// Contains the precedence of the parent expression and whether the target type is sized. + DerefStable(i8, bool), /// Any other location which will trigger auto-reborrowing. + /// Contains the precedence of the parent expression. ReborrowStable(i8), + /// Contains the precedence of the parent expression. Other(i8), } impl Position { fn is_deref_stable(self) -> bool { - matches!(self, Self::DerefStable(_)) + matches!(self, Self::DerefStable(..)) } fn is_reborrow_stable(self) -> bool { - matches!(self, Self::DerefStable(_) | Self::ReborrowStable(_)) + matches!(self, Self::DerefStable(..) | Self::ReborrowStable(_)) } fn can_auto_borrow(self) -> bool { @@ -628,7 +631,7 @@ impl Position { } fn lint_explicit_deref(self) -> bool { - matches!(self, Self::Other(_) | Self::DerefStable(_) | Self::ReborrowStable(_)) + matches!(self, Self::Other(_) | Self::DerefStable(..) | Self::ReborrowStable(_)) } fn precedence(self) -> i8 { @@ -639,7 +642,7 @@ impl Position { | Self::FieldAccess(_) | Self::Postfix => PREC_POSTFIX, Self::Deref => PREC_PREFIX, - Self::DerefStable(p) | Self::ReborrowStable(p) | Self::Other(p) => p, + Self::DerefStable(p, _) | Self::ReborrowStable(p) | Self::Other(p) => p, } } } @@ -659,7 +662,7 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & } match parent { Node::Local(Local { ty: Some(ty), span, .. }) if span.ctxt() == ctxt => { - Some(binding_ty_auto_deref_stability(ty, precedence)) + Some(binding_ty_auto_deref_stability(cx, ty, precedence)) }, Node::Item(&Item { kind: ItemKind::Static(..) | ItemKind::Const(..), @@ -680,8 +683,11 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & .. }) if span.ctxt() == ctxt => { let ty = cx.tcx.type_of(def_id); - Some(if ty.is_ref() { - Position::DerefStable(precedence) + Some(if let ty::Ref(_, ty, _) = *ty.kind() { + Position::DerefStable( + precedence, + ty.is_sized(cx.tcx.at(DUMMY_SP), cx.param_env.without_caller_bounds()), + ) } else { Position::Other(precedence) }) @@ -705,13 +711,20 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & span, .. }) if span.ctxt() == ctxt => { - let output = cx.tcx.fn_sig(def_id.to_def_id()).skip_binder().output(); - Some(if !output.is_ref() { - Position::Other(precedence) - } else if output.has_placeholders() || output.has_opaque_types() { - Position::ReborrowStable(precedence) + let output = cx + .tcx + .erase_late_bound_regions(cx.tcx.fn_sig(def_id.to_def_id()).output()); + Some(if let ty::Ref(_, ty, _) = *output.kind() { + if ty.has_placeholders() || ty.has_opaque_types() { + Position::ReborrowStable(precedence) + } else { + Position::DerefStable( + precedence, + ty.is_sized(cx.tcx.at(DUMMY_SP), cx.param_env.without_caller_bounds()), + ) + } } else { - Position::DerefStable(precedence) + Position::Other(precedence) }) }, @@ -725,21 +738,24 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & }) = cx.tcx.hir().get(owner_id) { match fn_decl.output { - FnRetTy::Return(ty) => binding_ty_auto_deref_stability(ty, precedence), + FnRetTy::Return(ty) => binding_ty_auto_deref_stability(cx, ty, precedence), FnRetTy::DefaultReturn(_) => Position::Other(precedence), } } else { let output = cx .tcx - .fn_sig(cx.tcx.hir().local_def_id(owner_id)) - .skip_binder() - .output(); - if !output.is_ref() { - Position::Other(precedence) - } else if output.has_placeholders() || output.has_opaque_types() { - Position::ReborrowStable(precedence) + .erase_late_bound_regions(cx.tcx.fn_sig(cx.tcx.hir().local_def_id(owner_id)).output()); + if let ty::Ref(_, ty, _) = *output.kind() { + if ty.has_placeholders() || ty.has_opaque_types() { + Position::ReborrowStable(precedence) + } else { + Position::DerefStable( + precedence, + ty.is_sized(cx.tcx.at(DUMMY_SP), cx.param_env.without_caller_bounds()), + ) + } } else { - Position::DerefStable(precedence) + Position::Other(precedence) } }, ) @@ -755,8 +771,8 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & .map(|(hir_ty, ty)| match hir_ty { // Type inference for closures can depend on how they're called. Only go by the explicit // types here. - Some(ty) => binding_ty_auto_deref_stability(ty, precedence), - None => param_auto_deref_stability(ty.skip_binder(), precedence), + Some(ty) => binding_ty_auto_deref_stability(cx, ty, precedence), + None => param_auto_deref_stability(cx, cx.tcx.erase_late_bound_regions(ty), precedence), }), ExprKind::MethodCall(_, args, _) => { let id = cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap(); @@ -797,7 +813,11 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & Position::MethodReceiver } } else { - param_auto_deref_stability(cx.tcx.fn_sig(id).skip_binder().inputs()[i], precedence) + param_auto_deref_stability( + cx, + cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i)), + precedence, + ) } }) }, @@ -808,7 +828,7 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & .find(|f| f.expr.hir_id == child_id) .zip(variant) .and_then(|(field, variant)| variant.fields.iter().find(|f| f.name == field.ident.name)) - .map(|field| param_auto_deref_stability(cx.tcx.type_of(field.did), precedence)) + .map(|field| param_auto_deref_stability(cx, cx.tcx.type_of(field.did), precedence)) }, ExprKind::Field(child, name) if child.hir_id == e.hir_id => Some(Position::FieldAccess(name.name)), ExprKind::Unary(UnOp::Deref, child) if child.hir_id == e.hir_id => Some(Position::Deref), @@ -840,7 +860,7 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & // // Here `y1` and `y2` would resolve to different types, so the type `&Box<_>` is not stable when // switching to auto-dereferencing. -fn binding_ty_auto_deref_stability(ty: &hir::Ty<'_>, precedence: i8) -> Position { +fn binding_ty_auto_deref_stability(cx: &LateContext<'_>, ty: &hir::Ty<'_>, precedence: i8) -> Position { let TyKind::Rptr(_, ty) = &ty.kind else { return Position::Other(precedence); }; @@ -870,7 +890,13 @@ fn binding_ty_auto_deref_stability(ty: &hir::Ty<'_>, precedence: i8) -> Position { Position::ReborrowStable(precedence) } else { - Position::DerefStable(precedence) + Position::DerefStable( + precedence, + cx + .typeck_results() + .node_type(ty.ty.hir_id) + .is_sized(cx.tcx.at(DUMMY_SP), cx.param_env.without_caller_bounds()), + ) } }, TyKind::Slice(_) @@ -880,7 +906,13 @@ fn binding_ty_auto_deref_stability(ty: &hir::Ty<'_>, precedence: i8) -> Position | TyKind::Tup(_) | TyKind::Ptr(_) | TyKind::TraitObject(..) - | TyKind::Path(_) => Position::DerefStable(precedence), + | TyKind::Path(_) => Position::DerefStable( + precedence, + cx + .typeck_results() + .node_type(ty.ty.hir_id) + .is_sized(cx.tcx.at(DUMMY_SP), cx.param_env.without_caller_bounds()), + ), TyKind::OpaqueDef(..) | TyKind::Infer | TyKind::Typeof(..) @@ -921,7 +953,7 @@ fn ty_contains_infer(ty: &hir::Ty<'_>) -> bool { } // Checks whether a type is stable when switching to auto dereferencing, -fn param_auto_deref_stability(ty: Ty<'_>, precedence: i8) -> Position { +fn param_auto_deref_stability<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, precedence: i8) -> Position { let ty::Ref(_, mut ty, _) = *ty.kind() else { return Position::Other(precedence); }; @@ -960,7 +992,10 @@ fn param_auto_deref_stability(ty: Ty<'_>, precedence: i8) -> Position { | ty::GeneratorWitness(..) | ty::Never | ty::Tuple(_) - | ty::Projection(_) => Position::DerefStable(precedence), + | ty::Projection(_) => Position::DerefStable( + precedence, + ty.is_sized(cx.tcx.at(DUMMY_SP), cx.param_env.without_caller_bounds()), + ), }; } } @@ -1040,6 +1075,19 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data }); }, State::ExplicitDeref { deref_span_id } => { + if matches!( + expr.kind, + ExprKind::Block(..) + | ExprKind::ConstBlock(_) + | ExprKind::If(..) + | ExprKind::Loop(..) + | ExprKind::Match(..) + ) && matches!(data.position, Position::DerefStable(_, true)) + { + // Rustc bug: auto deref doesn't work on block expression when targeting sized types. + return; + } + let (span, hir_id, precedence) = if let Some((span, hir_id)) = deref_span_id && !cx.typeck_results().expr_ty(expr).is_ref() { @@ -1067,6 +1115,19 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data ); }, State::ExplicitDerefField { .. } => { + if matches!( + expr.kind, + ExprKind::Block(..) + | ExprKind::ConstBlock(_) + | ExprKind::If(..) + | ExprKind::Loop(..) + | ExprKind::Match(..) + ) && matches!(data.position, Position::DerefStable(_, true)) + { + // Rustc bug: auto deref doesn't work on block expression when targeting sized types. + return; + } + span_lint_hir_and_then( cx, EXPLICIT_AUTO_DEREF, diff --git a/tests/ui/explicit_auto_deref.fixed b/tests/ui/explicit_auto_deref.fixed index a650fdc1f8972..327cfbaf32428 100644 --- a/tests/ui/explicit_auto_deref.fixed +++ b/tests/ui/explicit_auto_deref.fixed @@ -67,6 +67,7 @@ fn main() { let s = String::new(); let _: &str = &s; + let _: &str = &{ String::new() }; let _ = &*s; // Don't lint. Inferred type would change. let _: &_ = &*s; // Don't lint. Inferred type would change. @@ -215,4 +216,20 @@ fn main() { let s = &"str"; let _ = || return *s; let _ = || -> &'static str { return s }; + + struct X; + struct Y(X); + impl core::ops::Deref for Y { + type Target = X; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + let _: &X = &*{ Y(X) }; + let _: &X = &*match 0 { + #[rustfmt::skip] + 0 => { Y(X) }, + _ => panic!(), + }; + let _: &X = &*if true { Y(X) } else { panic!() }; } diff --git a/tests/ui/explicit_auto_deref.rs b/tests/ui/explicit_auto_deref.rs index 8f4f352576a73..471a03d60a96b 100644 --- a/tests/ui/explicit_auto_deref.rs +++ b/tests/ui/explicit_auto_deref.rs @@ -67,6 +67,7 @@ fn main() { let s = String::new(); let _: &str = &*s; + let _: &str = &*{ String::new() }; let _ = &*s; // Don't lint. Inferred type would change. let _: &_ = &*s; // Don't lint. Inferred type would change. @@ -215,4 +216,20 @@ fn main() { let s = &"str"; let _ = || return *s; let _ = || -> &'static str { return *s }; + + struct X; + struct Y(X); + impl core::ops::Deref for Y { + type Target = X; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + let _: &X = &*{ Y(X) }; + let _: &X = &*match 0 { + #[rustfmt::skip] + 0 => { Y(X) }, + _ => panic!(), + }; + let _: &X = &*if true { Y(X) } else { panic!() }; } diff --git a/tests/ui/explicit_auto_deref.stderr b/tests/ui/explicit_auto_deref.stderr index 92765307ea73d..d1bc51f5bddf7 100644 --- a/tests/ui/explicit_auto_deref.stderr +++ b/tests/ui/explicit_auto_deref.stderr @@ -7,196 +7,202 @@ LL | let _: &str = &*s; = note: `-D clippy::explicit-auto-deref` implied by `-D warnings` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:73:12 + --> $DIR/explicit_auto_deref.rs:70:20 + | +LL | let _: &str = &*{ String::new() }; + | ^^^^^^^^^^^^^^^^^^ help: try this: `{ String::new() }` + +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:74:12 | LL | f_str(&*s); | ^^ help: try this: `s` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:77:14 + --> $DIR/explicit_auto_deref.rs:78:14 | LL | f_str_t(&*s, &*s); // Don't lint second param. | ^^ help: try this: `s` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:80:25 + --> $DIR/explicit_auto_deref.rs:81:25 | LL | let _: &Box = &**b; | ^^^ help: try this: `b` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:86:8 + --> $DIR/explicit_auto_deref.rs:87:8 | LL | c(&*s); | ^^ help: try this: `s` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:92:9 + --> $DIR/explicit_auto_deref.rs:93:9 | LL | &**x | ^^^^ help: try this: `x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:96:11 + --> $DIR/explicit_auto_deref.rs:97:11 | LL | { &**x } | ^^^^ help: try this: `x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:100:9 + --> $DIR/explicit_auto_deref.rs:101:9 | LL | &**{ x } | ^^^^^^^^ help: try this: `{ x }` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:104:9 + --> $DIR/explicit_auto_deref.rs:105:9 | LL | &***x | ^^^^^ help: try this: `x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:121:13 + --> $DIR/explicit_auto_deref.rs:122:13 | LL | f1(&*x); | ^^ help: try this: `x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:122:13 + --> $DIR/explicit_auto_deref.rs:123:13 | LL | f2(&*x); | ^^ help: try this: `x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:123:13 + --> $DIR/explicit_auto_deref.rs:124:13 | LL | f3(&*x); | ^^ help: try this: `x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:124:28 + --> $DIR/explicit_auto_deref.rs:125:28 | LL | f4.callable_str()(&*x); | ^^ help: try this: `x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:125:13 + --> $DIR/explicit_auto_deref.rs:126:13 | LL | f5(&*x); | ^^ help: try this: `x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:126:13 + --> $DIR/explicit_auto_deref.rs:127:13 | LL | f6(&*x); | ^^ help: try this: `x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:127:28 + --> $DIR/explicit_auto_deref.rs:128:28 | LL | f7.callable_str()(&*x); | ^^ help: try this: `x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:128:26 + --> $DIR/explicit_auto_deref.rs:129:26 | LL | f8.callable_t()(&*x); | ^^ help: try this: `x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:129:13 + --> $DIR/explicit_auto_deref.rs:130:13 | LL | f9(&*x); | ^^ help: try this: `x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:130:14 + --> $DIR/explicit_auto_deref.rs:131:14 | LL | f10(&*x); | ^^ help: try this: `x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:131:27 + --> $DIR/explicit_auto_deref.rs:132:27 | LL | f11.callable_t()(&*x); | ^^ help: try this: `x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:135:17 + --> $DIR/explicit_auto_deref.rs:136:17 | LL | let _ = S1(&*s); | ^^ help: try this: `s` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:140:22 + --> $DIR/explicit_auto_deref.rs:141:22 | LL | let _ = S2 { s: &*s }; | ^^ help: try this: `s` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:156:30 + --> $DIR/explicit_auto_deref.rs:157:30 | LL | let _ = Self::S1(&**s); | ^^^^ help: try this: `s` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:157:35 + --> $DIR/explicit_auto_deref.rs:158:35 | LL | let _ = Self::S2 { s: &**s }; | ^^^^ help: try this: `s` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:160:21 + --> $DIR/explicit_auto_deref.rs:161:21 | LL | let _ = E1::S1(&*s); | ^^ help: try this: `s` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:161:26 + --> $DIR/explicit_auto_deref.rs:162:26 | LL | let _ = E1::S2 { s: &*s }; | ^^ help: try this: `s` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:179:13 + --> $DIR/explicit_auto_deref.rs:180:13 | LL | let _ = (*b).foo; | ^^^^ help: try this: `b` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:180:13 + --> $DIR/explicit_auto_deref.rs:181:13 | LL | let _ = (**b).foo; | ^^^^^ help: try this: `b` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:195:19 + --> $DIR/explicit_auto_deref.rs:196:19 | LL | let _ = f_str(*ref_str); | ^^^^^^^^ help: try this: `ref_str` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:197:19 + --> $DIR/explicit_auto_deref.rs:198:19 | LL | let _ = f_str(**ref_ref_str); | ^^^^^^^^^^^^^ help: try this: `ref_ref_str` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:207:13 + --> $DIR/explicit_auto_deref.rs:208:13 | LL | f_str(&&*ref_str); // `needless_borrow` will suggest removing both references | ^^^^^^^^ help: try this: `ref_str` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:208:12 + --> $DIR/explicit_auto_deref.rs:209:12 | LL | f_str(&&**ref_str); // `needless_borrow` will suggest removing only one reference | ^^^^^^^^^^ help: try this: `ref_str` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:217:41 + --> $DIR/explicit_auto_deref.rs:218:41 | LL | let _ = || -> &'static str { return *s }; | ^^ help: try this: `s` -error: aborting due to 33 previous errors +error: aborting due to 34 previous errors From 9ce0f82b8ab44869777d441b51aecfb9d8ebdef9 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Tue, 5 Jul 2022 22:30:36 -0400 Subject: [PATCH 03/62] Include the borrow in the suggestion for `explicit_auto_deref` --- clippy_lints/src/dereference.rs | 79 ++++++++----------- tests/ui/explicit_auto_deref.fixed | 1 + tests/ui/explicit_auto_deref.rs | 1 + tests/ui/explicit_auto_deref.stderr | 118 +++++++++++++++------------- 4 files changed, 98 insertions(+), 101 deletions(-) diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index b87d41455d9b6..8495d2c6df712 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -183,24 +183,24 @@ enum State { }, DerefedBorrow(DerefedBorrow), ExplicitDeref { - // Span and id of the top-level deref expression if the parent expression is a borrow. - deref_span_id: Option<(Span, HirId)>, + mutability: Option, }, ExplicitDerefField { name: Symbol, }, Reborrow { - deref_span: Span, - deref_hir_id: HirId, + mutability: Mutability, + }, + Borrow { + mutability: Mutability, }, - Borrow, } // A reference operation considered by this lint pass enum RefOp { Method(Mutability), Deref, - AddrOf, + AddrOf(Mutability), } struct RefPat { @@ -263,7 +263,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { )); } else if position.is_deref_stable() { self.state = Some(( - State::ExplicitDeref { deref_span_id: None }, + State::ExplicitDeref { mutability: None }, StateData { span: expr.span, hir_id: expr.hir_id, position }, )); } @@ -289,7 +289,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { }, )); }, - RefOp::AddrOf => { + RefOp::AddrOf(mutability) => { // Find the number of times the borrow is auto-derefed. let mut iter = adjustments.iter(); let mut deref_count = 0usize; @@ -359,7 +359,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { )); } else if position.is_deref_stable() { self.state = Some(( - State::Borrow, + State::Borrow { mutability }, StateData { span: expr.span, hir_id: expr.hir_id, @@ -395,7 +395,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { data, )); }, - (Some((State::DerefedBorrow(state), data)), RefOp::AddrOf) if state.count != 0 => { + (Some((State::DerefedBorrow(state), data)), RefOp::AddrOf(_)) if state.count != 0 => { self.state = Some(( State::DerefedBorrow(DerefedBorrow { count: state.count - 1, @@ -404,12 +404,12 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { data, )); }, - (Some((State::DerefedBorrow(state), data)), RefOp::AddrOf) => { + (Some((State::DerefedBorrow(state), data)), RefOp::AddrOf(mutability)) => { let position = data.position; report(cx, expr, State::DerefedBorrow(state), data); if position.is_deref_stable() { self.state = Some(( - State::Borrow, + State::Borrow { mutability }, StateData { span: expr.span, hir_id: expr.hir_id, @@ -430,43 +430,28 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { )); } else if position.is_deref_stable() { self.state = Some(( - State::ExplicitDeref { deref_span_id: None }, + State::ExplicitDeref { mutability: None }, StateData { span: expr.span, hir_id: expr.hir_id, position }, )); } }, - (Some((State::Borrow, data)), RefOp::Deref) => { + (Some((State::Borrow { mutability }, data)), RefOp::Deref) => { if typeck.expr_ty(sub_expr).is_ref() { - self.state = Some(( - State::Reborrow { - deref_span: expr.span, - deref_hir_id: expr.hir_id, - }, - data, - )); + self.state = Some((State::Reborrow { mutability }, data)); } else { self.state = Some(( State::ExplicitDeref { - deref_span_id: Some((expr.span, expr.hir_id)), + mutability: Some(mutability), }, data, )); } }, - ( - Some(( - State::Reborrow { - deref_span, - deref_hir_id, - }, - data, - )), - RefOp::Deref, - ) => { + (Some((State::Reborrow { mutability }, data)), RefOp::Deref) => { self.state = Some(( State::ExplicitDeref { - deref_span_id: Some((deref_span, deref_hir_id)), + mutability: Some(mutability), }, data, )); @@ -573,7 +558,7 @@ fn try_parse_ref_op<'tcx>( ExprKind::Unary(UnOp::Deref, sub_expr) if !typeck.expr_ty(sub_expr).is_unsafe_ptr() => { return Some((RefOp::Deref, sub_expr)); }, - ExprKind::AddrOf(BorrowKind::Ref, _, sub_expr) => return Some((RefOp::AddrOf, sub_expr)), + ExprKind::AddrOf(BorrowKind::Ref, mutability, sub_expr) => return Some((RefOp::AddrOf(mutability), sub_expr)), _ => return None, }; if tcx.is_diagnostic_item(sym::deref_method, def_id) { @@ -1074,7 +1059,7 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data diag.span_suggestion(data.span, "change this to", sugg, app); }); }, - State::ExplicitDeref { deref_span_id } => { + State::ExplicitDeref { mutability } => { if matches!( expr.kind, ExprKind::Block(..) @@ -1088,29 +1073,33 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data return; } - let (span, hir_id, precedence) = if let Some((span, hir_id)) = deref_span_id + let (prefix, precedence) = if let Some(mutability) = mutability && !cx.typeck_results().expr_ty(expr).is_ref() { - (span, hir_id, PREC_PREFIX) + let prefix = match mutability { + Mutability::Not => "&", + Mutability::Mut => "&mut ", + }; + (prefix, 0) } else { - (data.span, data.hir_id, data.position.precedence()) + ("", data.position.precedence()) }; span_lint_hir_and_then( cx, EXPLICIT_AUTO_DEREF, - hir_id, - span, + data.hir_id, + data.span, "deref which would be done by auto-deref", |diag| { let mut app = Applicability::MachineApplicable; - let (snip, snip_is_macro) = snippet_with_context(cx, expr.span, span.ctxt(), "..", &mut app); + let (snip, snip_is_macro) = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app); let sugg = if !snip_is_macro && expr.precedence().order() < precedence && !has_enclosing_paren(&snip) { - format!("({})", snip) + format!("{}({})", prefix, snip) } else { - snip.into() + format!("{}{}", prefix, snip) }; - diag.span_suggestion(span, "try this", sugg, app); + diag.span_suggestion(data.span, "try this", sugg, app); }, ); }, @@ -1141,7 +1130,7 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data }, ); }, - State::Borrow | State::Reborrow { .. } => (), + State::Borrow { .. } | State::Reborrow { .. } => (), } } diff --git a/tests/ui/explicit_auto_deref.fixed b/tests/ui/explicit_auto_deref.fixed index 327cfbaf32428..d3efc29941454 100644 --- a/tests/ui/explicit_auto_deref.fixed +++ b/tests/ui/explicit_auto_deref.fixed @@ -68,6 +68,7 @@ fn main() { let _: &str = &s; let _: &str = &{ String::new() }; + let _: &str = &mut { String::new() }; let _ = &*s; // Don't lint. Inferred type would change. let _: &_ = &*s; // Don't lint. Inferred type would change. diff --git a/tests/ui/explicit_auto_deref.rs b/tests/ui/explicit_auto_deref.rs index 471a03d60a96b..e25ccbe78cef6 100644 --- a/tests/ui/explicit_auto_deref.rs +++ b/tests/ui/explicit_auto_deref.rs @@ -68,6 +68,7 @@ fn main() { let _: &str = &*s; let _: &str = &*{ String::new() }; + let _: &str = &mut *{ String::new() }; let _ = &*s; // Don't lint. Inferred type would change. let _: &_ = &*s; // Don't lint. Inferred type would change. diff --git a/tests/ui/explicit_auto_deref.stderr b/tests/ui/explicit_auto_deref.stderr index d1bc51f5bddf7..0d7a9564a900e 100644 --- a/tests/ui/explicit_auto_deref.stderr +++ b/tests/ui/explicit_auto_deref.stderr @@ -1,208 +1,214 @@ error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:69:20 + --> $DIR/explicit_auto_deref.rs:69:19 | LL | let _: &str = &*s; - | ^^ help: try this: `s` + | ^^^ help: try this: `&s` | = note: `-D clippy::explicit-auto-deref` implied by `-D warnings` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:70:20 + --> $DIR/explicit_auto_deref.rs:70:19 | LL | let _: &str = &*{ String::new() }; - | ^^^^^^^^^^^^^^^^^^ help: try this: `{ String::new() }` + | ^^^^^^^^^^^^^^^^^^^ help: try this: `&{ String::new() }` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:74:12 + --> $DIR/explicit_auto_deref.rs:71:19 + | +LL | let _: &str = &mut *{ String::new() }; + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&mut { String::new() }` + +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:75:11 | LL | f_str(&*s); - | ^^ help: try this: `s` + | ^^^ help: try this: `&s` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:78:14 + --> $DIR/explicit_auto_deref.rs:79:13 | LL | f_str_t(&*s, &*s); // Don't lint second param. - | ^^ help: try this: `s` + | ^^^ help: try this: `&s` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:81:25 + --> $DIR/explicit_auto_deref.rs:82:24 | LL | let _: &Box = &**b; - | ^^^ help: try this: `b` + | ^^^^ help: try this: `&b` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:87:8 + --> $DIR/explicit_auto_deref.rs:88:7 | LL | c(&*s); - | ^^ help: try this: `s` + | ^^^ help: try this: `&s` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:93:9 + --> $DIR/explicit_auto_deref.rs:94:9 | LL | &**x | ^^^^ help: try this: `x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:97:11 + --> $DIR/explicit_auto_deref.rs:98:11 | LL | { &**x } | ^^^^ help: try this: `x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:101:9 + --> $DIR/explicit_auto_deref.rs:102:9 | LL | &**{ x } | ^^^^^^^^ help: try this: `{ x }` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:105:9 + --> $DIR/explicit_auto_deref.rs:106:9 | LL | &***x | ^^^^^ help: try this: `x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:122:13 + --> $DIR/explicit_auto_deref.rs:123:12 | LL | f1(&*x); - | ^^ help: try this: `x` + | ^^^ help: try this: `&x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:123:13 + --> $DIR/explicit_auto_deref.rs:124:12 | LL | f2(&*x); - | ^^ help: try this: `x` + | ^^^ help: try this: `&x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:124:13 + --> $DIR/explicit_auto_deref.rs:125:12 | LL | f3(&*x); - | ^^ help: try this: `x` + | ^^^ help: try this: `&x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:125:28 + --> $DIR/explicit_auto_deref.rs:126:27 | LL | f4.callable_str()(&*x); - | ^^ help: try this: `x` + | ^^^ help: try this: `&x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:126:13 + --> $DIR/explicit_auto_deref.rs:127:12 | LL | f5(&*x); - | ^^ help: try this: `x` + | ^^^ help: try this: `&x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:127:13 + --> $DIR/explicit_auto_deref.rs:128:12 | LL | f6(&*x); - | ^^ help: try this: `x` + | ^^^ help: try this: `&x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:128:28 + --> $DIR/explicit_auto_deref.rs:129:27 | LL | f7.callable_str()(&*x); - | ^^ help: try this: `x` + | ^^^ help: try this: `&x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:129:26 + --> $DIR/explicit_auto_deref.rs:130:25 | LL | f8.callable_t()(&*x); - | ^^ help: try this: `x` + | ^^^ help: try this: `&x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:130:13 + --> $DIR/explicit_auto_deref.rs:131:12 | LL | f9(&*x); - | ^^ help: try this: `x` + | ^^^ help: try this: `&x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:131:14 + --> $DIR/explicit_auto_deref.rs:132:13 | LL | f10(&*x); - | ^^ help: try this: `x` + | ^^^ help: try this: `&x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:132:27 + --> $DIR/explicit_auto_deref.rs:133:26 | LL | f11.callable_t()(&*x); - | ^^ help: try this: `x` + | ^^^ help: try this: `&x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:136:17 + --> $DIR/explicit_auto_deref.rs:137:16 | LL | let _ = S1(&*s); - | ^^ help: try this: `s` + | ^^^ help: try this: `&s` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:141:22 + --> $DIR/explicit_auto_deref.rs:142:21 | LL | let _ = S2 { s: &*s }; - | ^^ help: try this: `s` + | ^^^ help: try this: `&s` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:157:30 + --> $DIR/explicit_auto_deref.rs:158:30 | LL | let _ = Self::S1(&**s); | ^^^^ help: try this: `s` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:158:35 + --> $DIR/explicit_auto_deref.rs:159:35 | LL | let _ = Self::S2 { s: &**s }; | ^^^^ help: try this: `s` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:161:21 + --> $DIR/explicit_auto_deref.rs:162:20 | LL | let _ = E1::S1(&*s); - | ^^ help: try this: `s` + | ^^^ help: try this: `&s` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:162:26 + --> $DIR/explicit_auto_deref.rs:163:25 | LL | let _ = E1::S2 { s: &*s }; - | ^^ help: try this: `s` + | ^^^ help: try this: `&s` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:180:13 + --> $DIR/explicit_auto_deref.rs:181:13 | LL | let _ = (*b).foo; | ^^^^ help: try this: `b` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:181:13 + --> $DIR/explicit_auto_deref.rs:182:13 | LL | let _ = (**b).foo; | ^^^^^ help: try this: `b` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:196:19 + --> $DIR/explicit_auto_deref.rs:197:19 | LL | let _ = f_str(*ref_str); | ^^^^^^^^ help: try this: `ref_str` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:198:19 + --> $DIR/explicit_auto_deref.rs:199:19 | LL | let _ = f_str(**ref_ref_str); | ^^^^^^^^^^^^^ help: try this: `ref_ref_str` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:208:13 + --> $DIR/explicit_auto_deref.rs:209:13 | LL | f_str(&&*ref_str); // `needless_borrow` will suggest removing both references | ^^^^^^^^ help: try this: `ref_str` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:209:12 + --> $DIR/explicit_auto_deref.rs:210:12 | LL | f_str(&&**ref_str); // `needless_borrow` will suggest removing only one reference | ^^^^^^^^^^ help: try this: `ref_str` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:218:41 + --> $DIR/explicit_auto_deref.rs:219:41 | LL | let _ = || -> &'static str { return *s }; | ^^ help: try this: `s` -error: aborting due to 34 previous errors +error: aborting due to 35 previous errors From 84e03b621522799a72f55d3e728d63aebb561139 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 10 Jul 2022 15:04:29 -0400 Subject: [PATCH 04/62] Don't lint `explicit_auto_deref` on `dyn Trait` return --- clippy_lints/src/dereference.rs | 122 ++++++++++++++-------------- clippy_utils/src/ty.rs | 51 +++++++----- tests/ui/explicit_auto_deref.fixed | 9 ++ tests/ui/explicit_auto_deref.rs | 9 ++ tests/ui/explicit_auto_deref.stderr | 8 +- 5 files changed, 119 insertions(+), 80 deletions(-) diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 8495d2c6df712..40e62dbd58643 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -668,14 +668,7 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & .. }) if span.ctxt() == ctxt => { let ty = cx.tcx.type_of(def_id); - Some(if let ty::Ref(_, ty, _) = *ty.kind() { - Position::DerefStable( - precedence, - ty.is_sized(cx.tcx.at(DUMMY_SP), cx.param_env.without_caller_bounds()), - ) - } else { - Position::Other(precedence) - }) + Some(ty_auto_deref_stability(cx, ty, precedence).position_for_result(cx)) }, Node::Item(&Item { @@ -699,18 +692,7 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & let output = cx .tcx .erase_late_bound_regions(cx.tcx.fn_sig(def_id.to_def_id()).output()); - Some(if let ty::Ref(_, ty, _) = *output.kind() { - if ty.has_placeholders() || ty.has_opaque_types() { - Position::ReborrowStable(precedence) - } else { - Position::DerefStable( - precedence, - ty.is_sized(cx.tcx.at(DUMMY_SP), cx.param_env.without_caller_bounds()), - ) - } - } else { - Position::Other(precedence) - }) + Some(ty_auto_deref_stability(cx, output, precedence).position_for_result(cx)) }, Node::Expr(parent) if parent.span.ctxt() == ctxt => match parent.kind { @@ -730,18 +712,7 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & let output = cx .tcx .erase_late_bound_regions(cx.tcx.fn_sig(cx.tcx.hir().local_def_id(owner_id)).output()); - if let ty::Ref(_, ty, _) = *output.kind() { - if ty.has_placeholders() || ty.has_opaque_types() { - Position::ReborrowStable(precedence) - } else { - Position::DerefStable( - precedence, - ty.is_sized(cx.tcx.at(DUMMY_SP), cx.param_env.without_caller_bounds()), - ) - } - } else { - Position::Other(precedence) - } + ty_auto_deref_stability(cx, output, precedence).position_for_result(cx) }, ) }, @@ -757,7 +728,8 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & // Type inference for closures can depend on how they're called. Only go by the explicit // types here. Some(ty) => binding_ty_auto_deref_stability(cx, ty, precedence), - None => param_auto_deref_stability(cx, cx.tcx.erase_late_bound_regions(ty), precedence), + None => ty_auto_deref_stability(cx, cx.tcx.erase_late_bound_regions(ty), precedence) + .position_for_arg(), }), ExprKind::MethodCall(_, args, _) => { let id = cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap(); @@ -798,11 +770,12 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & Position::MethodReceiver } } else { - param_auto_deref_stability( + ty_auto_deref_stability( cx, cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i)), precedence, ) + .position_for_arg() } }) }, @@ -813,7 +786,9 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & .find(|f| f.expr.hir_id == child_id) .zip(variant) .and_then(|(field, variant)| variant.fields.iter().find(|f| f.name == field.ident.name)) - .map(|field| param_auto_deref_stability(cx, cx.tcx.type_of(field.did), precedence)) + .map(|field| { + ty_auto_deref_stability(cx, cx.tcx.type_of(field.did), precedence).position_for_arg() + }) }, ExprKind::Field(child, name) if child.hir_id == e.hir_id => Some(Position::FieldAccess(name.name)), ExprKind::Unary(UnOp::Deref, child) if child.hir_id == e.hir_id => Some(Position::Deref), @@ -890,17 +865,17 @@ fn binding_ty_auto_deref_stability(cx: &LateContext<'_>, ty: &hir::Ty<'_>, prece | TyKind::Never | TyKind::Tup(_) | TyKind::Ptr(_) - | TyKind::TraitObject(..) | TyKind::Path(_) => Position::DerefStable( precedence, cx - .typeck_results() - .node_type(ty.ty.hir_id) - .is_sized(cx.tcx.at(DUMMY_SP), cx.param_env.without_caller_bounds()), + .typeck_results() + .node_type(ty.ty.hir_id) + .is_sized(cx.tcx.at(DUMMY_SP), cx.param_env.without_caller_bounds()), ), TyKind::OpaqueDef(..) | TyKind::Infer | TyKind::Typeof(..) + | TyKind::TraitObject(..) | TyKind::Err => Position::ReborrowStable(precedence), }; } @@ -937,10 +912,39 @@ fn ty_contains_infer(ty: &hir::Ty<'_>) -> bool { v.0 } +struct TyPosition<'tcx> { + position: Position, + ty: Option>, +} +impl From for TyPosition<'_> { + fn from(position: Position) -> Self { + Self { position, ty: None } + } +} +impl<'tcx> TyPosition<'tcx> { + fn new_deref_stable_for_result(precedence: i8, ty: Ty<'tcx>) -> Self { + Self { + position: Position::ReborrowStable(precedence), + ty: Some(ty), + } + } + fn position_for_result(self, cx: &LateContext<'tcx>) -> Position { + match (self.position, self.ty) { + (Position::ReborrowStable(precedence), Some(ty)) => { + Position::DerefStable(precedence, ty.is_sized(cx.tcx.at(DUMMY_SP), cx.param_env)) + }, + (position, _) => position, + } + } + fn position_for_arg(self) -> Position { + self.position + } +} + // Checks whether a type is stable when switching to auto dereferencing, -fn param_auto_deref_stability<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, precedence: i8) -> Position { +fn ty_auto_deref_stability<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, precedence: i8) -> TyPosition<'tcx> { let ty::Ref(_, mut ty, _) = *ty.kind() else { - return Position::Other(precedence); + return Position::Other(precedence).into(); }; loop { @@ -949,38 +953,38 @@ fn param_auto_deref_stability<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, preced ty = ref_ty; continue; }, - ty::Infer(_) - | ty::Error(_) - | ty::Param(_) - | ty::Bound(..) - | ty::Opaque(..) - | ty::Placeholder(_) - | ty::Dynamic(..) => Position::ReborrowStable(precedence), - ty::Adt(..) if ty.has_placeholders() || ty.has_param_types_or_consts() => { - Position::ReborrowStable(precedence) + ty::Param(_) => TyPosition::new_deref_stable_for_result(precedence, ty), + ty::Infer(_) | ty::Error(_) | ty::Bound(..) | ty::Opaque(..) | ty::Placeholder(_) | ty::Dynamic(..) => { + Position::ReborrowStable(precedence).into() }, - ty::Adt(..) - | ty::Bool + ty::Adt(..) if ty.has_placeholders() || ty.has_opaque_types() => { + Position::ReborrowStable(precedence).into() + }, + ty::Adt(_, substs) if substs.has_param_types_or_consts() => { + TyPosition::new_deref_stable_for_result(precedence, ty) + }, + ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) - | ty::Float(_) - | ty::Foreign(_) - | ty::Str | ty::Array(..) - | ty::Slice(..) + | ty::Float(_) | ty::RawPtr(..) + | ty::FnPtr(_) => Position::DerefStable(precedence, true).into(), + ty::Str | ty::Slice(..) => Position::DerefStable(precedence, false).into(), + ty::Adt(..) + | ty::Foreign(_) | ty::FnDef(..) - | ty::FnPtr(_) - | ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) + | ty::Closure(..) | ty::Never | ty::Tuple(_) | ty::Projection(_) => Position::DerefStable( precedence, ty.is_sized(cx.tcx.at(DUMMY_SP), cx.param_env.without_caller_bounds()), - ), + ) + .into(), }; } } diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index a05d633d980c3..d394360fc678b 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -503,7 +503,7 @@ pub fn all_predicates_of(tcx: TyCtxt<'_>, id: DefId) -> impl Iterator { Sig(Binder<'tcx, FnSig<'tcx>>, Option), Closure(Option<&'tcx FnDecl<'tcx>>, Binder<'tcx, FnSig<'tcx>>), - Trait(Binder<'tcx, Ty<'tcx>>, Option>>), + Trait(Binder<'tcx, Ty<'tcx>>, Option>>, Option), } impl<'tcx> ExprFnSig<'tcx> { /// Gets the argument type at the given offset. This will return `None` when the index is out of @@ -518,7 +518,7 @@ impl<'tcx> ExprFnSig<'tcx> { } }, Self::Closure(_, sig) => Some(sig.input(0).map_bound(|ty| ty.tuple_fields()[i])), - Self::Trait(inputs, _) => Some(inputs.map_bound(|ty| ty.tuple_fields()[i])), + Self::Trait(inputs, _, _) => Some(inputs.map_bound(|ty| ty.tuple_fields()[i])), } } @@ -541,7 +541,7 @@ impl<'tcx> ExprFnSig<'tcx> { decl.and_then(|decl| decl.inputs.get(i)), sig.input(0).map_bound(|ty| ty.tuple_fields()[i]), )), - Self::Trait(inputs, _) => Some((None, inputs.map_bound(|ty| ty.tuple_fields()[i]))), + Self::Trait(inputs, _, _) => Some((None, inputs.map_bound(|ty| ty.tuple_fields()[i]))), } } @@ -550,12 +550,16 @@ impl<'tcx> ExprFnSig<'tcx> { pub fn output(self) -> Option>> { match self { Self::Sig(sig, _) | Self::Closure(_, sig) => Some(sig.output()), - Self::Trait(_, output) => output, + Self::Trait(_, output, _) => output, } } pub fn predicates_id(&self) -> Option { - if let ExprFnSig::Sig(_, id) = *self { id } else { None } + if let ExprFnSig::Sig(_, id) | ExprFnSig::Trait(_, _, id) = *self { + id + } else { + None + } } } @@ -580,7 +584,7 @@ fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option> Some(ExprFnSig::Closure(decl, subs.as_closure().sig())) }, ty::FnDef(id, subs) => Some(ExprFnSig::Sig(cx.tcx.bound_fn_sig(id).subst(cx.tcx, subs), Some(id))), - ty::Opaque(id, _) => ty_sig(cx, cx.tcx.type_of(id)), + ty::Opaque(id, _) => sig_from_bounds(cx, ty, cx.tcx.item_bounds(id), cx.tcx.opt_parent(id)), ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig, None)), ty::Dynamic(bounds, _) => { let lang_items = cx.tcx.lang_items(); @@ -594,26 +598,31 @@ fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option> .projection_bounds() .find(|p| lang_items.fn_once_output().map_or(false, |id| id == p.item_def_id())) .map(|p| p.map_bound(|p| p.term.ty().unwrap())); - Some(ExprFnSig::Trait(bound.map_bound(|b| b.substs.type_at(0)), output)) + Some(ExprFnSig::Trait(bound.map_bound(|b| b.substs.type_at(0)), output, None)) }, _ => None, } }, ty::Projection(proj) => match cx.tcx.try_normalize_erasing_regions(cx.param_env, ty) { Ok(normalized_ty) if normalized_ty != ty => ty_sig(cx, normalized_ty), - _ => sig_for_projection(cx, proj).or_else(|| sig_from_bounds(cx, ty)), + _ => sig_for_projection(cx, proj).or_else(|| sig_from_bounds(cx, ty, cx.param_env.caller_bounds(), None)), }, - ty::Param(_) => sig_from_bounds(cx, ty), + ty::Param(_) => sig_from_bounds(cx, ty, cx.param_env.caller_bounds(), None), _ => None, } } -fn sig_from_bounds<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option> { +fn sig_from_bounds<'tcx>( + cx: &LateContext<'tcx>, + ty: Ty<'tcx>, + predicates: &'tcx [Predicate<'tcx>], + predicates_id: Option, +) -> Option> { let mut inputs = None; let mut output = None; let lang_items = cx.tcx.lang_items(); - for (pred, _) in all_predicates_of(cx.tcx, cx.typeck_results().hir_owner.to_def_id()) { + for pred in predicates { match pred.kind().skip_binder() { PredicateKind::Trait(p) if (lang_items.fn_trait() == Some(p.def_id()) @@ -621,11 +630,12 @@ fn sig_from_bounds<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option { - if inputs.is_some() { + let i = pred.kind().rebind(p.trait_ref.substs.type_at(1)); + if inputs.map_or(false, |inputs| i != inputs) { // Multiple different fn trait impls. Is this even allowed? return None; } - inputs = Some(pred.kind().rebind(p.trait_ref.substs.type_at(1))); + inputs = Some(i); }, PredicateKind::Projection(p) if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output() @@ -641,7 +651,7 @@ fn sig_from_bounds<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option(cx: &LateContext<'tcx>, ty: ProjectionTy<'tcx>) -> Option> { @@ -661,14 +671,15 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: ProjectionTy<'tcx>) -> O || lang_items.fn_mut_trait() == Some(p.def_id()) || lang_items.fn_once_trait() == Some(p.def_id())) => { - if inputs.is_some() { + let i = pred + .map_bound(|pred| pred.kind().rebind(p.trait_ref.substs.type_at(1))) + .subst(cx.tcx, ty.substs); + + if inputs.map_or(false, |inputs| inputs != i) { // Multiple different fn trait impls. Is this even allowed? return None; } - inputs = Some( - pred.map_bound(|pred| pred.kind().rebind(p.trait_ref.substs.type_at(1))) - .subst(cx.tcx, ty.substs), - ); + inputs = Some(i); }, PredicateKind::Projection(p) if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output() => { if output.is_some() { @@ -684,7 +695,7 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: ProjectionTy<'tcx>) -> O } } - inputs.map(|ty| ExprFnSig::Trait(ty, output)) + inputs.map(|ty| ExprFnSig::Trait(ty, output, None)) } #[derive(Clone, Copy)] diff --git a/tests/ui/explicit_auto_deref.fixed b/tests/ui/explicit_auto_deref.fixed index d3efc29941454..464dd2dc0da6a 100644 --- a/tests/ui/explicit_auto_deref.fixed +++ b/tests/ui/explicit_auto_deref.fixed @@ -233,4 +233,13 @@ fn main() { _ => panic!(), }; let _: &X = &*if true { Y(X) } else { panic!() }; + + fn deref_to_u>(x: &T) -> &U { + x + } + + let _ = |x: &'static Box>| -> &'static dyn Iterator { &**x }; + fn ret_any(x: &Box) -> &dyn std::any::Any { + &**x + } } diff --git a/tests/ui/explicit_auto_deref.rs b/tests/ui/explicit_auto_deref.rs index e25ccbe78cef6..453b90f09b33c 100644 --- a/tests/ui/explicit_auto_deref.rs +++ b/tests/ui/explicit_auto_deref.rs @@ -233,4 +233,13 @@ fn main() { _ => panic!(), }; let _: &X = &*if true { Y(X) } else { panic!() }; + + fn deref_to_u>(x: &T) -> &U { + &**x + } + + let _ = |x: &'static Box>| -> &'static dyn Iterator { &**x }; + fn ret_any(x: &Box) -> &dyn std::any::Any { + &**x + } } diff --git a/tests/ui/explicit_auto_deref.stderr b/tests/ui/explicit_auto_deref.stderr index 0d7a9564a900e..f2933390fb95c 100644 --- a/tests/ui/explicit_auto_deref.stderr +++ b/tests/ui/explicit_auto_deref.stderr @@ -210,5 +210,11 @@ error: deref which would be done by auto-deref LL | let _ = || -> &'static str { return *s }; | ^^ help: try this: `s` -error: aborting due to 35 previous errors +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:238:9 + | +LL | &**x + | ^^^^ help: try this: `x` + +error: aborting due to 36 previous errors From d602ab1445a7c1982583df9297e21e137b450eb2 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 17 Jul 2022 11:12:25 -0400 Subject: [PATCH 05/62] Don't lint `exlipicit_auto_deref` when other adjustments are needed --- clippy_lints/src/dereference.rs | 6 +++++- tests/ui/explicit_auto_deref.fixed | 13 +++++++++++++ tests/ui/explicit_auto_deref.rs | 13 +++++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 40e62dbd58643..05dbc7434855c 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -357,7 +357,11 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { }), StateData { span: expr.span, hir_id: expr.hir_id, position }, )); - } else if position.is_deref_stable() { + } else if position.is_deref_stable() + // Auto-deref doesn't combine with other adjustments + && next_adjust.map_or(true, |a| matches!(a.kind, Adjust::Deref(_) | Adjust::Borrow(_))) + && iter.all(|a| matches!(a.kind, Adjust::Deref(_) | Adjust::Borrow(_))) + { self.state = Some(( State::Borrow { mutability }, StateData { diff --git a/tests/ui/explicit_auto_deref.fixed b/tests/ui/explicit_auto_deref.fixed index 464dd2dc0da6a..1e868af87cb80 100644 --- a/tests/ui/explicit_auto_deref.fixed +++ b/tests/ui/explicit_auto_deref.fixed @@ -242,4 +242,17 @@ fn main() { fn ret_any(x: &Box) -> &dyn std::any::Any { &**x } + + let x = String::new(); + let _: *const str = &*x; + + struct S7([u32; 1]); + impl core::ops::Deref for S7 { + type Target = [u32; 1]; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + let x = S7([0]); + let _: &[u32] = &*x; } diff --git a/tests/ui/explicit_auto_deref.rs b/tests/ui/explicit_auto_deref.rs index 453b90f09b33c..a2157d9b4f05a 100644 --- a/tests/ui/explicit_auto_deref.rs +++ b/tests/ui/explicit_auto_deref.rs @@ -242,4 +242,17 @@ fn main() { fn ret_any(x: &Box) -> &dyn std::any::Any { &**x } + + let x = String::new(); + let _: *const str = &*x; + + struct S7([u32; 1]); + impl core::ops::Deref for S7 { + type Target = [u32; 1]; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + let x = S7([0]); + let _: &[u32] = &*x; } From 6ee03e2b014fc98e1bbfdbf5c39872b8308cd15d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Thu, 21 Jul 2022 22:45:12 +0200 Subject: [PATCH 06/62] unwrap_used: Stop recommending using `expect` when the `expect_used` lint is not allowed --- clippy_lints/src/methods/unwrap_used.rs | 21 +++++++++------ tests/ui/unwrap_expect_used.rs | 10 +++++++ tests/ui/unwrap_expect_used.stderr | 36 +++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 8 deletions(-) create mode 100644 tests/ui/unwrap_expect_used.rs create mode 100644 tests/ui/unwrap_expect_used.stderr diff --git a/clippy_lints/src/methods/unwrap_used.rs b/clippy_lints/src/methods/unwrap_used.rs index 5c761014927c2..eae6ba693a292 100644 --- a/clippy_lints/src/methods/unwrap_used.rs +++ b/clippy_lints/src/methods/unwrap_used.rs @@ -1,11 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::is_in_test_function; use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{is_in_test_function, is_lint_allowed}; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::sym; -use super::UNWRAP_USED; +use super::{EXPECT_USED, UNWRAP_USED}; /// lint use of `unwrap()` for `Option`s and `Result`s pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, allow_unwrap_in_tests: bool) { @@ -24,17 +24,22 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr } if let Some((lint, kind, none_value)) = mess { + let help = if is_lint_allowed(cx, EXPECT_USED, expr.hir_id) { + format!( + "if you don't want to handle the `{none_value}` case gracefully, consider \ + using `expect()` to provide a better panic message" + ) + } else { + format!("if this value is an `{none_value}`, it will panic") + }; + span_lint_and_help( cx, lint, expr.span, - &format!("used `unwrap()` on `{}` value", kind,), + &format!("used `unwrap()` on `{kind}` value"), None, - &format!( - "if you don't want to handle the `{}` case gracefully, consider \ - using `expect()` to provide a better panic message", - none_value, - ), + &help, ); } } diff --git a/tests/ui/unwrap_expect_used.rs b/tests/ui/unwrap_expect_used.rs new file mode 100644 index 0000000000000..0d4a0504a6e04 --- /dev/null +++ b/tests/ui/unwrap_expect_used.rs @@ -0,0 +1,10 @@ +#![warn(clippy::unwrap_used, clippy::expect_used)] + +fn main() { + Some(3).unwrap(); + Some(3).expect("Hello world!"); + + let a: Result = Ok(3); + a.unwrap(); + a.expect("Hello world!"); +} diff --git a/tests/ui/unwrap_expect_used.stderr b/tests/ui/unwrap_expect_used.stderr new file mode 100644 index 0000000000000..a44aed4cb38de --- /dev/null +++ b/tests/ui/unwrap_expect_used.stderr @@ -0,0 +1,36 @@ +error: used `unwrap()` on `an Option` value + --> $DIR/unwrap_expect_used.rs:4:5 + | +LL | Some(3).unwrap(); + | ^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::unwrap-used` implied by `-D warnings` + = help: if this value is an `None`, it will panic + +error: used `expect()` on `an Option` value + --> $DIR/unwrap_expect_used.rs:5:5 + | +LL | Some(3).expect("Hello world!"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::expect-used` implied by `-D warnings` + = help: if this value is an `None`, it will panic + +error: used `unwrap()` on `a Result` value + --> $DIR/unwrap_expect_used.rs:8:5 + | +LL | a.unwrap(); + | ^^^^^^^^^^ + | + = help: if this value is an `Err`, it will panic + +error: used `expect()` on `a Result` value + --> $DIR/unwrap_expect_used.rs:9:5 + | +LL | a.expect("Hello world!"); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: if this value is an `Err`, it will panic + +error: aborting due to 4 previous errors + From 3e5203147176bf4e7895c917d694a14d33e13419 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Fri, 22 Jul 2022 19:14:31 +0200 Subject: [PATCH 07/62] unwrap_used: Fix help, "an `None`" -> "`None`" --- clippy_lints/src/methods/expect_used.rs | 10 +++++----- clippy_lints/src/methods/unwrap_used.rs | 8 ++++---- tests/ui-toml/expect_used/expect_used.stderr | 2 +- tests/ui/expect.stderr | 2 +- tests/ui/unwrap_expect_used.stderr | 4 ++-- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/clippy_lints/src/methods/expect_used.rs b/clippy_lints/src/methods/expect_used.rs index fbc3348f1855f..5ef08ca6290ba 100644 --- a/clippy_lints/src/methods/expect_used.rs +++ b/clippy_lints/src/methods/expect_used.rs @@ -12,9 +12,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs(); let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) { - Some((EXPECT_USED, "an Option", "None")) + Some((EXPECT_USED, "an Option", "None", "")) } else if is_type_diagnostic_item(cx, obj_ty, sym::Result) { - Some((EXPECT_USED, "a Result", "Err")) + Some((EXPECT_USED, "a Result", "Err", "an ")) } else { None }; @@ -23,14 +23,14 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr return; } - if let Some((lint, kind, none_value)) = mess { + if let Some((lint, kind, none_value, none_prefix)) = mess { span_lint_and_help( cx, lint, expr.span, - &format!("used `expect()` on `{}` value", kind,), + &format!("used `expect()` on `{kind}` value"), None, - &format!("if this value is an `{}`, it will panic", none_value,), + &format!("if this value is {none_prefix}`{none_value}`, it will panic"), ); } } diff --git a/clippy_lints/src/methods/unwrap_used.rs b/clippy_lints/src/methods/unwrap_used.rs index eae6ba693a292..ce1a52e5480af 100644 --- a/clippy_lints/src/methods/unwrap_used.rs +++ b/clippy_lints/src/methods/unwrap_used.rs @@ -12,9 +12,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs(); let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) { - Some((UNWRAP_USED, "an Option", "None")) + Some((UNWRAP_USED, "an Option", "None", "")) } else if is_type_diagnostic_item(cx, obj_ty, sym::Result) { - Some((UNWRAP_USED, "a Result", "Err")) + Some((UNWRAP_USED, "a Result", "Err", "an ")) } else { None }; @@ -23,14 +23,14 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr return; } - if let Some((lint, kind, none_value)) = mess { + if let Some((lint, kind, none_value, none_prefix)) = mess { let help = if is_lint_allowed(cx, EXPECT_USED, expr.hir_id) { format!( "if you don't want to handle the `{none_value}` case gracefully, consider \ using `expect()` to provide a better panic message" ) } else { - format!("if this value is an `{none_value}`, it will panic") + format!("if this value is {none_prefix}`{none_value}`, it will panic") }; span_lint_and_help( diff --git a/tests/ui-toml/expect_used/expect_used.stderr b/tests/ui-toml/expect_used/expect_used.stderr index 9cb2199ed21cb..c5d95cb8a147f 100644 --- a/tests/ui-toml/expect_used/expect_used.stderr +++ b/tests/ui-toml/expect_used/expect_used.stderr @@ -5,7 +5,7 @@ LL | let _ = opt.expect(""); | ^^^^^^^^^^^^^^ | = note: `-D clippy::expect-used` implied by `-D warnings` - = help: if this value is an `None`, it will panic + = help: if this value is `None`, it will panic error: used `expect()` on `a Result` value --> $DIR/expect_used.rs:11:13 diff --git a/tests/ui/expect.stderr b/tests/ui/expect.stderr index 9d3fc7df15cc7..ab28aac45563b 100644 --- a/tests/ui/expect.stderr +++ b/tests/ui/expect.stderr @@ -5,7 +5,7 @@ LL | let _ = opt.expect(""); | ^^^^^^^^^^^^^^ | = note: `-D clippy::expect-used` implied by `-D warnings` - = help: if this value is an `None`, it will panic + = help: if this value is `None`, it will panic error: used `expect()` on `a Result` value --> $DIR/expect.rs:10:13 diff --git a/tests/ui/unwrap_expect_used.stderr b/tests/ui/unwrap_expect_used.stderr index a44aed4cb38de..f54bfd617c4ee 100644 --- a/tests/ui/unwrap_expect_used.stderr +++ b/tests/ui/unwrap_expect_used.stderr @@ -5,7 +5,7 @@ LL | Some(3).unwrap(); | ^^^^^^^^^^^^^^^^ | = note: `-D clippy::unwrap-used` implied by `-D warnings` - = help: if this value is an `None`, it will panic + = help: if this value is `None`, it will panic error: used `expect()` on `an Option` value --> $DIR/unwrap_expect_used.rs:5:5 @@ -14,7 +14,7 @@ LL | Some(3).expect("Hello world!"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::expect-used` implied by `-D warnings` - = help: if this value is an `None`, it will panic + = help: if this value is `None`, it will panic error: used `unwrap()` on `a Result` value --> $DIR/unwrap_expect_used.rs:8:5 From af8ae10678612959a5d6036e0b99aca688b3e545 Mon Sep 17 00:00:00 2001 From: Preston From Date: Sat, 16 Jul 2022 15:13:14 -0600 Subject: [PATCH 08/62] Generate correct suggestion with named arguments used positionally Address issue #99265 by checking each positionally used argument to see if the argument is named and adding a lint to use the name instead. This way, when named arguments are used positionally in a different order than their argument order, the suggested lint is correct. For example: ``` println!("{b} {}", a=1, b=2); ``` This will now generate the suggestion: ``` println!("{b} {a}", a=1, b=2); ``` Additionally, this check now also correctly replaces or inserts only where the positional argument is (or would be if implicit). Also, width and precision are replaced with their argument names when they exists. Since the issues were so closely related, this fix for issue #99265 also fixes issue #99266. Fixes #99265 Fixes #99266 --- clippy_lints/src/write.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index 08b8894752011..3a99d1b417fee 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -441,7 +441,7 @@ impl SimpleFormatArgs { }; match arg.position { - ArgumentIs(n) | ArgumentImplicitlyIs(n) => { + ArgumentIs(n, _) | ArgumentImplicitlyIs(n) => { if self.unnamed.len() <= n { // Use a dummy span to mark all unseen arguments. self.unnamed.resize_with(n, || vec![DUMMY_SP]); From 08e7ec40478203a7c1e0959461515ecdaf5754a7 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Wed, 27 Jul 2022 17:18:20 +0100 Subject: [PATCH 09/62] Read and use deprecated configuration (as well as emitting a warning) Co-authored-by: Andy Caldwell --- clippy_lints/src/lib.rs | 11 +++++++++- clippy_lints/src/utils/conf.rs | 20 +++++++++++++------ tests/ui-toml/conf_deprecated_key/clippy.toml | 2 +- .../conf_deprecated_key.rs | 10 ++++++++++ .../conf_deprecated_key.stderr | 13 ++++++++++-- 5 files changed, 46 insertions(+), 10 deletions(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 5a311163239b2..5bec503402c3c 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -487,7 +487,7 @@ pub fn read_conf(sess: &Session) -> Conf { }, }; - let TryConf { conf, errors } = utils::conf::read(&file_name); + let TryConf { conf, errors, warnings } = utils::conf::read(&file_name); // all conf errors are non-fatal, we just use the default conf in case of error for error in errors { sess.err(&format!( @@ -497,6 +497,15 @@ pub fn read_conf(sess: &Session) -> Conf { )); } + for warning in warnings { + sess.struct_warn(&format!( + "error reading Clippy's configuration file `{}`: {}", + file_name.display(), + format_error(warning) + )) + .emit(); + } + conf } diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 6e033b3be2d87..60f4b388761dd 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -68,6 +68,7 @@ pub enum DisallowedType { pub struct TryConf { pub conf: Conf, pub errors: Vec>, + pub warnings: Vec>, } impl TryConf { @@ -75,6 +76,7 @@ impl TryConf { Self { conf: Conf::default(), errors: vec![Box::new(error)], + warnings: vec![], } } } @@ -97,7 +99,7 @@ fn conf_error(s: String) -> Box { macro_rules! define_Conf { ($( $(#[doc = $doc:literal])+ - $(#[conf_deprecated($dep:literal)])? + $(#[conf_deprecated($dep:literal, $new_conf:ident)])? ($name:ident: $ty:ty = $default:expr), )*) => { /// Clippy lint configuration @@ -137,17 +139,23 @@ macro_rules! define_Conf { fn visit_map(self, mut map: V) -> Result where V: MapAccess<'de> { let mut errors = Vec::new(); + let mut warnings = Vec::new(); $(let mut $name = None;)* // could get `Field` here directly, but get `str` first for diagnostics while let Some(name) = map.next_key::<&str>()? { match Field::deserialize(name.into_deserializer())? { $(Field::$name => { - $(errors.push(conf_error(format!("deprecated field `{}`. {}", name, $dep)));)? + $(warnings.push(conf_error(format!("deprecated field `{}`. {}", name, $dep)));)? match map.next_value() { Err(e) => errors.push(conf_error(e.to_string())), Ok(value) => match $name { Some(_) => errors.push(conf_error(format!("duplicate field `{}`", name))), - None => $name = Some(value), + None => { + $name = Some(value); + // $new_conf is the same as one of the defined `$name`s, so + // this variable is defined in line 2 of this function. + $($new_conf = Some(value);)? + }, } } })* @@ -156,7 +164,7 @@ macro_rules! define_Conf { } } let conf = Conf { $($name: $name.unwrap_or_else(defaults::$name),)* }; - Ok(TryConf { conf, errors }) + Ok(TryConf { conf, errors, warnings }) } } @@ -216,8 +224,8 @@ define_Conf! { /// DEPRECATED LINT: CYCLOMATIC_COMPLEXITY. /// /// Use the Cognitive Complexity lint instead. - #[conf_deprecated("Please use `cognitive-complexity-threshold` instead")] - (cyclomatic_complexity_threshold: Option = None), + #[conf_deprecated("Please use `cognitive-complexity-threshold` instead", cognitive_complexity_threshold)] + (cyclomatic_complexity_threshold: u64 = 25), /// Lint: DOC_MARKDOWN. /// /// The list of words this lint should not consider as identifiers needing ticks. The value diff --git a/tests/ui-toml/conf_deprecated_key/clippy.toml b/tests/ui-toml/conf_deprecated_key/clippy.toml index ac47b195042eb..138160d7ac8bf 100644 --- a/tests/ui-toml/conf_deprecated_key/clippy.toml +++ b/tests/ui-toml/conf_deprecated_key/clippy.toml @@ -1,5 +1,5 @@ # that one is an error -cyclomatic-complexity-threshold = 42 +cyclomatic-complexity-threshold = 2 # that one is white-listed [third-party] diff --git a/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.rs b/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.rs index f328e4d9d04c3..b4e677ea124b7 100644 --- a/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.rs +++ b/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.rs @@ -1 +1,11 @@ fn main() {} + +#[warn(clippy::cognitive_complexity)] +fn cognitive_complexity() { + let x = vec![1, 2, 3]; + for i in x { + if i == 1 { + println!("{}", i); + } + } +} diff --git a/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr b/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr index 90021a034a3d3..3b4c72044da82 100644 --- a/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr +++ b/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr @@ -1,4 +1,13 @@ -error: error reading Clippy's configuration file `$DIR/clippy.toml`: deprecated field `cyclomatic-complexity-threshold`. Please use `cognitive-complexity-threshold` instead +warning: error reading Clippy's configuration file `$DIR/clippy.toml`: deprecated field `cyclomatic-complexity-threshold`. Please use `cognitive-complexity-threshold` instead -error: aborting due to previous error +error: the function has a cognitive complexity of (3/2) + --> $DIR/conf_deprecated_key.rs:4:4 + | +LL | fn cognitive_complexity() { + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::cognitive-complexity` implied by `-D warnings` + = help: you could split it up into multiple smaller functions + +error: aborting due to previous error; 1 warning emitted From 38e80132d5179525c82f4c75648303cba57215af Mon Sep 17 00:00:00 2001 From: alex-semenyuk Date: Thu, 28 Jul 2022 10:57:01 +0300 Subject: [PATCH 10/62] Enable test empty_loop_no_std on windows --- tests/ui/empty_loop_no_std.rs | 1 - tests/ui/empty_loop_no_std.stderr | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/ui/empty_loop_no_std.rs b/tests/ui/empty_loop_no_std.rs index 235e0fc51799f..e742b396fcde0 100644 --- a/tests/ui/empty_loop_no_std.rs +++ b/tests/ui/empty_loop_no_std.rs @@ -1,6 +1,5 @@ // compile-flags: -Clink-arg=-nostartfiles // ignore-macos -// ignore-windows #![warn(clippy::empty_loop)] #![feature(lang_items, start, libc)] diff --git a/tests/ui/empty_loop_no_std.stderr b/tests/ui/empty_loop_no_std.stderr index 520248fcb689c..5ded35a6f0d8d 100644 --- a/tests/ui/empty_loop_no_std.stderr +++ b/tests/ui/empty_loop_no_std.stderr @@ -1,5 +1,5 @@ error: empty `loop {}` wastes CPU cycles - --> $DIR/empty_loop_no_std.rs:14:5 + --> $DIR/empty_loop_no_std.rs:13:5 | LL | loop {} | ^^^^^^^ @@ -8,7 +8,7 @@ LL | loop {} = help: you should either use `panic!()` or add a call pausing or sleeping the thread to the loop body error: empty `loop {}` wastes CPU cycles - --> $DIR/empty_loop_no_std.rs:26:5 + --> $DIR/empty_loop_no_std.rs:25:5 | LL | loop {} | ^^^^^^^ From 67c405cc1d6cc898cf26586dfe68390cc05a8e40 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 28 Jul 2022 19:08:22 +0200 Subject: [PATCH 11/62] Merge commit '3c7e7dbc1583a0b06df5bd7623dd354a4debd23d' into clippyup --- CHANGELOG.md | 3 + Cargo.toml | 1 + .../continuous_integration/github_actions.md | 6 +- book/src/development/adding_lints.md | 45 ++- book/src/development/infrastructure/book.md | 2 +- clippy_dev/src/fmt.rs | 8 +- clippy_dev/src/main.rs | 11 +- clippy_dev/src/new_lint.rs | 321 ++++++++++++++++-- clippy_dev/src/update_lints.rs | 10 +- clippy_lints/src/as_conversions.rs | 2 +- .../src/assertions_on_result_states.rs | 98 ++++++ clippy_lints/src/cargo/mod.rs | 10 +- ...se_sensitive_file_extension_comparisons.rs | 5 +- clippy_lints/src/dereference.rs | 3 +- clippy_lints/src/format.rs | 19 +- clippy_lints/src/format_impl.rs | 2 +- clippy_lints/src/lib.register_all.rs | 2 + clippy_lints/src/lib.register_lints.rs | 3 + clippy_lints/src/lib.register_restriction.rs | 1 + clippy_lints/src/lib.register_style.rs | 2 + clippy_lints/src/lib.rs | 8 +- clippy_lints/src/lifetimes.rs | 2 - clippy_lints/src/matches/mod.rs | 30 +- .../src/methods/inefficient_to_string.rs | 2 +- clippy_lints/src/methods/mod.rs | 34 ++ .../src/methods/obfuscated_if_else.rs | 42 +++ .../src/mismatching_type_param_order.rs | 24 +- clippy_lints/src/non_copy_const.rs | 18 +- clippy_lints/src/operators/arithmetic.rs | 119 +++++++ .../src/operators/assign_op_pattern.rs | 80 +++++ clippy_lints/src/operators/mod.rs | 47 ++- clippy_lints/src/question_mark.rs | 4 +- clippy_lints/src/std_instead_of_core.rs | 96 +++--- clippy_lints/src/strings.rs | 4 +- clippy_lints/src/unused_self.rs | 17 +- clippy_lints/src/utils/conf.rs | 6 +- clippy_utils/src/consts.rs | 20 +- clippy_utils/src/hir_utils.rs | 33 +- clippy_utils/src/lib.rs | 3 +- rust-toolchain | 2 +- tests/compile-test.rs | 41 ++- .../cargo_common_metadata/fail/Cargo.toml | 2 +- .../fail/src/main.stderr | 12 +- .../fail_publish/Cargo.toml | 2 +- .../fail_publish/src/main.stderr | 12 +- .../fail_publish_true/Cargo.toml | 2 +- .../fail_publish_true/src/main.stderr | 12 +- .../cargo_common_metadata/pass/Cargo.toml | 2 +- .../pass_publish_empty/Cargo.toml | 2 +- .../pass_publish_false/Cargo.toml | 2 +- .../fail_both_diff/Cargo.toml | 1 + .../fail_both_same/Cargo.toml | 1 + .../cargo_rust_version/fail_cargo/Cargo.toml | 1 + .../cargo_rust_version/fail_clippy/Cargo.toml | 1 + .../fail_file_attr/Cargo.toml | 1 + .../pass_both_same/Cargo.toml | 3 +- .../cargo_rust_version/pass_cargo/Cargo.toml | 3 +- .../cargo_rust_version/pass_clippy/Cargo.toml | 3 +- .../pass_file_attr/Cargo.toml | 3 +- .../warn_both_diff/Cargo.toml | 1 + .../ui-cargo/module_style/fail_mod/Cargo.toml | 3 +- .../module_style/fail_no_mod/Cargo.toml | 3 +- .../ui-cargo/module_style/pass_mod/Cargo.toml | 3 +- .../module_style/pass_no_mod/Cargo.toml | 3 +- .../multiple_config_files/no_warn/Cargo.toml | 1 + .../multiple_config_files/warn/Cargo.toml | 1 + .../multiple_config_files/warn/src/main.rs | 2 - .../multiple_crate_versions/pass/Cargo.toml | 2 +- .../check_clippy_version_attribute.stderr | 8 +- tests/ui-internal/default_lint.stderr | 2 +- tests/ui-internal/if_chain_style.stderr | 2 +- .../arithmetic_allowed/arithmetic_allowed.rs | 24 ++ tests/ui-toml/arithmetic_allowed/clippy.toml | 1 + .../toml_unknown_key/conf_unknown_key.stderr | 1 + tests/ui/arithmetic.fixed | 27 ++ tests/ui/arithmetic.rs | 27 ++ tests/ui/assertions_on_result_states.fixed | 69 ++++ tests/ui/assertions_on_result_states.rs | 69 ++++ tests/ui/assertions_on_result_states.stderr | 40 +++ tests/ui/assign_ops.fixed | 11 + tests/ui/assign_ops.rs | 11 + tests/ui/assign_ops.stderr | 32 +- tests/ui/crashes/ice-9238.rs | 12 + tests/ui/crashes/ice-9242.rs | 8 + .../entrypoint_recursion.rs | 1 - .../entrypoint_recursion.stderr | 2 +- .../declare_interior_mutable_const/others.rs | 22 +- .../others.stderr | 13 +- tests/ui/format.fixed | 6 + tests/ui/format.rs | 6 + tests/ui/format.stderr | 14 +- tests/ui/match_same_arms2.rs | 10 +- tests/ui/mismatching_type_param_order.rs | 4 + tests/ui/needless_borrow.fixed | 25 ++ tests/ui/needless_borrow.rs | 25 ++ tests/ui/needless_borrow.stderr | 14 +- tests/ui/obfuscated_if_else.fixed | 7 + tests/ui/obfuscated_if_else.rs | 7 + tests/ui/obfuscated_if_else.stderr | 10 + tests/ui/std_instead_of_core.rs | 6 + tests/ui/std_instead_of_core.stderr | 28 +- tests/ui/unused_self.rs | 9 + 102 files changed, 1526 insertions(+), 297 deletions(-) create mode 100644 clippy_lints/src/assertions_on_result_states.rs create mode 100644 clippy_lints/src/methods/obfuscated_if_else.rs create mode 100644 clippy_lints/src/operators/arithmetic.rs create mode 100644 tests/ui-toml/arithmetic_allowed/arithmetic_allowed.rs create mode 100644 tests/ui-toml/arithmetic_allowed/clippy.toml create mode 100644 tests/ui/arithmetic.fixed create mode 100644 tests/ui/arithmetic.rs create mode 100644 tests/ui/assertions_on_result_states.fixed create mode 100644 tests/ui/assertions_on_result_states.rs create mode 100644 tests/ui/assertions_on_result_states.stderr create mode 100644 tests/ui/crashes/ice-9238.rs create mode 100644 tests/ui/crashes/ice-9242.rs create mode 100644 tests/ui/obfuscated_if_else.fixed create mode 100644 tests/ui/obfuscated_if_else.rs create mode 100644 tests/ui/obfuscated_if_else.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 920d397add716..2278a8dc16ba0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3437,9 +3437,11 @@ Released 2018-09-13 [`almost_complete_letter_range`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_complete_letter_range [`almost_swapped`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_swapped [`approx_constant`]: https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant +[`arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic [`as_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_conversions [`as_underscore`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_underscore [`assertions_on_constants`]: https://rust-lang.github.io/rust-clippy/master/index.html#assertions_on_constants +[`assertions_on_result_states`]: https://rust-lang.github.io/rust-clippy/master/index.html#assertions_on_result_states [`assign_op_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#assign_op_pattern [`assign_ops`]: https://rust-lang.github.io/rust-clippy/master/index.html#assign_ops [`async_yields_async`]: https://rust-lang.github.io/rust-clippy/master/index.html#async_yields_async @@ -3793,6 +3795,7 @@ Released 2018-09-13 [`nonsensical_open_options`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonsensical_open_options [`nonstandard_macro_braces`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonstandard_macro_braces [`not_unsafe_ptr_arg_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#not_unsafe_ptr_arg_deref +[`obfuscated_if_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#obfuscated_if_else [`octal_escapes`]: https://rust-lang.github.io/rust-clippy/master/index.html#octal_escapes [`ok_expect`]: https://rust-lang.github.io/rust-clippy/master/index.html#ok_expect [`only_used_in_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#only_used_in_recursion diff --git a/Cargo.toml b/Cargo.toml index 644ca6318f625..1c875c3adcf55 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,6 +32,7 @@ compiletest_rs = { version = "0.8", features = ["tmp"] } tester = "0.9" regex = "1.5" toml = "0.5" +walkdir = "2.3" # This is used by the `collect-metadata` alias. filetime = "0.2" diff --git a/book/src/continuous_integration/github_actions.md b/book/src/continuous_integration/github_actions.md index 42a43ef138016..339287a7dd95f 100644 --- a/book/src/continuous_integration/github_actions.md +++ b/book/src/continuous_integration/github_actions.md @@ -1,7 +1,7 @@ # GitHub Actions -On the GitHub hosted runners, Clippy from the latest stable Rust version comes -pre-installed. So all you have to do is to run `cargo clippy`. +GitHub hosted runners using the latest stable version of Rust have Clippy pre-installed. +It is as simple as running `cargo clippy` to run lints against the codebase. ```yml on: push @@ -15,7 +15,7 @@ jobs: clippy_check: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v3 - name: Run Clippy run: cargo clippy --all-targets --all-features ``` diff --git a/book/src/development/adding_lints.md b/book/src/development/adding_lints.md index d06297f2e079a..da781eb970df7 100644 --- a/book/src/development/adding_lints.md +++ b/book/src/development/adding_lints.md @@ -10,6 +10,10 @@ because that's clearly a non-descriptive name. - [Adding a new lint](#adding-a-new-lint) - [Setup](#setup) - [Getting Started](#getting-started) + - [Defining Our Lint](#defining-our-lint) + - [Standalone](#standalone) + - [Specific Type](#specific-type) + - [Tests Location](#tests-location) - [Testing](#testing) - [Cargo lints](#cargo-lints) - [Rustfix tests](#rustfix-tests) @@ -36,17 +40,38 @@ See the [Basics](basics.md#get-the-code) documentation. ## Getting Started There is a bit of boilerplate code that needs to be set up when creating a new -lint. Fortunately, you can use the clippy dev tools to handle this for you. We +lint. Fortunately, you can use the Clippy dev tools to handle this for you. We are naming our new lint `foo_functions` (lints are generally written in snake -case), and we don't need type information so it will have an early pass type -(more on this later on). If you're not sure if the name you chose fits the lint, -take a look at our [lint naming guidelines][lint_naming]. To get started on this -lint you can run `cargo dev new_lint --name=foo_functions --pass=early ---category=pedantic` (category will default to nursery if not provided). This -command will create two files: `tests/ui/foo_functions.rs` and -`clippy_lints/src/foo_functions.rs`, as well as [registering the -lint](#lint-registration). For cargo lints, two project hierarchies (fail/pass) -will be created by default under `tests/ui-cargo`. +case), and we don't need type information, so it will have an early pass type +(more on this later). If you're unsure if the name you chose fits the lint, +take a look at our [lint naming guidelines][lint_naming]. + +## Defining Our Lint +To get started, there are two ways to define our lint. + +### Standalone +Command: `cargo dev new_lint --name=foo_functions --pass=early --category=pedantic` +(category will default to nursery if not provided) + +This command will create a new file: `clippy_lints/src/foo_functions.rs`, as well +as [register the lint](#lint-registration). + +### Specific Type +Command: `cargo dev new_lint --name=foo_functions --type=functions --category=pedantic` + +This command will create a new file: `clippy_lints/src/{type}/foo_functions.rs`. + +Notice how this command has a `--type` flag instead of `--pass`. Unlike a standalone +definition, this lint won't be registered in the traditional sense. Instead, you will +call your lint from within the type's lint pass, found in `clippy_lints/src/{type}/mod.rs`. + +A "type" is just the name of a directory in `clippy_lints/src`, like `functions` in +the example command. These are groupings of lints with common behaviors, so if your +lint falls into one, it would be best to add it to that type. + +### Tests Location +Both commands will create a file: `tests/ui/foo_functions.rs`. For cargo lints, +two project hierarchies (fail/pass) will be created by default under `tests/ui-cargo`. Next, we'll open up these files and add our lint! diff --git a/book/src/development/infrastructure/book.md b/book/src/development/infrastructure/book.md index b62314c6735a2..a48742191850b 100644 --- a/book/src/development/infrastructure/book.md +++ b/book/src/development/infrastructure/book.md @@ -25,7 +25,7 @@ instructions for other options. ## Make changes The book's -[src](https://github.com/joshrotenberg/rust-clippy/tree/clippy_guide/book/src) +[src](https://github.com/rust-lang/rust-clippy/tree/master/book/src) directory contains all of the markdown files used to generate the book. If you want to see your changes in real time, you can use the mdbook `serve` command to run a web server locally that will automatically update changes as they are diff --git a/clippy_dev/src/fmt.rs b/clippy_dev/src/fmt.rs index d513a229b7e38..3b27f061eb0b4 100644 --- a/clippy_dev/src/fmt.rs +++ b/clippy_dev/src/fmt.rs @@ -13,7 +13,7 @@ pub enum CliError { IoError(io::Error), RustfmtNotInstalled, WalkDirError(walkdir::Error), - RaSetupActive, + IntellijSetupActive, } impl From for CliError { @@ -48,7 +48,7 @@ pub fn run(check: bool, verbose: bool) { .expect("Failed to read clippy Cargo.toml") .contains(&"[target.'cfg(NOT_A_PLATFORM)'.dependencies]") { - return Err(CliError::RaSetupActive); + return Err(CliError::IntellijSetupActive); } rustfmt_test(context)?; @@ -93,11 +93,11 @@ pub fn run(check: bool, verbose: bool) { CliError::WalkDirError(err) => { eprintln!("error: {}", err); }, - CliError::RaSetupActive => { + CliError::IntellijSetupActive => { eprintln!( "error: a local rustc repo is enabled as path dependency via `cargo dev setup intellij`. Not formatting because that would format the local repo as well! -Please revert the changes to Cargo.tomls first." +Please revert the changes to Cargo.tomls with `cargo dev remove intellij`." ); }, } diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index a29ba2d0c85e3..a417d3dd8a4e7 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -36,7 +36,8 @@ fn main() { match new_lint::create( matches.get_one::("pass"), matches.get_one::("name"), - matches.get_one::("category"), + matches.get_one::("category").map(String::as_str), + matches.get_one::("type").map(String::as_str), matches.contains_id("msrv"), ) { Ok(_) => update_lints::update(update_lints::UpdateMode::Change), @@ -157,7 +158,8 @@ fn get_clap_config() -> ArgMatches { .help("Specify whether the lint runs during the early or late pass") .takes_value(true) .value_parser([PossibleValue::new("early"), PossibleValue::new("late")]) - .required(true), + .conflicts_with("type") + .required_unless_present("type"), Arg::new("name") .short('n') .long("name") @@ -183,6 +185,11 @@ fn get_clap_config() -> ArgMatches { PossibleValue::new("internal_warn"), ]) .takes_value(true), + Arg::new("type") + .long("type") + .help("What directory the lint belongs in") + .takes_value(true) + .required(false), Arg::new("msrv").long("msrv").help("Add MSRV config code to the lint"), ]), Command::new("setup") diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index 7d7e760ef446c..03d2ef3d19edd 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -1,5 +1,5 @@ use crate::clippy_project_root; -use indoc::indoc; +use indoc::{indoc, writedoc}; use std::fmt::Write as _; use std::fs::{self, OpenOptions}; use std::io::prelude::*; @@ -10,6 +10,7 @@ struct LintData<'a> { pass: &'a str, name: &'a str, category: &'a str, + ty: Option<&'a str>, project_root: PathBuf, } @@ -37,26 +38,44 @@ impl Context for io::Result { pub fn create( pass: Option<&String>, lint_name: Option<&String>, - category: Option<&String>, + category: Option<&str>, + mut ty: Option<&str>, msrv: bool, ) -> io::Result<()> { + if category == Some("cargo") && ty.is_none() { + // `cargo` is a special category, these lints should always be in `clippy_lints/src/cargo` + ty = Some("cargo"); + } + let lint = LintData { - pass: pass.expect("`pass` argument is validated by clap"), + pass: pass.map_or("", String::as_str), name: lint_name.expect("`name` argument is validated by clap"), category: category.expect("`category` argument is validated by clap"), + ty, project_root: clippy_project_root(), }; create_lint(&lint, msrv).context("Unable to create lint implementation")?; create_test(&lint).context("Unable to create a test for the new lint")?; - add_lint(&lint, msrv).context("Unable to add lint to clippy_lints/src/lib.rs") + + if lint.ty.is_none() { + add_lint(&lint, msrv).context("Unable to add lint to clippy_lints/src/lib.rs")?; + } + + Ok(()) } fn create_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> { - let lint_contents = get_lint_file_contents(lint, enable_msrv); + if let Some(ty) = lint.ty { + create_lint_for_ty(lint, enable_msrv, ty) + } else { + let lint_contents = get_lint_file_contents(lint, enable_msrv); + let lint_path = format!("clippy_lints/src/{}.rs", lint.name); + write_file(lint.project_root.join(&lint_path), lint_contents.as_bytes())?; + println!("Generated lint file: `{}`", lint_path); - let lint_path = format!("clippy_lints/src/{}.rs", lint.name); - write_file(lint.project_root.join(&lint_path), lint_contents.as_bytes()) + Ok(()) + } } fn create_test(lint: &LintData<'_>) -> io::Result<()> { @@ -75,16 +94,22 @@ fn create_test(lint: &LintData<'_>) -> io::Result<()> { if lint.category == "cargo" { let relative_test_dir = format!("tests/ui-cargo/{}", lint.name); - let test_dir = lint.project_root.join(relative_test_dir); + let test_dir = lint.project_root.join(&relative_test_dir); fs::create_dir(&test_dir)?; create_project_layout(lint.name, &test_dir, "fail", "Content that triggers the lint goes here")?; - create_project_layout(lint.name, &test_dir, "pass", "This file should not trigger the lint") + create_project_layout(lint.name, &test_dir, "pass", "This file should not trigger the lint")?; + + println!("Generated test directories: `{relative_test_dir}/pass`, `{relative_test_dir}/fail`"); } else { let test_path = format!("tests/ui/{}.rs", lint.name); let test_contents = get_test_file_contents(lint.name, None); - write_file(lint.project_root.join(test_path), test_contents) + write_file(lint.project_root.join(&test_path), test_contents)?; + + println!("Generated test file: `{}`", test_path); } + + Ok(()) } fn add_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> { @@ -204,7 +229,6 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { }, }; - let version = get_stabilization_version(); let lint_name = lint.name; let category = lint.category; let name_camel = to_camel_case(lint.name); @@ -238,32 +262,7 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { ) }); - let _ = write!( - result, - indoc! {r#" - declare_clippy_lint! {{ - /// ### What it does - /// - /// ### Why is this bad? - /// - /// ### Example - /// ```rust - /// // example code where clippy issues a warning - /// ``` - /// Use instead: - /// ```rust - /// // example code which does not raise clippy warning - /// ``` - #[clippy::version = "{version}"] - pub {name_upper}, - {category}, - "default lint description" - }} - "#}, - version = version, - name_upper = name_upper, - category = category, - ); + let _ = write!(result, "{}", get_lint_declaration(&name_upper, category)); result.push_str(&if enable_msrv { format!( @@ -312,6 +311,254 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { result } +fn get_lint_declaration(name_upper: &str, category: &str) -> String { + format!( + indoc! {r#" + declare_clippy_lint! {{ + /// ### What it does + /// + /// ### Why is this bad? + /// + /// ### Example + /// ```rust + /// // example code where clippy issues a warning + /// ``` + /// Use instead: + /// ```rust + /// // example code which does not raise clippy warning + /// ``` + #[clippy::version = "{version}"] + pub {name_upper}, + {category}, + "default lint description" + }} + "#}, + version = get_stabilization_version(), + name_upper = name_upper, + category = category, + ) +} + +fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::Result<()> { + match ty { + "cargo" => assert_eq!( + lint.category, "cargo", + "Lints of type `cargo` must have the `cargo` category" + ), + _ if lint.category == "cargo" => panic!("Lints of category `cargo` must have the `cargo` type"), + _ => {}, + } + + let ty_dir = lint.project_root.join(format!("clippy_lints/src/{}", ty)); + assert!( + ty_dir.exists() && ty_dir.is_dir(), + "Directory `{}` does not exist!", + ty_dir.display() + ); + + let lint_file_path = ty_dir.join(format!("{}.rs", lint.name)); + assert!( + !lint_file_path.exists(), + "File `{}` already exists", + lint_file_path.display() + ); + + let mod_file_path = ty_dir.join("mod.rs"); + let context_import = setup_mod_file(&mod_file_path, lint)?; + + let name_upper = lint.name.to_uppercase(); + let mut lint_file_contents = String::new(); + + if enable_msrv { + let _ = writedoc!( + lint_file_contents, + r#" + use clippy_utils::{{meets_msrv, msrvs}}; + use rustc_lint::{{{context_import}, LintContext}}; + use rustc_semver::RustcVersion; + + use super::{name_upper}; + + // TODO: Adjust the parameters as necessary + pub(super) fn check(cx: &{context_import}, msrv: Option) {{ + if !meets_msrv(msrv, todo!("Add a new entry in `clippy_utils/src/msrvs`")) {{ + return; + }} + todo!(); + }} + "#, + context_import = context_import, + name_upper = name_upper, + ); + } else { + let _ = writedoc!( + lint_file_contents, + r#" + use rustc_lint::{{{context_import}, LintContext}}; + + use super::{name_upper}; + + // TODO: Adjust the parameters as necessary + pub(super) fn check(cx: &{context_import}) {{ + todo!(); + }} + "#, + context_import = context_import, + name_upper = name_upper, + ); + } + + write_file(lint_file_path.as_path(), lint_file_contents)?; + println!("Generated lint file: `clippy_lints/src/{}/{}.rs`", ty, lint.name); + println!( + "Be sure to add a call to `{}::check` in `clippy_lints/src/{}/mod.rs`!", + lint.name, ty + ); + + Ok(()) +} + +#[allow(clippy::too_many_lines)] +fn setup_mod_file(path: &Path, lint: &LintData<'_>) -> io::Result<&'static str> { + use super::update_lints::{match_tokens, LintDeclSearchResult}; + use rustc_lexer::TokenKind; + + let lint_name_upper = lint.name.to_uppercase(); + + let mut file_contents = fs::read_to_string(path)?; + assert!( + !file_contents.contains(&lint_name_upper), + "Lint `{}` already defined in `{}`", + lint.name, + path.display() + ); + + let mut offset = 0usize; + let mut last_decl_curly_offset = None; + let mut lint_context = None; + + let mut iter = rustc_lexer::tokenize(&file_contents).map(|t| { + let range = offset..offset + t.len; + offset = range.end; + + LintDeclSearchResult { + token_kind: t.kind, + content: &file_contents[range.clone()], + range, + } + }); + + // Find both the last lint declaration (declare_clippy_lint!) and the lint pass impl + while let Some(LintDeclSearchResult { content, .. }) = iter.find(|result| result.token_kind == TokenKind::Ident) { + let mut iter = iter + .by_ref() + .filter(|t| !matches!(t.token_kind, TokenKind::Whitespace | TokenKind::LineComment { .. })); + + match content { + "declare_clippy_lint" => { + // matches `!{` + match_tokens!(iter, Bang OpenBrace); + if let Some(LintDeclSearchResult { range, .. }) = + iter.find(|result| result.token_kind == TokenKind::CloseBrace) + { + last_decl_curly_offset = Some(range.end); + } + }, + "impl" => { + let mut token = iter.next(); + match token { + // matches <'foo> + Some(LintDeclSearchResult { + token_kind: TokenKind::Lt, + .. + }) => { + match_tokens!(iter, Lifetime { .. } Gt); + token = iter.next(); + }, + None => break, + _ => {}, + } + + if let Some(LintDeclSearchResult { + token_kind: TokenKind::Ident, + content, + .. + }) = token + { + // Get the appropriate lint context struct + lint_context = match content { + "LateLintPass" => Some("LateContext"), + "EarlyLintPass" => Some("EarlyContext"), + _ => continue, + }; + } + }, + _ => {}, + } + } + + drop(iter); + + let last_decl_curly_offset = + last_decl_curly_offset.unwrap_or_else(|| panic!("No lint declarations found in `{}`", path.display())); + let lint_context = + lint_context.unwrap_or_else(|| panic!("No lint pass implementation found in `{}`", path.display())); + + // Add the lint declaration to `mod.rs` + file_contents.replace_range( + // Remove the trailing newline, which should always be present + last_decl_curly_offset..=last_decl_curly_offset, + &format!("\n\n{}", get_lint_declaration(&lint_name_upper, lint.category)), + ); + + // Add the lint to `impl_lint_pass`/`declare_lint_pass` + let impl_lint_pass_start = file_contents.find("impl_lint_pass!").unwrap_or_else(|| { + file_contents + .find("declare_lint_pass!") + .unwrap_or_else(|| panic!("failed to find `impl_lint_pass`/`declare_lint_pass`")) + }); + + let mut arr_start = file_contents[impl_lint_pass_start..].find('[').unwrap_or_else(|| { + panic!("malformed `impl_lint_pass`/`declare_lint_pass`"); + }); + + arr_start += impl_lint_pass_start; + + let mut arr_end = file_contents[arr_start..] + .find(']') + .expect("failed to find `impl_lint_pass` terminator"); + + arr_end += arr_start; + + let mut arr_content = file_contents[arr_start + 1..arr_end].to_string(); + arr_content.retain(|c| !c.is_whitespace()); + + let mut new_arr_content = String::new(); + for ident in arr_content + .split(',') + .chain(std::iter::once(&*lint_name_upper)) + .filter(|s| !s.is_empty()) + { + let _ = write!(new_arr_content, "\n {},", ident); + } + new_arr_content.push('\n'); + + file_contents.replace_range(arr_start + 1..arr_end, &new_arr_content); + + // Just add the mod declaration at the top, it'll be fixed by rustfmt + file_contents.insert_str(0, &format!("mod {};\n", &lint.name)); + + let mut file = OpenOptions::new() + .write(true) + .truncate(true) + .open(path) + .context(format!("trying to open: `{}`", path.display()))?; + file.write_all(file_contents.as_bytes()) + .context(format!("writing to file: `{}`", path.display()))?; + + Ok(lint_context) +} + #[test] fn test_camel_case() { let s = "a_lint"; diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs index c089f4d8ce4bb..aed38bc281760 100644 --- a/clippy_dev/src/update_lints.rs +++ b/clippy_dev/src/update_lints.rs @@ -824,10 +824,12 @@ macro_rules! match_tokens { } } -struct LintDeclSearchResult<'a> { - token_kind: TokenKind, - content: &'a str, - range: Range, +pub(crate) use match_tokens; + +pub(crate) struct LintDeclSearchResult<'a> { + pub token_kind: TokenKind, + pub content: &'a str, + pub range: Range, } /// Parse a source file looking for `declare_clippy_lint` macro invocations. diff --git a/clippy_lints/src/as_conversions.rs b/clippy_lints/src/as_conversions.rs index 6e5c8f445818e..c7a76e5f9077c 100644 --- a/clippy_lints/src/as_conversions.rs +++ b/clippy_lints/src/as_conversions.rs @@ -11,7 +11,7 @@ declare_clippy_lint! { /// Note that this lint is specialized in linting *every single* use of `as` /// regardless of whether good alternatives exist or not. /// If you want more precise lints for `as`, please consider using these separate lints: - /// `unnecessary_cast`, `cast_lossless/possible_truncation/possible_wrap/precision_loss/sign_loss`, + /// `unnecessary_cast`, `cast_lossless/cast_possible_truncation/cast_possible_wrap/cast_precision_loss/cast_sign_loss`, /// `fn_to_numeric_cast(_with_truncation)`, `char_lit_as_u8`, `ref_to_mut` and `ptr_as_ptr`. /// There is a good explanation the reason why this lint should work in this way and how it is useful /// [in this issue](https://github.com/rust-lang/rust-clippy/issues/5122). diff --git a/clippy_lints/src/assertions_on_result_states.rs b/clippy_lints/src/assertions_on_result_states.rs new file mode 100644 index 0000000000000..b6affdee52364 --- /dev/null +++ b/clippy_lints/src/assertions_on_result_states.rs @@ -0,0 +1,98 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::macros::{find_assert_args, root_macro_call_first_node, PanicExpn}; +use clippy_utils::path_res; +use clippy_utils::source::snippet_with_context; +use clippy_utils::ty::{implements_trait, is_copy, is_type_diagnostic_item}; +use clippy_utils::usage::local_used_after_expr; +use rustc_errors::Applicability; +use rustc_hir::def::Res; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::{self, Ty}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; + +declare_clippy_lint! { + /// ### What it does + /// Checks for `assert!(r.is_ok())` or `assert!(r.is_err())` calls. + /// + /// ### Why is this bad? + /// An assertion failure cannot output an useful message of the error. + /// + /// ### Example + /// ```rust,ignore + /// # let r = Ok::<_, ()>(()); + /// assert!(r.is_ok()); + /// # let r = Err::<_, ()>(()); + /// assert!(r.is_err()); + /// ``` + #[clippy::version = "1.64.0"] + pub ASSERTIONS_ON_RESULT_STATES, + style, + "`assert!(r.is_ok())`/`assert!(r.is_err())` gives worse error message than directly calling `r.unwrap()`/`r.unwrap_err()`" +} + +declare_lint_pass!(AssertionsOnResultStates => [ASSERTIONS_ON_RESULT_STATES]); + +impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates { + fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { + if let Some(macro_call) = root_macro_call_first_node(cx, e) + && matches!(cx.tcx.get_diagnostic_name(macro_call.def_id), Some(sym::assert_macro)) + && let Some((condition, panic_expn)) = find_assert_args(cx, e, macro_call.expn) + && matches!(panic_expn, PanicExpn::Empty) + && let ExprKind::MethodCall(method_segment, [recv], _) = condition.kind + && let result_type_with_refs = cx.typeck_results().expr_ty(recv) + && let result_type = result_type_with_refs.peel_refs() + && is_type_diagnostic_item(cx, result_type, sym::Result) + && let ty::Adt(_, substs) = result_type.kind() + { + if !is_copy(cx, result_type) { + if result_type_with_refs != result_type { + return; + } else if let Res::Local(binding_id) = path_res(cx, recv) + && local_used_after_expr(cx, binding_id, recv) { + return; + } + } + let mut app = Applicability::MachineApplicable; + match method_segment.ident.as_str() { + "is_ok" if has_debug_impl(cx, substs.type_at(1)) => { + span_lint_and_sugg( + cx, + ASSERTIONS_ON_RESULT_STATES, + macro_call.span, + "called `assert!` with `Result::is_ok`", + "replace with", + format!( + "{}.unwrap()", + snippet_with_context(cx, recv.span, condition.span.ctxt(), "..", &mut app).0 + ), + app, + ); + } + "is_err" if has_debug_impl(cx, substs.type_at(0)) => { + span_lint_and_sugg( + cx, + ASSERTIONS_ON_RESULT_STATES, + macro_call.span, + "called `assert!` with `Result::is_err`", + "replace with", + format!( + "{}.unwrap_err()", + snippet_with_context(cx, recv.span, condition.span.ctxt(), "..", &mut app).0 + ), + app, + ); + } + _ => (), + }; + } + } +} + +/// This checks whether a given type is known to implement Debug. +fn has_debug_impl<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { + cx.tcx + .get_diagnostic_item(sym::Debug) + .map_or(false, |debug| implements_trait(cx, ty, debug, &[])) +} diff --git a/clippy_lints/src/cargo/mod.rs b/clippy_lints/src/cargo/mod.rs index abe95c6663f70..9f45db86a0913 100644 --- a/clippy_lints/src/cargo/mod.rs +++ b/clippy_lints/src/cargo/mod.rs @@ -1,3 +1,8 @@ +mod common_metadata; +mod feature_name; +mod multiple_crate_versions; +mod wildcard_dependencies; + use cargo_metadata::MetadataCommand; use clippy_utils::diagnostics::span_lint; use clippy_utils::is_lint_allowed; @@ -6,11 +11,6 @@ use rustc_lint::{LateContext, LateLintPass, Lint}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::DUMMY_SP; -mod common_metadata; -mod feature_name; -mod multiple_crate_versions; -mod wildcard_dependencies; - declare_clippy_lint! { /// ### What it does /// Checks to see if all common metadata is defined in diff --git a/clippy_lints/src/case_sensitive_file_extension_comparisons.rs b/clippy_lints/src/case_sensitive_file_extension_comparisons.rs index 7af200708ff03..7eff71d500743 100644 --- a/clippy_lints/src/case_sensitive_file_extension_comparisons.rs +++ b/clippy_lints/src/case_sensitive_file_extension_comparisons.rs @@ -24,7 +24,10 @@ declare_clippy_lint! { /// Use instead: /// ```rust /// fn is_rust_file(filename: &str) -> bool { - /// filename.rsplit('.').next().map(|ext| ext.eq_ignore_ascii_case("rs")) == Some(true) + /// let filename = std::path::Path::new(filename); + /// filename.extension() + /// .map(|ext| ext.eq_ignore_ascii_case("rs")) + /// .unwrap_or(false) /// } /// ``` #[clippy::version = "1.51.0"] diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 8c7cf7748be13..a90f894a7b19c 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -1028,9 +1028,10 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data let mut app = Applicability::MachineApplicable; let (snip, snip_is_macro) = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app); span_lint_hir_and_then(cx, NEEDLESS_BORROW, data.hir_id, data.span, state.msg, |diag| { + let calls_field = matches!(expr.kind, ExprKind::Field(..)) && matches!(data.position, Position::Callee); let sugg = if !snip_is_macro - && expr.precedence().order() < data.position.precedence() && !has_enclosing_paren(&snip) + && (expr.precedence().order() < data.position.precedence() || calls_field) { format!("({})", snip) } else { diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index 0aa085fc71bfe..925a8cb8deed9 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -9,7 +9,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::kw; -use rustc_span::{sym, BytePos, Span}; +use rustc_span::{sym, Span}; declare_clippy_lint! { /// ### What it does @@ -85,22 +85,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat { ExprKind::MethodCall(path, ..) => path.ident.name == sym::to_string, _ => false, }; - let sugg = if format_args.format_string_span.contains(value.span) { - // Implicit argument. e.g. `format!("{x}")` span points to `{x}` - let spdata = value.span.data(); - let span = Span::new( - spdata.lo + BytePos(1), - spdata.hi - BytePos(1), - spdata.ctxt, - spdata.parent - ); - let snip = snippet_with_applicability(cx, span, "..", &mut applicability); - if is_new_string { - snip.into() - } else { - format!("{snip}.to_string()") - } - } else if is_new_string { + let sugg = if is_new_string { snippet_with_applicability(cx, value.span, "..", &mut applicability).into_owned() } else { let sugg = Sugg::hir_with_applicability(cx, value, "", &mut applicability); diff --git a/clippy_lints/src/format_impl.rs b/clippy_lints/src/format_impl.rs index ef8be9e878f6c..04b5be6c80ec6 100644 --- a/clippy_lints/src/format_impl.rs +++ b/clippy_lints/src/format_impl.rs @@ -141,7 +141,7 @@ fn check_to_string_in_display(cx: &LateContext<'_>, expr: &Expr<'_>) { // Get the hir_id of the object we are calling the method on if let ExprKind::MethodCall(path, [ref self_arg, ..], _) = expr.kind; // Is the method to_string() ? - if path.ident.name == sym!(to_string); + if path.ident.name == sym::to_string; // Is the method a part of the ToString trait? (i.e. not to_string() implemented // separately) if let Some(expr_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index 9afc714b11ca1..5be1c417bf8f6 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -6,6 +6,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(almost_complete_letter_range::ALMOST_COMPLETE_LETTER_RANGE), LintId::of(approx_const::APPROX_CONSTANT), LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS), + LintId::of(assertions_on_result_states::ASSERTIONS_ON_RESULT_STATES), LintId::of(async_yields_async::ASYNC_YIELDS_ASYNC), LintId::of(attrs::BLANKET_CLIPPY_RESTRICTION_LINTS), LintId::of(attrs::DEPRECATED_CFG_ATTR), @@ -187,6 +188,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(methods::NEEDLESS_SPLITN), LintId::of(methods::NEW_RET_NO_SELF), LintId::of(methods::NO_EFFECT_REPLACE), + LintId::of(methods::OBFUSCATED_IF_ELSE), LintId::of(methods::OK_EXPECT), LintId::of(methods::OPTION_AS_REF_DEREF), LintId::of(methods::OPTION_FILTER_MAP), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 91d27bf526d09..99bde35cf152b 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -42,6 +42,7 @@ store.register_lints(&[ asm_syntax::INLINE_ASM_X86_ATT_SYNTAX, asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX, assertions_on_constants::ASSERTIONS_ON_CONSTANTS, + assertions_on_result_states::ASSERTIONS_ON_RESULT_STATES, async_yields_async::ASYNC_YIELDS_ASYNC, attrs::ALLOW_ATTRIBUTES_WITHOUT_REASON, attrs::BLANKET_CLIPPY_RESTRICTION_LINTS, @@ -330,6 +331,7 @@ store.register_lints(&[ methods::NEEDLESS_SPLITN, methods::NEW_RET_NO_SELF, methods::NO_EFFECT_REPLACE, + methods::OBFUSCATED_IF_ELSE, methods::OK_EXPECT, methods::OPTION_AS_REF_DEREF, methods::OPTION_FILTER_MAP, @@ -417,6 +419,7 @@ store.register_lints(&[ only_used_in_recursion::ONLY_USED_IN_RECURSION, open_options::NONSENSICAL_OPEN_OPTIONS, operators::ABSURD_EXTREME_COMPARISONS, + operators::ARITHMETIC, operators::ASSIGN_OP_PATTERN, operators::BAD_BIT_MASK, operators::CMP_NAN, diff --git a/clippy_lints/src/lib.register_restriction.rs b/clippy_lints/src/lib.register_restriction.rs index 43f1c892eb9b9..495abd8387e85 100644 --- a/clippy_lints/src/lib.register_restriction.rs +++ b/clippy_lints/src/lib.register_restriction.rs @@ -48,6 +48,7 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve LintId::of(mixed_read_write_in_expression::MIXED_READ_WRITE_IN_EXPRESSION), LintId::of(module_style::MOD_MODULE_FILES), LintId::of(module_style::SELF_NAMED_MODULE_FILES), + LintId::of(operators::ARITHMETIC), LintId::of(operators::FLOAT_ARITHMETIC), LintId::of(operators::FLOAT_CMP_CONST), LintId::of(operators::INTEGER_ARITHMETIC), diff --git a/clippy_lints/src/lib.register_style.rs b/clippy_lints/src/lib.register_style.rs index 15a1bc569af23..e029a5235e720 100644 --- a/clippy_lints/src/lib.register_style.rs +++ b/clippy_lints/src/lib.register_style.rs @@ -4,6 +4,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS), + LintId::of(assertions_on_result_states::ASSERTIONS_ON_RESULT_STATES), LintId::of(blacklisted_name::BLACKLISTED_NAME), LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS), LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON), @@ -70,6 +71,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(methods::MANUAL_SATURATING_ARITHMETIC), LintId::of(methods::MAP_COLLECT_RESULT_UNIT), LintId::of(methods::NEW_RET_NO_SELF), + LintId::of(methods::OBFUSCATED_IF_ELSE), LintId::of(methods::OK_EXPECT), LintId::of(methods::OPTION_MAP_OR_NONE), LintId::of(methods::RESULT_MAP_OR_INTO_OPTION), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 1988c24578e0b..eb3841272b17f 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -174,6 +174,7 @@ mod as_conversions; mod as_underscore; mod asm_syntax; mod assertions_on_constants; +mod assertions_on_result_states; mod async_yields_async; mod attrs; mod await_holding_invalid; @@ -548,6 +549,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(utils::internal_lints::MsrvAttrImpl)); } + let arithmetic_allowed = conf.arithmetic_allowed.clone(); + store.register_late_pass(move || Box::new(operators::arithmetic::Arithmetic::new(arithmetic_allowed.clone()))); store.register_late_pass(|| Box::new(utils::dump_hir::DumpHir)); store.register_late_pass(|| Box::new(utils::author::Author)); let await_holding_invalid_types = conf.await_holding_invalid_types.clone(); @@ -727,6 +730,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(unnecessary_sort_by::UnnecessarySortBy)); store.register_late_pass(move || Box::new(unnecessary_wraps::UnnecessaryWraps::new(avoid_breaking_exported_api))); store.register_late_pass(|| Box::new(assertions_on_constants::AssertionsOnConstants)); + store.register_late_pass(|| Box::new(assertions_on_result_states::AssertionsOnResultStates)); store.register_late_pass(|| Box::new(transmuting_null::TransmutingNull)); store.register_late_pass(|| Box::new(path_buf_push_overwrite::PathBufPushOverwrite)); store.register_late_pass(|| Box::new(inherent_to_string::InherentToString)); @@ -782,7 +786,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: )) }); store.register_late_pass(|| Box::new(default::Default::default())); - store.register_late_pass(|| Box::new(unused_self::UnusedSelf)); + store.register_late_pass(move || Box::new(unused_self::UnusedSelf::new(avoid_breaking_exported_api))); store.register_late_pass(|| Box::new(mutable_debug_assertion::DebugAssertWithMutCall)); store.register_late_pass(|| Box::new(exit::Exit)); store.register_late_pass(|| Box::new(to_digit_is_some::ToDigitIsSome)); @@ -916,7 +920,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: let verbose_bit_mask_threshold = conf.verbose_bit_mask_threshold; store.register_late_pass(move || Box::new(operators::Operators::new(verbose_bit_mask_threshold))); store.register_late_pass(|| Box::new(invalid_utf8_in_unchecked::InvalidUtf8InUnchecked)); - store.register_late_pass(|| Box::new(std_instead_of_core::StdReexports)); + store.register_late_pass(|| Box::new(std_instead_of_core::StdReexports::default())); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 3f69cc2038839..573a7c016b8e8 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -460,7 +460,6 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> { let mut sub_visitor = RefVisitor::new(self.cx); sub_visitor.visit_fn_decl(decl); self.nested_elision_site_lts.append(&mut sub_visitor.all_lts()); - return; }, TyKind::TraitObject(bounds, ref lt, _) => { if !lt.is_elided() { @@ -469,7 +468,6 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> { for bound in bounds { self.visit_poly_trait_ref(bound, TraitBoundModifier::None); } - return; }, _ => walk_ty(self, ty), } diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs index d55082c66dc86..b638f27160282 100644 --- a/clippy_lints/src/matches/mod.rs +++ b/clippy_lints/src/matches/mod.rs @@ -1,13 +1,3 @@ -use clippy_utils::source::{snippet_opt, span_starts_with, walk_span_to_context}; -use clippy_utils::{higher, in_constant, meets_msrv, msrvs}; -use rustc_hir::{Arm, Expr, ExprKind, Local, MatchSource, Pat}; -use rustc_lexer::{tokenize, TokenKind}; -use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; -use rustc_semver::RustcVersion; -use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::{Span, SpanData, SyntaxContext}; - mod collapsible_match; mod infallible_destructuring_match; mod manual_map; @@ -31,6 +21,16 @@ mod single_match; mod try_err; mod wild_in_or_pats; +use clippy_utils::source::{snippet_opt, span_starts_with, walk_span_to_context}; +use clippy_utils::{higher, in_constant, meets_msrv, msrvs}; +use rustc_hir::{Arm, Expr, ExprKind, Local, MatchSource, Pat}; +use rustc_lexer::{tokenize, TokenKind}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; +use rustc_semver::RustcVersion; +use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::{Span, SpanData, SyntaxContext}; + declare_clippy_lint! { /// ### What it does /// Checks for matches with a single arm where an `if let` @@ -793,18 +793,13 @@ declare_clippy_lint! { /// ### Example /// ```rust,ignore /// # use std::sync::Mutex; - /// /// # struct State {} - /// /// # impl State { /// # fn foo(&self) -> bool { /// # true /// # } - /// /// # fn bar(&self) {} /// # } - /// - /// /// let mutex = Mutex::new(State {}); /// /// match mutex.lock().unwrap().foo() { @@ -815,22 +810,17 @@ declare_clippy_lint! { /// }; /// /// println!("All done!"); - /// /// ``` /// Use instead: /// ```rust /// # use std::sync::Mutex; - /// /// # struct State {} - /// /// # impl State { /// # fn foo(&self) -> bool { /// # true /// # } - /// /// # fn bar(&self) {} /// # } - /// /// let mutex = Mutex::new(State {}); /// /// let is_foo = mutex.lock().unwrap().foo(); diff --git a/clippy_lints/src/methods/inefficient_to_string.rs b/clippy_lints/src/methods/inefficient_to_string.rs index 06ead144afa24..f52170df662ca 100644 --- a/clippy_lints/src/methods/inefficient_to_string.rs +++ b/clippy_lints/src/methods/inefficient_to_string.rs @@ -14,7 +14,7 @@ use super::INEFFICIENT_TO_STRING; /// Checks for the `INEFFICIENT_TO_STRING` lint pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Symbol, args: &[hir::Expr<'_>]) { if_chain! { - if args.len() == 1 && method_name == sym!(to_string); + if args.len() == 1 && method_name == sym::to_string; if let Some(to_string_meth_did) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if match_def_path(cx, to_string_meth_did, &paths::TO_STRING_METHOD); if let Some(substs) = cx.typeck_results().node_substs_opt(expr.hir_id); diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 6981b4a66318e..202fbc1f7f668 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -46,6 +46,7 @@ mod map_unwrap_or; mod needless_option_as_deref; mod needless_option_take; mod no_effect_replace; +mod obfuscated_if_else; mod ok_expect; mod option_as_ref_deref; mod option_map_or_none; @@ -2263,6 +2264,35 @@ declare_clippy_lint! { "replace with no effect" } +declare_clippy_lint! { + /// ### What it does + /// Checks for usages of `.then_some(..).unwrap_or(..)` + /// + /// ### Why is this bad? + /// This can be written more clearly with `if .. else ..` + /// + /// ### Limitations + /// This lint currently only looks for usages of + /// `.then_some(..).unwrap_or(..)`, but will be expanded + /// to account for similar patterns. + /// + /// ### Example + /// ```rust + /// let x = true; + /// x.then_some("a").unwrap_or("b"); + /// ``` + /// Use instead: + /// ```rust + /// let x = true; + /// if x { "a" } else { "b" }; + /// ``` + #[clippy::version = "1.64.0"] + pub OBFUSCATED_IF_ELSE, + style, + "use of `.then_some(..).unwrap_or(..)` can be written \ + more clearly with `if .. else ..`" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -2364,6 +2394,7 @@ impl_lint_pass!(Methods => [ IS_DIGIT_ASCII_RADIX, NEEDLESS_OPTION_TAKE, NO_EFFECT_REPLACE, + OBFUSCATED_IF_ELSE, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -2772,6 +2803,9 @@ impl Methods { Some(("map", [m_recv, m_arg], span)) => { option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span); }, + Some(("then_some", [t_recv, t_arg], _)) => { + obfuscated_if_else::check(cx, expr, t_recv, t_arg, u_arg); + }, _ => {}, }, ("unwrap_or_else", [u_arg]) => match method_call(recv) { diff --git a/clippy_lints/src/methods/obfuscated_if_else.rs b/clippy_lints/src/methods/obfuscated_if_else.rs new file mode 100644 index 0000000000000..4d7427b266213 --- /dev/null +++ b/clippy_lints/src/methods/obfuscated_if_else.rs @@ -0,0 +1,42 @@ +// run-rustfix + +use super::OBFUSCATED_IF_ELSE; +use clippy_utils::{diagnostics::span_lint_and_sugg, source::snippet_with_applicability}; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'_>, + then_recv: &'tcx hir::Expr<'_>, + then_arg: &'tcx hir::Expr<'_>, + unwrap_arg: &'tcx hir::Expr<'_>, +) { + // something.then_some(blah).unwrap_or(blah) + // ^^^^^^^^^-then_recv ^^^^-then_arg ^^^^- unwrap_arg + // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- expr + + let recv_ty = cx.typeck_results().expr_ty(then_recv); + + if recv_ty.is_bool() { + let mut applicability = Applicability::MachineApplicable; + let sugg = format!( + "if {} {{ {} }} else {{ {} }}", + snippet_with_applicability(cx, then_recv.span, "..", &mut applicability), + snippet_with_applicability(cx, then_arg.span, "..", &mut applicability), + snippet_with_applicability(cx, unwrap_arg.span, "..", &mut applicability) + ); + + span_lint_and_sugg( + cx, + OBFUSCATED_IF_ELSE, + expr.span, + "use of `.then_some(..).unwrap_or(..)` can be written \ + more clearly with `if .. else ..`", + "try", + sugg, + applicability, + ); + } +} diff --git a/clippy_lints/src/mismatching_type_param_order.rs b/clippy_lints/src/mismatching_type_param_order.rs index 254d9a70010a8..f763e0d24c944 100644 --- a/clippy_lints/src/mismatching_type_param_order.rs +++ b/clippy_lints/src/mismatching_type_param_order.rs @@ -18,6 +18,11 @@ declare_clippy_lint! { /// Naming type parameters inconsistently may cause you to refer to the /// wrong type parameter. /// + /// ### Limitations + /// This lint only applies to impl blocks with simple generic params, e.g. + /// `A`. If there is anything more complicated, such as a tuple, it will be + /// ignored. + /// /// ### Example /// ```rust /// struct Foo { @@ -53,14 +58,15 @@ impl<'tcx> LateLintPass<'tcx> for TypeParamMismatch { if !generic_args.args.is_empty(); then { // get the name and span of the generic parameters in the Impl - let impl_params = generic_args.args.iter() - .filter_map(|p| + let mut impl_params = Vec::new(); + for p in generic_args.args.iter() { match p { GenericArg::Type(Ty {kind: TyKind::Path(QPath::Resolved(_, path)), ..}) => - Some((path.segments[0].ident.to_string(), path.span)), - _ => None, - } - ); + impl_params.push((path.segments[0].ident.to_string(), path.span)), + GenericArg::Type(_) => return, + _ => (), + }; + } // find the type that the Impl is for // only lint on struct/enum/union for now @@ -83,8 +89,8 @@ impl<'tcx> LateLintPass<'tcx> for TypeParamMismatch { type_param_names.iter().enumerate().map(|(i, param)| (param, i)).collect(); let type_name = segment.ident; - for (i, (impl_param_name, impl_param_span)) in impl_params.enumerate() { - if mismatch_param_name(i, &impl_param_name, &type_param_names_hashmap) { + for (i, (impl_param_name, impl_param_span)) in impl_params.iter().enumerate() { + if mismatch_param_name(i, impl_param_name, &type_param_names_hashmap) { let msg = format!("`{}` has a similarly named generic type parameter `{}` in its declaration, but in a different order", type_name, impl_param_name); let help = format!("try `{}`, or a name that does not conflict with `{}`'s generic params", @@ -92,7 +98,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeParamMismatch { span_lint_and_help( cx, MISMATCHING_TYPE_PARAM_ORDER, - impl_param_span, + *impl_param_span, &msg, None, &help diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 6bce5fbd4c1fe..72c86f28bbc6c 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -251,14 +251,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx Item<'_>) { if let ItemKind::Const(hir_ty, body_id) = it.kind { let ty = hir_ty_to_ty(cx.tcx, hir_ty); - if !macro_backtrace(it.span).last().map_or(false, |macro_call| { - matches!( - cx.tcx.get_diagnostic_name(macro_call.def_id), - Some(sym::thread_local_macro) - ) - }) && is_unfrozen(cx, ty) - && is_value_unfrozen_poly(cx, body_id, ty) - { + if !ignored_macro(cx, it) && is_unfrozen(cx, ty) && is_value_unfrozen_poly(cx, body_id, ty) { lint(cx, Source::Item { item: it.span }); } } @@ -445,3 +438,12 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { } } } + +fn ignored_macro(cx: &LateContext<'_>, it: &rustc_hir::Item<'_>) -> bool { + macro_backtrace(it.span).any(|macro_call| { + matches!( + cx.tcx.get_diagnostic_name(macro_call.def_id), + Some(sym::thread_local_macro) + ) + }) +} diff --git a/clippy_lints/src/operators/arithmetic.rs b/clippy_lints/src/operators/arithmetic.rs new file mode 100644 index 0000000000000..800cf249f5c78 --- /dev/null +++ b/clippy_lints/src/operators/arithmetic.rs @@ -0,0 +1,119 @@ +#![allow( + // False positive + clippy::match_same_arms +)] + +use super::ARITHMETIC; +use clippy_utils::{consts::constant_simple, diagnostics::span_lint}; +use rustc_data_structures::fx::FxHashSet; +use rustc_hir as hir; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::impl_lint_pass; +use rustc_span::source_map::Span; + +const HARD_CODED_ALLOWED: &[&str] = &["std::num::Saturating", "std::string::String", "std::num::Wrapping"]; + +#[derive(Debug)] +pub struct Arithmetic { + allowed: FxHashSet, + // Used to check whether expressions are constants, such as in enum discriminants and consts + const_span: Option, + expr_span: Option, +} + +impl_lint_pass!(Arithmetic => [ARITHMETIC]); + +impl Arithmetic { + #[must_use] + pub fn new(mut allowed: FxHashSet) -> Self { + allowed.extend(HARD_CODED_ALLOWED.iter().copied().map(String::from)); + Self { + allowed, + const_span: None, + expr_span: None, + } + } + + /// Checks if the given `expr` has any of the inner `allowed` elements. + fn is_allowed_ty(&self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { + self.allowed.contains( + cx.typeck_results() + .expr_ty(expr) + .to_string() + .split('<') + .next() + .unwrap_or_default(), + ) + } + + fn issue_lint(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) { + span_lint(cx, ARITHMETIC, expr.span, "arithmetic detected"); + self.expr_span = Some(expr.span); + } +} + +impl<'tcx> LateLintPass<'tcx> for Arithmetic { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { + if self.expr_span.is_some() { + return; + } + if let Some(span) = self.const_span && span.contains(expr.span) { + return; + } + match &expr.kind { + hir::ExprKind::Binary(op, lhs, rhs) | hir::ExprKind::AssignOp(op, lhs, rhs) => { + let ( + hir::BinOpKind::Add + | hir::BinOpKind::Sub + | hir::BinOpKind::Mul + | hir::BinOpKind::Div + | hir::BinOpKind::Rem + | hir::BinOpKind::Shl + | hir::BinOpKind::Shr + ) = op.node else { + return; + }; + if self.is_allowed_ty(cx, lhs) || self.is_allowed_ty(cx, rhs) { + return; + } + self.issue_lint(cx, expr); + }, + hir::ExprKind::Unary(hir::UnOp::Neg, _) => { + // CTFE already takes care of things like `-1` that do not overflow. + if constant_simple(cx, cx.typeck_results(), expr).is_none() { + self.issue_lint(cx, expr); + } + }, + _ => {}, + } + } + + fn check_body(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) { + let body_owner = cx.tcx.hir().body_owner_def_id(body.id()); + match cx.tcx.hir().body_owner_kind(body_owner) { + hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => { + let body_span = cx.tcx.def_span(body_owner); + if let Some(span) = self.const_span && span.contains(body_span) { + return; + } + self.const_span = Some(body_span); + }, + hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::Fn => {}, + } + } + + fn check_body_post(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) { + let body_owner = cx.tcx.hir().body_owner(body.id()); + let body_span = cx.tcx.hir().span(body_owner); + if let Some(span) = self.const_span && span.contains(body_span) { + return; + } + self.const_span = None; + } + + fn check_expr_post(&mut self, _: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { + if Some(expr.span) == self.expr_span { + self.expr_span = None; + } + } +} diff --git a/clippy_lints/src/operators/assign_op_pattern.rs b/clippy_lints/src/operators/assign_op_pattern.rs index 979e0a66707dd..945a09a647c41 100644 --- a/clippy_lints/src/operators/assign_op_pattern.rs +++ b/clippy_lints/src/operators/assign_op_pattern.rs @@ -8,6 +8,10 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_lint::LateContext; +use rustc_middle::mir::FakeReadCause; +use rustc_middle::ty::BorrowKind; +use rustc_trait_selection::infer::TyCtxtInferExt; +use rustc_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; use super::ASSIGN_OP_PATTERN; @@ -29,6 +33,16 @@ pub(super) fn check<'tcx>( .map_or(true, |t| t.path.res.def_id() != trait_id); if implements_trait(cx, ty, trait_id, &[rty.into()]); then { + // Primitive types execute assign-ops right-to-left. Every other type is left-to-right. + if !(ty.is_primitive() && rty.is_primitive()) { + // TODO: This will have false negatives as it doesn't check if the borrows are + // actually live at the end of their respective expressions. + let mut_borrows = mut_borrows_in_expr(cx, assignee); + let imm_borrows = imm_borrows_in_expr(cx, rhs); + if mut_borrows.iter().any(|id| imm_borrows.contains(id)) { + return; + } + } span_lint_and_then( cx, ASSIGN_OP_PATTERN, @@ -99,3 +113,69 @@ impl<'a, 'tcx> Visitor<'tcx> for ExprVisitor<'a, 'tcx> { walk_expr(self, expr); } } + +fn imm_borrows_in_expr(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> hir::HirIdSet { + struct S(hir::HirIdSet); + impl Delegate<'_> for S { + fn borrow(&mut self, place: &PlaceWithHirId<'_>, _: hir::HirId, kind: BorrowKind) { + if matches!(kind, BorrowKind::ImmBorrow | BorrowKind::UniqueImmBorrow) { + self.0.insert(match place.place.base { + PlaceBase::Local(id) => id, + PlaceBase::Upvar(id) => id.var_path.hir_id, + _ => return, + }); + } + } + + fn consume(&mut self, _: &PlaceWithHirId<'_>, _: hir::HirId) {} + fn mutate(&mut self, _: &PlaceWithHirId<'_>, _: hir::HirId) {} + fn fake_read(&mut self, _: &PlaceWithHirId<'_>, _: FakeReadCause, _: hir::HirId) {} + fn copy(&mut self, _: &PlaceWithHirId<'_>, _: hir::HirId) {} + } + + let mut s = S(hir::HirIdSet::default()); + cx.tcx.infer_ctxt().enter(|infcx| { + let mut v = ExprUseVisitor::new( + &mut s, + &infcx, + cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap()), + cx.param_env, + cx.typeck_results(), + ); + v.consume_expr(e); + }); + s.0 +} + +fn mut_borrows_in_expr(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> hir::HirIdSet { + struct S(hir::HirIdSet); + impl Delegate<'_> for S { + fn borrow(&mut self, place: &PlaceWithHirId<'_>, _: hir::HirId, kind: BorrowKind) { + if matches!(kind, BorrowKind::MutBorrow) { + self.0.insert(match place.place.base { + PlaceBase::Local(id) => id, + PlaceBase::Upvar(id) => id.var_path.hir_id, + _ => return, + }); + } + } + + fn consume(&mut self, _: &PlaceWithHirId<'_>, _: hir::HirId) {} + fn mutate(&mut self, _: &PlaceWithHirId<'_>, _: hir::HirId) {} + fn fake_read(&mut self, _: &PlaceWithHirId<'_>, _: FakeReadCause, _: hir::HirId) {} + fn copy(&mut self, _: &PlaceWithHirId<'_>, _: hir::HirId) {} + } + + let mut s = S(hir::HirIdSet::default()); + cx.tcx.infer_ctxt().enter(|infcx| { + let mut v = ExprUseVisitor::new( + &mut s, + &infcx, + cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap()), + cx.param_env, + cx.typeck_results(), + ); + v.consume_expr(e); + }); + s.0 +} diff --git a/clippy_lints/src/operators/mod.rs b/clippy_lints/src/operators/mod.rs index 35fe405bcf14f..bb6d99406b493 100644 --- a/clippy_lints/src/operators/mod.rs +++ b/clippy_lints/src/operators/mod.rs @@ -1,7 +1,3 @@ -use rustc_hir::{Body, Expr, ExprKind, UnOp}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; - mod absurd_extreme_comparisons; mod assign_op_pattern; mod bit_mask; @@ -25,6 +21,12 @@ mod ptr_eq; mod self_assignment; mod verbose_bit_mask; +pub(crate) mod arithmetic; + +use rustc_hir::{Body, Expr, ExprKind, UnOp}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; + declare_clippy_lint! { /// ### What it does /// Checks for comparisons where one side of the relation is @@ -57,6 +59,42 @@ declare_clippy_lint! { "a comparison with a maximum or minimum value that is always true or false" } +declare_clippy_lint! { + /// ### What it does + /// Checks for any kind of arithmetic operation of any type. + /// + /// Operators like `+`, `-`, `*` or `<<` are usually capable of overflowing according to the [Rust + /// Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow), + /// or can panic (`/`, `%`). Known safe built-in types like `Wrapping` or `Saturing` are filtered + /// away. + /// + /// ### Why is this bad? + /// Integer overflow will trigger a panic in debug builds or will wrap in + /// release mode. Division by zero will cause a panic in either mode. In some applications one + /// wants explicitly checked, wrapping or saturating arithmetic. + /// + /// #### Example + /// ```rust + /// # let a = 0; + /// a + 1; + /// ``` + /// + /// Third-party types also tend to overflow. + /// + /// #### Example + /// ```ignore,rust + /// use rust_decimal::Decimal; + /// let _n = Decimal::MAX + Decimal::MAX; + /// ``` + /// + /// ### Allowed types + /// Custom allowed types can be specified through the "arithmetic-allowed" filter. + #[clippy::version = "1.64.0"] + pub ARITHMETIC, + restriction, + "any arithmetic expression that could overflow or panic" +} + declare_clippy_lint! { /// ### What it does /// Checks for integer arithmetic operations which could overflow or panic. @@ -747,6 +785,7 @@ pub struct Operators { } impl_lint_pass!(Operators => [ ABSURD_EXTREME_COMPARISONS, + ARITHMETIC, INTEGER_ARITHMETIC, FLOAT_ARITHMETIC, ASSIGN_OP_PATTERN, diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index f0155ed6051f6..fd0a53839e6ea 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -123,8 +123,8 @@ fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: if_chain! { if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else }) = higher::IfLet::hir(cx, expr); if !is_else_clause(cx.tcx, expr); - if let PatKind::TupleStruct(ref path1, fields, None) = let_pat.kind; - if let PatKind::Binding(annot, bind_id, ident, _) = fields[0].kind; + if let PatKind::TupleStruct(ref path1, [field], None) = let_pat.kind; + if let PatKind::Binding(annot, bind_id, ident, _) = field.kind; let caller_ty = cx.typeck_results().expr_ty(let_expr); let if_block = IfBlockType::IfLet(path1, caller_ty, ident.name, let_expr, if_then, if_else); if (is_early_return(sym::Option, cx, &if_block) && path_to_local_id(peel_blocks(if_then), bind_id)) diff --git a/clippy_lints/src/std_instead_of_core.rs b/clippy_lints/src/std_instead_of_core.rs index 56f2a7bae152b..ffd63cc687a11 100644 --- a/clippy_lints/src/std_instead_of_core.rs +++ b/clippy_lints/src/std_instead_of_core.rs @@ -1,8 +1,8 @@ use clippy_utils::diagnostics::span_lint_and_help; use rustc_hir::{def::Res, HirId, Path, PathSegment}; -use rustc_lint::{LateContext, LateLintPass, Lint}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::{sym, symbol::kw, Symbol}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::{sym, symbol::kw, Span}; declare_clippy_lint! { /// ### What it does @@ -63,7 +63,7 @@ declare_clippy_lint! { /// ### Why is this bad? /// /// Crates which have `no_std` compatibility and may optionally require alloc may wish to ensure types are - /// imported from alloc to ensure disabling `alloc` does not cause the crate to fail to compile. This lint + /// imported from core to ensure disabling `alloc` does not cause the crate to fail to compile. This lint /// is also useful for crates migrating to become `no_std` compatible. /// /// ### Example @@ -81,39 +81,55 @@ declare_clippy_lint! { "type is imported from alloc when available in core" } -declare_lint_pass!(StdReexports => [STD_INSTEAD_OF_CORE, STD_INSTEAD_OF_ALLOC, ALLOC_INSTEAD_OF_CORE]); +#[derive(Default)] +pub struct StdReexports { + // Paths which can be either a module or a macro (e.g. `std::env`) will cause this check to happen + // twice. First for the mod, second for the macro. This is used to avoid the lint reporting for the macro + // when the path could be also be used to access the module. + prev_span: Span, +} +impl_lint_pass!(StdReexports => [STD_INSTEAD_OF_CORE, STD_INSTEAD_OF_ALLOC, ALLOC_INSTEAD_OF_CORE]); impl<'tcx> LateLintPass<'tcx> for StdReexports { fn check_path(&mut self, cx: &LateContext<'tcx>, path: &Path<'tcx>, _: HirId) { - // std_instead_of_core - check_path(cx, path, sym::std, sym::core, STD_INSTEAD_OF_CORE); - // std_instead_of_alloc - check_path(cx, path, sym::std, sym::alloc, STD_INSTEAD_OF_ALLOC); - // alloc_instead_of_core - check_path(cx, path, sym::alloc, sym::core, ALLOC_INSTEAD_OF_CORE); - } -} - -fn check_path(cx: &LateContext<'_>, path: &Path<'_>, krate: Symbol, suggested_crate: Symbol, lint: &'static Lint) { - if_chain! { - // check if path resolves to the suggested crate. - if let Res::Def(_, def_id) = path.res; - if suggested_crate == cx.tcx.crate_name(def_id.krate); - - // check if the first segment of the path is the crate we want to identify - if let Some(path_root_segment) = get_first_segment(path); - - // check if the path matches the crate we want to suggest the other path for. - if krate == path_root_segment.ident.name; - then { - span_lint_and_help( - cx, - lint, - path.span, - &format!("used import from `{}` instead of `{}`", krate, suggested_crate), - None, - &format!("consider importing the item from `{}`", suggested_crate), - ); + if let Res::Def(_, def_id) = path.res + && let Some(first_segment) = get_first_segment(path) + { + let (lint, msg, help) = match first_segment.ident.name { + sym::std => match cx.tcx.crate_name(def_id.krate) { + sym::core => ( + STD_INSTEAD_OF_CORE, + "used import from `std` instead of `core`", + "consider importing the item from `core`", + ), + sym::alloc => ( + STD_INSTEAD_OF_ALLOC, + "used import from `std` instead of `alloc`", + "consider importing the item from `alloc`", + ), + _ => { + self.prev_span = path.span; + return; + }, + }, + sym::alloc => { + if cx.tcx.crate_name(def_id.krate) == sym::core { + ( + ALLOC_INSTEAD_OF_CORE, + "used import from `alloc` instead of `core`", + "consider importing the item from `core`", + ) + } else { + self.prev_span = path.span; + return; + } + }, + _ => return, + }; + if path.span != self.prev_span { + span_lint_and_help(cx, lint, path.span, msg, None, help); + self.prev_span = path.span; + } } } } @@ -123,12 +139,10 @@ fn check_path(cx: &LateContext<'_>, path: &Path<'_>, krate: Symbol, suggested_cr /// If this is a global path (such as `::std::fmt::Debug`), then the segment after [`kw::PathRoot`] /// is returned. fn get_first_segment<'tcx>(path: &Path<'tcx>) -> Option<&'tcx PathSegment<'tcx>> { - let segment = path.segments.first()?; - - // A global path will have PathRoot as the first segment. In this case, return the segment after. - if segment.ident.name == kw::PathRoot { - path.segments.get(1) - } else { - Some(segment) + match path.segments { + // A global path will have PathRoot as the first segment. In this case, return the segment after. + [x, y, ..] if x.ident.name == kw::PathRoot => Some(y), + [x, ..] => Some(x), + _ => None, } } diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index eb704a07451ca..22eb06b364632 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -394,7 +394,7 @@ impl<'tcx> LateLintPass<'tcx> for StrToString { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) { if_chain! { if let ExprKind::MethodCall(path, [self_arg, ..], _) = &expr.kind; - if path.ident.name == sym!(to_string); + if path.ident.name == sym::to_string; let ty = cx.typeck_results().expr_ty(self_arg); if let ty::Ref(_, ty, ..) = ty.kind(); if *ty.kind() == ty::Str; @@ -444,7 +444,7 @@ impl<'tcx> LateLintPass<'tcx> for StringToString { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) { if_chain! { if let ExprKind::MethodCall(path, [self_arg, ..], _) = &expr.kind; - if path.ident.name == sym!(to_string); + if path.ident.name == sym::to_string; let ty = cx.typeck_results().expr_ty(self_arg); if is_type_diagnostic_item(cx, ty, sym::String); then { diff --git a/clippy_lints/src/unused_self.rs b/clippy_lints/src/unused_self.rs index fd9d5b52e501f..51c65d898cf5f 100644 --- a/clippy_lints/src/unused_self.rs +++ b/clippy_lints/src/unused_self.rs @@ -3,7 +3,7 @@ use clippy_utils::visitors::is_local_used; use if_chain::if_chain; use rustc_hir::{Impl, ImplItem, ImplItemKind, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; declare_clippy_lint! { /// ### What it does @@ -35,7 +35,19 @@ declare_clippy_lint! { "methods that contain a `self` argument but don't use it" } -declare_lint_pass!(UnusedSelf => [UNUSED_SELF]); +pub struct UnusedSelf { + avoid_breaking_exported_api: bool, +} + +impl_lint_pass!(UnusedSelf => [UNUSED_SELF]); + +impl UnusedSelf { + pub fn new(avoid_breaking_exported_api: bool) -> Self { + Self { + avoid_breaking_exported_api, + } + } +} impl<'tcx> LateLintPass<'tcx> for UnusedSelf { fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &ImplItem<'_>) { @@ -49,6 +61,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedSelf { if let ItemKind::Impl(Impl { of_trait: None, .. }) = parent_item.kind; if assoc_item.fn_has_self_parameter; if let ImplItemKind::Fn(.., body_id) = &impl_item.kind; + if !cx.access_levels.is_exported(impl_item.def_id) || !self.avoid_breaking_exported_api; let body = cx.tcx.hir().body(*body_id); if let [self_param, ..] = body.params; if !is_local_used(cx, body, self_param.pat.hir_id); diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 38e5c5e5b7365..6e033b3be2d87 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -191,7 +191,11 @@ macro_rules! define_Conf { } define_Conf! { - /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX. + /// Lint: Arithmetic. + /// + /// Suppress checking of the passed type names. + (arithmetic_allowed: rustc_data_structures::fx::FxHashSet = <_>::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. /// /// Suppress lints whenever the suggested change would cause breakage for other crates. (avoid_breaking_exported_api: bool = true), diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 6d4a48b53de3c..351a3f4aec8c8 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -619,32 +619,24 @@ pub fn miri_to_const<'tcx>(tcx: TyCtxt<'tcx>, result: mir::ConstantKind<'tcx>) - }, mir::ConstantKind::Val(ConstValue::ByRef { alloc, offset: _ }, _) => match result.ty().kind() { ty::Array(sub_type, len) => match sub_type.kind() { - ty::Float(FloatTy::F32) => match len.to_valtree().try_to_machine_usize(tcx) { + ty::Float(FloatTy::F32) => match len.kind().try_to_machine_usize(tcx) { Some(len) => alloc .inner() .inspect_with_uninit_and_ptr_outside_interpreter(0..(4 * usize::try_from(len).unwrap())) .to_owned() - .chunks(4) - .map(|chunk| { - Some(Constant::F32(f32::from_le_bytes( - chunk.try_into().expect("this shouldn't happen"), - ))) - }) + .array_chunks::<4>() + .map(|&chunk| Some(Constant::F32(f32::from_le_bytes(chunk)))) .collect::>>() .map(Constant::Vec), _ => None, }, - ty::Float(FloatTy::F64) => match len.to_valtree().try_to_machine_usize(tcx) { + ty::Float(FloatTy::F64) => match len.kind().try_to_machine_usize(tcx) { Some(len) => alloc .inner() .inspect_with_uninit_and_ptr_outside_interpreter(0..(8 * usize::try_from(len).unwrap())) .to_owned() - .chunks(8) - .map(|chunk| { - Some(Constant::F64(f64::from_le_bytes( - chunk.try_into().expect("this shouldn't happen"), - ))) - }) + .array_chunks::<8>() + .map(|&chunk| Some(Constant::F64(f64::from_le_bytes(chunk)))) .collect::>>() .map(Constant::Vec), _ => None, diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index 77c974582ecb0..eaf260ddfb832 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -127,9 +127,6 @@ impl HirEqInterExpr<'_, '_, '_> { /// Checks whether two blocks are the same. fn eq_block(&mut self, left: &Block<'_>, right: &Block<'_>) -> bool { - if self.cannot_be_compared_block(left) || self.cannot_be_compared_block(right) { - return false; - } match (left.stmts, left.expr, right.stmts, right.expr) { ([], None, [], None) => { // For empty blocks, check to see if the tokens are equal. This will catch the case where a macro @@ -180,36 +177,13 @@ impl HirEqInterExpr<'_, '_, '_> { } } - fn cannot_be_compared_block(&mut self, block: &Block<'_>) -> bool { - if block.stmts.last().map_or(false, |stmt| { - matches!( - stmt.kind, - StmtKind::Semi(semi_expr) if self.should_ignore(semi_expr) - ) - }) { - return true; - } - - if let Some(block_expr) = block.expr - && self.should_ignore(block_expr) - { - return true - } - - false - } - fn should_ignore(&mut self, expr: &Expr<'_>) -> bool { - if macro_backtrace(expr.span).last().map_or(false, |macro_call| { + macro_backtrace(expr.span).last().map_or(false, |macro_call| { matches!( &self.inner.cx.tcx.get_diagnostic_name(macro_call.def_id), Some(sym::todo_macro | sym::unimplemented_macro) ) - }) { - return true; - } - - false + }) } pub fn eq_array_length(&mut self, left: ArrayLen, right: ArrayLen) -> bool { @@ -327,7 +301,8 @@ impl HirEqInterExpr<'_, '_, '_> { (&ExprKind::DropTemps(le), &ExprKind::DropTemps(re)) => self.eq_expr(le, re), _ => false, }; - is_eq || self.inner.expr_fallback.as_mut().map_or(false, |f| f(left, right)) + (is_eq && (!self.should_ignore(left) || !self.should_ignore(right))) + || self.inner.expr_fallback.as_mut().map_or(false, |f| f(left, right)) } fn eq_exprs(&mut self, left: &[Expr<'_>], right: &[Expr<'_>]) -> bool { diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 2fdda9fac1629..34a1cdaf1d52a 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1,3 +1,4 @@ +#![feature(array_chunks)] #![feature(box_patterns)] #![feature(control_flow_enum)] #![feature(let_else)] @@ -2141,7 +2142,7 @@ pub fn is_hir_ty_cfg_dependant(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool { static TEST_ITEM_NAMES_CACHE: OnceLock>>> = OnceLock::new(); -fn with_test_item_names<'tcx>(tcx: TyCtxt<'tcx>, module: LocalDefId, f: impl Fn(&[Symbol]) -> bool) -> bool { +fn with_test_item_names(tcx: TyCtxt<'_>, module: LocalDefId, f: impl Fn(&[Symbol]) -> bool) -> bool { let cache = TEST_ITEM_NAMES_CACHE.get_or_init(|| Mutex::new(FxHashMap::default())); let mut map: MutexGuard<'_, FxHashMap>> = cache.lock().unwrap(); let value = map.entry(module); diff --git a/rust-toolchain b/rust-toolchain index e693e6837592f..23ba7c712779e 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2022-07-15" +channel = "nightly-2022-07-28" components = ["cargo", "llvm-tools-preview", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 3615d07154dfb..92ac1a2be5614 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -433,7 +433,7 @@ fn rustfix_coverage_known_exceptions_accuracy() { let rs_path = Path::new("tests/ui").join(filename); assert!( rs_path.exists(), - "`{}` does not exists", + "`{}` does not exist", rs_path.strip_prefix(env!("CARGO_MANIFEST_DIR")).unwrap().display() ); let fixed_path = rs_path.with_extension("fixed"); @@ -445,6 +445,45 @@ fn rustfix_coverage_known_exceptions_accuracy() { } } +#[test] +fn ui_cargo_toml_metadata() { + let ui_cargo_path = Path::new("tests/ui-cargo"); + let cargo_common_metadata_path = ui_cargo_path.join("cargo_common_metadata"); + let publish_exceptions = + ["fail_publish", "fail_publish_true", "pass_publish_empty"].map(|path| cargo_common_metadata_path.join(path)); + + for entry in walkdir::WalkDir::new(ui_cargo_path) { + let entry = entry.unwrap(); + let path = entry.path(); + if path.file_name() != Some(OsStr::new("Cargo.toml")) { + continue; + } + + let toml = fs::read_to_string(path).unwrap().parse::().unwrap(); + + let package = toml.as_table().unwrap().get("package").unwrap().as_table().unwrap(); + + let name = package.get("name").unwrap().as_str().unwrap().replace('-', "_"); + assert!( + path.parent() + .unwrap() + .components() + .map(|component| component.as_os_str().to_string_lossy().replace('-', "_")) + .any(|s| *s == name) + || path.starts_with(&cargo_common_metadata_path), + "{:?} has incorrect package name", + path + ); + + let publish = package.get("publish").and_then(toml::Value::as_bool).unwrap_or(true); + assert!( + !publish || publish_exceptions.contains(&path.parent().unwrap().to_path_buf()), + "{:?} lacks `publish = false`", + path + ); + } +} + /// Restores an env var on drop #[must_use] struct VarGuard { diff --git a/tests/ui-cargo/cargo_common_metadata/fail/Cargo.toml b/tests/ui-cargo/cargo_common_metadata/fail/Cargo.toml index ae0a603299629..bc8e428f8595b 100644 --- a/tests/ui-cargo/cargo_common_metadata/fail/Cargo.toml +++ b/tests/ui-cargo/cargo_common_metadata/fail/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "cargo_common_metadata" +name = "cargo_common_metadata_fail" version = "0.1.0" publish = false diff --git a/tests/ui-cargo/cargo_common_metadata/fail/src/main.stderr b/tests/ui-cargo/cargo_common_metadata/fail/src/main.stderr index 5e9aa8dc36a6e..86953142befad 100644 --- a/tests/ui-cargo/cargo_common_metadata/fail/src/main.stderr +++ b/tests/ui-cargo/cargo_common_metadata/fail/src/main.stderr @@ -1,16 +1,16 @@ -error: package `cargo_common_metadata` is missing `package.description` metadata +error: package `cargo_common_metadata_fail` is missing `package.description` metadata | = note: `-D clippy::cargo-common-metadata` implied by `-D warnings` -error: package `cargo_common_metadata` is missing `either package.license or package.license_file` metadata +error: package `cargo_common_metadata_fail` is missing `either package.license or package.license_file` metadata -error: package `cargo_common_metadata` is missing `package.repository` metadata +error: package `cargo_common_metadata_fail` is missing `package.repository` metadata -error: package `cargo_common_metadata` is missing `package.readme` metadata +error: package `cargo_common_metadata_fail` is missing `package.readme` metadata -error: package `cargo_common_metadata` is missing `package.keywords` metadata +error: package `cargo_common_metadata_fail` is missing `package.keywords` metadata -error: package `cargo_common_metadata` is missing `package.categories` metadata +error: package `cargo_common_metadata_fail` is missing `package.categories` metadata error: aborting due to 6 previous errors diff --git a/tests/ui-cargo/cargo_common_metadata/fail_publish/Cargo.toml b/tests/ui-cargo/cargo_common_metadata/fail_publish/Cargo.toml index 7595696353cd4..5005b83f59d14 100644 --- a/tests/ui-cargo/cargo_common_metadata/fail_publish/Cargo.toml +++ b/tests/ui-cargo/cargo_common_metadata/fail_publish/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "cargo_common_metadata" +name = "cargo_common_metadata_fail_publish" version = "0.1.0" publish = ["some-registry-name"] diff --git a/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.stderr b/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.stderr index 5e9aa8dc36a6e..ac1b5e8e90347 100644 --- a/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.stderr +++ b/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.stderr @@ -1,16 +1,16 @@ -error: package `cargo_common_metadata` is missing `package.description` metadata +error: package `cargo_common_metadata_fail_publish` is missing `package.description` metadata | = note: `-D clippy::cargo-common-metadata` implied by `-D warnings` -error: package `cargo_common_metadata` is missing `either package.license or package.license_file` metadata +error: package `cargo_common_metadata_fail_publish` is missing `either package.license or package.license_file` metadata -error: package `cargo_common_metadata` is missing `package.repository` metadata +error: package `cargo_common_metadata_fail_publish` is missing `package.repository` metadata -error: package `cargo_common_metadata` is missing `package.readme` metadata +error: package `cargo_common_metadata_fail_publish` is missing `package.readme` metadata -error: package `cargo_common_metadata` is missing `package.keywords` metadata +error: package `cargo_common_metadata_fail_publish` is missing `package.keywords` metadata -error: package `cargo_common_metadata` is missing `package.categories` metadata +error: package `cargo_common_metadata_fail_publish` is missing `package.categories` metadata error: aborting due to 6 previous errors diff --git a/tests/ui-cargo/cargo_common_metadata/fail_publish_true/Cargo.toml b/tests/ui-cargo/cargo_common_metadata/fail_publish_true/Cargo.toml index 7e5b88383ccc3..51858eecd0a6f 100644 --- a/tests/ui-cargo/cargo_common_metadata/fail_publish_true/Cargo.toml +++ b/tests/ui-cargo/cargo_common_metadata/fail_publish_true/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "cargo_common_metadata" +name = "cargo_common_metadata_fail_publish_true" version = "0.1.0" publish = true diff --git a/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.stderr b/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.stderr index 5e9aa8dc36a6e..be32c0dc418fa 100644 --- a/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.stderr +++ b/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.stderr @@ -1,16 +1,16 @@ -error: package `cargo_common_metadata` is missing `package.description` metadata +error: package `cargo_common_metadata_fail_publish_true` is missing `package.description` metadata | = note: `-D clippy::cargo-common-metadata` implied by `-D warnings` -error: package `cargo_common_metadata` is missing `either package.license or package.license_file` metadata +error: package `cargo_common_metadata_fail_publish_true` is missing `either package.license or package.license_file` metadata -error: package `cargo_common_metadata` is missing `package.repository` metadata +error: package `cargo_common_metadata_fail_publish_true` is missing `package.repository` metadata -error: package `cargo_common_metadata` is missing `package.readme` metadata +error: package `cargo_common_metadata_fail_publish_true` is missing `package.readme` metadata -error: package `cargo_common_metadata` is missing `package.keywords` metadata +error: package `cargo_common_metadata_fail_publish_true` is missing `package.keywords` metadata -error: package `cargo_common_metadata` is missing `package.categories` metadata +error: package `cargo_common_metadata_fail_publish_true` is missing `package.categories` metadata error: aborting due to 6 previous errors diff --git a/tests/ui-cargo/cargo_common_metadata/pass/Cargo.toml b/tests/ui-cargo/cargo_common_metadata/pass/Cargo.toml index cb4774d43a2c1..9f6e51fb4d9f0 100644 --- a/tests/ui-cargo/cargo_common_metadata/pass/Cargo.toml +++ b/tests/ui-cargo/cargo_common_metadata/pass/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "cargo_common_metadata" +name = "cargo_common_metadata_pass" version = "0.1.0" publish = false description = "A test package for the cargo_common_metadata lint" diff --git a/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/Cargo.toml b/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/Cargo.toml index 0a879c99b5bd8..828efee3a8f8b 100644 --- a/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/Cargo.toml +++ b/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "cargo_common_metadata" +name = "cargo_common_metadata_pass_publish_empty" version = "0.1.0" publish = [] diff --git a/tests/ui-cargo/cargo_common_metadata/pass_publish_false/Cargo.toml b/tests/ui-cargo/cargo_common_metadata/pass_publish_false/Cargo.toml index ae0a603299629..45a5bf7c57459 100644 --- a/tests/ui-cargo/cargo_common_metadata/pass_publish_false/Cargo.toml +++ b/tests/ui-cargo/cargo_common_metadata/pass_publish_false/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "cargo_common_metadata" +name = "cargo_common_metadata_pass_publish_false" version = "0.1.0" publish = false diff --git a/tests/ui-cargo/cargo_rust_version/fail_both_diff/Cargo.toml b/tests/ui-cargo/cargo_rust_version/fail_both_diff/Cargo.toml index 73ec29c5803bd..946d1b366f099 100644 --- a/tests/ui-cargo/cargo_rust_version/fail_both_diff/Cargo.toml +++ b/tests/ui-cargo/cargo_rust_version/fail_both_diff/Cargo.toml @@ -2,6 +2,7 @@ name = "fail-both-diff" version = "0.1.0" rust-version = "1.56" +publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/tests/ui-cargo/cargo_rust_version/fail_both_same/Cargo.toml b/tests/ui-cargo/cargo_rust_version/fail_both_same/Cargo.toml index 2d6d547e4fe3a..46b92a1050e31 100644 --- a/tests/ui-cargo/cargo_rust_version/fail_both_same/Cargo.toml +++ b/tests/ui-cargo/cargo_rust_version/fail_both_same/Cargo.toml @@ -2,6 +2,7 @@ name = "fail-both-same" version = "0.1.0" rust-version = "1.57.0" +publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/tests/ui-cargo/cargo_rust_version/fail_cargo/Cargo.toml b/tests/ui-cargo/cargo_rust_version/fail_cargo/Cargo.toml index 36a53bd829d9e..189cc9f68dc4b 100644 --- a/tests/ui-cargo/cargo_rust_version/fail_cargo/Cargo.toml +++ b/tests/ui-cargo/cargo_rust_version/fail_cargo/Cargo.toml @@ -2,6 +2,7 @@ name = "fail-cargo" version = "0.1.0" rust-version = "1.56.1" +publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/tests/ui-cargo/cargo_rust_version/fail_clippy/Cargo.toml b/tests/ui-cargo/cargo_rust_version/fail_clippy/Cargo.toml index 9f644a1a39a50..bdb7f261d9e4f 100644 --- a/tests/ui-cargo/cargo_rust_version/fail_clippy/Cargo.toml +++ b/tests/ui-cargo/cargo_rust_version/fail_clippy/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "fail-clippy" version = "0.1.0" +publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/tests/ui-cargo/cargo_rust_version/fail_file_attr/Cargo.toml b/tests/ui-cargo/cargo_rust_version/fail_file_attr/Cargo.toml index 5380e993b2936..84448ea41f647 100644 --- a/tests/ui-cargo/cargo_rust_version/fail_file_attr/Cargo.toml +++ b/tests/ui-cargo/cargo_rust_version/fail_file_attr/Cargo.toml @@ -2,6 +2,7 @@ name = "fail-file-attr" version = "0.1.0" rust-version = "1.13" +publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/tests/ui-cargo/cargo_rust_version/pass_both_same/Cargo.toml b/tests/ui-cargo/cargo_rust_version/pass_both_same/Cargo.toml index 1f9bd8f9a84e3..809c0e74875b9 100644 --- a/tests/ui-cargo/cargo_rust_version/pass_both_same/Cargo.toml +++ b/tests/ui-cargo/cargo_rust_version/pass_both_same/Cargo.toml @@ -1,7 +1,8 @@ [package] -name = "fail-both-same" +name = "pass-both-same" version = "0.1.0" rust-version = "1.13.0" +publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/tests/ui-cargo/cargo_rust_version/pass_cargo/Cargo.toml b/tests/ui-cargo/cargo_rust_version/pass_cargo/Cargo.toml index 77538027c0f87..32d404f842cf4 100644 --- a/tests/ui-cargo/cargo_rust_version/pass_cargo/Cargo.toml +++ b/tests/ui-cargo/cargo_rust_version/pass_cargo/Cargo.toml @@ -1,7 +1,8 @@ [package] -name = "fail-cargo" +name = "pass-cargo" version = "0.1.0" rust-version = "1.13.0" +publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/tests/ui-cargo/cargo_rust_version/pass_clippy/Cargo.toml b/tests/ui-cargo/cargo_rust_version/pass_clippy/Cargo.toml index 9f644a1a39a50..cc937d6e62547 100644 --- a/tests/ui-cargo/cargo_rust_version/pass_clippy/Cargo.toml +++ b/tests/ui-cargo/cargo_rust_version/pass_clippy/Cargo.toml @@ -1,6 +1,7 @@ [package] -name = "fail-clippy" +name = "pass-clippy" version = "0.1.0" +publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/tests/ui-cargo/cargo_rust_version/pass_file_attr/Cargo.toml b/tests/ui-cargo/cargo_rust_version/pass_file_attr/Cargo.toml index f0387cd90b80f..8ef689880d414 100644 --- a/tests/ui-cargo/cargo_rust_version/pass_file_attr/Cargo.toml +++ b/tests/ui-cargo/cargo_rust_version/pass_file_attr/Cargo.toml @@ -1,7 +1,8 @@ [package] -name = "fail-file-attr" +name = "pass-file-attr" version = "0.1.0" rust-version = "1.59" +publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/tests/ui-cargo/cargo_rust_version/warn_both_diff/Cargo.toml b/tests/ui-cargo/cargo_rust_version/warn_both_diff/Cargo.toml index a19d5b33fe563..e9f94594f702c 100644 --- a/tests/ui-cargo/cargo_rust_version/warn_both_diff/Cargo.toml +++ b/tests/ui-cargo/cargo_rust_version/warn_both_diff/Cargo.toml @@ -2,6 +2,7 @@ name = "warn-both-diff" version = "0.1.0" rust-version = "1.56.0" +publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/tests/ui-cargo/module_style/fail_mod/Cargo.toml b/tests/ui-cargo/module_style/fail_mod/Cargo.toml index 27b61c09fb48b..b3d36a9fb6457 100644 --- a/tests/ui-cargo/module_style/fail_mod/Cargo.toml +++ b/tests/ui-cargo/module_style/fail_mod/Cargo.toml @@ -1,7 +1,8 @@ [package] -name = "fail" +name = "fail-mod" version = "0.1.0" edition = "2018" +publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/tests/ui-cargo/module_style/fail_no_mod/Cargo.toml b/tests/ui-cargo/module_style/fail_no_mod/Cargo.toml index 27b61c09fb48b..3610d13c1f30d 100644 --- a/tests/ui-cargo/module_style/fail_no_mod/Cargo.toml +++ b/tests/ui-cargo/module_style/fail_no_mod/Cargo.toml @@ -1,7 +1,8 @@ [package] -name = "fail" +name = "fail-no-mod" version = "0.1.0" edition = "2018" +publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/tests/ui-cargo/module_style/pass_mod/Cargo.toml b/tests/ui-cargo/module_style/pass_mod/Cargo.toml index 27b61c09fb48b..1c2991695bc0c 100644 --- a/tests/ui-cargo/module_style/pass_mod/Cargo.toml +++ b/tests/ui-cargo/module_style/pass_mod/Cargo.toml @@ -1,7 +1,8 @@ [package] -name = "fail" +name = "pass-mod" version = "0.1.0" edition = "2018" +publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/tests/ui-cargo/module_style/pass_no_mod/Cargo.toml b/tests/ui-cargo/module_style/pass_no_mod/Cargo.toml index 3c0896dd2cda7..4180aaf5185cf 100644 --- a/tests/ui-cargo/module_style/pass_no_mod/Cargo.toml +++ b/tests/ui-cargo/module_style/pass_no_mod/Cargo.toml @@ -1,7 +1,8 @@ [package] -name = "pass" +name = "pass-no-mod" version = "0.1.0" edition = "2018" +publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/tests/ui-cargo/multiple_config_files/no_warn/Cargo.toml b/tests/ui-cargo/multiple_config_files/no_warn/Cargo.toml index 79c973cbfd2d5..7eb56cc4e9d97 100644 --- a/tests/ui-cargo/multiple_config_files/no_warn/Cargo.toml +++ b/tests/ui-cargo/multiple_config_files/no_warn/Cargo.toml @@ -2,6 +2,7 @@ name = "no_warn" version = "0.1.0" edition = "2021" +publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/tests/ui-cargo/multiple_config_files/warn/Cargo.toml b/tests/ui-cargo/multiple_config_files/warn/Cargo.toml index 3d5c707579bca..b4847d070aab8 100644 --- a/tests/ui-cargo/multiple_config_files/warn/Cargo.toml +++ b/tests/ui-cargo/multiple_config_files/warn/Cargo.toml @@ -2,6 +2,7 @@ name = "warn" version = "0.1.0" edition = "2021" +publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/tests/ui-cargo/multiple_config_files/warn/src/main.rs b/tests/ui-cargo/multiple_config_files/warn/src/main.rs index 2d0b4a7948c4a..e7a11a969c037 100644 --- a/tests/ui-cargo/multiple_config_files/warn/src/main.rs +++ b/tests/ui-cargo/multiple_config_files/warn/src/main.rs @@ -1,5 +1,3 @@ -// ignore-windows - fn main() { println!("Hello, world!"); } diff --git a/tests/ui-cargo/multiple_crate_versions/pass/Cargo.toml b/tests/ui-cargo/multiple_crate_versions/pass/Cargo.toml index b4b49bb369acd..6c46571c5bf6e 100644 --- a/tests/ui-cargo/multiple_crate_versions/pass/Cargo.toml +++ b/tests/ui-cargo/multiple_crate_versions/pass/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "cargo_common_metadata" +name = "multiple_crate_versions" version = "0.1.0" publish = false diff --git a/tests/ui-internal/check_clippy_version_attribute.stderr b/tests/ui-internal/check_clippy_version_attribute.stderr index 67e1a07b7f5fa..5331075885c1d 100644 --- a/tests/ui-internal/check_clippy_version_attribute.stderr +++ b/tests/ui-internal/check_clippy_version_attribute.stderr @@ -17,7 +17,7 @@ LL | #![deny(clippy::internal)] | ^^^^^^^^^^^^^^^^ = note: `#[deny(clippy::invalid_clippy_version_attribute)]` implied by `#[deny(clippy::internal)]` = help: please use a valid sematic version, see `doc/adding_lints.md` - = note: this error originates in the macro `$crate::declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::declare_tool_lint` which comes from the expansion of the macro `declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info) error: this item has an invalid `clippy::version` attribute --> $DIR/check_clippy_version_attribute.rs:48:1 @@ -32,7 +32,7 @@ LL | | } | |_^ | = help: please use a valid sematic version, see `doc/adding_lints.md` - = note: this error originates in the macro `$crate::declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::declare_tool_lint` which comes from the expansion of the macro `declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info) error: this lint is missing the `clippy::version` attribute or version value --> $DIR/check_clippy_version_attribute.rs:59:1 @@ -48,7 +48,7 @@ LL | | } | = note: `#[deny(clippy::missing_clippy_version_attribute)]` implied by `#[deny(clippy::internal)]` = help: please use a `clippy::version` attribute, see `doc/adding_lints.md` - = note: this error originates in the macro `$crate::declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::declare_tool_lint` which comes from the expansion of the macro `declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info) error: this lint is missing the `clippy::version` attribute or version value --> $DIR/check_clippy_version_attribute.rs:67:1 @@ -62,7 +62,7 @@ LL | | } | |_^ | = help: please use a `clippy::version` attribute, see `doc/adding_lints.md` - = note: this error originates in the macro `$crate::declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::declare_tool_lint` which comes from the expansion of the macro `declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 4 previous errors diff --git a/tests/ui-internal/default_lint.stderr b/tests/ui-internal/default_lint.stderr index af6735f4e4d82..8961bd4624f45 100644 --- a/tests/ui-internal/default_lint.stderr +++ b/tests/ui-internal/default_lint.stderr @@ -15,7 +15,7 @@ note: the lint level is defined here LL | #![deny(clippy::internal)] | ^^^^^^^^^^^^^^^^ = note: `#[deny(clippy::default_lint)]` implied by `#[deny(clippy::internal)]` - = note: this error originates in the macro `$crate::declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::declare_tool_lint` which comes from the expansion of the macro `declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/tests/ui-internal/if_chain_style.stderr b/tests/ui-internal/if_chain_style.stderr index d0f100f00692f..24106510e73be 100644 --- a/tests/ui-internal/if_chain_style.stderr +++ b/tests/ui-internal/if_chain_style.stderr @@ -56,7 +56,7 @@ LL | | } LL | | } | |_____^ | - = note: this error originates in the macro `__if_chain` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__if_chain` which comes from the expansion of the macro `if_chain` (in Nightly builds, run with -Z macro-backtrace for more info) error: `let` expression should be above the `if_chain!` --> $DIR/if_chain_style.rs:40:9 diff --git a/tests/ui-toml/arithmetic_allowed/arithmetic_allowed.rs b/tests/ui-toml/arithmetic_allowed/arithmetic_allowed.rs new file mode 100644 index 0000000000000..195fabdbf710b --- /dev/null +++ b/tests/ui-toml/arithmetic_allowed/arithmetic_allowed.rs @@ -0,0 +1,24 @@ +#![warn(clippy::arithmetic)] + +use core::ops::Add; + +#[derive(Clone, Copy)] +struct Point { + x: i32, + y: i32, +} + +impl Add for Point { + type Output = Self; + + fn add(self, other: Self) -> Self { + todo!() + } +} + +fn main() { + let _ = Point { x: 1, y: 0 } + Point { x: 2, y: 3 }; + + let point: Point = Point { x: 1, y: 0 }; + let _ = point + point; +} diff --git a/tests/ui-toml/arithmetic_allowed/clippy.toml b/tests/ui-toml/arithmetic_allowed/clippy.toml new file mode 100644 index 0000000000000..cc40570b12a08 --- /dev/null +++ b/tests/ui-toml/arithmetic_allowed/clippy.toml @@ -0,0 +1 @@ +arithmetic-allowed = ["Point"] diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index 1d87fd91a2532..fe5139c47680c 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -3,6 +3,7 @@ error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown fie allow-expect-in-tests allow-unwrap-in-tests allowed-scripts + arithmetic-allowed array-size-threshold avoid-breaking-exported-api await-holding-invalid-types diff --git a/tests/ui/arithmetic.fixed b/tests/ui/arithmetic.fixed new file mode 100644 index 0000000000000..a2a1c4394c21f --- /dev/null +++ b/tests/ui/arithmetic.fixed @@ -0,0 +1,27 @@ +// run-rustfix + +#![allow(clippy::unnecessary_owned_empty_strings)] +#![feature(saturating_int_impl)] +#![warn(clippy::arithmetic)] + +use core::num::{Saturating, Wrapping}; + +pub fn hard_coded_allowed() { + let _ = Saturating(0u32) + Saturating(0u32); + let _ = String::new() + ""; + let _ = Wrapping(0u32) + Wrapping(0u32); + + let saturating: Saturating = Saturating(0u32); + let string: String = String::new(); + let wrapping: Wrapping = Wrapping(0u32); + + let inferred_saturating = saturating + saturating; + let inferred_string = string + ""; + let inferred_wrapping = wrapping + wrapping; + + let _ = inferred_saturating + inferred_saturating; + let _ = inferred_string + ""; + let _ = inferred_wrapping + inferred_wrapping; +} + +fn main() {} diff --git a/tests/ui/arithmetic.rs b/tests/ui/arithmetic.rs new file mode 100644 index 0000000000000..a2a1c4394c21f --- /dev/null +++ b/tests/ui/arithmetic.rs @@ -0,0 +1,27 @@ +// run-rustfix + +#![allow(clippy::unnecessary_owned_empty_strings)] +#![feature(saturating_int_impl)] +#![warn(clippy::arithmetic)] + +use core::num::{Saturating, Wrapping}; + +pub fn hard_coded_allowed() { + let _ = Saturating(0u32) + Saturating(0u32); + let _ = String::new() + ""; + let _ = Wrapping(0u32) + Wrapping(0u32); + + let saturating: Saturating = Saturating(0u32); + let string: String = String::new(); + let wrapping: Wrapping = Wrapping(0u32); + + let inferred_saturating = saturating + saturating; + let inferred_string = string + ""; + let inferred_wrapping = wrapping + wrapping; + + let _ = inferred_saturating + inferred_saturating; + let _ = inferred_string + ""; + let _ = inferred_wrapping + inferred_wrapping; +} + +fn main() {} diff --git a/tests/ui/assertions_on_result_states.fixed b/tests/ui/assertions_on_result_states.fixed new file mode 100644 index 0000000000000..7bde72e4b6b57 --- /dev/null +++ b/tests/ui/assertions_on_result_states.fixed @@ -0,0 +1,69 @@ +// run-rustfix +#![warn(clippy::assertions_on_result_states)] + +use std::result::Result; + +struct Foo; + +#[derive(Debug)] +struct DebugFoo; + +#[derive(Copy, Clone, Debug)] +struct CopyFoo; + +macro_rules! get_ok_macro { + () => { + Ok::<_, DebugFoo>(Foo) + }; +} + +fn main() { + // test ok + let r: Result = Ok(Foo); + debug_assert!(r.is_ok()); + r.unwrap(); + + // test ok with non-debug error type + let r: Result = Ok(Foo); + assert!(r.is_ok()); + + // test temporary ok + fn get_ok() -> Result { + Ok(Foo) + } + get_ok().unwrap(); + + // test macro ok + get_ok_macro!().unwrap(); + + // test ok that shouldn't be moved + let r: Result = Ok(CopyFoo); + fn test_ref_unmoveable_ok(r: &Result) { + assert!(r.is_ok()); + } + test_ref_unmoveable_ok(&r); + assert!(r.is_ok()); + r.unwrap(); + + // test ok that is copied + let r: Result = Ok(CopyFoo); + r.unwrap(); + r.unwrap(); + + // test reference to ok + let r: Result = Ok(CopyFoo); + fn test_ref_copy_ok(r: &Result) { + r.unwrap(); + } + test_ref_copy_ok(&r); + r.unwrap(); + + // test err + let r: Result = Err(Foo); + debug_assert!(r.is_err()); + r.unwrap_err(); + + // test err with non-debug value type + let r: Result = Err(Foo); + assert!(r.is_err()); +} diff --git a/tests/ui/assertions_on_result_states.rs b/tests/ui/assertions_on_result_states.rs new file mode 100644 index 0000000000000..4c5af81efc23f --- /dev/null +++ b/tests/ui/assertions_on_result_states.rs @@ -0,0 +1,69 @@ +// run-rustfix +#![warn(clippy::assertions_on_result_states)] + +use std::result::Result; + +struct Foo; + +#[derive(Debug)] +struct DebugFoo; + +#[derive(Copy, Clone, Debug)] +struct CopyFoo; + +macro_rules! get_ok_macro { + () => { + Ok::<_, DebugFoo>(Foo) + }; +} + +fn main() { + // test ok + let r: Result = Ok(Foo); + debug_assert!(r.is_ok()); + assert!(r.is_ok()); + + // test ok with non-debug error type + let r: Result = Ok(Foo); + assert!(r.is_ok()); + + // test temporary ok + fn get_ok() -> Result { + Ok(Foo) + } + assert!(get_ok().is_ok()); + + // test macro ok + assert!(get_ok_macro!().is_ok()); + + // test ok that shouldn't be moved + let r: Result = Ok(CopyFoo); + fn test_ref_unmoveable_ok(r: &Result) { + assert!(r.is_ok()); + } + test_ref_unmoveable_ok(&r); + assert!(r.is_ok()); + r.unwrap(); + + // test ok that is copied + let r: Result = Ok(CopyFoo); + assert!(r.is_ok()); + r.unwrap(); + + // test reference to ok + let r: Result = Ok(CopyFoo); + fn test_ref_copy_ok(r: &Result) { + assert!(r.is_ok()); + } + test_ref_copy_ok(&r); + r.unwrap(); + + // test err + let r: Result = Err(Foo); + debug_assert!(r.is_err()); + assert!(r.is_err()); + + // test err with non-debug value type + let r: Result = Err(Foo); + assert!(r.is_err()); +} diff --git a/tests/ui/assertions_on_result_states.stderr b/tests/ui/assertions_on_result_states.stderr new file mode 100644 index 0000000000000..13c2dd877a976 --- /dev/null +++ b/tests/ui/assertions_on_result_states.stderr @@ -0,0 +1,40 @@ +error: called `assert!` with `Result::is_ok` + --> $DIR/assertions_on_result_states.rs:24:5 + | +LL | assert!(r.is_ok()); + | ^^^^^^^^^^^^^^^^^^ help: replace with: `r.unwrap()` + | + = note: `-D clippy::assertions-on-result-states` implied by `-D warnings` + +error: called `assert!` with `Result::is_ok` + --> $DIR/assertions_on_result_states.rs:34:5 + | +LL | assert!(get_ok().is_ok()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `get_ok().unwrap()` + +error: called `assert!` with `Result::is_ok` + --> $DIR/assertions_on_result_states.rs:37:5 + | +LL | assert!(get_ok_macro!().is_ok()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `get_ok_macro!().unwrap()` + +error: called `assert!` with `Result::is_ok` + --> $DIR/assertions_on_result_states.rs:50:5 + | +LL | assert!(r.is_ok()); + | ^^^^^^^^^^^^^^^^^^ help: replace with: `r.unwrap()` + +error: called `assert!` with `Result::is_ok` + --> $DIR/assertions_on_result_states.rs:56:9 + | +LL | assert!(r.is_ok()); + | ^^^^^^^^^^^^^^^^^^ help: replace with: `r.unwrap()` + +error: called `assert!` with `Result::is_err` + --> $DIR/assertions_on_result_states.rs:64:5 + | +LL | assert!(r.is_err()); + | ^^^^^^^^^^^^^^^^^^^ help: replace with: `r.unwrap_err()` + +error: aborting due to 6 previous errors + diff --git a/tests/ui/assign_ops.fixed b/tests/ui/assign_ops.fixed index 52b1b3afe16fe..da034b51cfdb9 100644 --- a/tests/ui/assign_ops.fixed +++ b/tests/ui/assign_ops.fixed @@ -1,5 +1,7 @@ // run-rustfix +use core::num::Wrapping; + #[allow(dead_code, unused_assignments)] #[warn(clippy::assign_op_pattern)] fn main() { @@ -18,4 +20,13 @@ fn main() { a = 6 << a; let mut s = String::new(); s += "bla"; + + // Issue #9180 + let mut a = Wrapping(0u32); + a += Wrapping(1u32); + let mut v = vec![0u32, 1u32]; + v[0] += v[1]; + let mut v = vec![Wrapping(0u32), Wrapping(1u32)]; + v[0] = v[0] + v[1]; + let _ = || v[0] = v[0] + v[1]; } diff --git a/tests/ui/assign_ops.rs b/tests/ui/assign_ops.rs index 527a46b2c2bb9..337bb02c8a612 100644 --- a/tests/ui/assign_ops.rs +++ b/tests/ui/assign_ops.rs @@ -1,5 +1,7 @@ // run-rustfix +use core::num::Wrapping; + #[allow(dead_code, unused_assignments)] #[warn(clippy::assign_op_pattern)] fn main() { @@ -18,4 +20,13 @@ fn main() { a = 6 << a; let mut s = String::new(); s = s + "bla"; + + // Issue #9180 + let mut a = Wrapping(0u32); + a = a + Wrapping(1u32); + let mut v = vec![0u32, 1u32]; + v[0] = v[0] + v[1]; + let mut v = vec![Wrapping(0u32), Wrapping(1u32)]; + v[0] = v[0] + v[1]; + let _ = || v[0] = v[0] + v[1]; } diff --git a/tests/ui/assign_ops.stderr b/tests/ui/assign_ops.stderr index 3486bd8da4d07..63a938ab4b435 100644 --- a/tests/ui/assign_ops.stderr +++ b/tests/ui/assign_ops.stderr @@ -1,5 +1,5 @@ error: manual implementation of an assign operation - --> $DIR/assign_ops.rs:7:5 + --> $DIR/assign_ops.rs:9:5 | LL | a = a + 1; | ^^^^^^^^^ help: replace it with: `a += 1` @@ -7,52 +7,64 @@ LL | a = a + 1; = note: `-D clippy::assign-op-pattern` implied by `-D warnings` error: manual implementation of an assign operation - --> $DIR/assign_ops.rs:8:5 + --> $DIR/assign_ops.rs:10:5 | LL | a = 1 + a; | ^^^^^^^^^ help: replace it with: `a += 1` error: manual implementation of an assign operation - --> $DIR/assign_ops.rs:9:5 + --> $DIR/assign_ops.rs:11:5 | LL | a = a - 1; | ^^^^^^^^^ help: replace it with: `a -= 1` error: manual implementation of an assign operation - --> $DIR/assign_ops.rs:10:5 + --> $DIR/assign_ops.rs:12:5 | LL | a = a * 99; | ^^^^^^^^^^ help: replace it with: `a *= 99` error: manual implementation of an assign operation - --> $DIR/assign_ops.rs:11:5 + --> $DIR/assign_ops.rs:13:5 | LL | a = 42 * a; | ^^^^^^^^^^ help: replace it with: `a *= 42` error: manual implementation of an assign operation - --> $DIR/assign_ops.rs:12:5 + --> $DIR/assign_ops.rs:14:5 | LL | a = a / 2; | ^^^^^^^^^ help: replace it with: `a /= 2` error: manual implementation of an assign operation - --> $DIR/assign_ops.rs:13:5 + --> $DIR/assign_ops.rs:15:5 | LL | a = a % 5; | ^^^^^^^^^ help: replace it with: `a %= 5` error: manual implementation of an assign operation - --> $DIR/assign_ops.rs:14:5 + --> $DIR/assign_ops.rs:16:5 | LL | a = a & 1; | ^^^^^^^^^ help: replace it with: `a &= 1` error: manual implementation of an assign operation - --> $DIR/assign_ops.rs:20:5 + --> $DIR/assign_ops.rs:22:5 | LL | s = s + "bla"; | ^^^^^^^^^^^^^ help: replace it with: `s += "bla"` -error: aborting due to 9 previous errors +error: manual implementation of an assign operation + --> $DIR/assign_ops.rs:26:5 + | +LL | a = a + Wrapping(1u32); + | ^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `a += Wrapping(1u32)` + +error: manual implementation of an assign operation + --> $DIR/assign_ops.rs:28:5 + | +LL | v[0] = v[0] + v[1]; + | ^^^^^^^^^^^^^^^^^^ help: replace it with: `v[0] += v[1]` + +error: aborting due to 11 previous errors diff --git a/tests/ui/crashes/ice-9238.rs b/tests/ui/crashes/ice-9238.rs new file mode 100644 index 0000000000000..ee6abd519f16e --- /dev/null +++ b/tests/ui/crashes/ice-9238.rs @@ -0,0 +1,12 @@ +#![allow(incomplete_features)] +#![feature(generic_const_exprs)] +#![warn(clippy::branches_sharing_code)] + +const fn f() -> usize { + 2 +} +const C: [f64; f()] = [0f64; f()]; + +fn main() { + let _ = if true { C[0] } else { C[1] }; +} diff --git a/tests/ui/crashes/ice-9242.rs b/tests/ui/crashes/ice-9242.rs new file mode 100644 index 0000000000000..0099e6e2f34b8 --- /dev/null +++ b/tests/ui/crashes/ice-9242.rs @@ -0,0 +1,8 @@ +enum E { + X(), + Y, +} + +fn main() { + let _ = if let E::X() = E::X() { 1 } else { 2 }; +} diff --git a/tests/ui/crate_level_checks/entrypoint_recursion.rs b/tests/ui/crate_level_checks/entrypoint_recursion.rs index 7ff5a16ed86ca..1b3bcece6f1e7 100644 --- a/tests/ui/crate_level_checks/entrypoint_recursion.rs +++ b/tests/ui/crate_level_checks/entrypoint_recursion.rs @@ -1,5 +1,4 @@ // ignore-macos -// ignore-windows #![feature(rustc_attrs)] diff --git a/tests/ui/crate_level_checks/entrypoint_recursion.stderr b/tests/ui/crate_level_checks/entrypoint_recursion.stderr index f52fc949f6c3e..459cf12a1c209 100644 --- a/tests/ui/crate_level_checks/entrypoint_recursion.stderr +++ b/tests/ui/crate_level_checks/entrypoint_recursion.stderr @@ -1,5 +1,5 @@ error: recursing into entrypoint `a` - --> $DIR/entrypoint_recursion.rs:11:5 + --> $DIR/entrypoint_recursion.rs:10:5 | LL | a(); | ^ diff --git a/tests/ui/declare_interior_mutable_const/others.rs b/tests/ui/declare_interior_mutable_const/others.rs index 62af545db503b..896596b567922 100644 --- a/tests/ui/declare_interior_mutable_const/others.rs +++ b/tests/ui/declare_interior_mutable_const/others.rs @@ -31,9 +31,25 @@ const NO_ANN: &dyn Display = &70; static STATIC_TUPLE: (AtomicUsize, String) = (ATOMIC, STRING); //^ there should be no lints on this line -// issue #8493 -thread_local! { - static THREAD_LOCAL: Cell = const { Cell::new(0) }; +mod issue_8493 { + use std::cell::Cell; + + thread_local! { + static _BAR: Cell = const { Cell::new(0) }; + } + + macro_rules! issue_8493 { + () => { + const _BAZ: Cell = Cell::new(0); //~ ERROR interior mutable + static _FOOBAR: () = { + thread_local! { + static _VAR: Cell = const { Cell::new(0) }; + } + }; + }; + } + + issue_8493!(); } fn main() {} diff --git a/tests/ui/declare_interior_mutable_const/others.stderr b/tests/ui/declare_interior_mutable_const/others.stderr index fd0689dfc4c99..1fd6d7322a76c 100644 --- a/tests/ui/declare_interior_mutable_const/others.stderr +++ b/tests/ui/declare_interior_mutable_const/others.stderr @@ -35,5 +35,16 @@ LL | declare_const!(_ONCE: Once = Once::new()); //~ ERROR interior mutable | = note: this error originates in the macro `declare_const` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 4 previous errors +error: a `const` item should never be interior mutable + --> $DIR/others.rs:43:13 + | +LL | const _BAZ: Cell = Cell::new(0); //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | issue_8493!(); + | ------------- in this macro invocation + | + = note: this error originates in the macro `issue_8493` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 5 previous errors diff --git a/tests/ui/format.fixed b/tests/ui/format.fixed index d08f8f52495ad..f4db2d20c713c 100644 --- a/tests/ui/format.fixed +++ b/tests/ui/format.fixed @@ -84,4 +84,10 @@ fn main() { let _ = x.to_string(); let _ = format!("{x:?}"); // Don't lint on debug let _ = x.to_string(); + + // Issue #9234 + let abc = "abc"; + let _ = abc.to_string(); + let xx = "xx"; + let _ = xx.to_string(); } diff --git a/tests/ui/format.rs b/tests/ui/format.rs index 4a10b580d2600..bf687cb1e96c7 100644 --- a/tests/ui/format.rs +++ b/tests/ui/format.rs @@ -86,4 +86,10 @@ fn main() { let _ = format!("{x}"); let _ = format!("{x:?}"); // Don't lint on debug let _ = format!("{y}", y = x); + + // Issue #9234 + let abc = "abc"; + let _ = format!("{abc}"); + let xx = "xx"; + let _ = format!("{xx}"); } diff --git a/tests/ui/format.stderr b/tests/ui/format.stderr index f25c7fb1ff1cb..a0f8e7d193791 100644 --- a/tests/ui/format.stderr +++ b/tests/ui/format.stderr @@ -111,5 +111,17 @@ error: useless use of `format!` LL | let _ = format!("{y}", y = x); | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()` -error: aborting due to 17 previous errors +error: useless use of `format!` + --> $DIR/format.rs:92:13 + | +LL | let _ = format!("{abc}"); + | ^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `abc.to_string()` + +error: useless use of `format!` + --> $DIR/format.rs:94:13 + | +LL | let _ = format!("{xx}"); + | ^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `xx.to_string()` + +error: aborting due to 19 previous errors diff --git a/tests/ui/match_same_arms2.rs b/tests/ui/match_same_arms2.rs index dbfeb4379d513..7aba5b447d553 100644 --- a/tests/ui/match_same_arms2.rs +++ b/tests/ui/match_same_arms2.rs @@ -1,5 +1,5 @@ #![warn(clippy::match_same_arms)] -#![allow(clippy::blacklisted_name)] +#![allow(clippy::blacklisted_name, clippy::diverging_sub_expression)] fn bar(_: T) {} fn foo() -> bool { @@ -227,4 +227,12 @@ fn main() { Some(Bar { y: 0, x: 5, .. }) => 1, _ => 200, }; + + let _ = match 0 { + 0 => todo!(), + 1 => todo!(), + 2 => core::convert::identity::(todo!()), + 3 => core::convert::identity::(todo!()), + _ => 5, + }; } diff --git a/tests/ui/mismatching_type_param_order.rs b/tests/ui/mismatching_type_param_order.rs index 8f286c9304ccb..8c0da84d8e975 100644 --- a/tests/ui/mismatching_type_param_order.rs +++ b/tests/ui/mismatching_type_param_order.rs @@ -57,4 +57,8 @@ fn main() { B: Copy, { } + + // if the types are complicated, do not lint + impl Foo<(K, V), B> {} + impl Foo<(K, V), A> {} } diff --git a/tests/ui/needless_borrow.fixed b/tests/ui/needless_borrow.fixed index 09afe2ddbbf62..bfd2725ecaaa8 100644 --- a/tests/ui/needless_borrow.fixed +++ b/tests/ui/needless_borrow.fixed @@ -158,3 +158,28 @@ fn check_expect_suppression() { #[expect(clippy::needless_borrow)] let _ = x(&&a); } + +#[allow(dead_code)] +mod issue9160 { + pub struct S { + f: F, + } + + impl S + where + F: Fn() -> T, + { + fn calls_field(&self) -> T { + (self.f)() + } + } + + impl S + where + F: FnMut() -> T, + { + fn calls_mut_field(&mut self) -> T { + (self.f)() + } + } +} diff --git a/tests/ui/needless_borrow.rs b/tests/ui/needless_borrow.rs index 3ae4722a1f898..c457d8c547188 100644 --- a/tests/ui/needless_borrow.rs +++ b/tests/ui/needless_borrow.rs @@ -158,3 +158,28 @@ fn check_expect_suppression() { #[expect(clippy::needless_borrow)] let _ = x(&&a); } + +#[allow(dead_code)] +mod issue9160 { + pub struct S { + f: F, + } + + impl S + where + F: Fn() -> T, + { + fn calls_field(&self) -> T { + (&self.f)() + } + } + + impl S + where + F: FnMut() -> T, + { + fn calls_mut_field(&mut self) -> T { + (&mut self.f)() + } + } +} diff --git a/tests/ui/needless_borrow.stderr b/tests/ui/needless_borrow.stderr index 8a2e2b9895908..66588689d8185 100644 --- a/tests/ui/needless_borrow.stderr +++ b/tests/ui/needless_borrow.stderr @@ -120,5 +120,17 @@ error: this expression creates a reference which is immediately dereferenced by LL | (&&5).foo(); | ^^^^^ help: change this to: `(&5)` -error: aborting due to 20 previous errors +error: this expression borrows a value the compiler would automatically borrow + --> $DIR/needless_borrow.rs:173:13 + | +LL | (&self.f)() + | ^^^^^^^^^ help: change this to: `(self.f)` + +error: this expression borrows a value the compiler would automatically borrow + --> $DIR/needless_borrow.rs:182:13 + | +LL | (&mut self.f)() + | ^^^^^^^^^^^^^ help: change this to: `(self.f)` + +error: aborting due to 22 previous errors diff --git a/tests/ui/obfuscated_if_else.fixed b/tests/ui/obfuscated_if_else.fixed new file mode 100644 index 0000000000000..62d932c2c6b79 --- /dev/null +++ b/tests/ui/obfuscated_if_else.fixed @@ -0,0 +1,7 @@ +// run-rustfix + +#![warn(clippy::obfuscated_if_else)] + +fn main() { + if true { "a" } else { "b" }; +} diff --git a/tests/ui/obfuscated_if_else.rs b/tests/ui/obfuscated_if_else.rs new file mode 100644 index 0000000000000..273be9092a745 --- /dev/null +++ b/tests/ui/obfuscated_if_else.rs @@ -0,0 +1,7 @@ +// run-rustfix + +#![warn(clippy::obfuscated_if_else)] + +fn main() { + true.then_some("a").unwrap_or("b"); +} diff --git a/tests/ui/obfuscated_if_else.stderr b/tests/ui/obfuscated_if_else.stderr new file mode 100644 index 0000000000000..e4180c288693f --- /dev/null +++ b/tests/ui/obfuscated_if_else.stderr @@ -0,0 +1,10 @@ +error: use of `.then_some(..).unwrap_or(..)` can be written more clearly with `if .. else ..` + --> $DIR/obfuscated_if_else.rs:6:5 + | +LL | true.then_some("a").unwrap_or("b"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { "a" } else { "b" }` + | + = note: `-D clippy::obfuscated-if-else` implied by `-D warnings` + +error: aborting due to previous error + diff --git a/tests/ui/std_instead_of_core.rs b/tests/ui/std_instead_of_core.rs index 74f05ec1f658a..6b27475de4c87 100644 --- a/tests/ui/std_instead_of_core.rs +++ b/tests/ui/std_instead_of_core.rs @@ -9,6 +9,8 @@ fn std_instead_of_core() { use std::hash::Hasher; // Absolute path use ::std::hash::Hash; + // Don't lint on `env` macro + use std::env; // Multiple imports use std::fmt::{Debug, Result}; @@ -20,10 +22,14 @@ fn std_instead_of_core() { // Types let cell = std::cell::Cell::new(8u32); let cell_absolute = ::std::cell::Cell::new(8u32); + + let _ = std::env!("PATH"); } #[warn(clippy::std_instead_of_alloc)] fn std_instead_of_alloc() { + // Only lint once. + use std::vec; use std::vec::Vec; } diff --git a/tests/ui/std_instead_of_core.stderr b/tests/ui/std_instead_of_core.stderr index 9f1644835c10d..bc49dabf5868a 100644 --- a/tests/ui/std_instead_of_core.stderr +++ b/tests/ui/std_instead_of_core.stderr @@ -16,7 +16,7 @@ LL | use ::std::hash::Hash; = help: consider importing the item from `core` error: used import from `std` instead of `core` - --> $DIR/std_instead_of_core.rs:14:20 + --> $DIR/std_instead_of_core.rs:16:20 | LL | use std::fmt::{Debug, Result}; | ^^^^^ @@ -24,7 +24,7 @@ LL | use std::fmt::{Debug, Result}; = help: consider importing the item from `core` error: used import from `std` instead of `core` - --> $DIR/std_instead_of_core.rs:14:27 + --> $DIR/std_instead_of_core.rs:16:27 | LL | use std::fmt::{Debug, Result}; | ^^^^^^ @@ -32,7 +32,7 @@ LL | use std::fmt::{Debug, Result}; = help: consider importing the item from `core` error: used import from `std` instead of `core` - --> $DIR/std_instead_of_core.rs:17:15 + --> $DIR/std_instead_of_core.rs:19:15 | LL | let ptr = std::ptr::null::(); | ^^^^^^^^^^^^^^^^^^^^^ @@ -40,7 +40,7 @@ LL | let ptr = std::ptr::null::(); = help: consider importing the item from `core` error: used import from `std` instead of `core` - --> $DIR/std_instead_of_core.rs:18:19 + --> $DIR/std_instead_of_core.rs:20:19 | LL | let ptr_mut = ::std::ptr::null_mut::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -48,7 +48,7 @@ LL | let ptr_mut = ::std::ptr::null_mut::(); = help: consider importing the item from `core` error: used import from `std` instead of `core` - --> $DIR/std_instead_of_core.rs:21:16 + --> $DIR/std_instead_of_core.rs:23:16 | LL | let cell = std::cell::Cell::new(8u32); | ^^^^^^^^^^^^^^^ @@ -56,7 +56,7 @@ LL | let cell = std::cell::Cell::new(8u32); = help: consider importing the item from `core` error: used import from `std` instead of `core` - --> $DIR/std_instead_of_core.rs:22:25 + --> $DIR/std_instead_of_core.rs:24:25 | LL | let cell_absolute = ::std::cell::Cell::new(8u32); | ^^^^^^^^^^^^^^^^^ @@ -64,16 +64,24 @@ LL | let cell_absolute = ::std::cell::Cell::new(8u32); = help: consider importing the item from `core` error: used import from `std` instead of `alloc` - --> $DIR/std_instead_of_core.rs:27:9 + --> $DIR/std_instead_of_core.rs:32:9 + | +LL | use std::vec; + | ^^^^^^^^ + | + = note: `-D clippy::std-instead-of-alloc` implied by `-D warnings` + = help: consider importing the item from `alloc` + +error: used import from `std` instead of `alloc` + --> $DIR/std_instead_of_core.rs:33:9 | LL | use std::vec::Vec; | ^^^^^^^^^^^^^ | - = note: `-D clippy::std-instead-of-alloc` implied by `-D warnings` = help: consider importing the item from `alloc` error: used import from `alloc` instead of `core` - --> $DIR/std_instead_of_core.rs:32:9 + --> $DIR/std_instead_of_core.rs:38:9 | LL | use alloc::slice::from_ref; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -81,5 +89,5 @@ LL | use alloc::slice::from_ref; = note: `-D clippy::alloc-instead-of-core` implied by `-D warnings` = help: consider importing the item from `core` -error: aborting due to 10 previous errors +error: aborting due to 11 previous errors diff --git a/tests/ui/unused_self.rs b/tests/ui/unused_self.rs index 08bf58fec7c3e..92e8e1dba69dd 100644 --- a/tests/ui/unused_self.rs +++ b/tests/ui/unused_self.rs @@ -53,8 +53,17 @@ mod unused_self_allow { // shouldn't trigger fn unused_self_move(self) {} } + + pub struct D; + + impl D { + // shouldn't trigger for public methods + pub fn unused_self_move(self) {} + } } +pub use unused_self_allow::D; + mod used_self { use std::pin::Pin; From 307b800f27aaab6363ad5ca09009a71852f6d7cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Thu, 28 Jul 2022 22:08:48 +0200 Subject: [PATCH 12/62] unwrap_used: Fix doc to not recommend expect when expect_used is not allowed --- clippy_lints/src/methods/mod.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 202fbc1f7f668..05f20e6cb9c59 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -197,13 +197,22 @@ declare_clippy_lint! { /// result.unwrap(); /// ``` /// - /// Use instead: + /// If [expect_used](#expect_used) is allowed, instead: /// ```rust /// # let option = Some(1); /// # let result: Result = Ok(1); /// option.expect("more helpful message"); /// result.expect("more helpful message"); /// ``` + /// + /// Otherwise try using + /// ```rust + /// option?; + /// + /// // or + /// + /// result?; + /// ``` #[clippy::version = "1.45.0"] pub UNWRAP_USED, restriction, From 1fd9f2d2716689022a0473f8bce5d2f40275bd64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Thu, 28 Jul 2022 22:27:50 +0200 Subject: [PATCH 13/62] Fix tests --- clippy_lints/src/methods/mod.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 05f20e6cb9c59..06e7af57ee17a 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -206,7 +206,9 @@ declare_clippy_lint! { /// ``` /// /// Otherwise try using - /// ```rust + /// ```rust,ignore + /// # let option = Some(1); + /// # let result: Result = Ok(1); /// option?; /// /// // or From ea25ef10cf942172e09b463c305b934fabccc8e2 Mon Sep 17 00:00:00 2001 From: Andy Caldwell Date: Thu, 28 Jul 2022 23:05:24 +0100 Subject: [PATCH 14/62] Harden duplicates checking and add tests --- clippy_lints/src/utils/conf.rs | 12 +++++++++--- tests/ui-toml/conf_deprecated_key/clippy.toml | 2 +- tests/ui-toml/duplicated_keys/clippy.toml | 5 +++++ tests/ui-toml/duplicated_keys/duplicated_keys.rs | 1 + tests/ui-toml/duplicated_keys/duplicated_keys.stderr | 8 ++++++++ 5 files changed, 24 insertions(+), 4 deletions(-) create mode 100644 tests/ui-toml/duplicated_keys/clippy.toml create mode 100644 tests/ui-toml/duplicated_keys/duplicated_keys.rs create mode 100644 tests/ui-toml/duplicated_keys/duplicated_keys.stderr diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 60f4b388761dd..1dd22cb3185e5 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -92,8 +92,8 @@ impl fmt::Display for ConfError { impl Error for ConfError {} -fn conf_error(s: String) -> Box { - Box::new(ConfError(s)) +fn conf_error(s: impl Into) -> Box { + Box::new(ConfError(s.into())) } macro_rules! define_Conf { @@ -154,7 +154,13 @@ macro_rules! define_Conf { $name = Some(value); // $new_conf is the same as one of the defined `$name`s, so // this variable is defined in line 2 of this function. - $($new_conf = Some(value);)? + $(match $new_conf { + Some(_) => errors.push(conf_error(concat!( + "duplicate field `", stringify!($new_conf), + "` (provided as `", stringify!($name), "`)" + ))), + None => $new_conf = Some(value), + })? }, } } diff --git a/tests/ui-toml/conf_deprecated_key/clippy.toml b/tests/ui-toml/conf_deprecated_key/clippy.toml index 138160d7ac8bf..30cd9eecd98d3 100644 --- a/tests/ui-toml/conf_deprecated_key/clippy.toml +++ b/tests/ui-toml/conf_deprecated_key/clippy.toml @@ -1,4 +1,4 @@ -# that one is an error +# that one is a warning cyclomatic-complexity-threshold = 2 # that one is white-listed diff --git a/tests/ui-toml/duplicated_keys/clippy.toml b/tests/ui-toml/duplicated_keys/clippy.toml new file mode 100644 index 0000000000000..63a893cc6c795 --- /dev/null +++ b/tests/ui-toml/duplicated_keys/clippy.toml @@ -0,0 +1,5 @@ +cognitive-complexity-threshold = 2 +# This is the deprecated name for the same key +cyclomatic-complexity-threshold = 3 +# Check we get duplication warning regardless of order +cognitive-complexity-threshold = 4 diff --git a/tests/ui-toml/duplicated_keys/duplicated_keys.rs b/tests/ui-toml/duplicated_keys/duplicated_keys.rs new file mode 100644 index 0000000000000..f328e4d9d04c3 --- /dev/null +++ b/tests/ui-toml/duplicated_keys/duplicated_keys.rs @@ -0,0 +1 @@ +fn main() {} diff --git a/tests/ui-toml/duplicated_keys/duplicated_keys.stderr b/tests/ui-toml/duplicated_keys/duplicated_keys.stderr new file mode 100644 index 0000000000000..d99490a242d4f --- /dev/null +++ b/tests/ui-toml/duplicated_keys/duplicated_keys.stderr @@ -0,0 +1,8 @@ +error: error reading Clippy's configuration file `$DIR/clippy.toml`: duplicate field `cognitive_complexity_threshold` (provided as `cyclomatic_complexity_threshold`) + +error: error reading Clippy's configuration file `$DIR/clippy.toml`: duplicate field `cognitive-complexity-threshold` + +warning: error reading Clippy's configuration file `$DIR/clippy.toml`: deprecated field `cyclomatic-complexity-threshold`. Please use `cognitive-complexity-threshold` instead + +error: aborting due to 2 previous errors; 1 warning emitted + From 1a6f02b1f25e497e9a9da5af955794a81307af3c Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 28 Jul 2022 10:31:04 +1000 Subject: [PATCH 15/62] Remove `TreeAndSpacing`. A `TokenStream` contains a `Lrc>`. But this is not quite right. `Spacing` makes sense for `TokenTree::Token`, but does not make sense for `TokenTree::Delimited`, because a `TokenTree::Delimited` cannot be joined with another `TokenTree`. This commit fixes this problem, by adding `Spacing` to `TokenTree::Token`, changing `TokenStream` to contain a `Lrc>`, and removing the `TreeAndSpacing` typedef. The commit removes these two impls: - `impl From for TokenStream` - `impl From for TreeAndSpacing` These were useful, but also resulted in code with many `.into()` calls that was hard to read, particularly for anyone not highly familiar with the relevant types. This commit makes some other changes to compensate: - `TokenTree::token()` becomes `TokenTree::token_{alone,joint}()`. - `TokenStream::token_{alone,joint}()` are added. - `TokenStream::delimited` is added. This results in things like this: ```rust TokenTree::token(token::Semi, stmt.span).into() ``` changing to this: ```rust TokenStream::token_alone(token::Semi, stmt.span) ``` This makes the type of the result, and its spacing, clearer. These changes also simplifies `Cursor` and `CursorRef`, because they no longer need to distinguish between `next` and `next_with_spacing`. --- clippy_lints/src/crate_in_macro_def.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/crate_in_macro_def.rs b/clippy_lints/src/crate_in_macro_def.rs index f6ec8fe7edc19..454ec23388af9 100644 --- a/clippy_lints/src/crate_in_macro_def.rs +++ b/clippy_lints/src/crate_in_macro_def.rs @@ -110,14 +110,14 @@ fn contains_unhygienic_crate_reference(tts: &TokenStream) -> Option { fn is_crate_keyword(tt: &TokenTree) -> Option { if_chain! { - if let TokenTree::Token(Token { kind: TokenKind::Ident(symbol, _), span }) = tt; + if let TokenTree::Token(Token { kind: TokenKind::Ident(symbol, _), span }, _) = tt; if symbol.as_str() == "crate"; then { Some(*span) } else { None } } } fn is_token(tt: &TokenTree, kind: &TokenKind) -> bool { - if let TokenTree::Token(Token { kind: other, .. }) = tt { + if let TokenTree::Token(Token { kind: other, .. }, _) = tt { kind == other } else { false From 2f48257cfb1732f6824fed7da10c559b01e9554e Mon Sep 17 00:00:00 2001 From: Andy Caldwell Date: Wed, 8 Jun 2022 16:20:30 +0100 Subject: [PATCH 16/62] Rename "blacklisted name" to "disallowed name" throughout --- CHANGELOG.md | 5 +- README.md | 2 +- book/src/configuration.md | 2 +- ...blacklisted_name.rs => disallowed_name.rs} | 26 +++--- clippy_lints/src/lib.register_all.rs | 2 +- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/lib.register_style.rs | 2 +- clippy_lints/src/lib.rs | 6 +- clippy_lints/src/renamed_lints.rs | 1 + clippy_lints/src/utils/conf.rs | 21 +++-- .../internal_lints/metadata_collector.rs | 4 +- tests/ui-toml/bad_toml_type/clippy.toml | 2 +- .../bad_toml_type/conf_bad_type.stderr | 2 +- .../blacklisted_names.stderr | 16 ---- .../blacklisted_names_append/clippy.toml | 1 - .../blacklisted_names.stderr | 10 --- .../blacklisted_names_replace/clippy.toml | 1 - .../disallowed_names_append/clippy.toml | 1 + .../disallowed_names.rs} | 4 +- .../disallowed_names.stderr | 16 ++++ .../disallowed_names_replace/clippy.toml | 1 + .../disallowed_names.rs} | 4 +- .../disallowed_names.stderr | 10 +++ tests/ui-toml/toml_blacklist/clippy.toml | 1 - .../conf_french_blacklisted_name.stderr | 46 ---------- tests/ui-toml/toml_disallow/clippy.toml | 1 + .../conf_french_disallowed_name.rs} | 2 +- .../conf_french_disallowed_name.stderr | 46 ++++++++++ .../toml_unknown_key/conf_unknown_key.stderr | 1 + tests/ui/blacklisted_name.stderr | 88 ------------------- tests/ui/borrow_box.rs | 2 +- tests/ui/box_collection.rs | 7 +- tests/ui/box_collection.stderr | 18 ++-- tests/ui/crashes/ice-2760.rs | 7 +- tests/ui/crashes/ice-3462.rs | 2 +- tests/ui/crashes/regressions.rs | 2 +- ...blacklisted_name.rs => disallowed_name.rs} | 4 +- tests/ui/disallowed_name.stderr | 88 +++++++++++++++++++ tests/ui/if_same_then_else.rs | 2 +- tests/ui/if_same_then_else2.rs | 2 +- tests/ui/iter_skip_next.fixed | 2 +- tests/ui/iter_skip_next.rs | 2 +- tests/ui/let_if_seq.rs | 2 +- tests/ui/manual_ok_or.fixed | 2 +- tests/ui/manual_ok_or.rs | 2 +- tests/ui/match_same_arms2.rs | 2 +- tests/ui/methods.rs | 2 +- tests/ui/mismatching_type_param_order.rs | 2 +- tests/ui/mixed_read_write_in_expression.rs | 2 +- tests/ui/op_ref.rs | 2 +- tests/ui/rc_mutex.rs | 2 +- tests/ui/redundant_allocation.rs | 2 +- tests/ui/redundant_allocation_fixable.fixed | 2 +- tests/ui/redundant_allocation_fixable.rs | 2 +- tests/ui/rename.fixed | 2 + tests/ui/rename.rs | 2 + tests/ui/rename.stderr | 78 ++++++++-------- tests/ui/skip_while_next.rs | 2 +- tests/ui/swap.fixed | 2 +- tests/ui/swap.rs | 2 +- tests/ui/trivially_copy_pass_by_ref.rs | 2 +- tests/ui/used_underscore_binding.rs | 2 +- 62 files changed, 294 insertions(+), 286 deletions(-) rename clippy_lints/src/{blacklisted_name.rs => disallowed_name.rs} (72%) delete mode 100644 tests/ui-toml/blacklisted_names_append/blacklisted_names.stderr delete mode 100644 tests/ui-toml/blacklisted_names_append/clippy.toml delete mode 100644 tests/ui-toml/blacklisted_names_replace/blacklisted_names.stderr delete mode 100644 tests/ui-toml/blacklisted_names_replace/clippy.toml create mode 100644 tests/ui-toml/disallowed_names_append/clippy.toml rename tests/ui-toml/{blacklisted_names_replace/blacklisted_names.rs => disallowed_names_append/disallowed_names.rs} (72%) create mode 100644 tests/ui-toml/disallowed_names_append/disallowed_names.stderr create mode 100644 tests/ui-toml/disallowed_names_replace/clippy.toml rename tests/ui-toml/{blacklisted_names_append/blacklisted_names.rs => disallowed_names_replace/disallowed_names.rs} (72%) create mode 100644 tests/ui-toml/disallowed_names_replace/disallowed_names.stderr delete mode 100644 tests/ui-toml/toml_blacklist/clippy.toml delete mode 100644 tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.stderr create mode 100644 tests/ui-toml/toml_disallow/clippy.toml rename tests/ui-toml/{toml_blacklist/conf_french_blacklisted_name.rs => toml_disallow/conf_french_disallowed_name.rs} (90%) create mode 100644 tests/ui-toml/toml_disallow/conf_french_disallowed_name.stderr delete mode 100644 tests/ui/blacklisted_name.stderr rename tests/ui/{blacklisted_name.rs => disallowed_name.rs} (90%) create mode 100644 tests/ui/disallowed_name.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 2278a8dc16ba0..d3d4d5a47844e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -965,7 +965,7 @@ Released 2021-09-09 [#7407](https://github.com/rust-lang/rust-clippy/pull/7407) * [`redundant_allocation`]: Now additionally supports the `Arc<>` type [#7308](https://github.com/rust-lang/rust-clippy/pull/7308) -* [`blacklisted_name`]: Now allows blacklisted names in test code +* [`disallowed_name`]: Now allows disallowed names in test code [#7379](https://github.com/rust-lang/rust-clippy/pull/7379) * [`redundant_closure`]: Suggests `&mut` for `FnMut` [#7437](https://github.com/rust-lang/rust-clippy/pull/7437) @@ -2066,7 +2066,7 @@ Released 2020-08-27 [#5692](https://github.com/rust-lang/rust-clippy/pull/5692) * [`if_same_then_else`]: Don't assume multiplication is always commutative [#5702](https://github.com/rust-lang/rust-clippy/pull/5702) -* [`blacklisted_name`]: Remove `bar` from the default configuration +* [`disallowed_name`]: Remove `bar` from the default configuration [#5712](https://github.com/rust-lang/rust-clippy/pull/5712) * [`redundant_pattern_matching`]: Avoid suggesting non-`const fn` calls in const contexts [#5724](https://github.com/rust-lang/rust-clippy/pull/5724) @@ -3522,6 +3522,7 @@ Released 2018-09-13 [`derive_partial_eq_without_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_partial_eq_without_eq [`disallowed_method`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_method [`disallowed_methods`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_methods +[`disallowed_name`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_name [`disallowed_script_idents`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_script_idents [`disallowed_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_type [`disallowed_types`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_types diff --git a/README.md b/README.md index 2c3defeaa8307..1193771ff736b 100644 --- a/README.md +++ b/README.md @@ -144,7 +144,7 @@ value` mapping e.g. ```toml avoid-breaking-exported-api = false -blacklisted-names = ["toto", "tata", "titi"] +disallowed-names = ["toto", "tata", "titi"] cognitive-complexity-threshold = 30 ``` diff --git a/book/src/configuration.md b/book/src/configuration.md index 6e295ac3181dd..77f1d2e8797a3 100644 --- a/book/src/configuration.md +++ b/book/src/configuration.md @@ -7,7 +7,7 @@ basic `variable = value` mapping eg. ```toml avoid-breaking-exported-api = false -blacklisted-names = ["toto", "tata", "titi"] +disallowed-names = ["toto", "tata", "titi"] cognitive-complexity-threshold = 30 ``` diff --git a/clippy_lints/src/blacklisted_name.rs b/clippy_lints/src/disallowed_name.rs similarity index 72% rename from clippy_lints/src/blacklisted_name.rs rename to clippy_lints/src/disallowed_name.rs index 1600fb25d89e2..98735ce7db187 100644 --- a/clippy_lints/src/blacklisted_name.rs +++ b/clippy_lints/src/disallowed_name.rs @@ -6,7 +6,7 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; declare_clippy_lint! { /// ### What it does - /// Checks for usage of blacklisted names for variables, such + /// Checks for usage of disallowed names for variables, such /// as `foo`. /// /// ### Why is this bad? @@ -18,21 +18,21 @@ declare_clippy_lint! { /// let foo = 3.14; /// ``` #[clippy::version = "pre 1.29.0"] - pub BLACKLISTED_NAME, + pub DISALLOWED_NAME, style, - "usage of a blacklisted/placeholder name" + "usage of a disallowed/placeholder name" } #[derive(Clone, Debug)] -pub struct BlacklistedName { - blacklist: FxHashSet, +pub struct DisallowedName { + disallow: FxHashSet, test_modules_deep: u32, } -impl BlacklistedName { - pub fn new(blacklist: FxHashSet) -> Self { +impl DisallowedName { + pub fn new(disallow: FxHashSet) -> Self { Self { - blacklist, + disallow, test_modules_deep: 0, } } @@ -42,9 +42,9 @@ impl BlacklistedName { } } -impl_lint_pass!(BlacklistedName => [BLACKLISTED_NAME]); +impl_lint_pass!(DisallowedName => [DISALLOWED_NAME]); -impl<'tcx> LateLintPass<'tcx> for BlacklistedName { +impl<'tcx> LateLintPass<'tcx> for DisallowedName { fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { if is_test_module_or_function(cx.tcx, item) { self.test_modules_deep = self.test_modules_deep.saturating_add(1); @@ -58,12 +58,12 @@ impl<'tcx> LateLintPass<'tcx> for BlacklistedName { } if let PatKind::Binding(.., ident, _) = pat.kind { - if self.blacklist.contains(&ident.name.to_string()) { + if self.disallow.contains(&ident.name.to_string()) { span_lint( cx, - BLACKLISTED_NAME, + DISALLOWED_NAME, ident.span, - &format!("use of a blacklisted/placeholder name `{}`", ident.name), + &format!("use of a disallowed/placeholder name `{}`", ident.name), ); } } diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index 5be1c417bf8f6..d8b6aa9793f78 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -16,7 +16,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(await_holding_invalid::AWAIT_HOLDING_INVALID_TYPE), LintId::of(await_holding_invalid::AWAIT_HOLDING_LOCK), LintId::of(await_holding_invalid::AWAIT_HOLDING_REFCELL_REF), - LintId::of(blacklisted_name::BLACKLISTED_NAME), LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS), LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON), LintId::of(booleans::LOGIC_BUG), @@ -47,6 +46,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(derive::DERIVE_ORD_XOR_PARTIAL_ORD), LintId::of(derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ), LintId::of(disallowed_methods::DISALLOWED_METHODS), + LintId::of(disallowed_name::DISALLOWED_NAME), LintId::of(disallowed_types::DISALLOWED_TYPES), LintId::of(doc::MISSING_SAFETY_DOC), LintId::of(doc::NEEDLESS_DOCTEST_MAIN), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 99bde35cf152b..562c755d10f7f 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -55,7 +55,6 @@ store.register_lints(&[ await_holding_invalid::AWAIT_HOLDING_INVALID_TYPE, await_holding_invalid::AWAIT_HOLDING_LOCK, await_holding_invalid::AWAIT_HOLDING_REFCELL_REF, - blacklisted_name::BLACKLISTED_NAME, blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS, bool_assert_comparison::BOOL_ASSERT_COMPARISON, booleans::LOGIC_BUG, @@ -116,6 +115,7 @@ store.register_lints(&[ derive::EXPL_IMPL_CLONE_ON_COPY, derive::UNSAFE_DERIVE_DESERIALIZE, disallowed_methods::DISALLOWED_METHODS, + disallowed_name::DISALLOWED_NAME, disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS, disallowed_types::DISALLOWED_TYPES, doc::DOC_MARKDOWN, diff --git a/clippy_lints/src/lib.register_style.rs b/clippy_lints/src/lib.register_style.rs index e029a5235e720..615a86a27e5bf 100644 --- a/clippy_lints/src/lib.register_style.rs +++ b/clippy_lints/src/lib.register_style.rs @@ -5,7 +5,6 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS), LintId::of(assertions_on_result_states::ASSERTIONS_ON_RESULT_STATES), - LintId::of(blacklisted_name::BLACKLISTED_NAME), LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS), LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON), LintId::of(casts::FN_TO_NUMERIC_CAST), @@ -18,6 +17,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(dereference::NEEDLESS_BORROW), LintId::of(derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ), LintId::of(disallowed_methods::DISALLOWED_METHODS), + LintId::of(disallowed_name::DISALLOWED_NAME), LintId::of(disallowed_types::DISALLOWED_TYPES), LintId::of(doc::MISSING_SAFETY_DOC), LintId::of(doc::NEEDLESS_DOCTEST_MAIN), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 54b0346b76735..ca398038f3e4b 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -177,7 +177,6 @@ mod assertions_on_result_states; mod async_yields_async; mod attrs; mod await_holding_invalid; -mod blacklisted_name; mod blocks_in_if_conditions; mod bool_assert_comparison; mod booleans; @@ -205,6 +204,7 @@ mod dereference; mod derivable_impls; mod derive; mod disallowed_methods; +mod disallowed_name; mod disallowed_script_idents; mod disallowed_types; mod doc; @@ -683,8 +683,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(swap::Swap)); store.register_late_pass(|| Box::new(overflow_check_conditional::OverflowCheckConditional)); store.register_late_pass(|| Box::new(new_without_default::NewWithoutDefault::default())); - let blacklisted_names = conf.blacklisted_names.iter().cloned().collect::>(); - store.register_late_pass(move || Box::new(blacklisted_name::BlacklistedName::new(blacklisted_names.clone()))); + let disallowed_names = conf.disallowed_names.iter().cloned().collect::>(); + store.register_late_pass(move || Box::new(disallowed_name::DisallowedName::new(disallowed_names.clone()))); let too_many_arguments_threshold = conf.too_many_arguments_threshold; let too_many_lines_threshold = conf.too_many_lines_threshold; store.register_late_pass(move || { diff --git a/clippy_lints/src/renamed_lints.rs b/clippy_lints/src/renamed_lints.rs index ba03ef9372118..f06af29e1e23b 100644 --- a/clippy_lints/src/renamed_lints.rs +++ b/clippy_lints/src/renamed_lints.rs @@ -5,6 +5,7 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[ ("clippy::block_in_if_condition_expr", "clippy::blocks_in_if_conditions"), ("clippy::block_in_if_condition_stmt", "clippy::blocks_in_if_conditions"), ("clippy::box_vec", "clippy::box_collection"), + ("clippy::blacklisted_name", "clippy::disallowed_name"), ("clippy::const_static_lifetime", "clippy::redundant_static_lifetimes"), ("clippy::cyclomatic_complexity", "clippy::cognitive_complexity"), ("clippy::disallowed_method", "clippy::disallowed_methods"), diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 1dd22cb3185e5..5a3fe7f8966d9 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -30,7 +30,7 @@ const DEFAULT_DOC_VALID_IDENTS: &[&str] = &[ "MinGW", "CamelCase", ]; -const DEFAULT_BLACKLISTED_NAMES: &[&str] = &["foo", "baz", "quux"]; +const DEFAULT_DISALLOWED_NAMES: &[&str] = &["foo", "baz", "quux"]; /// Holds information used by `MISSING_ENFORCED_IMPORT_RENAMES` lint. #[derive(Clone, Debug, Deserialize)] @@ -159,7 +159,7 @@ macro_rules! define_Conf { "duplicate field `", stringify!($new_conf), "` (provided as `", stringify!($name), "`)" ))), - None => $new_conf = Some(value), + None => $new_conf = $name.clone(), })? }, } @@ -217,12 +217,11 @@ define_Conf! { /// /// The minimum rust version that the project supports (msrv: Option = None), - /// Lint: BLACKLISTED_NAME. + /// DEPRECATED LINT: BLACKLISTED_NAME. /// - /// The list of blacklisted names to lint about. NB: `bar` is not here since it has legitimate uses. The value - /// `".."` can be used as part of the list to indicate, that the configured values should be appended to the - /// default configuration of Clippy. By default any configuraction will replace the default value. - (blacklisted_names: Vec = super::DEFAULT_BLACKLISTED_NAMES.iter().map(ToString::to_string).collect()), + /// Use the Disallowed Names lint instead + #[conf_deprecated("Please use `disallowed-names` instead", disallowed_names)] + (blacklisted_names: Vec = Vec::new()), /// Lint: COGNITIVE_COMPLEXITY. /// /// The maximum cognitive complexity a function can have @@ -232,6 +231,12 @@ define_Conf! { /// Use the Cognitive Complexity lint instead. #[conf_deprecated("Please use `cognitive-complexity-threshold` instead", cognitive_complexity_threshold)] (cyclomatic_complexity_threshold: u64 = 25), + /// Lint: DISALLOWED_NAME. + /// + /// The list of disallowed names to lint about. NB: `bar` is not here since it has legitimate uses. The value + /// `".."` can be used as part of the list to indicate, that the configured values should be appended to the + /// default configuration of Clippy. By default any configuration will replace the default value. + (disallowed_names: Vec = super::DEFAULT_DISALLOWED_NAMES.iter().map(ToString::to_string).collect()), /// Lint: DOC_MARKDOWN. /// /// The list of words this lint should not consider as identifiers needing ticks. The value @@ -434,7 +439,7 @@ pub fn read(path: &Path) -> TryConf { match toml::from_str::(&content) { 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.blacklisted_names, DEFAULT_BLACKLISTED_NAMES); + extend_vec_if_indicator_present(&mut conf.conf.disallowed_names, DEFAULT_DISALLOWED_NAMES); conf }, diff --git a/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/clippy_lints/src/utils/internal_lints/metadata_collector.rs index 92934c16d4b40..92cf42c7ad43f 100644 --- a/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ b/clippy_lints/src/utils/internal_lints/metadata_collector.rs @@ -619,7 +619,7 @@ impl<'hir> LateLintPass<'hir> for MetadataCollector { if_chain! { // item validation if is_lint_ref_type(cx, ty); - // blacklist check + // disallow check let lint_name = sym_to_string(item.ident.name).to_ascii_lowercase(); if !BLACK_LISTED_LINTS.contains(&lint_name.as_str()); // metadata extraction @@ -644,7 +644,7 @@ impl<'hir> LateLintPass<'hir> for MetadataCollector { if_chain! { if is_deprecated_lint(cx, ty); - // blacklist check + // disallow check let lint_name = sym_to_string(item.ident.name).to_ascii_lowercase(); if !BLACK_LISTED_LINTS.contains(&lint_name.as_str()); // Metadata the little we can get from a deprecated lint diff --git a/tests/ui-toml/bad_toml_type/clippy.toml b/tests/ui-toml/bad_toml_type/clippy.toml index 168675394d7f4..d48bab08f690b 100644 --- a/tests/ui-toml/bad_toml_type/clippy.toml +++ b/tests/ui-toml/bad_toml_type/clippy.toml @@ -1 +1 @@ -blacklisted-names = 42 +disallowed-names = 42 diff --git a/tests/ui-toml/bad_toml_type/conf_bad_type.stderr b/tests/ui-toml/bad_toml_type/conf_bad_type.stderr index c7bc261de6c5a..e3ec60192040e 100644 --- a/tests/ui-toml/bad_toml_type/conf_bad_type.stderr +++ b/tests/ui-toml/bad_toml_type/conf_bad_type.stderr @@ -1,4 +1,4 @@ -error: error reading Clippy's configuration file `$DIR/clippy.toml`: invalid type: integer `42`, expected a sequence for key `blacklisted-names` +error: error reading Clippy's configuration file `$DIR/clippy.toml`: invalid type: integer `42`, expected a sequence for key `disallowed-names` error: aborting due to previous error diff --git a/tests/ui-toml/blacklisted_names_append/blacklisted_names.stderr b/tests/ui-toml/blacklisted_names_append/blacklisted_names.stderr deleted file mode 100644 index 9169bb0e866ac..0000000000000 --- a/tests/ui-toml/blacklisted_names_append/blacklisted_names.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error: use of a blacklisted/placeholder name `foo` - --> $DIR/blacklisted_names.rs:5:9 - | -LL | let foo = "bar"; - | ^^^ - | - = note: `-D clippy::blacklisted-name` implied by `-D warnings` - -error: use of a blacklisted/placeholder name `ducks` - --> $DIR/blacklisted_names.rs:7:9 - | -LL | let ducks = ["quack", "quack"]; - | ^^^^^ - -error: aborting due to 2 previous errors - diff --git a/tests/ui-toml/blacklisted_names_append/clippy.toml b/tests/ui-toml/blacklisted_names_append/clippy.toml deleted file mode 100644 index 0e052ef50f07b..0000000000000 --- a/tests/ui-toml/blacklisted_names_append/clippy.toml +++ /dev/null @@ -1 +0,0 @@ -blacklisted-names = ["ducks", ".."] diff --git a/tests/ui-toml/blacklisted_names_replace/blacklisted_names.stderr b/tests/ui-toml/blacklisted_names_replace/blacklisted_names.stderr deleted file mode 100644 index ec6f7f084f2a5..0000000000000 --- a/tests/ui-toml/blacklisted_names_replace/blacklisted_names.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error: use of a blacklisted/placeholder name `ducks` - --> $DIR/blacklisted_names.rs:7:9 - | -LL | let ducks = ["quack", "quack"]; - | ^^^^^ - | - = note: `-D clippy::blacklisted-name` implied by `-D warnings` - -error: aborting due to previous error - diff --git a/tests/ui-toml/blacklisted_names_replace/clippy.toml b/tests/ui-toml/blacklisted_names_replace/clippy.toml deleted file mode 100644 index 4582f1c06674c..0000000000000 --- a/tests/ui-toml/blacklisted_names_replace/clippy.toml +++ /dev/null @@ -1 +0,0 @@ -blacklisted-names = ["ducks"] diff --git a/tests/ui-toml/disallowed_names_append/clippy.toml b/tests/ui-toml/disallowed_names_append/clippy.toml new file mode 100644 index 0000000000000..6df96a3c214bd --- /dev/null +++ b/tests/ui-toml/disallowed_names_append/clippy.toml @@ -0,0 +1 @@ +disallowed-names = ["ducks", ".."] diff --git a/tests/ui-toml/blacklisted_names_replace/blacklisted_names.rs b/tests/ui-toml/disallowed_names_append/disallowed_names.rs similarity index 72% rename from tests/ui-toml/blacklisted_names_replace/blacklisted_names.rs rename to tests/ui-toml/disallowed_names_append/disallowed_names.rs index fb2395cf90be3..939d48cb677a5 100644 --- a/tests/ui-toml/blacklisted_names_replace/blacklisted_names.rs +++ b/tests/ui-toml/disallowed_names_append/disallowed_names.rs @@ -1,9 +1,9 @@ -#[warn(clippy::blacklisted_name)] +#[warn(clippy::disallowed_name)] fn main() { // `foo` is part of the default configuration let foo = "bar"; - // `ducks` was unrightfully blacklisted + // `ducks` was unrightfully disallowed let ducks = ["quack", "quack"]; // `fox` is okay let fox = ["what", "does", "the", "fox", "say", "?"]; diff --git a/tests/ui-toml/disallowed_names_append/disallowed_names.stderr b/tests/ui-toml/disallowed_names_append/disallowed_names.stderr new file mode 100644 index 0000000000000..d59872b0cb397 --- /dev/null +++ b/tests/ui-toml/disallowed_names_append/disallowed_names.stderr @@ -0,0 +1,16 @@ +error: use of a disallowed/placeholder name `foo` + --> $DIR/disallowed_names.rs:5:9 + | +LL | let foo = "bar"; + | ^^^ + | + = note: `-D clippy::disallowed-name` implied by `-D warnings` + +error: use of a disallowed/placeholder name `ducks` + --> $DIR/disallowed_names.rs:7:9 + | +LL | let ducks = ["quack", "quack"]; + | ^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui-toml/disallowed_names_replace/clippy.toml b/tests/ui-toml/disallowed_names_replace/clippy.toml new file mode 100644 index 0000000000000..a1c515652d3cb --- /dev/null +++ b/tests/ui-toml/disallowed_names_replace/clippy.toml @@ -0,0 +1 @@ +disallowed-names = ["ducks"] diff --git a/tests/ui-toml/blacklisted_names_append/blacklisted_names.rs b/tests/ui-toml/disallowed_names_replace/disallowed_names.rs similarity index 72% rename from tests/ui-toml/blacklisted_names_append/blacklisted_names.rs rename to tests/ui-toml/disallowed_names_replace/disallowed_names.rs index fb2395cf90be3..939d48cb677a5 100644 --- a/tests/ui-toml/blacklisted_names_append/blacklisted_names.rs +++ b/tests/ui-toml/disallowed_names_replace/disallowed_names.rs @@ -1,9 +1,9 @@ -#[warn(clippy::blacklisted_name)] +#[warn(clippy::disallowed_name)] fn main() { // `foo` is part of the default configuration let foo = "bar"; - // `ducks` was unrightfully blacklisted + // `ducks` was unrightfully disallowed let ducks = ["quack", "quack"]; // `fox` is okay let fox = ["what", "does", "the", "fox", "say", "?"]; diff --git a/tests/ui-toml/disallowed_names_replace/disallowed_names.stderr b/tests/ui-toml/disallowed_names_replace/disallowed_names.stderr new file mode 100644 index 0000000000000..26f98bbb82db3 --- /dev/null +++ b/tests/ui-toml/disallowed_names_replace/disallowed_names.stderr @@ -0,0 +1,10 @@ +error: use of a disallowed/placeholder name `ducks` + --> $DIR/disallowed_names.rs:7:9 + | +LL | let ducks = ["quack", "quack"]; + | ^^^^^ + | + = note: `-D clippy::disallowed-name` implied by `-D warnings` + +error: aborting due to previous error + diff --git a/tests/ui-toml/toml_blacklist/clippy.toml b/tests/ui-toml/toml_blacklist/clippy.toml deleted file mode 100644 index 6abe5a3bbc273..0000000000000 --- a/tests/ui-toml/toml_blacklist/clippy.toml +++ /dev/null @@ -1 +0,0 @@ -blacklisted-names = ["toto", "tata", "titi"] diff --git a/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.stderr b/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.stderr deleted file mode 100644 index 84ba77851f77e..0000000000000 --- a/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.stderr +++ /dev/null @@ -1,46 +0,0 @@ -error: use of a blacklisted/placeholder name `toto` - --> $DIR/conf_french_blacklisted_name.rs:6:9 - | -LL | fn test(toto: ()) {} - | ^^^^ - | - = note: `-D clippy::blacklisted-name` implied by `-D warnings` - -error: use of a blacklisted/placeholder name `toto` - --> $DIR/conf_french_blacklisted_name.rs:9:9 - | -LL | let toto = 42; - | ^^^^ - -error: use of a blacklisted/placeholder name `tata` - --> $DIR/conf_french_blacklisted_name.rs:10:9 - | -LL | let tata = 42; - | ^^^^ - -error: use of a blacklisted/placeholder name `titi` - --> $DIR/conf_french_blacklisted_name.rs:11:9 - | -LL | let titi = 42; - | ^^^^ - -error: use of a blacklisted/placeholder name `toto` - --> $DIR/conf_french_blacklisted_name.rs:17:10 - | -LL | (toto, Some(tata), titi @ Some(_)) => (), - | ^^^^ - -error: use of a blacklisted/placeholder name `tata` - --> $DIR/conf_french_blacklisted_name.rs:17:21 - | -LL | (toto, Some(tata), titi @ Some(_)) => (), - | ^^^^ - -error: use of a blacklisted/placeholder name `titi` - --> $DIR/conf_french_blacklisted_name.rs:17:28 - | -LL | (toto, Some(tata), titi @ Some(_)) => (), - | ^^^^ - -error: aborting due to 7 previous errors - diff --git a/tests/ui-toml/toml_disallow/clippy.toml b/tests/ui-toml/toml_disallow/clippy.toml new file mode 100644 index 0000000000000..e4f0cb6df57af --- /dev/null +++ b/tests/ui-toml/toml_disallow/clippy.toml @@ -0,0 +1 @@ +disallowed-names = ["toto", "tata", "titi"] diff --git a/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.rs b/tests/ui-toml/toml_disallow/conf_french_disallowed_name.rs similarity index 90% rename from tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.rs rename to tests/ui-toml/toml_disallow/conf_french_disallowed_name.rs index cb35d0e8589d2..897daee0fa651 100644 --- a/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.rs +++ b/tests/ui-toml/toml_disallow/conf_french_disallowed_name.rs @@ -1,7 +1,7 @@ #![allow(dead_code)] #![allow(clippy::single_match)] #![allow(unused_variables)] -#![warn(clippy::blacklisted_name)] +#![warn(clippy::disallowed_name)] fn test(toto: ()) {} diff --git a/tests/ui-toml/toml_disallow/conf_french_disallowed_name.stderr b/tests/ui-toml/toml_disallow/conf_french_disallowed_name.stderr new file mode 100644 index 0000000000000..b9a15043f2de1 --- /dev/null +++ b/tests/ui-toml/toml_disallow/conf_french_disallowed_name.stderr @@ -0,0 +1,46 @@ +error: use of a disallowed/placeholder name `toto` + --> $DIR/conf_french_disallowed_name.rs:6:9 + | +LL | fn test(toto: ()) {} + | ^^^^ + | + = note: `-D clippy::disallowed-name` implied by `-D warnings` + +error: use of a disallowed/placeholder name `toto` + --> $DIR/conf_french_disallowed_name.rs:9:9 + | +LL | let toto = 42; + | ^^^^ + +error: use of a disallowed/placeholder name `tata` + --> $DIR/conf_french_disallowed_name.rs:10:9 + | +LL | let tata = 42; + | ^^^^ + +error: use of a disallowed/placeholder name `titi` + --> $DIR/conf_french_disallowed_name.rs:11:9 + | +LL | let titi = 42; + | ^^^^ + +error: use of a disallowed/placeholder name `toto` + --> $DIR/conf_french_disallowed_name.rs:17:10 + | +LL | (toto, Some(tata), titi @ Some(_)) => (), + | ^^^^ + +error: use of a disallowed/placeholder name `tata` + --> $DIR/conf_french_disallowed_name.rs:17:21 + | +LL | (toto, Some(tata), titi @ Some(_)) => (), + | ^^^^ + +error: use of a disallowed/placeholder name `titi` + --> $DIR/conf_french_disallowed_name.rs:17:28 + | +LL | (toto, Some(tata), titi @ Some(_)) => (), + | ^^^^ + +error: aborting due to 7 previous errors + diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index fe5139c47680c..9f8e778b3b9d1 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -12,6 +12,7 @@ error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown fie cognitive-complexity-threshold cyclomatic-complexity-threshold disallowed-methods + disallowed-names disallowed-types doc-valid-idents enable-raw-pointer-heuristic-for-send diff --git a/tests/ui/blacklisted_name.stderr b/tests/ui/blacklisted_name.stderr deleted file mode 100644 index 70dbdaece8b6b..0000000000000 --- a/tests/ui/blacklisted_name.stderr +++ /dev/null @@ -1,88 +0,0 @@ -error: use of a blacklisted/placeholder name `foo` - --> $DIR/blacklisted_name.rs:11:9 - | -LL | fn test(foo: ()) {} - | ^^^ - | - = note: `-D clippy::blacklisted-name` implied by `-D warnings` - -error: use of a blacklisted/placeholder name `foo` - --> $DIR/blacklisted_name.rs:14:9 - | -LL | let foo = 42; - | ^^^ - -error: use of a blacklisted/placeholder name `baz` - --> $DIR/blacklisted_name.rs:15:9 - | -LL | let baz = 42; - | ^^^ - -error: use of a blacklisted/placeholder name `quux` - --> $DIR/blacklisted_name.rs:16:9 - | -LL | let quux = 42; - | ^^^^ - -error: use of a blacklisted/placeholder name `foo` - --> $DIR/blacklisted_name.rs:27:10 - | -LL | (foo, Some(baz), quux @ Some(_)) => (), - | ^^^ - -error: use of a blacklisted/placeholder name `baz` - --> $DIR/blacklisted_name.rs:27:20 - | -LL | (foo, Some(baz), quux @ Some(_)) => (), - | ^^^ - -error: use of a blacklisted/placeholder name `quux` - --> $DIR/blacklisted_name.rs:27:26 - | -LL | (foo, Some(baz), quux @ Some(_)) => (), - | ^^^^ - -error: use of a blacklisted/placeholder name `foo` - --> $DIR/blacklisted_name.rs:32:19 - | -LL | fn issue_1647(mut foo: u8) { - | ^^^ - -error: use of a blacklisted/placeholder name `baz` - --> $DIR/blacklisted_name.rs:33:13 - | -LL | let mut baz = 0; - | ^^^ - -error: use of a blacklisted/placeholder name `quux` - --> $DIR/blacklisted_name.rs:34:21 - | -LL | if let Some(mut quux) = Some(42) {} - | ^^^^ - -error: use of a blacklisted/placeholder name `baz` - --> $DIR/blacklisted_name.rs:38:13 - | -LL | let ref baz = 0; - | ^^^ - -error: use of a blacklisted/placeholder name `quux` - --> $DIR/blacklisted_name.rs:39:21 - | -LL | if let Some(ref quux) = Some(42) {} - | ^^^^ - -error: use of a blacklisted/placeholder name `baz` - --> $DIR/blacklisted_name.rs:43:17 - | -LL | let ref mut baz = 0; - | ^^^ - -error: use of a blacklisted/placeholder name `quux` - --> $DIR/blacklisted_name.rs:44:25 - | -LL | if let Some(ref mut quux) = Some(42) {} - | ^^^^ - -error: aborting due to 14 previous errors - diff --git a/tests/ui/borrow_box.rs b/tests/ui/borrow_box.rs index b606f773cfbad..2a4f8b53e8b05 100644 --- a/tests/ui/borrow_box.rs +++ b/tests/ui/borrow_box.rs @@ -1,5 +1,5 @@ #![deny(clippy::borrowed_box)] -#![allow(clippy::blacklisted_name)] +#![allow(clippy::disallowed_name)] #![allow(unused_variables)] #![allow(dead_code)] diff --git a/tests/ui/box_collection.rs b/tests/ui/box_collection.rs index 1a74cdb3ff659..690ed905cdd68 100644 --- a/tests/ui/box_collection.rs +++ b/tests/ui/box_collection.rs @@ -1,10 +1,5 @@ #![warn(clippy::all)] -#![allow( - clippy::boxed_local, - clippy::needless_pass_by_value, - clippy::blacklisted_name, - unused -)] +#![allow(clippy::boxed_local, clippy::needless_pass_by_value, clippy::disallowed_name, unused)] use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList, VecDeque}; diff --git a/tests/ui/box_collection.stderr b/tests/ui/box_collection.stderr index 2b28598ded92f..4a559e616d19a 100644 --- a/tests/ui/box_collection.stderr +++ b/tests/ui/box_collection.stderr @@ -1,5 +1,5 @@ error: you seem to be trying to use `Box>`. Consider using just `Vec<..>` - --> $DIR/box_collection.rs:21:15 + --> $DIR/box_collection.rs:16:15 | LL | fn test1(foo: Box>) {} | ^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | fn test1(foo: Box>) {} = help: `Vec<..>` is already on the heap, `Box>` makes an extra allocation error: you seem to be trying to use `Box`. Consider using just `String` - --> $DIR/box_collection.rs:28:15 + --> $DIR/box_collection.rs:23:15 | LL | fn test3(foo: Box) {} | ^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | fn test3(foo: Box) {} = help: `String` is already on the heap, `Box` makes an extra allocation error: you seem to be trying to use `Box>`. Consider using just `HashMap<..>` - --> $DIR/box_collection.rs:30:15 + --> $DIR/box_collection.rs:25:15 | LL | fn test4(foo: Box>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL | fn test4(foo: Box>) {} = help: `HashMap<..>` is already on the heap, `Box>` makes an extra allocation error: you seem to be trying to use `Box>`. Consider using just `HashSet<..>` - --> $DIR/box_collection.rs:32:15 + --> $DIR/box_collection.rs:27:15 | LL | fn test5(foo: Box>) {} | ^^^^^^^^^^^^^^^^^ @@ -32,7 +32,7 @@ LL | fn test5(foo: Box>) {} = help: `HashSet<..>` is already on the heap, `Box>` makes an extra allocation error: you seem to be trying to use `Box>`. Consider using just `VecDeque<..>` - --> $DIR/box_collection.rs:34:15 + --> $DIR/box_collection.rs:29:15 | LL | fn test6(foo: Box>) {} | ^^^^^^^^^^^^^^^^^^ @@ -40,7 +40,7 @@ LL | fn test6(foo: Box>) {} = help: `VecDeque<..>` is already on the heap, `Box>` makes an extra allocation error: you seem to be trying to use `Box>`. Consider using just `LinkedList<..>` - --> $DIR/box_collection.rs:36:15 + --> $DIR/box_collection.rs:31:15 | LL | fn test7(foo: Box>) {} | ^^^^^^^^^^^^^^^^^^^^ @@ -48,7 +48,7 @@ LL | fn test7(foo: Box>) {} = help: `LinkedList<..>` is already on the heap, `Box>` makes an extra allocation error: you seem to be trying to use `Box>`. Consider using just `BTreeMap<..>` - --> $DIR/box_collection.rs:38:15 + --> $DIR/box_collection.rs:33:15 | LL | fn test8(foo: Box>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -56,7 +56,7 @@ LL | fn test8(foo: Box>) {} = help: `BTreeMap<..>` is already on the heap, `Box>` makes an extra allocation error: you seem to be trying to use `Box>`. Consider using just `BTreeSet<..>` - --> $DIR/box_collection.rs:40:15 + --> $DIR/box_collection.rs:35:15 | LL | fn test9(foo: Box>) {} | ^^^^^^^^^^^^^^^^^^ @@ -64,7 +64,7 @@ LL | fn test9(foo: Box>) {} = help: `BTreeSet<..>` is already on the heap, `Box>` makes an extra allocation error: you seem to be trying to use `Box>`. Consider using just `BinaryHeap<..>` - --> $DIR/box_collection.rs:42:16 + --> $DIR/box_collection.rs:37:16 | LL | fn test10(foo: Box>) {} | ^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/crashes/ice-2760.rs b/tests/ui/crashes/ice-2760.rs index f1a229f3f4faf..4504d31138528 100644 --- a/tests/ui/crashes/ice-2760.rs +++ b/tests/ui/crashes/ice-2760.rs @@ -1,9 +1,4 @@ -#![allow( - unused_variables, - clippy::blacklisted_name, - clippy::needless_pass_by_value, - dead_code -)] +#![allow(unused_variables, clippy::disallowed_name, clippy::needless_pass_by_value, dead_code)] /// This should not compile-fail with: /// diff --git a/tests/ui/crashes/ice-3462.rs b/tests/ui/crashes/ice-3462.rs index 02c49aa0d7c1f..a7d9017bc680b 100644 --- a/tests/ui/crashes/ice-3462.rs +++ b/tests/ui/crashes/ice-3462.rs @@ -1,5 +1,5 @@ #![warn(clippy::all)] -#![allow(clippy::blacklisted_name, clippy::equatable_if_let)] +#![allow(clippy::disallowed_name, clippy::equatable_if_let)] #![allow(unused)] /// Test for https://github.com/rust-lang/rust-clippy/issues/3462 diff --git a/tests/ui/crashes/regressions.rs b/tests/ui/crashes/regressions.rs index 6f9d98bbfe7f3..86985391fc0b0 100644 --- a/tests/ui/crashes/regressions.rs +++ b/tests/ui/crashes/regressions.rs @@ -1,4 +1,4 @@ -#![allow(clippy::blacklisted_name)] +#![allow(clippy::disallowed_name)] pub fn foo(bar: *const u8) { println!("{:#p}", bar); diff --git a/tests/ui/blacklisted_name.rs b/tests/ui/disallowed_name.rs similarity index 90% rename from tests/ui/blacklisted_name.rs rename to tests/ui/disallowed_name.rs index 27df732a08802..17acc8533e0b4 100644 --- a/tests/ui/blacklisted_name.rs +++ b/tests/ui/disallowed_name.rs @@ -6,7 +6,7 @@ unused_mut, unused_variables )] -#![warn(clippy::blacklisted_name)] +#![warn(clippy::disallowed_name)] fn test(foo: ()) {} @@ -46,7 +46,7 @@ fn issue_1647_ref_mut() { mod tests { fn issue_7305() { - // `blacklisted_name` lint should not be triggered inside of the test code. + // `disallowed_name` lint should not be triggered inside of the test code. let foo = 0; // Check that even in nested functions warning is still not triggered. diff --git a/tests/ui/disallowed_name.stderr b/tests/ui/disallowed_name.stderr new file mode 100644 index 0000000000000..240c167e22349 --- /dev/null +++ b/tests/ui/disallowed_name.stderr @@ -0,0 +1,88 @@ +error: use of a disallowed/placeholder name `foo` + --> $DIR/disallowed_name.rs:11:9 + | +LL | fn test(foo: ()) {} + | ^^^ + | + = note: `-D clippy::disallowed-name` implied by `-D warnings` + +error: use of a disallowed/placeholder name `foo` + --> $DIR/disallowed_name.rs:14:9 + | +LL | let foo = 42; + | ^^^ + +error: use of a disallowed/placeholder name `baz` + --> $DIR/disallowed_name.rs:15:9 + | +LL | let baz = 42; + | ^^^ + +error: use of a disallowed/placeholder name `quux` + --> $DIR/disallowed_name.rs:16:9 + | +LL | let quux = 42; + | ^^^^ + +error: use of a disallowed/placeholder name `foo` + --> $DIR/disallowed_name.rs:27:10 + | +LL | (foo, Some(baz), quux @ Some(_)) => (), + | ^^^ + +error: use of a disallowed/placeholder name `baz` + --> $DIR/disallowed_name.rs:27:20 + | +LL | (foo, Some(baz), quux @ Some(_)) => (), + | ^^^ + +error: use of a disallowed/placeholder name `quux` + --> $DIR/disallowed_name.rs:27:26 + | +LL | (foo, Some(baz), quux @ Some(_)) => (), + | ^^^^ + +error: use of a disallowed/placeholder name `foo` + --> $DIR/disallowed_name.rs:32:19 + | +LL | fn issue_1647(mut foo: u8) { + | ^^^ + +error: use of a disallowed/placeholder name `baz` + --> $DIR/disallowed_name.rs:33:13 + | +LL | let mut baz = 0; + | ^^^ + +error: use of a disallowed/placeholder name `quux` + --> $DIR/disallowed_name.rs:34:21 + | +LL | if let Some(mut quux) = Some(42) {} + | ^^^^ + +error: use of a disallowed/placeholder name `baz` + --> $DIR/disallowed_name.rs:38:13 + | +LL | let ref baz = 0; + | ^^^ + +error: use of a disallowed/placeholder name `quux` + --> $DIR/disallowed_name.rs:39:21 + | +LL | if let Some(ref quux) = Some(42) {} + | ^^^^ + +error: use of a disallowed/placeholder name `baz` + --> $DIR/disallowed_name.rs:43:17 + | +LL | let ref mut baz = 0; + | ^^^ + +error: use of a disallowed/placeholder name `quux` + --> $DIR/disallowed_name.rs:44:25 + | +LL | if let Some(ref mut quux) = Some(42) {} + | ^^^^ + +error: aborting due to 14 previous errors + diff --git a/tests/ui/if_same_then_else.rs b/tests/ui/if_same_then_else.rs index 2598c2ab426d3..dd25008cbbea3 100644 --- a/tests/ui/if_same_then_else.rs +++ b/tests/ui/if_same_then_else.rs @@ -1,6 +1,6 @@ #![warn(clippy::if_same_then_else)] #![allow( - clippy::blacklisted_name, + clippy::disallowed_name, clippy::eq_op, clippy::never_loop, clippy::no_effect, diff --git a/tests/ui/if_same_then_else2.rs b/tests/ui/if_same_then_else2.rs index 0016009a02f58..8b643c48914b0 100644 --- a/tests/ui/if_same_then_else2.rs +++ b/tests/ui/if_same_then_else2.rs @@ -1,6 +1,6 @@ #![warn(clippy::if_same_then_else)] #![allow( - clippy::blacklisted_name, + clippy::disallowed_name, clippy::collapsible_else_if, clippy::equatable_if_let, clippy::collapsible_if, diff --git a/tests/ui/iter_skip_next.fixed b/tests/ui/iter_skip_next.fixed index 2db4c2bee7f2b..2cb8966541119 100644 --- a/tests/ui/iter_skip_next.fixed +++ b/tests/ui/iter_skip_next.fixed @@ -2,7 +2,7 @@ // aux-build:option_helpers.rs #![warn(clippy::iter_skip_next)] -#![allow(clippy::blacklisted_name)] +#![allow(clippy::disallowed_name)] #![allow(clippy::iter_nth)] #![allow(unused_mut, dead_code)] diff --git a/tests/ui/iter_skip_next.rs b/tests/ui/iter_skip_next.rs index 692edb9aed939..972d1e2b51f7c 100644 --- a/tests/ui/iter_skip_next.rs +++ b/tests/ui/iter_skip_next.rs @@ -2,7 +2,7 @@ // aux-build:option_helpers.rs #![warn(clippy::iter_skip_next)] -#![allow(clippy::blacklisted_name)] +#![allow(clippy::disallowed_name)] #![allow(clippy::iter_nth)] #![allow(unused_mut, dead_code)] diff --git a/tests/ui/let_if_seq.rs b/tests/ui/let_if_seq.rs index c5cb2eb1fe1c2..ee351880b80e4 100644 --- a/tests/ui/let_if_seq.rs +++ b/tests/ui/let_if_seq.rs @@ -2,7 +2,7 @@ unused_variables, unused_assignments, clippy::similar_names, - clippy::blacklisted_name, + clippy::disallowed_name, clippy::branches_sharing_code, clippy::needless_late_init )] diff --git a/tests/ui/manual_ok_or.fixed b/tests/ui/manual_ok_or.fixed index 887a97d7a0173..9ee71bf9090b9 100644 --- a/tests/ui/manual_ok_or.fixed +++ b/tests/ui/manual_ok_or.fixed @@ -1,6 +1,6 @@ // run-rustfix #![warn(clippy::manual_ok_or)] -#![allow(clippy::blacklisted_name)] +#![allow(clippy::disallowed_name)] #![allow(clippy::redundant_closure)] #![allow(dead_code)] #![allow(unused_must_use)] diff --git a/tests/ui/manual_ok_or.rs b/tests/ui/manual_ok_or.rs index 3c99872f5022a..0e1bc0857691b 100644 --- a/tests/ui/manual_ok_or.rs +++ b/tests/ui/manual_ok_or.rs @@ -1,6 +1,6 @@ // run-rustfix #![warn(clippy::manual_ok_or)] -#![allow(clippy::blacklisted_name)] +#![allow(clippy::disallowed_name)] #![allow(clippy::redundant_closure)] #![allow(dead_code)] #![allow(unused_must_use)] diff --git a/tests/ui/match_same_arms2.rs b/tests/ui/match_same_arms2.rs index 7aba5b447d553..086e3e9b8059b 100644 --- a/tests/ui/match_same_arms2.rs +++ b/tests/ui/match_same_arms2.rs @@ -1,5 +1,5 @@ #![warn(clippy::match_same_arms)] -#![allow(clippy::blacklisted_name, clippy::diverging_sub_expression)] +#![allow(clippy::disallowed_name, clippy::diverging_sub_expression)] fn bar(_: T) {} fn foo() -> bool { diff --git a/tests/ui/methods.rs b/tests/ui/methods.rs index 1970c2eae5314..8d782f73821a9 100644 --- a/tests/ui/methods.rs +++ b/tests/ui/methods.rs @@ -2,7 +2,7 @@ #![warn(clippy::all, clippy::pedantic)] #![allow( - clippy::blacklisted_name, + clippy::disallowed_name, clippy::default_trait_access, clippy::missing_docs_in_private_items, clippy::missing_safety_doc, diff --git a/tests/ui/mismatching_type_param_order.rs b/tests/ui/mismatching_type_param_order.rs index 8c0da84d8e975..c2195bf18d1d0 100644 --- a/tests/ui/mismatching_type_param_order.rs +++ b/tests/ui/mismatching_type_param_order.rs @@ -1,5 +1,5 @@ #![warn(clippy::mismatching_type_param_order)] -#![allow(clippy::blacklisted_name)] +#![allow(clippy::disallowed_name)] fn main() { struct Foo { diff --git a/tests/ui/mixed_read_write_in_expression.rs b/tests/ui/mixed_read_write_in_expression.rs index 7640057ab6e36..6e413fcf5bb44 100644 --- a/tests/ui/mixed_read_write_in_expression.rs +++ b/tests/ui/mixed_read_write_in_expression.rs @@ -4,7 +4,7 @@ unused_variables, clippy::no_effect, dead_code, - clippy::blacklisted_name + clippy::disallowed_name )] fn main() { let mut x = 0; diff --git a/tests/ui/op_ref.rs b/tests/ui/op_ref.rs index d8bf66603d9f5..8e53f2073e58d 100644 --- a/tests/ui/op_ref.rs +++ b/tests/ui/op_ref.rs @@ -1,4 +1,4 @@ -#![allow(unused_variables, clippy::blacklisted_name)] +#![allow(unused_variables, clippy::disallowed_name)] #![warn(clippy::op_ref)] use std::collections::HashSet; use std::ops::{BitAnd, Mul}; diff --git a/tests/ui/rc_mutex.rs b/tests/ui/rc_mutex.rs index 18e8a2e01e022..ee707a630fa74 100644 --- a/tests/ui/rc_mutex.rs +++ b/tests/ui/rc_mutex.rs @@ -1,5 +1,5 @@ #![warn(clippy::rc_mutex)] -#![allow(unused, clippy::blacklisted_name)] +#![allow(unused, clippy::disallowed_name)] use std::rc::Rc; use std::sync::Mutex; diff --git a/tests/ui/redundant_allocation.rs b/tests/ui/redundant_allocation.rs index cf7d8c6e349af..7b9e02f974cd4 100644 --- a/tests/ui/redundant_allocation.rs +++ b/tests/ui/redundant_allocation.rs @@ -1,6 +1,6 @@ #![warn(clippy::all)] #![allow(clippy::boxed_local, clippy::needless_pass_by_value)] -#![allow(clippy::blacklisted_name, unused_variables, dead_code)] +#![allow(clippy::disallowed_name, unused_variables, dead_code)] #![allow(unused_imports)] pub struct MyStruct; diff --git a/tests/ui/redundant_allocation_fixable.fixed b/tests/ui/redundant_allocation_fixable.fixed index e7ed84731c02e..4c85b20afe57b 100644 --- a/tests/ui/redundant_allocation_fixable.fixed +++ b/tests/ui/redundant_allocation_fixable.fixed @@ -1,7 +1,7 @@ // run-rustfix #![warn(clippy::all)] #![allow(clippy::boxed_local, clippy::needless_pass_by_value)] -#![allow(clippy::blacklisted_name, unused_variables, dead_code)] +#![allow(clippy::disallowed_name, unused_variables, dead_code)] #![allow(unused_imports)] pub struct MyStruct; diff --git a/tests/ui/redundant_allocation_fixable.rs b/tests/ui/redundant_allocation_fixable.rs index de763f98b5c89..8b402e478738e 100644 --- a/tests/ui/redundant_allocation_fixable.rs +++ b/tests/ui/redundant_allocation_fixable.rs @@ -1,7 +1,7 @@ // run-rustfix #![warn(clippy::all)] #![allow(clippy::boxed_local, clippy::needless_pass_by_value)] -#![allow(clippy::blacklisted_name, unused_variables, dead_code)] +#![allow(clippy::disallowed_name, unused_variables, dead_code)] #![allow(unused_imports)] pub struct MyStruct; diff --git a/tests/ui/rename.fixed b/tests/ui/rename.fixed index 53288be9404c2..e65327737ce69 100644 --- a/tests/ui/rename.fixed +++ b/tests/ui/rename.fixed @@ -6,6 +6,7 @@ #![allow(clippy::blocks_in_if_conditions)] #![allow(clippy::box_collection)] +#![allow(clippy::disallowed_name)] #![allow(clippy::redundant_static_lifetimes)] #![allow(clippy::cognitive_complexity)] #![allow(clippy::disallowed_methods)] @@ -36,6 +37,7 @@ #![warn(clippy::blocks_in_if_conditions)] #![warn(clippy::blocks_in_if_conditions)] #![warn(clippy::box_collection)] +#![warn(clippy::disallowed_name)] #![warn(clippy::redundant_static_lifetimes)] #![warn(clippy::cognitive_complexity)] #![warn(clippy::disallowed_methods)] diff --git a/tests/ui/rename.rs b/tests/ui/rename.rs index 539f34f847acd..8125b153589a9 100644 --- a/tests/ui/rename.rs +++ b/tests/ui/rename.rs @@ -6,6 +6,7 @@ #![allow(clippy::blocks_in_if_conditions)] #![allow(clippy::box_collection)] +#![allow(clippy::disallowed_name)] #![allow(clippy::redundant_static_lifetimes)] #![allow(clippy::cognitive_complexity)] #![allow(clippy::disallowed_methods)] @@ -36,6 +37,7 @@ #![warn(clippy::block_in_if_condition_expr)] #![warn(clippy::block_in_if_condition_stmt)] #![warn(clippy::box_vec)] +#![warn(clippy::blacklisted_name)] #![warn(clippy::const_static_lifetime)] #![warn(clippy::cyclomatic_complexity)] #![warn(clippy::disallowed_method)] diff --git a/tests/ui/rename.stderr b/tests/ui/rename.stderr index 8ea46b580a8c9..d282931105953 100644 --- a/tests/ui/rename.stderr +++ b/tests/ui/rename.stderr @@ -1,5 +1,5 @@ error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions` - --> $DIR/rename.rs:36:9 + --> $DIR/rename.rs:37:9 | LL | #![warn(clippy::block_in_if_condition_expr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` @@ -7,208 +7,214 @@ LL | #![warn(clippy::block_in_if_condition_expr)] = note: `-D renamed-and-removed-lints` implied by `-D warnings` error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions` - --> $DIR/rename.rs:37:9 + --> $DIR/rename.rs:38:9 | LL | #![warn(clippy::block_in_if_condition_stmt)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` error: lint `clippy::box_vec` has been renamed to `clippy::box_collection` - --> $DIR/rename.rs:38:9 + --> $DIR/rename.rs:39:9 | LL | #![warn(clippy::box_vec)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection` +error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_name` + --> $DIR/rename.rs:40:9 + | +LL | #![warn(clippy::blacklisted_name)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_name` + error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes` - --> $DIR/rename.rs:39:9 + --> $DIR/rename.rs:41:9 | LL | #![warn(clippy::const_static_lifetime)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes` error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity` - --> $DIR/rename.rs:40:9 + --> $DIR/rename.rs:42:9 | LL | #![warn(clippy::cyclomatic_complexity)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity` error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods` - --> $DIR/rename.rs:41:9 + --> $DIR/rename.rs:43:9 | LL | #![warn(clippy::disallowed_method)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods` error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types` - --> $DIR/rename.rs:42:9 + --> $DIR/rename.rs:44:9 | LL | #![warn(clippy::disallowed_type)] | ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types` error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression` - --> $DIR/rename.rs:43:9 + --> $DIR/rename.rs:45:9 | LL | #![warn(clippy::eval_order_dependence)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression` error: lint `clippy::for_loop_over_option` has been renamed to `clippy::for_loops_over_fallibles` - --> $DIR/rename.rs:44:9 + --> $DIR/rename.rs:46:9 | LL | #![warn(clippy::for_loop_over_option)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles` error: lint `clippy::for_loop_over_result` has been renamed to `clippy::for_loops_over_fallibles` - --> $DIR/rename.rs:45:9 + --> $DIR/rename.rs:47:9 | LL | #![warn(clippy::for_loop_over_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles` error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion` - --> $DIR/rename.rs:46:9 + --> $DIR/rename.rs:48:9 | LL | #![warn(clippy::identity_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion` error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok` - --> $DIR/rename.rs:47:9 + --> $DIR/rename.rs:49:9 | LL | #![warn(clippy::if_let_some_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok` error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default` - --> $DIR/rename.rs:48:9 + --> $DIR/rename.rs:50:9 | LL | #![warn(clippy::new_without_default_derive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default` error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map` - --> $DIR/rename.rs:49:9 + --> $DIR/rename.rs:51:9 | LL | #![warn(clippy::option_and_then_some)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map` error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used` - --> $DIR/rename.rs:50:9 + --> $DIR/rename.rs:52:9 | LL | #![warn(clippy::option_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:51:9 + --> $DIR/rename.rs:53:9 | LL | #![warn(clippy::option_map_unwrap_or)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:52:9 + --> $DIR/rename.rs:54:9 | LL | #![warn(clippy::option_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used` - --> $DIR/rename.rs:53:9 + --> $DIR/rename.rs:55:9 | LL | #![warn(clippy::option_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow` - --> $DIR/rename.rs:54:9 + --> $DIR/rename.rs:56:9 | LL | #![warn(clippy::ref_in_deref)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow` error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used` - --> $DIR/rename.rs:55:9 + --> $DIR/rename.rs:57:9 | LL | #![warn(clippy::result_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:56:9 + --> $DIR/rename.rs:58:9 | LL | #![warn(clippy::result_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used` - --> $DIR/rename.rs:57:9 + --> $DIR/rename.rs:59:9 | LL | #![warn(clippy::result_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str` - --> $DIR/rename.rs:58:9 + --> $DIR/rename.rs:60:9 | LL | #![warn(clippy::single_char_push_str)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str` error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions` - --> $DIR/rename.rs:59:9 + --> $DIR/rename.rs:61:9 | LL | #![warn(clippy::stutter)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions` error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl` - --> $DIR/rename.rs:60:9 + --> $DIR/rename.rs:62:9 | LL | #![warn(clippy::to_string_in_display)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl` error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters` - --> $DIR/rename.rs:61:9 + --> $DIR/rename.rs:63:9 | LL | #![warn(clippy::zero_width_space)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters` error: lint `clippy::drop_bounds` has been renamed to `drop_bounds` - --> $DIR/rename.rs:62:9 + --> $DIR/rename.rs:64:9 | LL | #![warn(clippy::drop_bounds)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds` error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter` - --> $DIR/rename.rs:63:9 + --> $DIR/rename.rs:65:9 | LL | #![warn(clippy::into_iter_on_array)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter` error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering` - --> $DIR/rename.rs:64:9 + --> $DIR/rename.rs:66:9 | LL | #![warn(clippy::invalid_atomic_ordering)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering` error: lint `clippy::invalid_ref` has been renamed to `invalid_value` - --> $DIR/rename.rs:65:9 + --> $DIR/rename.rs:67:9 | LL | #![warn(clippy::invalid_ref)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value` error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums` - --> $DIR/rename.rs:66:9 + --> $DIR/rename.rs:68:9 | LL | #![warn(clippy::mem_discriminant_non_enum)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums` error: lint `clippy::panic_params` has been renamed to `non_fmt_panics` - --> $DIR/rename.rs:67:9 + --> $DIR/rename.rs:69:9 | LL | #![warn(clippy::panic_params)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics` error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr` - --> $DIR/rename.rs:68:9 + --> $DIR/rename.rs:70:9 | LL | #![warn(clippy::temporary_cstring_as_ptr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr` error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints` - --> $DIR/rename.rs:69:9 + --> $DIR/rename.rs:71:9 | LL | #![warn(clippy::unknown_clippy_lints)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints` error: lint `clippy::unused_label` has been renamed to `unused_labels` - --> $DIR/rename.rs:70:9 + --> $DIR/rename.rs:72:9 | LL | #![warn(clippy::unused_label)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels` -error: aborting due to 35 previous errors +error: aborting due to 36 previous errors diff --git a/tests/ui/skip_while_next.rs b/tests/ui/skip_while_next.rs index a522c0f08b207..bedd2704100cf 100644 --- a/tests/ui/skip_while_next.rs +++ b/tests/ui/skip_while_next.rs @@ -1,7 +1,7 @@ // aux-build:option_helpers.rs #![warn(clippy::skip_while_next)] -#![allow(clippy::blacklisted_name)] +#![allow(clippy::disallowed_name)] extern crate option_helpers; use option_helpers::IteratorFalsePositives; diff --git a/tests/ui/swap.fixed b/tests/ui/swap.fixed index 3329efbd4ff42..0865287c08a39 100644 --- a/tests/ui/swap.fixed +++ b/tests/ui/swap.fixed @@ -2,7 +2,7 @@ #![warn(clippy::all)] #![allow( - clippy::blacklisted_name, + clippy::disallowed_name, clippy::no_effect, clippy::redundant_clone, redundant_semicolons, diff --git a/tests/ui/swap.rs b/tests/ui/swap.rs index 8179ac1f2ab02..8f87c488462a6 100644 --- a/tests/ui/swap.rs +++ b/tests/ui/swap.rs @@ -2,7 +2,7 @@ #![warn(clippy::all)] #![allow( - clippy::blacklisted_name, + clippy::disallowed_name, clippy::no_effect, clippy::redundant_clone, redundant_semicolons, diff --git a/tests/ui/trivially_copy_pass_by_ref.rs b/tests/ui/trivially_copy_pass_by_ref.rs index 8f78f16a0a1a6..732b139ea12f5 100644 --- a/tests/ui/trivially_copy_pass_by_ref.rs +++ b/tests/ui/trivially_copy_pass_by_ref.rs @@ -2,7 +2,7 @@ // normalize-stderr-test "\(limit: \d+ byte\)" -> "(limit: N byte)" #![deny(clippy::trivially_copy_pass_by_ref)] -#![allow(clippy::blacklisted_name, clippy::redundant_field_names)] +#![allow(clippy::disallowed_name, clippy::redundant_field_names)] #[derive(Copy, Clone)] struct Foo(u32); diff --git a/tests/ui/used_underscore_binding.rs b/tests/ui/used_underscore_binding.rs index d20977d55d29d..91c8807936384 100644 --- a/tests/ui/used_underscore_binding.rs +++ b/tests/ui/used_underscore_binding.rs @@ -2,7 +2,7 @@ #![feature(rustc_private)] #![warn(clippy::all)] -#![allow(clippy::blacklisted_name, clippy::eq_op)] +#![allow(clippy::disallowed_name, clippy::eq_op)] #![warn(clippy::used_underscore_binding)] #[macro_use] From 66b46749e68bc4d8c3ed754722631746a2331518 Mon Sep 17 00:00:00 2001 From: Andy Caldwell Date: Wed, 8 Jun 2022 20:08:37 +0100 Subject: [PATCH 17/62] Change lint name to plural --- CHANGELOG.md | 6 ++-- ...disallowed_name.rs => disallowed_names.rs} | 12 ++++---- clippy_lints/src/lib.register_all.rs | 2 +- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/lib.register_style.rs | 2 +- clippy_lints/src/lib.rs | 4 +-- clippy_lints/src/renamed_lints.rs | 2 +- clippy_lints/src/utils/conf.rs | 2 +- .../disallowed_names.rs | 2 +- .../disallowed_names.stderr | 2 +- .../disallowed_names.rs | 2 +- .../disallowed_names.stderr | 2 +- .../conf_french_disallowed_name.rs | 2 +- .../conf_french_disallowed_name.stderr | 2 +- tests/ui/borrow_box.rs | 2 +- tests/ui/box_collection.rs | 7 ++++- tests/ui/box_collection.stderr | 18 +++++------ tests/ui/crashes/ice-2760.rs | 7 ++++- tests/ui/crashes/ice-3462.rs | 2 +- tests/ui/crashes/regressions.rs | 2 +- ...disallowed_name.rs => disallowed_names.rs} | 4 +-- ...ed_name.stderr => disallowed_names.stderr} | 30 +++++++++---------- tests/ui/if_same_then_else.rs | 2 +- tests/ui/if_same_then_else2.rs | 2 +- tests/ui/iter_skip_next.fixed | 2 +- tests/ui/iter_skip_next.rs | 2 +- tests/ui/let_if_seq.rs | 2 +- tests/ui/manual_ok_or.fixed | 2 +- tests/ui/manual_ok_or.rs | 2 +- tests/ui/match_same_arms2.rs | 2 +- tests/ui/methods.rs | 2 +- tests/ui/mismatching_type_param_order.rs | 2 +- tests/ui/mixed_read_write_in_expression.rs | 2 +- tests/ui/op_ref.rs | 2 +- tests/ui/rc_mutex.rs | 2 +- tests/ui/redundant_allocation.rs | 2 +- tests/ui/redundant_allocation_fixable.fixed | 2 +- tests/ui/redundant_allocation_fixable.rs | 2 +- tests/ui/rename.fixed | 4 +-- tests/ui/rename.rs | 2 +- tests/ui/rename.stderr | 4 +-- tests/ui/skip_while_next.rs | 2 +- tests/ui/swap.fixed | 2 +- tests/ui/swap.rs | 2 +- tests/ui/trivially_copy_pass_by_ref.rs | 2 +- tests/ui/used_underscore_binding.rs | 2 +- 46 files changed, 89 insertions(+), 79 deletions(-) rename clippy_lints/src/{disallowed_name.rs => disallowed_names.rs} (89%) rename tests/ui/{disallowed_name.rs => disallowed_names.rs} (90%) rename tests/ui/{disallowed_name.stderr => disallowed_names.stderr} (74%) diff --git a/CHANGELOG.md b/CHANGELOG.md index d3d4d5a47844e..646e1128e9a31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -965,7 +965,7 @@ Released 2021-09-09 [#7407](https://github.com/rust-lang/rust-clippy/pull/7407) * [`redundant_allocation`]: Now additionally supports the `Arc<>` type [#7308](https://github.com/rust-lang/rust-clippy/pull/7308) -* [`disallowed_name`]: Now allows disallowed names in test code +* [`disallowed_names`]: Now allows disallowed names in test code [#7379](https://github.com/rust-lang/rust-clippy/pull/7379) * [`redundant_closure`]: Suggests `&mut` for `FnMut` [#7437](https://github.com/rust-lang/rust-clippy/pull/7437) @@ -2066,7 +2066,7 @@ Released 2020-08-27 [#5692](https://github.com/rust-lang/rust-clippy/pull/5692) * [`if_same_then_else`]: Don't assume multiplication is always commutative [#5702](https://github.com/rust-lang/rust-clippy/pull/5702) -* [`disallowed_name`]: Remove `bar` from the default configuration +* [`disallowed_names`]: Remove `bar` from the default configuration [#5712](https://github.com/rust-lang/rust-clippy/pull/5712) * [`redundant_pattern_matching`]: Avoid suggesting non-`const fn` calls in const contexts [#5724](https://github.com/rust-lang/rust-clippy/pull/5724) @@ -3522,7 +3522,7 @@ Released 2018-09-13 [`derive_partial_eq_without_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_partial_eq_without_eq [`disallowed_method`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_method [`disallowed_methods`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_methods -[`disallowed_name`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_name +[`disallowed_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_names [`disallowed_script_idents`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_script_idents [`disallowed_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_type [`disallowed_types`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_types diff --git a/clippy_lints/src/disallowed_name.rs b/clippy_lints/src/disallowed_names.rs similarity index 89% rename from clippy_lints/src/disallowed_name.rs rename to clippy_lints/src/disallowed_names.rs index 98735ce7db187..6e6615f08ee71 100644 --- a/clippy_lints/src/disallowed_name.rs +++ b/clippy_lints/src/disallowed_names.rs @@ -18,18 +18,18 @@ declare_clippy_lint! { /// let foo = 3.14; /// ``` #[clippy::version = "pre 1.29.0"] - pub DISALLOWED_NAME, + pub DISALLOWED_NAMES, style, "usage of a disallowed/placeholder name" } #[derive(Clone, Debug)] -pub struct DisallowedName { +pub struct DisallowedNames { disallow: FxHashSet, test_modules_deep: u32, } -impl DisallowedName { +impl DisallowedNames { pub fn new(disallow: FxHashSet) -> Self { Self { disallow, @@ -42,9 +42,9 @@ impl DisallowedName { } } -impl_lint_pass!(DisallowedName => [DISALLOWED_NAME]); +impl_lint_pass!(DisallowedNames => [DISALLOWED_NAMES]); -impl<'tcx> LateLintPass<'tcx> for DisallowedName { +impl<'tcx> LateLintPass<'tcx> for DisallowedNames { fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { if is_test_module_or_function(cx.tcx, item) { self.test_modules_deep = self.test_modules_deep.saturating_add(1); @@ -61,7 +61,7 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedName { if self.disallow.contains(&ident.name.to_string()) { span_lint( cx, - DISALLOWED_NAME, + DISALLOWED_NAMES, ident.span, &format!("use of a disallowed/placeholder name `{}`", ident.name), ); diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index d8b6aa9793f78..cb33b3b3279de 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -46,7 +46,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(derive::DERIVE_ORD_XOR_PARTIAL_ORD), LintId::of(derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ), LintId::of(disallowed_methods::DISALLOWED_METHODS), - LintId::of(disallowed_name::DISALLOWED_NAME), + LintId::of(disallowed_names::DISALLOWED_NAMES), LintId::of(disallowed_types::DISALLOWED_TYPES), LintId::of(doc::MISSING_SAFETY_DOC), LintId::of(doc::NEEDLESS_DOCTEST_MAIN), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 562c755d10f7f..430b8585f6dbf 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -115,7 +115,7 @@ store.register_lints(&[ derive::EXPL_IMPL_CLONE_ON_COPY, derive::UNSAFE_DERIVE_DESERIALIZE, disallowed_methods::DISALLOWED_METHODS, - disallowed_name::DISALLOWED_NAME, + disallowed_names::DISALLOWED_NAMES, disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS, disallowed_types::DISALLOWED_TYPES, doc::DOC_MARKDOWN, diff --git a/clippy_lints/src/lib.register_style.rs b/clippy_lints/src/lib.register_style.rs index 615a86a27e5bf..31852881615dd 100644 --- a/clippy_lints/src/lib.register_style.rs +++ b/clippy_lints/src/lib.register_style.rs @@ -17,7 +17,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(dereference::NEEDLESS_BORROW), LintId::of(derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ), LintId::of(disallowed_methods::DISALLOWED_METHODS), - LintId::of(disallowed_name::DISALLOWED_NAME), + LintId::of(disallowed_names::DISALLOWED_NAMES), LintId::of(disallowed_types::DISALLOWED_TYPES), LintId::of(doc::MISSING_SAFETY_DOC), LintId::of(doc::NEEDLESS_DOCTEST_MAIN), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index ca398038f3e4b..6ebf19831563b 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -204,7 +204,7 @@ mod dereference; mod derivable_impls; mod derive; mod disallowed_methods; -mod disallowed_name; +mod disallowed_names; mod disallowed_script_idents; mod disallowed_types; mod doc; @@ -684,7 +684,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(overflow_check_conditional::OverflowCheckConditional)); store.register_late_pass(|| Box::new(new_without_default::NewWithoutDefault::default())); let disallowed_names = conf.disallowed_names.iter().cloned().collect::>(); - store.register_late_pass(move || Box::new(disallowed_name::DisallowedName::new(disallowed_names.clone()))); + store.register_late_pass(move || Box::new(disallowed_names::DisallowedNames::new(disallowed_names.clone()))); let too_many_arguments_threshold = conf.too_many_arguments_threshold; let too_many_lines_threshold = conf.too_many_lines_threshold; store.register_late_pass(move || { diff --git a/clippy_lints/src/renamed_lints.rs b/clippy_lints/src/renamed_lints.rs index f06af29e1e23b..be16bd6413225 100644 --- a/clippy_lints/src/renamed_lints.rs +++ b/clippy_lints/src/renamed_lints.rs @@ -5,7 +5,7 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[ ("clippy::block_in_if_condition_expr", "clippy::blocks_in_if_conditions"), ("clippy::block_in_if_condition_stmt", "clippy::blocks_in_if_conditions"), ("clippy::box_vec", "clippy::box_collection"), - ("clippy::blacklisted_name", "clippy::disallowed_name"), + ("clippy::blacklisted_name", "clippy::disallowed_names"), ("clippy::const_static_lifetime", "clippy::redundant_static_lifetimes"), ("clippy::cyclomatic_complexity", "clippy::cognitive_complexity"), ("clippy::disallowed_method", "clippy::disallowed_methods"), diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 5a3fe7f8966d9..3faae9ac0d2b2 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -231,7 +231,7 @@ define_Conf! { /// Use the Cognitive Complexity lint instead. #[conf_deprecated("Please use `cognitive-complexity-threshold` instead", cognitive_complexity_threshold)] (cyclomatic_complexity_threshold: u64 = 25), - /// Lint: DISALLOWED_NAME. + /// Lint: DISALLOWED_NAMES. /// /// The list of disallowed names to lint about. NB: `bar` is not here since it has legitimate uses. The value /// `".."` can be used as part of the list to indicate, that the configured values should be appended to the diff --git a/tests/ui-toml/disallowed_names_append/disallowed_names.rs b/tests/ui-toml/disallowed_names_append/disallowed_names.rs index 939d48cb677a5..a2e2b46c42693 100644 --- a/tests/ui-toml/disallowed_names_append/disallowed_names.rs +++ b/tests/ui-toml/disallowed_names_append/disallowed_names.rs @@ -1,4 +1,4 @@ -#[warn(clippy::disallowed_name)] +#[warn(clippy::disallowed_names)] fn main() { // `foo` is part of the default configuration diff --git a/tests/ui-toml/disallowed_names_append/disallowed_names.stderr b/tests/ui-toml/disallowed_names_append/disallowed_names.stderr index d59872b0cb397..23c3e96a8d082 100644 --- a/tests/ui-toml/disallowed_names_append/disallowed_names.stderr +++ b/tests/ui-toml/disallowed_names_append/disallowed_names.stderr @@ -4,7 +4,7 @@ error: use of a disallowed/placeholder name `foo` LL | let foo = "bar"; | ^^^ | - = note: `-D clippy::disallowed-name` implied by `-D warnings` + = note: `-D clippy::disallowed-names` implied by `-D warnings` error: use of a disallowed/placeholder name `ducks` --> $DIR/disallowed_names.rs:7:9 diff --git a/tests/ui-toml/disallowed_names_replace/disallowed_names.rs b/tests/ui-toml/disallowed_names_replace/disallowed_names.rs index 939d48cb677a5..a2e2b46c42693 100644 --- a/tests/ui-toml/disallowed_names_replace/disallowed_names.rs +++ b/tests/ui-toml/disallowed_names_replace/disallowed_names.rs @@ -1,4 +1,4 @@ -#[warn(clippy::disallowed_name)] +#[warn(clippy::disallowed_names)] fn main() { // `foo` is part of the default configuration diff --git a/tests/ui-toml/disallowed_names_replace/disallowed_names.stderr b/tests/ui-toml/disallowed_names_replace/disallowed_names.stderr index 26f98bbb82db3..d961fa34074b3 100644 --- a/tests/ui-toml/disallowed_names_replace/disallowed_names.stderr +++ b/tests/ui-toml/disallowed_names_replace/disallowed_names.stderr @@ -4,7 +4,7 @@ error: use of a disallowed/placeholder name `ducks` LL | let ducks = ["quack", "quack"]; | ^^^^^ | - = note: `-D clippy::disallowed-name` implied by `-D warnings` + = note: `-D clippy::disallowed-names` implied by `-D warnings` error: aborting due to previous error diff --git a/tests/ui-toml/toml_disallow/conf_french_disallowed_name.rs b/tests/ui-toml/toml_disallow/conf_french_disallowed_name.rs index 897daee0fa651..2f86b3eda4c52 100644 --- a/tests/ui-toml/toml_disallow/conf_french_disallowed_name.rs +++ b/tests/ui-toml/toml_disallow/conf_french_disallowed_name.rs @@ -1,7 +1,7 @@ #![allow(dead_code)] #![allow(clippy::single_match)] #![allow(unused_variables)] -#![warn(clippy::disallowed_name)] +#![warn(clippy::disallowed_names)] fn test(toto: ()) {} diff --git a/tests/ui-toml/toml_disallow/conf_french_disallowed_name.stderr b/tests/ui-toml/toml_disallow/conf_french_disallowed_name.stderr index b9a15043f2de1..9082c1c54c36b 100644 --- a/tests/ui-toml/toml_disallow/conf_french_disallowed_name.stderr +++ b/tests/ui-toml/toml_disallow/conf_french_disallowed_name.stderr @@ -4,7 +4,7 @@ error: use of a disallowed/placeholder name `toto` LL | fn test(toto: ()) {} | ^^^^ | - = note: `-D clippy::disallowed-name` implied by `-D warnings` + = note: `-D clippy::disallowed-names` implied by `-D warnings` error: use of a disallowed/placeholder name `toto` --> $DIR/conf_french_disallowed_name.rs:9:9 diff --git a/tests/ui/borrow_box.rs b/tests/ui/borrow_box.rs index 2a4f8b53e8b05..35ed87b0f182f 100644 --- a/tests/ui/borrow_box.rs +++ b/tests/ui/borrow_box.rs @@ -1,5 +1,5 @@ #![deny(clippy::borrowed_box)] -#![allow(clippy::disallowed_name)] +#![allow(clippy::disallowed_names)] #![allow(unused_variables)] #![allow(dead_code)] diff --git a/tests/ui/box_collection.rs b/tests/ui/box_collection.rs index 690ed905cdd68..0780c8f0586e0 100644 --- a/tests/ui/box_collection.rs +++ b/tests/ui/box_collection.rs @@ -1,5 +1,10 @@ #![warn(clippy::all)] -#![allow(clippy::boxed_local, clippy::needless_pass_by_value, clippy::disallowed_name, unused)] +#![allow( + clippy::boxed_local, + clippy::needless_pass_by_value, + clippy::disallowed_names, + unused +)] use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList, VecDeque}; diff --git a/tests/ui/box_collection.stderr b/tests/ui/box_collection.stderr index 4a559e616d19a..2b28598ded92f 100644 --- a/tests/ui/box_collection.stderr +++ b/tests/ui/box_collection.stderr @@ -1,5 +1,5 @@ error: you seem to be trying to use `Box>`. Consider using just `Vec<..>` - --> $DIR/box_collection.rs:16:15 + --> $DIR/box_collection.rs:21:15 | LL | fn test1(foo: Box>) {} | ^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | fn test1(foo: Box>) {} = help: `Vec<..>` is already on the heap, `Box>` makes an extra allocation error: you seem to be trying to use `Box`. Consider using just `String` - --> $DIR/box_collection.rs:23:15 + --> $DIR/box_collection.rs:28:15 | LL | fn test3(foo: Box) {} | ^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | fn test3(foo: Box) {} = help: `String` is already on the heap, `Box` makes an extra allocation error: you seem to be trying to use `Box>`. Consider using just `HashMap<..>` - --> $DIR/box_collection.rs:25:15 + --> $DIR/box_collection.rs:30:15 | LL | fn test4(foo: Box>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL | fn test4(foo: Box>) {} = help: `HashMap<..>` is already on the heap, `Box>` makes an extra allocation error: you seem to be trying to use `Box>`. Consider using just `HashSet<..>` - --> $DIR/box_collection.rs:27:15 + --> $DIR/box_collection.rs:32:15 | LL | fn test5(foo: Box>) {} | ^^^^^^^^^^^^^^^^^ @@ -32,7 +32,7 @@ LL | fn test5(foo: Box>) {} = help: `HashSet<..>` is already on the heap, `Box>` makes an extra allocation error: you seem to be trying to use `Box>`. Consider using just `VecDeque<..>` - --> $DIR/box_collection.rs:29:15 + --> $DIR/box_collection.rs:34:15 | LL | fn test6(foo: Box>) {} | ^^^^^^^^^^^^^^^^^^ @@ -40,7 +40,7 @@ LL | fn test6(foo: Box>) {} = help: `VecDeque<..>` is already on the heap, `Box>` makes an extra allocation error: you seem to be trying to use `Box>`. Consider using just `LinkedList<..>` - --> $DIR/box_collection.rs:31:15 + --> $DIR/box_collection.rs:36:15 | LL | fn test7(foo: Box>) {} | ^^^^^^^^^^^^^^^^^^^^ @@ -48,7 +48,7 @@ LL | fn test7(foo: Box>) {} = help: `LinkedList<..>` is already on the heap, `Box>` makes an extra allocation error: you seem to be trying to use `Box>`. Consider using just `BTreeMap<..>` - --> $DIR/box_collection.rs:33:15 + --> $DIR/box_collection.rs:38:15 | LL | fn test8(foo: Box>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -56,7 +56,7 @@ LL | fn test8(foo: Box>) {} = help: `BTreeMap<..>` is already on the heap, `Box>` makes an extra allocation error: you seem to be trying to use `Box>`. Consider using just `BTreeSet<..>` - --> $DIR/box_collection.rs:35:15 + --> $DIR/box_collection.rs:40:15 | LL | fn test9(foo: Box>) {} | ^^^^^^^^^^^^^^^^^^ @@ -64,7 +64,7 @@ LL | fn test9(foo: Box>) {} = help: `BTreeSet<..>` is already on the heap, `Box>` makes an extra allocation error: you seem to be trying to use `Box>`. Consider using just `BinaryHeap<..>` - --> $DIR/box_collection.rs:37:16 + --> $DIR/box_collection.rs:42:16 | LL | fn test10(foo: Box>) {} | ^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/crashes/ice-2760.rs b/tests/ui/crashes/ice-2760.rs index 4504d31138528..61ef24804986e 100644 --- a/tests/ui/crashes/ice-2760.rs +++ b/tests/ui/crashes/ice-2760.rs @@ -1,4 +1,9 @@ -#![allow(unused_variables, clippy::disallowed_name, clippy::needless_pass_by_value, dead_code)] +#![allow( + unused_variables, + clippy::disallowed_names, + clippy::needless_pass_by_value, + dead_code +)] /// This should not compile-fail with: /// diff --git a/tests/ui/crashes/ice-3462.rs b/tests/ui/crashes/ice-3462.rs index a7d9017bc680b..b402052882adc 100644 --- a/tests/ui/crashes/ice-3462.rs +++ b/tests/ui/crashes/ice-3462.rs @@ -1,5 +1,5 @@ #![warn(clippy::all)] -#![allow(clippy::disallowed_name, clippy::equatable_if_let)] +#![allow(clippy::disallowed_names, clippy::equatable_if_let)] #![allow(unused)] /// Test for https://github.com/rust-lang/rust-clippy/issues/3462 diff --git a/tests/ui/crashes/regressions.rs b/tests/ui/crashes/regressions.rs index 86985391fc0b0..55a8b403407cd 100644 --- a/tests/ui/crashes/regressions.rs +++ b/tests/ui/crashes/regressions.rs @@ -1,4 +1,4 @@ -#![allow(clippy::disallowed_name)] +#![allow(clippy::disallowed_names)] pub fn foo(bar: *const u8) { println!("{:#p}", bar); diff --git a/tests/ui/disallowed_name.rs b/tests/ui/disallowed_names.rs similarity index 90% rename from tests/ui/disallowed_name.rs rename to tests/ui/disallowed_names.rs index 17acc8533e0b4..e937c49f3897f 100644 --- a/tests/ui/disallowed_name.rs +++ b/tests/ui/disallowed_names.rs @@ -6,7 +6,7 @@ unused_mut, unused_variables )] -#![warn(clippy::disallowed_name)] +#![warn(clippy::disallowed_names)] fn test(foo: ()) {} @@ -46,7 +46,7 @@ fn issue_1647_ref_mut() { mod tests { fn issue_7305() { - // `disallowed_name` lint should not be triggered inside of the test code. + // `disallowed_names` lint should not be triggered inside of the test code. let foo = 0; // Check that even in nested functions warning is still not triggered. diff --git a/tests/ui/disallowed_name.stderr b/tests/ui/disallowed_names.stderr similarity index 74% rename from tests/ui/disallowed_name.stderr rename to tests/ui/disallowed_names.stderr index 240c167e22349..78cb55096ff0c 100644 --- a/tests/ui/disallowed_name.stderr +++ b/tests/ui/disallowed_names.stderr @@ -1,85 +1,85 @@ error: use of a disallowed/placeholder name `foo` - --> $DIR/disallowed_name.rs:11:9 + --> $DIR/disallowed_names.rs:11:9 | LL | fn test(foo: ()) {} | ^^^ | - = note: `-D clippy::disallowed-name` implied by `-D warnings` + = note: `-D clippy::disallowed-names` implied by `-D warnings` error: use of a disallowed/placeholder name `foo` - --> $DIR/disallowed_name.rs:14:9 + --> $DIR/disallowed_names.rs:14:9 | LL | let foo = 42; | ^^^ error: use of a disallowed/placeholder name `baz` - --> $DIR/disallowed_name.rs:15:9 + --> $DIR/disallowed_names.rs:15:9 | LL | let baz = 42; | ^^^ error: use of a disallowed/placeholder name `quux` - --> $DIR/disallowed_name.rs:16:9 + --> $DIR/disallowed_names.rs:16:9 | LL | let quux = 42; | ^^^^ error: use of a disallowed/placeholder name `foo` - --> $DIR/disallowed_name.rs:27:10 + --> $DIR/disallowed_names.rs:27:10 | LL | (foo, Some(baz), quux @ Some(_)) => (), | ^^^ error: use of a disallowed/placeholder name `baz` - --> $DIR/disallowed_name.rs:27:20 + --> $DIR/disallowed_names.rs:27:20 | LL | (foo, Some(baz), quux @ Some(_)) => (), | ^^^ error: use of a disallowed/placeholder name `quux` - --> $DIR/disallowed_name.rs:27:26 + --> $DIR/disallowed_names.rs:27:26 | LL | (foo, Some(baz), quux @ Some(_)) => (), | ^^^^ error: use of a disallowed/placeholder name `foo` - --> $DIR/disallowed_name.rs:32:19 + --> $DIR/disallowed_names.rs:32:19 | LL | fn issue_1647(mut foo: u8) { | ^^^ error: use of a disallowed/placeholder name `baz` - --> $DIR/disallowed_name.rs:33:13 + --> $DIR/disallowed_names.rs:33:13 | LL | let mut baz = 0; | ^^^ error: use of a disallowed/placeholder name `quux` - --> $DIR/disallowed_name.rs:34:21 + --> $DIR/disallowed_names.rs:34:21 | LL | if let Some(mut quux) = Some(42) {} | ^^^^ error: use of a disallowed/placeholder name `baz` - --> $DIR/disallowed_name.rs:38:13 + --> $DIR/disallowed_names.rs:38:13 | LL | let ref baz = 0; | ^^^ error: use of a disallowed/placeholder name `quux` - --> $DIR/disallowed_name.rs:39:21 + --> $DIR/disallowed_names.rs:39:21 | LL | if let Some(ref quux) = Some(42) {} | ^^^^ error: use of a disallowed/placeholder name `baz` - --> $DIR/disallowed_name.rs:43:17 + --> $DIR/disallowed_names.rs:43:17 | LL | let ref mut baz = 0; | ^^^ error: use of a disallowed/placeholder name `quux` - --> $DIR/disallowed_name.rs:44:25 + --> $DIR/disallowed_names.rs:44:25 | LL | if let Some(ref mut quux) = Some(42) {} | ^^^^ diff --git a/tests/ui/if_same_then_else.rs b/tests/ui/if_same_then_else.rs index dd25008cbbea3..07d2002eb27f8 100644 --- a/tests/ui/if_same_then_else.rs +++ b/tests/ui/if_same_then_else.rs @@ -1,6 +1,6 @@ #![warn(clippy::if_same_then_else)] #![allow( - clippy::disallowed_name, + clippy::disallowed_names, clippy::eq_op, clippy::never_loop, clippy::no_effect, diff --git a/tests/ui/if_same_then_else2.rs b/tests/ui/if_same_then_else2.rs index 8b643c48914b0..58167f4446dba 100644 --- a/tests/ui/if_same_then_else2.rs +++ b/tests/ui/if_same_then_else2.rs @@ -1,6 +1,6 @@ #![warn(clippy::if_same_then_else)] #![allow( - clippy::disallowed_name, + clippy::disallowed_names, clippy::collapsible_else_if, clippy::equatable_if_let, clippy::collapsible_if, diff --git a/tests/ui/iter_skip_next.fixed b/tests/ui/iter_skip_next.fixed index 2cb8966541119..d56d623b5268e 100644 --- a/tests/ui/iter_skip_next.fixed +++ b/tests/ui/iter_skip_next.fixed @@ -2,7 +2,7 @@ // aux-build:option_helpers.rs #![warn(clippy::iter_skip_next)] -#![allow(clippy::disallowed_name)] +#![allow(clippy::disallowed_names)] #![allow(clippy::iter_nth)] #![allow(unused_mut, dead_code)] diff --git a/tests/ui/iter_skip_next.rs b/tests/ui/iter_skip_next.rs index 972d1e2b51f7c..3ec5d1b821426 100644 --- a/tests/ui/iter_skip_next.rs +++ b/tests/ui/iter_skip_next.rs @@ -2,7 +2,7 @@ // aux-build:option_helpers.rs #![warn(clippy::iter_skip_next)] -#![allow(clippy::disallowed_name)] +#![allow(clippy::disallowed_names)] #![allow(clippy::iter_nth)] #![allow(unused_mut, dead_code)] diff --git a/tests/ui/let_if_seq.rs b/tests/ui/let_if_seq.rs index ee351880b80e4..959567f686703 100644 --- a/tests/ui/let_if_seq.rs +++ b/tests/ui/let_if_seq.rs @@ -2,7 +2,7 @@ unused_variables, unused_assignments, clippy::similar_names, - clippy::disallowed_name, + clippy::disallowed_names, clippy::branches_sharing_code, clippy::needless_late_init )] diff --git a/tests/ui/manual_ok_or.fixed b/tests/ui/manual_ok_or.fixed index 9ee71bf9090b9..d864f85545349 100644 --- a/tests/ui/manual_ok_or.fixed +++ b/tests/ui/manual_ok_or.fixed @@ -1,6 +1,6 @@ // run-rustfix #![warn(clippy::manual_ok_or)] -#![allow(clippy::disallowed_name)] +#![allow(clippy::disallowed_names)] #![allow(clippy::redundant_closure)] #![allow(dead_code)] #![allow(unused_must_use)] diff --git a/tests/ui/manual_ok_or.rs b/tests/ui/manual_ok_or.rs index 0e1bc0857691b..6264768460ef6 100644 --- a/tests/ui/manual_ok_or.rs +++ b/tests/ui/manual_ok_or.rs @@ -1,6 +1,6 @@ // run-rustfix #![warn(clippy::manual_ok_or)] -#![allow(clippy::disallowed_name)] +#![allow(clippy::disallowed_names)] #![allow(clippy::redundant_closure)] #![allow(dead_code)] #![allow(unused_must_use)] diff --git a/tests/ui/match_same_arms2.rs b/tests/ui/match_same_arms2.rs index 086e3e9b8059b..61793e80c98d4 100644 --- a/tests/ui/match_same_arms2.rs +++ b/tests/ui/match_same_arms2.rs @@ -1,5 +1,5 @@ #![warn(clippy::match_same_arms)] -#![allow(clippy::disallowed_name, clippy::diverging_sub_expression)] +#![allow(clippy::disallowed_names, clippy::diverging_sub_expression)] fn bar(_: T) {} fn foo() -> bool { diff --git a/tests/ui/methods.rs b/tests/ui/methods.rs index 8d782f73821a9..6f22366eab29a 100644 --- a/tests/ui/methods.rs +++ b/tests/ui/methods.rs @@ -2,7 +2,7 @@ #![warn(clippy::all, clippy::pedantic)] #![allow( - clippy::disallowed_name, + clippy::disallowed_names, clippy::default_trait_access, clippy::missing_docs_in_private_items, clippy::missing_safety_doc, diff --git a/tests/ui/mismatching_type_param_order.rs b/tests/ui/mismatching_type_param_order.rs index c2195bf18d1d0..40c1fcae1fd3f 100644 --- a/tests/ui/mismatching_type_param_order.rs +++ b/tests/ui/mismatching_type_param_order.rs @@ -1,5 +1,5 @@ #![warn(clippy::mismatching_type_param_order)] -#![allow(clippy::disallowed_name)] +#![allow(clippy::disallowed_names)] fn main() { struct Foo { diff --git a/tests/ui/mixed_read_write_in_expression.rs b/tests/ui/mixed_read_write_in_expression.rs index 6e413fcf5bb44..6efc7657ec0c9 100644 --- a/tests/ui/mixed_read_write_in_expression.rs +++ b/tests/ui/mixed_read_write_in_expression.rs @@ -4,7 +4,7 @@ unused_variables, clippy::no_effect, dead_code, - clippy::disallowed_name + clippy::disallowed_names )] fn main() { let mut x = 0; diff --git a/tests/ui/op_ref.rs b/tests/ui/op_ref.rs index 8e53f2073e58d..07226b0a1a83b 100644 --- a/tests/ui/op_ref.rs +++ b/tests/ui/op_ref.rs @@ -1,4 +1,4 @@ -#![allow(unused_variables, clippy::disallowed_name)] +#![allow(unused_variables, clippy::disallowed_names)] #![warn(clippy::op_ref)] use std::collections::HashSet; use std::ops::{BitAnd, Mul}; diff --git a/tests/ui/rc_mutex.rs b/tests/ui/rc_mutex.rs index ee707a630fa74..432972bbc3175 100644 --- a/tests/ui/rc_mutex.rs +++ b/tests/ui/rc_mutex.rs @@ -1,5 +1,5 @@ #![warn(clippy::rc_mutex)] -#![allow(unused, clippy::disallowed_name)] +#![allow(unused, clippy::disallowed_names)] use std::rc::Rc; use std::sync::Mutex; diff --git a/tests/ui/redundant_allocation.rs b/tests/ui/redundant_allocation.rs index 7b9e02f974cd4..9f2b1f4a2819f 100644 --- a/tests/ui/redundant_allocation.rs +++ b/tests/ui/redundant_allocation.rs @@ -1,6 +1,6 @@ #![warn(clippy::all)] #![allow(clippy::boxed_local, clippy::needless_pass_by_value)] -#![allow(clippy::disallowed_name, unused_variables, dead_code)] +#![allow(clippy::disallowed_names, unused_variables, dead_code)] #![allow(unused_imports)] pub struct MyStruct; diff --git a/tests/ui/redundant_allocation_fixable.fixed b/tests/ui/redundant_allocation_fixable.fixed index 4c85b20afe57b..6db02718c70bb 100644 --- a/tests/ui/redundant_allocation_fixable.fixed +++ b/tests/ui/redundant_allocation_fixable.fixed @@ -1,7 +1,7 @@ // run-rustfix #![warn(clippy::all)] #![allow(clippy::boxed_local, clippy::needless_pass_by_value)] -#![allow(clippy::disallowed_name, unused_variables, dead_code)] +#![allow(clippy::disallowed_names, unused_variables, dead_code)] #![allow(unused_imports)] pub struct MyStruct; diff --git a/tests/ui/redundant_allocation_fixable.rs b/tests/ui/redundant_allocation_fixable.rs index 8b402e478738e..c15806f30c049 100644 --- a/tests/ui/redundant_allocation_fixable.rs +++ b/tests/ui/redundant_allocation_fixable.rs @@ -1,7 +1,7 @@ // run-rustfix #![warn(clippy::all)] #![allow(clippy::boxed_local, clippy::needless_pass_by_value)] -#![allow(clippy::disallowed_name, unused_variables, dead_code)] +#![allow(clippy::disallowed_names, unused_variables, dead_code)] #![allow(unused_imports)] pub struct MyStruct; diff --git a/tests/ui/rename.fixed b/tests/ui/rename.fixed index e65327737ce69..2a74c6e54f46e 100644 --- a/tests/ui/rename.fixed +++ b/tests/ui/rename.fixed @@ -6,7 +6,7 @@ #![allow(clippy::blocks_in_if_conditions)] #![allow(clippy::box_collection)] -#![allow(clippy::disallowed_name)] +#![allow(clippy::disallowed_names)] #![allow(clippy::redundant_static_lifetimes)] #![allow(clippy::cognitive_complexity)] #![allow(clippy::disallowed_methods)] @@ -37,7 +37,7 @@ #![warn(clippy::blocks_in_if_conditions)] #![warn(clippy::blocks_in_if_conditions)] #![warn(clippy::box_collection)] -#![warn(clippy::disallowed_name)] +#![warn(clippy::disallowed_names)] #![warn(clippy::redundant_static_lifetimes)] #![warn(clippy::cognitive_complexity)] #![warn(clippy::disallowed_methods)] diff --git a/tests/ui/rename.rs b/tests/ui/rename.rs index 8125b153589a9..fa88af959743a 100644 --- a/tests/ui/rename.rs +++ b/tests/ui/rename.rs @@ -6,7 +6,7 @@ #![allow(clippy::blocks_in_if_conditions)] #![allow(clippy::box_collection)] -#![allow(clippy::disallowed_name)] +#![allow(clippy::disallowed_names)] #![allow(clippy::redundant_static_lifetimes)] #![allow(clippy::cognitive_complexity)] #![allow(clippy::disallowed_methods)] diff --git a/tests/ui/rename.stderr b/tests/ui/rename.stderr index d282931105953..d510951b1217b 100644 --- a/tests/ui/rename.stderr +++ b/tests/ui/rename.stderr @@ -18,11 +18,11 @@ error: lint `clippy::box_vec` has been renamed to `clippy::box_collection` LL | #![warn(clippy::box_vec)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection` -error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_name` +error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names` --> $DIR/rename.rs:40:9 | LL | #![warn(clippy::blacklisted_name)] - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_name` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names` error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes` --> $DIR/rename.rs:41:9 diff --git a/tests/ui/skip_while_next.rs b/tests/ui/skip_while_next.rs index bedd2704100cf..a551c19d98bcd 100644 --- a/tests/ui/skip_while_next.rs +++ b/tests/ui/skip_while_next.rs @@ -1,7 +1,7 @@ // aux-build:option_helpers.rs #![warn(clippy::skip_while_next)] -#![allow(clippy::disallowed_name)] +#![allow(clippy::disallowed_names)] extern crate option_helpers; use option_helpers::IteratorFalsePositives; diff --git a/tests/ui/swap.fixed b/tests/ui/swap.fixed index 0865287c08a39..24b229235d33a 100644 --- a/tests/ui/swap.fixed +++ b/tests/ui/swap.fixed @@ -2,7 +2,7 @@ #![warn(clippy::all)] #![allow( - clippy::disallowed_name, + clippy::disallowed_names, clippy::no_effect, clippy::redundant_clone, redundant_semicolons, diff --git a/tests/ui/swap.rs b/tests/ui/swap.rs index 8f87c488462a6..a318c27919c8a 100644 --- a/tests/ui/swap.rs +++ b/tests/ui/swap.rs @@ -2,7 +2,7 @@ #![warn(clippy::all)] #![allow( - clippy::disallowed_name, + clippy::disallowed_names, clippy::no_effect, clippy::redundant_clone, redundant_semicolons, diff --git a/tests/ui/trivially_copy_pass_by_ref.rs b/tests/ui/trivially_copy_pass_by_ref.rs index 732b139ea12f5..c0c64ebcabfbb 100644 --- a/tests/ui/trivially_copy_pass_by_ref.rs +++ b/tests/ui/trivially_copy_pass_by_ref.rs @@ -2,7 +2,7 @@ // normalize-stderr-test "\(limit: \d+ byte\)" -> "(limit: N byte)" #![deny(clippy::trivially_copy_pass_by_ref)] -#![allow(clippy::disallowed_name, clippy::redundant_field_names)] +#![allow(clippy::disallowed_names, clippy::redundant_field_names)] #[derive(Copy, Clone)] struct Foo(u32); diff --git a/tests/ui/used_underscore_binding.rs b/tests/ui/used_underscore_binding.rs index 91c8807936384..322083511ac18 100644 --- a/tests/ui/used_underscore_binding.rs +++ b/tests/ui/used_underscore_binding.rs @@ -2,7 +2,7 @@ #![feature(rustc_private)] #![warn(clippy::all)] -#![allow(clippy::disallowed_name, clippy::eq_op)] +#![allow(clippy::disallowed_names, clippy::eq_op)] #![warn(clippy::used_underscore_binding)] #[macro_use] From 56c9cc458dc7405ac6d829531e19ff80bdeb99d7 Mon Sep 17 00:00:00 2001 From: Andy Caldwell Date: Thu, 9 Jun 2022 16:11:19 +0100 Subject: [PATCH 18/62] Add deprecation test for old configuration entry --- tests/ui-toml/conf_deprecated_key/clippy.toml | 3 ++- tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/ui-toml/conf_deprecated_key/clippy.toml b/tests/ui-toml/conf_deprecated_key/clippy.toml index 30cd9eecd98d3..d79a98d05af48 100644 --- a/tests/ui-toml/conf_deprecated_key/clippy.toml +++ b/tests/ui-toml/conf_deprecated_key/clippy.toml @@ -1,5 +1,6 @@ -# that one is a warning +# Expect errors from these deprecated configs cyclomatic-complexity-threshold = 2 +blacklisted-names = [ "..", "wibble" ] # that one is white-listed [third-party] diff --git a/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr b/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr index 3b4c72044da82..4c560299ebdd1 100644 --- a/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr +++ b/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr @@ -1,5 +1,7 @@ warning: error reading Clippy's configuration file `$DIR/clippy.toml`: deprecated field `cyclomatic-complexity-threshold`. Please use `cognitive-complexity-threshold` instead +warning: error reading Clippy's configuration file `$DIR/clippy.toml`: deprecated field `blacklisted-names`. Please use `disallowed-names` instead + error: the function has a cognitive complexity of (3/2) --> $DIR/conf_deprecated_key.rs:4:4 | @@ -9,5 +11,5 @@ LL | fn cognitive_complexity() { = note: `-D clippy::cognitive-complexity` implied by `-D warnings` = help: you could split it up into multiple smaller functions -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error; 2 warnings emitted From ca0996e3a04983098b0ea81c85fba2019e3eed7b Mon Sep 17 00:00:00 2001 From: Miguel Guarniz Date: Fri, 15 Jul 2022 23:13:04 -0400 Subject: [PATCH 19/62] Change maybe_body_owned_by to take local def id Signed-off-by: Miguel Guarniz --- clippy_lints/src/utils/author.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index bbb04c9945a09..59e07313f549e 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -138,7 +138,7 @@ impl<'tcx> LateLintPass<'tcx> for Author { fn check_item(cx: &LateContext<'_>, hir_id: HirId) { let hir = cx.tcx.hir(); - if let Some(body_id) = hir.maybe_body_owned_by(hir_id) { + if let Some(body_id) = hir.maybe_body_owned_by(hir.local_def_id(hir_id)) { check_node(cx, hir_id, |v| { v.expr(&v.bind("expr", &hir.body(body_id).value)); }); From 29a0f69f9c5862f6c81fc7dda6065fb0a0c779b6 Mon Sep 17 00:00:00 2001 From: Miguel Guarniz Date: Tue, 19 Jul 2022 17:06:52 -0400 Subject: [PATCH 20/62] Rename local_did to def_id Signed-off-by: Miguel Guarniz --- clippy_lints/src/utils/author.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index 59e07313f549e..c0726868f77e2 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -138,7 +138,7 @@ impl<'tcx> LateLintPass<'tcx> for Author { fn check_item(cx: &LateContext<'_>, hir_id: HirId) { let hir = cx.tcx.hir(); - if let Some(body_id) = hir.maybe_body_owned_by(hir.local_def_id(hir_id)) { + if let Some(body_id) = hir.maybe_body_owned_by(hir_id.expect_owner()) { check_node(cx, hir_id, |v| { v.expr(&v.bind("expr", &hir.body(body_id).value)); }); From ce5fa10cce7a0b550be87da853aef2b5f9a87b1e Mon Sep 17 00:00:00 2001 From: Miguel Guarniz Date: Tue, 19 Jul 2022 17:47:49 -0400 Subject: [PATCH 21/62] Change enclosing_body_owner to return LocalDefId Signed-off-by: Miguel Guarniz --- clippy_utils/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 34a1cdaf1d52a..50bb008098dcb 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1353,7 +1353,7 @@ pub fn is_integer_const(cx: &LateContext<'_>, e: &Expr<'_>, value: u128) -> bool if is_integer_literal(e, value) { return true; } - let enclosing_body = cx.tcx.hir().local_def_id(cx.tcx.hir().enclosing_body_owner(e.hir_id)); + let enclosing_body = cx.tcx.hir().enclosing_body_owner(e.hir_id); if let Some((Constant::Int(v), _)) = constant(cx, cx.tcx.typeck(enclosing_body), e) { return value == v; } From 6c1110ef5be83670d516abcc4484c1dc19dc4dd4 Mon Sep 17 00:00:00 2001 From: Miguel Guarniz Date: Tue, 19 Jul 2022 22:51:52 -0400 Subject: [PATCH 22/62] Avoid ICE when fetching LocalDefId Signed-off-by: Miguel Guarniz --- clippy_lints/src/methods/suspicious_map.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/methods/suspicious_map.rs b/clippy_lints/src/methods/suspicious_map.rs index 18ded291915e1..9c3375bf35e7d 100644 --- a/clippy_lints/src/methods/suspicious_map.rs +++ b/clippy_lints/src/methods/suspicious_map.rs @@ -12,7 +12,8 @@ pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, count_recv: &hi if_chain! { if is_trait_method(cx, count_recv, sym::Iterator); let closure = expr_or_init(cx, map_arg); - if let Some(body_id) = cx.tcx.hir().maybe_body_owned_by(closure.hir_id); + if let Some(def_id) = cx.tcx.hir().opt_local_def_id(closure.hir_id); + if let Some(body_id) = cx.tcx.hir().maybe_body_owned_by(def_id); let closure_body = cx.tcx.hir().body(body_id); if !cx.typeck_results().expr_ty(&closure_body.value).is_unit(); then { From 23b4fe6da55291a5937535d09af2bdfed8a9a50d Mon Sep 17 00:00:00 2001 From: Sosthene <51865119+sgued@users.noreply.github.com> Date: Sat, 30 Jul 2022 13:17:51 +0200 Subject: [PATCH 23/62] Apply suggestions from code review The expect_used lint is allow-by-default, so it would be better to show the case where this is enabled. Co-authored-by: Takayuki Nakata --- clippy_lints/src/methods/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 06e7af57ee17a..5ac6b09f0aa27 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -197,7 +197,7 @@ declare_clippy_lint! { /// result.unwrap(); /// ``` /// - /// If [expect_used](#expect_used) is allowed, instead: + /// Use instead: /// ```rust /// # let option = Some(1); /// # let result: Result = Ok(1); @@ -205,7 +205,7 @@ declare_clippy_lint! { /// result.expect("more helpful message"); /// ``` /// - /// Otherwise try using + /// If [expect_used](#expect_used) is enabled, instead: /// ```rust,ignore /// # let option = Some(1); /// # let result: Result = Ok(1); From 62907727af48847c546b524a9b5e72f7dbc3babc Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Tue, 12 Jul 2022 09:10:22 -0500 Subject: [PATCH 24/62] Use LocalDefId for closures more --- clippy_utils/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 34a1cdaf1d52a..018059facbd18 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -968,7 +968,7 @@ pub fn can_move_expr_to_closure<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<' } }, ExprKind::Closure { .. } => { - let closure_id = self.cx.tcx.hir().local_def_id(e.hir_id).to_def_id(); + let closure_id = self.cx.tcx.hir().local_def_id(e.hir_id); for capture in self.cx.typeck_results().closure_min_captures_flattened(closure_id) { let local_id = match capture.place.base { PlaceBase::Local(id) => id, From cd135749920d85596bc539ce393d02698b49429f Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Sun, 31 Jul 2022 15:11:00 +0000 Subject: [PATCH 25/62] Always include a position span in rustc_parse_format::Argument --- clippy_lints/src/write.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index 3a99d1b417fee..32718200c0b3a 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -441,7 +441,7 @@ impl SimpleFormatArgs { }; match arg.position { - ArgumentIs(n, _) | ArgumentImplicitlyIs(n) => { + ArgumentIs(n) | ArgumentImplicitlyIs(n) => { if self.unnamed.len() <= n { // Use a dummy span to mark all unseen arguments. self.unnamed.resize_with(n, || vec![DUMMY_SP]); @@ -462,7 +462,7 @@ impl SimpleFormatArgs { } } }, - ArgumentNamed(n, _) => { + ArgumentNamed(n) => { let n = Symbol::intern(n); if let Some(x) = self.named.iter_mut().find(|x| x.0 == n) { match x.1.as_slice() { From 09f9acea0a611cdd3185e311b8124737ffd30332 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 27 Jul 2022 13:59:30 +1000 Subject: [PATCH 26/62] Shrink `Token`. From 72 bytes to 12 bytes (on x86-64). There are two parts to this: - Changing various source code offsets from 64-bit to 32-bit. This is not a problem because the rest of rustc also uses 32-bit source code offsets. This means `Token` is no longer `Copy` but this causes no problems. - Removing the `RawStrError` from `LiteralKind`. Raw string literal invalidity is now indicated by a `None` value within `RawStr`/`RawByteStr`, and the new `validate_raw_str` function can be used to re-lex an invalid raw string literal to get the `RawStrError`. There is one very small change in behaviour. Previously, if a raw string literal matched both the `InvalidStarter` and `TooManyHashes` cases, the latter would override the former. This has now changed, because `raw_double_quoted_string` now uses `?` and so returns immediately upon detecting the `InvalidStarter` case. I think this is a slight improvement to report the earlier-detected error, and it explains the change in the `test_too_many_hashes` test. The commit also removes a couple of comments that refer to #77629 and say that the size of these types don't affect performance. These comments are wrong, though the performance effect is small. --- clippy_lints/src/matches/mod.rs | 2 +- clippy_lints/src/undocumented_unsafe_blocks.rs | 2 +- clippy_utils/src/hir_utils.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs index b638f27160282..e9e13aece18f6 100644 --- a/clippy_lints/src/matches/mod.rs +++ b/clippy_lints/src/matches/mod.rs @@ -1112,7 +1112,7 @@ fn span_contains_cfg(cx: &LateContext<'_>, s: Span) -> bool { let mut pos = 0usize; let mut iter = tokenize(&snip).map(|t| { let start = pos; - pos += t.len; + pos += t.len as usize; (t.kind, start..pos) }); diff --git a/clippy_lints/src/undocumented_unsafe_blocks.rs b/clippy_lints/src/undocumented_unsafe_blocks.rs index 04f16fd2161c5..d2e675a783eaa 100644 --- a/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -345,7 +345,7 @@ fn text_has_safety_comment(src: &str, line_starts: &[BytePos], offset: usize) -> if line.starts_with("/*") { let src = src[line_start..line_starts.last().unwrap().to_usize() - offset].trim_start(); let mut tokens = tokenize(src); - return src[..tokens.next().unwrap().len] + return src[..tokens.next().unwrap().len as usize] .to_ascii_uppercase() .contains("SAFETY:") && tokens.all(|t| t.kind == TokenKind::Whitespace); diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index eaf260ddfb832..1834e2a2de872 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -141,7 +141,7 @@ impl HirEqInterExpr<'_, '_, '_> { let mut left_pos = 0; let left = tokenize(&left) .map(|t| { - let end = left_pos + t.len; + let end = left_pos + t.len as usize; let s = &left[left_pos..end]; left_pos = end; (t, s) @@ -156,7 +156,7 @@ impl HirEqInterExpr<'_, '_, '_> { let mut right_pos = 0; let right = tokenize(&right) .map(|t| { - let end = right_pos + t.len; + let end = right_pos + t.len as usize; let s = &right[right_pos..end]; right_pos = end; (t, s) From e00ceb99cdee70a30ba15ff490f3c249495c9c03 Mon Sep 17 00:00:00 2001 From: tabokie Date: Mon, 1 Aug 2022 13:22:16 +0800 Subject: [PATCH 27/62] move [`assertions_on_result_states`] to restriction Signed-off-by: tabokie --- clippy_lints/src/assertions_on_result_states.rs | 5 ++++- clippy_lints/src/lib.register_all.rs | 1 - clippy_lints/src/lib.register_restriction.rs | 1 + clippy_lints/src/lib.register_style.rs | 1 - 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/assertions_on_result_states.rs b/clippy_lints/src/assertions_on_result_states.rs index b6affdee52364..4caab6230909c 100644 --- a/clippy_lints/src/assertions_on_result_states.rs +++ b/clippy_lints/src/assertions_on_result_states.rs @@ -19,6 +19,9 @@ declare_clippy_lint! { /// ### Why is this bad? /// An assertion failure cannot output an useful message of the error. /// + /// ### Known problems + /// The suggested replacement decreases the readability of code and log output. + /// /// ### Example /// ```rust,ignore /// # let r = Ok::<_, ()>(()); @@ -28,7 +31,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.64.0"] pub ASSERTIONS_ON_RESULT_STATES, - style, + restriction, "`assert!(r.is_ok())`/`assert!(r.is_err())` gives worse error message than directly calling `r.unwrap()`/`r.unwrap_err()`" } diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index cb33b3b3279de..b9cc9fc1e85b0 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -6,7 +6,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(almost_complete_letter_range::ALMOST_COMPLETE_LETTER_RANGE), LintId::of(approx_const::APPROX_CONSTANT), LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS), - LintId::of(assertions_on_result_states::ASSERTIONS_ON_RESULT_STATES), LintId::of(async_yields_async::ASYNC_YIELDS_ASYNC), LintId::of(attrs::BLANKET_CLIPPY_RESTRICTION_LINTS), LintId::of(attrs::DEPRECATED_CFG_ATTR), diff --git a/clippy_lints/src/lib.register_restriction.rs b/clippy_lints/src/lib.register_restriction.rs index 495abd8387e85..a7339ef272174 100644 --- a/clippy_lints/src/lib.register_restriction.rs +++ b/clippy_lints/src/lib.register_restriction.rs @@ -7,6 +7,7 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve LintId::of(as_underscore::AS_UNDERSCORE), LintId::of(asm_syntax::INLINE_ASM_X86_ATT_SYNTAX), LintId::of(asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX), + LintId::of(assertions_on_result_states::ASSERTIONS_ON_RESULT_STATES), LintId::of(attrs::ALLOW_ATTRIBUTES_WITHOUT_REASON), LintId::of(casts::FN_TO_NUMERIC_CAST_ANY), LintId::of(create_dir::CREATE_DIR), diff --git a/clippy_lints/src/lib.register_style.rs b/clippy_lints/src/lib.register_style.rs index 31852881615dd..ebc0933e31d27 100644 --- a/clippy_lints/src/lib.register_style.rs +++ b/clippy_lints/src/lib.register_style.rs @@ -4,7 +4,6 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS), - LintId::of(assertions_on_result_states::ASSERTIONS_ON_RESULT_STATES), LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS), LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON), LintId::of(casts::FN_TO_NUMERIC_CAST), From 72e7064b011d66e46cad74e8c7b219d624d237b8 Mon Sep 17 00:00:00 2001 From: Michael Schubart Date: Sun, 31 Jul 2022 23:16:23 +0100 Subject: [PATCH 28/62] Make it easier to find the developer guide Adding the link that I wish had been there when I first looked for this info. --- CONTRIBUTING.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6e15133d267ba..28b4cfd5f0995 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -30,10 +30,10 @@ All contributors are expected to follow the [Rust Code of Conduct]. ## The Clippy book If you're new to Clippy and don't know where to start the [Clippy book] includes -a developer guide and is a good place to start your journey. +a [developer guide] and is a good place to start your journey. - -[Clippy book]: book/src +[Clippy book]: https://doc.rust-lang.org/nightly/clippy/index.html +[developer guide]: https://doc.rust-lang.org/nightly/clippy/development/index.html ## High level approach From 48ad9d8bc7d50fd5ebe90c1bbe760fcb8dc0dc14 Mon Sep 17 00:00:00 2001 From: tabokie Date: Mon, 1 Aug 2022 13:30:43 +0800 Subject: [PATCH 29/62] do not apply [`assertions_on_result_states`] to unwrap unit type Signed-off-by: tabokie --- clippy_lints/src/assertions_on_result_states.rs | 11 ++++++++--- tests/ui/assertions_on_result_states.fixed | 8 ++++++++ tests/ui/assertions_on_result_states.rs | 8 ++++++++ tests/ui/assertions_on_result_states.stderr | 10 +++++----- 4 files changed, 29 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/assertions_on_result_states.rs b/clippy_lints/src/assertions_on_result_states.rs index 4caab6230909c..6a6554f968b33 100644 --- a/clippy_lints/src/assertions_on_result_states.rs +++ b/clippy_lints/src/assertions_on_result_states.rs @@ -53,13 +53,14 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates { if result_type_with_refs != result_type { return; } else if let Res::Local(binding_id) = path_res(cx, recv) - && local_used_after_expr(cx, binding_id, recv) { + && local_used_after_expr(cx, binding_id, recv) + { return; } } let mut app = Applicability::MachineApplicable; match method_segment.ident.as_str() { - "is_ok" if has_debug_impl(cx, substs.type_at(1)) => { + "is_ok" if type_suitable_to_unwrap(cx, substs.type_at(1)) => { span_lint_and_sugg( cx, ASSERTIONS_ON_RESULT_STATES, @@ -73,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates { app, ); } - "is_err" if has_debug_impl(cx, substs.type_at(0)) => { + "is_err" if type_suitable_to_unwrap(cx, substs.type_at(0)) => { span_lint_and_sugg( cx, ASSERTIONS_ON_RESULT_STATES, @@ -99,3 +100,7 @@ fn has_debug_impl<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { .get_diagnostic_item(sym::Debug) .map_or(false, |debug| implements_trait(cx, ty, debug, &[])) } + +fn type_suitable_to_unwrap<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { + has_debug_impl(cx, ty) && !ty.is_unit() && !ty.is_never() +} diff --git a/tests/ui/assertions_on_result_states.fixed b/tests/ui/assertions_on_result_states.fixed index 7bde72e4b6b57..795f435f24cd4 100644 --- a/tests/ui/assertions_on_result_states.fixed +++ b/tests/ui/assertions_on_result_states.fixed @@ -27,6 +27,14 @@ fn main() { let r: Result = Ok(Foo); assert!(r.is_ok()); + // test ok with some messages + let r: Result = Ok(Foo); + assert!(r.is_ok(), "oops"); + + // test ok with unit error + let r: Result = Ok(Foo); + assert!(r.is_ok()); + // test temporary ok fn get_ok() -> Result { Ok(Foo) diff --git a/tests/ui/assertions_on_result_states.rs b/tests/ui/assertions_on_result_states.rs index 4c5af81efc23f..1101aec1e1b34 100644 --- a/tests/ui/assertions_on_result_states.rs +++ b/tests/ui/assertions_on_result_states.rs @@ -27,6 +27,14 @@ fn main() { let r: Result = Ok(Foo); assert!(r.is_ok()); + // test ok with some messages + let r: Result = Ok(Foo); + assert!(r.is_ok(), "oops"); + + // test ok with unit error + let r: Result = Ok(Foo); + assert!(r.is_ok()); + // test temporary ok fn get_ok() -> Result { Ok(Foo) diff --git a/tests/ui/assertions_on_result_states.stderr b/tests/ui/assertions_on_result_states.stderr index 13c2dd877a976..97a5f3dfca4a6 100644 --- a/tests/ui/assertions_on_result_states.stderr +++ b/tests/ui/assertions_on_result_states.stderr @@ -7,31 +7,31 @@ LL | assert!(r.is_ok()); = note: `-D clippy::assertions-on-result-states` implied by `-D warnings` error: called `assert!` with `Result::is_ok` - --> $DIR/assertions_on_result_states.rs:34:5 + --> $DIR/assertions_on_result_states.rs:42:5 | LL | assert!(get_ok().is_ok()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `get_ok().unwrap()` error: called `assert!` with `Result::is_ok` - --> $DIR/assertions_on_result_states.rs:37:5 + --> $DIR/assertions_on_result_states.rs:45:5 | LL | assert!(get_ok_macro!().is_ok()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `get_ok_macro!().unwrap()` error: called `assert!` with `Result::is_ok` - --> $DIR/assertions_on_result_states.rs:50:5 + --> $DIR/assertions_on_result_states.rs:58:5 | LL | assert!(r.is_ok()); | ^^^^^^^^^^^^^^^^^^ help: replace with: `r.unwrap()` error: called `assert!` with `Result::is_ok` - --> $DIR/assertions_on_result_states.rs:56:9 + --> $DIR/assertions_on_result_states.rs:64:9 | LL | assert!(r.is_ok()); | ^^^^^^^^^^^^^^^^^^ help: replace with: `r.unwrap()` error: called `assert!` with `Result::is_err` - --> $DIR/assertions_on_result_states.rs:64:5 + --> $DIR/assertions_on_result_states.rs:72:5 | LL | assert!(r.is_err()); | ^^^^^^^^^^^^^^^^^^^ help: replace with: `r.unwrap_err()` From d17a30a05d6212d80466f3bfca9b7021b0bb581c Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 12 Mar 2022 19:36:11 +0100 Subject: [PATCH 30/62] Store associated item defaultness in impl_defaultness. --- clippy_lints/src/missing_inline.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/missing_inline.rs b/clippy_lints/src/missing_inline.rs index 0d95329918984..9e14ccd34334b 100644 --- a/clippy_lints/src/missing_inline.rs +++ b/clippy_lints/src/missing_inline.rs @@ -105,7 +105,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline { match tit_.kind { hir::TraitItemKind::Const(..) | hir::TraitItemKind::Type(..) => {}, hir::TraitItemKind::Fn(..) => { - if tit.defaultness.has_value() { + if cx.tcx.impl_defaultness(tit.id.def_id).has_value() { // trait method with default body needs inline in case // an impl is not provided let desc = "a default trait method"; From 119247ad3274ee0f38a0f5454c6e5235dbb6eecf Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 13 Mar 2022 00:52:25 +0100 Subject: [PATCH 31/62] Remove DefId from AssocItemContainer. --- clippy_lints/src/eta_reduction.rs | 8 +++++--- clippy_lints/src/missing_doc.rs | 15 +++++++-------- clippy_lints/src/missing_inline.rs | 8 +++++--- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index 80c84014bfdeb..4f9ff97f1fd1a 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -220,9 +220,11 @@ fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure_ty: Ty<'tcx>, call_ty: Ty<'tc } fn get_ufcs_type_name(cx: &LateContext<'_>, method_def_id: DefId) -> String { - match cx.tcx.associated_item(method_def_id).container { - ty::TraitContainer(def_id) => cx.tcx.def_path_str(def_id), - ty::ImplContainer(def_id) => { + let assoc_item = cx.tcx.associated_item(method_def_id); + let def_id = assoc_item.container_id(cx.tcx); + match assoc_item.container { + ty::TraitContainer => cx.tcx.def_path_str(def_id), + ty::ImplContainer => { let ty = cx.tcx.type_of(def_id); match ty.kind() { ty::Adt(adt, _) => cx.tcx.def_path_str(adt.did()), diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index a20377f320b23..88ba002927a94 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -10,7 +10,7 @@ use clippy_utils::diagnostics::span_lint; use rustc_ast::ast; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::ty::{self, DefIdTree}; +use rustc_middle::ty::DefIdTree; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::source_map::Span; @@ -153,13 +153,12 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) { // If the method is an impl for a trait, don't doc. - match cx.tcx.associated_item(impl_item.def_id).container { - ty::TraitContainer(_) => return, - ty::ImplContainer(cid) => { - if cx.tcx.impl_trait_ref(cid).is_some() { - return; - } - }, + if let Some(cid) = cx.tcx.associated_item(impl_item.def_id).impl_container(cx.tcx) { + if cx.tcx.impl_trait_ref(cid).is_some() { + return; + } + } else { + return; } let (article, desc) = cx.tcx.article_and_description(impl_item.def_id.to_def_id()); diff --git a/clippy_lints/src/missing_inline.rs b/clippy_lints/src/missing_inline.rs index 9e14ccd34334b..07bc2ca5d3cd2 100644 --- a/clippy_lints/src/missing_inline.rs +++ b/clippy_lints/src/missing_inline.rs @@ -151,9 +151,11 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline { hir::ImplItemKind::Const(..) | hir::ImplItemKind::TyAlias(_) => return, }; - let trait_def_id = match cx.tcx.associated_item(impl_item.def_id).container { - TraitContainer(cid) => Some(cid), - ImplContainer(cid) => cx.tcx.impl_trait_ref(cid).map(|t| t.def_id), + let assoc_item = cx.tcx.associated_item(impl_item.def_id); + let container_id = assoc_item.container_id(cx.tcx); + let trait_def_id = match assoc_item.container { + TraitContainer => Some(container_id), + ImplContainer => cx.tcx.impl_trait_ref(container_id).map(|t| t.def_id), }; if let Some(trait_def_id) = trait_def_id { From 0696624ba789acbe84a2d9e5e76e929fd2511381 Mon Sep 17 00:00:00 2001 From: Federico Guerinoni Date: Sat, 30 Jul 2022 14:33:10 +0200 Subject: [PATCH 32/62] Add `elapsed_instant` lint Closes #8603 Signed-off-by: Federico Guerinoni --- CHANGELOG.md | 1 + clippy_lints/src/lib.register_lints.rs | 1 + clippy_lints/src/lib.register_pedantic.rs | 1 + clippy_lints/src/lib.rs | 2 + clippy_lints/src/manual_instant_elapsed.rs | 69 ++++++++++++++++++++++ clippy_utils/src/paths.rs | 2 + tests/ui/manual_instant_elapsed.fixed | 27 +++++++++ tests/ui/manual_instant_elapsed.rs | 27 +++++++++ tests/ui/manual_instant_elapsed.stderr | 16 +++++ 9 files changed, 146 insertions(+) create mode 100644 clippy_lints/src/manual_instant_elapsed.rs create mode 100644 tests/ui/manual_instant_elapsed.fixed create mode 100644 tests/ui/manual_instant_elapsed.rs create mode 100644 tests/ui/manual_instant_elapsed.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 646e1128e9a31..84f06d9887997 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3686,6 +3686,7 @@ Released 2018-09-13 [`manual_find`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find [`manual_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find_map [`manual_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_flatten +[`manual_instant_elapsed`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_instant_elapsed [`manual_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_map [`manual_memcpy`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_memcpy [`manual_non_exhaustive`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 430b8585f6dbf..c2bc4badc43cc 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -244,6 +244,7 @@ store.register_lints(&[ manual_assert::MANUAL_ASSERT, manual_async_fn::MANUAL_ASYNC_FN, manual_bits::MANUAL_BITS, + manual_instant_elapsed::MANUAL_INSTANT_ELAPSED, manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE, manual_ok_or::MANUAL_OK_OR, manual_rem_euclid::MANUAL_REM_EUCLID, diff --git a/clippy_lints/src/lib.register_pedantic.rs b/clippy_lints/src/lib.register_pedantic.rs index 4d4b89687d040..4250ee055e6c9 100644 --- a/clippy_lints/src/lib.register_pedantic.rs +++ b/clippy_lints/src/lib.register_pedantic.rs @@ -49,6 +49,7 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ LintId::of(loops::EXPLICIT_ITER_LOOP), LintId::of(macro_use::MACRO_USE_IMPORTS), LintId::of(manual_assert::MANUAL_ASSERT), + LintId::of(manual_instant_elapsed::MANUAL_INSTANT_ELAPSED), LintId::of(manual_ok_or::MANUAL_OK_OR), LintId::of(matches::MATCH_BOOL), LintId::of(matches::MATCH_ON_VEC_ITEMS), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 6ebf19831563b..88c1a727f8dc3 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -273,6 +273,7 @@ mod main_recursion; mod manual_assert; mod manual_async_fn; mod manual_bits; +mod manual_instant_elapsed; mod manual_non_exhaustive; mod manual_ok_or; mod manual_rem_euclid; @@ -929,6 +930,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move || Box::new(operators::Operators::new(verbose_bit_mask_threshold))); store.register_late_pass(|| Box::new(invalid_utf8_in_unchecked::InvalidUtf8InUnchecked)); store.register_late_pass(|| Box::new(std_instead_of_core::StdReexports::default())); + store.register_late_pass(|| Box::new(manual_instant_elapsed::ManualInstantElapsed)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/manual_instant_elapsed.rs b/clippy_lints/src/manual_instant_elapsed.rs new file mode 100644 index 0000000000000..331cda1db8990 --- /dev/null +++ b/clippy_lints/src/manual_instant_elapsed.rs @@ -0,0 +1,69 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::source_map::Spanned; + +declare_clippy_lint! { + /// ### What it does + /// Lints subtraction between `Instant::now()` and another `Instant`. + /// + /// ### Why is this bad? + /// It is easy to accidentally write `prev_instant - Instant::now()`, which will always be 0ns + /// as `Instant` subtraction saturates. + /// + /// `prev_instant.elapsed()` also more clearly signals intention. + /// + /// ### Example + /// ```rust + /// use std::time::Instant; + /// let prev_instant = Instant::now(); + /// let duration = Instant::now() - prev_instant; + /// ``` + /// Use instead: + /// ```rust + /// use std::time::Instant; + /// let prev_instant = Instant::now(); + /// let duration = prev_instant.elapsed(); + /// ``` + #[clippy::version = "1.64.0"] + pub MANUAL_INSTANT_ELAPSED, + pedantic, + "subtraction between `Instant::now()` and previous `Instant`" +} + +declare_lint_pass!(ManualInstantElapsed => [MANUAL_INSTANT_ELAPSED]); + +impl LateLintPass<'_> for ManualInstantElapsed { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) { + if let ExprKind::Binary(Spanned {node: BinOpKind::Sub, ..}, lhs, rhs) = expr.kind + && check_instant_now_call(cx, lhs) + && let ty_resolved = cx.typeck_results().expr_ty(rhs) + && let rustc_middle::ty::Adt(def, _) = ty_resolved.kind() + && clippy_utils::match_def_path(cx, def.did(), &clippy_utils::paths::INSTANT) + && let Some(sugg) = clippy_utils::sugg::Sugg::hir_opt(cx, rhs) + { + span_lint_and_sugg( + cx, + MANUAL_INSTANT_ELAPSED, + expr.span, + "manual implementation of `Instant::elapsed`", + "try", + format!("{}.elapsed()", sugg.maybe_par()), + Applicability::MachineApplicable, + ); + } + } +} + +fn check_instant_now_call(cx: &LateContext<'_>, expr_block: &'_ Expr<'_>) -> bool { + if let ExprKind::Call(fn_expr, []) = expr_block.kind + && let Some(fn_id) = clippy_utils::path_def_id(cx, fn_expr) + && clippy_utils::match_def_path(cx, fn_id, &clippy_utils::paths::INSTANT_NOW) + { + true + } else { + false + } +} diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 05429d05d9ebe..8d697a301c444 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -194,3 +194,5 @@ pub const VEC_RESIZE: [&str; 4] = ["alloc", "vec", "Vec", "resize"]; pub const WEAK_ARC: [&str; 3] = ["alloc", "sync", "Weak"]; pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"]; pub const PTR_NON_NULL: [&str; 4] = ["core", "ptr", "non_null", "NonNull"]; +pub const INSTANT_NOW: [&str; 4] = ["std", "time", "Instant", "now"]; +pub const INSTANT: [&str; 3] = ["std", "time", "Instant"]; diff --git a/tests/ui/manual_instant_elapsed.fixed b/tests/ui/manual_instant_elapsed.fixed new file mode 100644 index 0000000000000..0fa776b7b2e4e --- /dev/null +++ b/tests/ui/manual_instant_elapsed.fixed @@ -0,0 +1,27 @@ +// run-rustfix +#![warn(clippy::manual_instant_elapsed)] +#![allow(clippy::unnecessary_operation)] +#![allow(unused_variables)] +#![allow(unused_must_use)] + +use std::time::Instant; + +fn main() { + let prev_instant = Instant::now(); + + { + // don't influence + let another_instant = Instant::now(); + } + + let duration = prev_instant.elapsed(); + + // don't catch + let duration = prev_instant.elapsed(); + + Instant::now() - duration; + + let ref_to_instant = &Instant::now(); + + (*ref_to_instant).elapsed(); // to ensure parens are added correctly +} diff --git a/tests/ui/manual_instant_elapsed.rs b/tests/ui/manual_instant_elapsed.rs new file mode 100644 index 0000000000000..5b11b84535ddc --- /dev/null +++ b/tests/ui/manual_instant_elapsed.rs @@ -0,0 +1,27 @@ +// run-rustfix +#![warn(clippy::manual_instant_elapsed)] +#![allow(clippy::unnecessary_operation)] +#![allow(unused_variables)] +#![allow(unused_must_use)] + +use std::time::Instant; + +fn main() { + let prev_instant = Instant::now(); + + { + // don't influence + let another_instant = Instant::now(); + } + + let duration = Instant::now() - prev_instant; + + // don't catch + let duration = prev_instant.elapsed(); + + Instant::now() - duration; + + let ref_to_instant = &Instant::now(); + + Instant::now() - *ref_to_instant; // to ensure parens are added correctly +} diff --git a/tests/ui/manual_instant_elapsed.stderr b/tests/ui/manual_instant_elapsed.stderr new file mode 100644 index 0000000000000..5537f5642a23c --- /dev/null +++ b/tests/ui/manual_instant_elapsed.stderr @@ -0,0 +1,16 @@ +error: manual implementation of `Instant::elapsed` + --> $DIR/manual_instant_elapsed.rs:17:20 + | +LL | let duration = Instant::now() - prev_instant; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `prev_instant.elapsed()` + | + = note: `-D clippy::manual-instant-elapsed` implied by `-D warnings` + +error: manual implementation of `Instant::elapsed` + --> $DIR/manual_instant_elapsed.rs:26:5 + | +LL | Instant::now() - *ref_to_instant; // to ensure parens are added correctly + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(*ref_to_instant).elapsed()` + +error: aborting due to 2 previous errors + From 2fcaac79bcaf6b100172d9b5b932790923dcc97f Mon Sep 17 00:00:00 2001 From: tabokie Date: Mon, 1 Aug 2022 13:22:16 +0800 Subject: [PATCH 33/62] move [`assertions_on_result_states`] to restriction Signed-off-by: tabokie --- clippy_lints/src/assertions_on_result_states.rs | 5 ++++- clippy_lints/src/lib.register_all.rs | 1 - clippy_lints/src/lib.register_restriction.rs | 1 + clippy_lints/src/lib.register_style.rs | 1 - 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/assertions_on_result_states.rs b/clippy_lints/src/assertions_on_result_states.rs index b6affdee52364..4caab6230909c 100644 --- a/clippy_lints/src/assertions_on_result_states.rs +++ b/clippy_lints/src/assertions_on_result_states.rs @@ -19,6 +19,9 @@ declare_clippy_lint! { /// ### Why is this bad? /// An assertion failure cannot output an useful message of the error. /// + /// ### Known problems + /// The suggested replacement decreases the readability of code and log output. + /// /// ### Example /// ```rust,ignore /// # let r = Ok::<_, ()>(()); @@ -28,7 +31,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.64.0"] pub ASSERTIONS_ON_RESULT_STATES, - style, + restriction, "`assert!(r.is_ok())`/`assert!(r.is_err())` gives worse error message than directly calling `r.unwrap()`/`r.unwrap_err()`" } diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index 5be1c417bf8f6..0ba9b7ae7e581 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -6,7 +6,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(almost_complete_letter_range::ALMOST_COMPLETE_LETTER_RANGE), LintId::of(approx_const::APPROX_CONSTANT), LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS), - LintId::of(assertions_on_result_states::ASSERTIONS_ON_RESULT_STATES), LintId::of(async_yields_async::ASYNC_YIELDS_ASYNC), LintId::of(attrs::BLANKET_CLIPPY_RESTRICTION_LINTS), LintId::of(attrs::DEPRECATED_CFG_ATTR), diff --git a/clippy_lints/src/lib.register_restriction.rs b/clippy_lints/src/lib.register_restriction.rs index 495abd8387e85..a7339ef272174 100644 --- a/clippy_lints/src/lib.register_restriction.rs +++ b/clippy_lints/src/lib.register_restriction.rs @@ -7,6 +7,7 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve LintId::of(as_underscore::AS_UNDERSCORE), LintId::of(asm_syntax::INLINE_ASM_X86_ATT_SYNTAX), LintId::of(asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX), + LintId::of(assertions_on_result_states::ASSERTIONS_ON_RESULT_STATES), LintId::of(attrs::ALLOW_ATTRIBUTES_WITHOUT_REASON), LintId::of(casts::FN_TO_NUMERIC_CAST_ANY), LintId::of(create_dir::CREATE_DIR), diff --git a/clippy_lints/src/lib.register_style.rs b/clippy_lints/src/lib.register_style.rs index e029a5235e720..e95bab1d0454d 100644 --- a/clippy_lints/src/lib.register_style.rs +++ b/clippy_lints/src/lib.register_style.rs @@ -4,7 +4,6 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS), - LintId::of(assertions_on_result_states::ASSERTIONS_ON_RESULT_STATES), LintId::of(blacklisted_name::BLACKLISTED_NAME), LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS), LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON), From 9ab6146afea0119afb1a06afef5fbed5a3efe422 Mon Sep 17 00:00:00 2001 From: tabokie Date: Tue, 2 Aug 2022 11:37:44 +0800 Subject: [PATCH 34/62] simplify unit type check Signed-off-by: tabokie --- clippy_lints/src/map_unit_fn.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs index af9d948af00e6..6db852c3ffe79 100644 --- a/clippy_lints/src/map_unit_fn.rs +++ b/clippy_lints/src/map_unit_fn.rs @@ -97,11 +97,7 @@ declare_clippy_lint! { declare_lint_pass!(MapUnit => [OPTION_MAP_UNIT_FN, RESULT_MAP_UNIT_FN]); fn is_unit_type(ty: Ty<'_>) -> bool { - match ty.kind() { - ty::Tuple(slice) => slice.is_empty(), - ty::Never => true, - _ => false, - } + ty.is_unit() || ty.is_never() } fn is_unit_function(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { From ac7a91ea161d2fec96f8eda01c3925e161bf9f38 Mon Sep 17 00:00:00 2001 From: tabokie Date: Tue, 2 Aug 2022 12:01:36 +0800 Subject: [PATCH 35/62] use slice match more often Signed-off-by: tabokie --- clippy_lints/src/checked_conversions.rs | 5 +--- clippy_lints/src/create_dir.rs | 4 ++-- clippy_lints/src/from_str_radix_10.rs | 11 ++++----- clippy_lints/src/loops/manual_memcpy.rs | 10 +++----- clippy_lints/src/loops/needless_range_loop.rs | 5 ++-- clippy_lints/src/manual_ok_or.rs | 11 ++++----- clippy_lints/src/map_err_ignore.rs | 6 ++--- clippy_lints/src/matches/match_as_ref.rs | 6 ++--- clippy_lints/src/matches/try_err.rs | 6 ++--- clippy_lints/src/mem_replace.rs | 6 ++--- clippy_lints/src/path_buf_push_overwrite.rs | 6 ++--- clippy_lints/src/question_mark.rs | 3 +-- clippy_lints/src/ranges.rs | 12 +++++----- clippy_lints/src/regex.rs | 11 ++++----- .../src/slow_vector_initialization.rs | 9 ++------ clippy_lints/src/stable_sort_primitive.rs | 5 ++-- clippy_lints/src/useless_conversion.rs | 23 +++++++++---------- clippy_lints/src/verbose_file_reads.rs | 6 ++--- 18 files changed, 59 insertions(+), 86 deletions(-) diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs index 17fc81951f95b..37b2fdcff09ff 100644 --- a/clippy_lints/src/checked_conversions.rs +++ b/clippy_lints/src/checked_conversions.rs @@ -270,10 +270,7 @@ fn get_types_from_cast<'a>( let limit_from: Option<(&Expr<'_>, &str)> = call_from_cast.or_else(|| { if_chain! { // `from_type::from, to_type::max_value()` - if let ExprKind::Call(from_func, args) = &expr.kind; - // `to_type::max_value()` - if args.len() == 1; - if let limit = &args[0]; + if let ExprKind::Call(from_func, [limit]) = &expr.kind; // `from_type::from` if let ExprKind::Path(ref path) = &from_func.kind; if let Some(from_sym) = get_implementing_type(path, INTS, "from"); diff --git a/clippy_lints/src/create_dir.rs b/clippy_lints/src/create_dir.rs index 18d34370a7b87..878248a6bdc8c 100644 --- a/clippy_lints/src/create_dir.rs +++ b/clippy_lints/src/create_dir.rs @@ -34,7 +34,7 @@ declare_lint_pass!(CreateDir => [CREATE_DIR]); impl LateLintPass<'_> for CreateDir { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { if_chain! { - if let ExprKind::Call(func, args) = expr.kind; + if let ExprKind::Call(func, [arg, ..]) = expr.kind; if let ExprKind::Path(ref path) = func.kind; if let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id(); if match_def_path(cx, def_id, &paths::STD_FS_CREATE_DIR); @@ -45,7 +45,7 @@ impl LateLintPass<'_> for CreateDir { expr.span, "calling `std::fs::create_dir` where there may be a better way", "consider calling `std::fs::create_dir_all` instead", - format!("create_dir_all({})", snippet(cx, args[0].span, "..")), + format!("create_dir_all({})", snippet(cx, arg.span, "..")), Applicability::MaybeIncorrect, ) } diff --git a/clippy_lints/src/from_str_radix_10.rs b/clippy_lints/src/from_str_radix_10.rs index 57b0751320521..74941d817be36 100644 --- a/clippy_lints/src/from_str_radix_10.rs +++ b/clippy_lints/src/from_str_radix_10.rs @@ -46,7 +46,7 @@ declare_lint_pass!(FromStrRadix10 => [FROM_STR_RADIX_10]); impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 { fn check_expr(&mut self, cx: &LateContext<'tcx>, exp: &Expr<'tcx>) { if_chain! { - if let ExprKind::Call(maybe_path, arguments) = &exp.kind; + if let ExprKind::Call(maybe_path, [src, radix]) = &exp.kind; if let ExprKind::Path(QPath::TypeRelative(ty, pathseg)) = &maybe_path.kind; // check if the first part of the path is some integer primitive @@ -60,20 +60,19 @@ impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 { if pathseg.ident.name.as_str() == "from_str_radix"; // check if the second argument is a primitive `10` - if arguments.len() == 2; - if let ExprKind::Lit(lit) = &arguments[1].kind; + if let ExprKind::Lit(lit) = &radix.kind; if let rustc_ast::ast::LitKind::Int(10, _) = lit.node; then { - let expr = if let ExprKind::AddrOf(_, _, expr) = &arguments[0].kind { + let expr = if let ExprKind::AddrOf(_, _, expr) = &src.kind { let ty = cx.typeck_results().expr_ty(expr); if is_ty_stringish(cx, ty) { expr } else { - &arguments[0] + &src } } else { - &arguments[0] + &src }; let sugg = Sugg::hir_with_applicability( diff --git a/clippy_lints/src/loops/manual_memcpy.rs b/clippy_lints/src/loops/manual_memcpy.rs index b31015d195b52..a65df48e413e8 100644 --- a/clippy_lints/src/loops/manual_memcpy.rs +++ b/clippy_lints/src/loops/manual_memcpy.rs @@ -119,11 +119,9 @@ fn build_manual_memcpy_suggestion<'tcx>( let print_limit = |end: &Expr<'_>, end_str: &str, base: &Expr<'_>, sugg: MinifyingSugg<'static>| { if_chain! { - if let ExprKind::MethodCall(method, len_args, _) = end.kind; + if let ExprKind::MethodCall(method, [recv], _) = end.kind; if method.ident.name == sym::len; - if len_args.len() == 1; - if let Some(arg) = len_args.get(0); - if path_to_local(arg) == path_to_local(base); + if path_to_local(recv) == path_to_local(base); then { if sugg.to_string() == end_str { sugg::EMPTY.into() @@ -343,10 +341,8 @@ fn get_slice_like_element_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Opti fn fetch_cloned_expr<'tcx>(expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> { if_chain! { - if let ExprKind::MethodCall(method, args, _) = expr.kind; + if let ExprKind::MethodCall(method, [arg], _) = expr.kind; if method.ident.name == sym::clone; - if args.len() == 1; - if let Some(arg) = args.get(0); then { arg } else { expr } } } diff --git a/clippy_lints/src/loops/needless_range_loop.rs b/clippy_lints/src/loops/needless_range_loop.rs index a7ef562b21fc4..7ca4a7c4ebfc2 100644 --- a/clippy_lints/src/loops/needless_range_loop.rs +++ b/clippy_lints/src/loops/needless_range_loop.rs @@ -188,10 +188,9 @@ pub(super) fn check<'tcx>( fn is_len_call(expr: &Expr<'_>, var: Symbol) -> bool { if_chain! { - if let ExprKind::MethodCall(method, len_args, _) = expr.kind; - if len_args.len() == 1; + if let ExprKind::MethodCall(method, [recv], _) = expr.kind; if method.ident.name == sym::len; - if let ExprKind::Path(QPath::Resolved(_, path)) = len_args[0].kind; + if let ExprKind::Path(QPath::Resolved(_, path)) = recv.kind; if path.segments.len() == 1; if path.segments[0].ident.name == var; then { diff --git a/clippy_lints/src/manual_ok_or.rs b/clippy_lints/src/manual_ok_or.rs index 9abf2507b921c..cf5004399b884 100644 --- a/clippy_lints/src/manual_ok_or.rs +++ b/clippy_lints/src/manual_ok_or.rs @@ -47,17 +47,14 @@ impl<'tcx> LateLintPass<'tcx> for ManualOkOr { } if_chain! { - if let ExprKind::MethodCall(method_segment, args, _) = scrutinee.kind; + if let ExprKind::MethodCall(method_segment, [receiver, or_expr, map_expr], _) = scrutinee.kind; if method_segment.ident.name == sym!(map_or); - if args.len() == 3; - let method_receiver = &args[0]; - let ty = cx.typeck_results().expr_ty(method_receiver); + let ty = cx.typeck_results().expr_ty(receiver); if is_type_diagnostic_item(cx, ty, sym::Option); - let or_expr = &args[1]; - if is_ok_wrapping(cx, &args[2]); + if is_ok_wrapping(cx, map_expr); if let ExprKind::Call(Expr { kind: ExprKind::Path(err_path), .. }, &[ref err_arg]) = or_expr.kind; if is_lang_ctor(cx, err_path, ResultErr); - if let Some(method_receiver_snippet) = snippet_opt(cx, method_receiver.span); + if let Some(method_receiver_snippet) = snippet_opt(cx, receiver.span); if let Some(err_arg_snippet) = snippet_opt(cx, err_arg.span); if let Some(indent) = indent_of(cx, scrutinee.span); then { diff --git a/clippy_lints/src/map_err_ignore.rs b/clippy_lints/src/map_err_ignore.rs index 21d0e19eb0a48..1e542447c96ec 100644 --- a/clippy_lints/src/map_err_ignore.rs +++ b/clippy_lints/src/map_err_ignore.rs @@ -113,10 +113,10 @@ impl<'tcx> LateLintPass<'tcx> for MapErrIgnore { } // check if this is a method call (e.g. x.foo()) - if let ExprKind::MethodCall(method, args, _) = e.kind { + if let ExprKind::MethodCall(method, [_, arg], _) = e.kind { // only work if the method name is `map_err` and there are only 2 arguments (e.g. x.map_err(|_|[1] // Enum::Variant[2])) - if method.ident.as_str() == "map_err" && args.len() == 2 { + if method.ident.name == sym!(map_err) { // make sure the first argument is a closure, and grab the CaptureRef, BodyId, and fn_decl_span // fields if let ExprKind::Closure(&Closure { @@ -124,7 +124,7 @@ impl<'tcx> LateLintPass<'tcx> for MapErrIgnore { body, fn_decl_span, .. - }) = args[1].kind + }) = arg.kind { // check if this is by Reference (meaning there's no move statement) if capture_clause == CaptureBy::Ref { diff --git a/clippy_lints/src/matches/match_as_ref.rs b/clippy_lints/src/matches/match_as_ref.rs index d914eba01716b..a0efdecec67f4 100644 --- a/clippy_lints/src/matches/match_as_ref.rs +++ b/clippy_lints/src/matches/match_as_ref.rs @@ -72,10 +72,10 @@ fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, scrutine // val, // }; if_chain! { - if let ExprKind::Call(match_fun, try_args) = scrutinee.kind; + if let ExprKind::Call(match_fun, [try_arg, ..]) = scrutinee.kind; if let ExprKind::Path(ref match_fun_path) = match_fun.kind; if matches!(match_fun_path, QPath::LangItem(LangItem::TryTraitBranch, ..)); - if let Some(try_arg) = try_args.get(0); - if let ExprKind::Call(err_fun, err_args) = try_arg.kind; - if let Some(err_arg) = err_args.get(0); + if let ExprKind::Call(err_fun, [err_arg, ..]) = try_arg.kind; if let ExprKind::Path(ref err_fun_path) = err_fun.kind; if is_lang_ctor(cx, err_fun_path, ResultErr); if let Some(return_ty) = find_return_type(cx, &expr.kind); diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index 41073d40f3d79..cad3ea2a176cd 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -163,8 +163,7 @@ fn check_replace_with_uninit(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<' } if_chain! { - if let ExprKind::Call(repl_func, repl_args) = src.kind; - if repl_args.is_empty(); + if let ExprKind::Call(repl_func, []) = src.kind; if let ExprKind::Path(ref repl_func_qpath) = repl_func.kind; if let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id(); then { @@ -246,11 +245,10 @@ impl<'tcx> LateLintPass<'tcx> for MemReplace { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if_chain! { // Check that `expr` is a call to `mem::replace()` - if let ExprKind::Call(func, func_args) = expr.kind; + if let ExprKind::Call(func, [dest, src]) = expr.kind; if let ExprKind::Path(ref func_qpath) = func.kind; if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id(); if cx.tcx.is_diagnostic_item(sym::mem_replace, def_id); - if let [dest, src] = func_args; then { check_replace_option_with_none(cx, src, dest, expr.span); check_replace_with_uninit(cx, src, dest, expr.span); diff --git a/clippy_lints/src/path_buf_push_overwrite.rs b/clippy_lints/src/path_buf_push_overwrite.rs index 3f940ce61c03e..bc6a918f70355 100644 --- a/clippy_lints/src/path_buf_push_overwrite.rs +++ b/clippy_lints/src/path_buf_push_overwrite.rs @@ -46,11 +46,9 @@ declare_lint_pass!(PathBufPushOverwrite => [PATH_BUF_PUSH_OVERWRITE]); impl<'tcx> LateLintPass<'tcx> for PathBufPushOverwrite { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if_chain! { - if let ExprKind::MethodCall(path, args, _) = expr.kind; + if let ExprKind::MethodCall(path, [recv, get_index_arg], _) = expr.kind; if path.ident.name == sym!(push); - if args.len() == 2; - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]).peel_refs(), sym::PathBuf); - if let Some(get_index_arg) = args.get(1); + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv).peel_refs(), sym::PathBuf); if let ExprKind::Lit(ref lit) = get_index_arg.kind; if let LitKind::Str(ref path_lit, _) = lit.node; if let pushed_path = Path::new(path_lit.as_str()); diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index fd0a53839e6ea..964a057f00d32 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -86,8 +86,7 @@ fn check_is_none_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: &Ex if_chain! { if let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr); if !is_else_clause(cx.tcx, expr); - if let ExprKind::MethodCall(segment, args, _) = &cond.kind; - if let Some(caller) = args.get(0); + if let ExprKind::MethodCall(segment, [caller, ..], _) = &cond.kind; let caller_ty = cx.typeck_results().expr_ty(caller); let if_block = IfBlockType::IfIs(caller, caller_ty, segment.ident.name, then, r#else); if is_early_return(sym::Option, cx, &if_block) || is_early_return(sym::Result, cx, &if_block); diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 056637c2048ee..fbf842c339e49 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -385,24 +385,24 @@ fn check_range_zip_with_len(cx: &LateContext<'_>, path: &PathSegment<'_>, args: if path.ident.as_str() == "zip"; if let [iter, zip_arg] = args; // `.iter()` call - if let ExprKind::MethodCall(iter_path, iter_args, _) = iter.kind; + if let ExprKind::MethodCall(iter_path, [iter_caller, ..], _) = iter.kind; if iter_path.ident.name == sym::iter; // range expression in `.zip()` call: `0..x.len()` if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::Range::hir(zip_arg); if is_integer_const(cx, start, 0); // `.len()` call - if let ExprKind::MethodCall(len_path, len_args, _) = end.kind; - if len_path.ident.name == sym::len && len_args.len() == 1; + if let ExprKind::MethodCall(len_path, [len_caller], _) = end.kind; + if len_path.ident.name == sym::len; // `.iter()` and `.len()` called on same `Path` - if let ExprKind::Path(QPath::Resolved(_, iter_path)) = iter_args[0].kind; - if let ExprKind::Path(QPath::Resolved(_, len_path)) = len_args[0].kind; + if let ExprKind::Path(QPath::Resolved(_, iter_path)) = iter_caller.kind; + if let ExprKind::Path(QPath::Resolved(_, len_path)) = len_caller.kind; if SpanlessEq::new(cx).eq_path_segments(iter_path.segments, len_path.segments); then { span_lint(cx, RANGE_ZIP_WITH_LEN, span, &format!("it is more idiomatic to use `{}.iter().enumerate()`", - snippet(cx, iter_args[0].span, "_")) + snippet(cx, iter_caller.span, "_")) ); } } diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index f9a9b0691935a..6bcae0da8f48f 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -57,21 +57,20 @@ declare_lint_pass!(Regex => [INVALID_REGEX, TRIVIAL_REGEX]); impl<'tcx> LateLintPass<'tcx> for Regex { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if_chain! { - if let ExprKind::Call(fun, args) = expr.kind; + if let ExprKind::Call(fun, [arg]) = expr.kind; if let ExprKind::Path(ref qpath) = fun.kind; - if args.len() == 1; if let Some(def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id(); then { if match_def_path(cx, def_id, &paths::REGEX_NEW) || match_def_path(cx, def_id, &paths::REGEX_BUILDER_NEW) { - check_regex(cx, &args[0], true); + check_regex(cx, arg, true); } else if match_def_path(cx, def_id, &paths::REGEX_BYTES_NEW) || match_def_path(cx, def_id, &paths::REGEX_BYTES_BUILDER_NEW) { - check_regex(cx, &args[0], false); + check_regex(cx, arg, false); } else if match_def_path(cx, def_id, &paths::REGEX_SET_NEW) { - check_set(cx, &args[0], true); + check_set(cx, arg, true); } else if match_def_path(cx, def_id, &paths::REGEX_BYTES_SET_NEW) { - check_set(cx, &args[0], false); + check_set(cx, arg, false); } } } diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index 2c8aa17e80dbd..b59a25e3a4004 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -233,15 +233,10 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> { /// Returns `true` if give expression is `repeat(0).take(...)` fn is_repeat_take(&self, expr: &Expr<'_>) -> bool { if_chain! { - if let ExprKind::MethodCall(take_path, take_args, _) = expr.kind; + if let ExprKind::MethodCall(take_path, [recv, len_arg, ..], _) = expr.kind; if take_path.ident.name == sym!(take); - // Check that take is applied to `repeat(0)` - if let Some(repeat_expr) = take_args.get(0); - if self.is_repeat_zero(repeat_expr); - - if let Some(len_arg) = take_args.get(1); - + if self.is_repeat_zero(recv); then { // Check that len expression is equals to `with_capacity` expression if SpanlessEq::new(self.cx).eq_expr(len_arg, self.vec_alloc.len_expr) { diff --git a/clippy_lints/src/stable_sort_primitive.rs b/clippy_lints/src/stable_sort_primitive.rs index a6c685df721d6..6d54935f81ab2 100644 --- a/clippy_lints/src/stable_sort_primitive.rs +++ b/clippy_lints/src/stable_sort_primitive.rs @@ -97,12 +97,11 @@ struct LintDetection { fn detect_stable_sort_primitive(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { if_chain! { - if let ExprKind::MethodCall(method_name, args, _) = &expr.kind; - if let Some(slice) = &args.get(0); + if let ExprKind::MethodCall(method_name, [slice, args @ ..], _) = &expr.kind; if let Some(method) = SortingKind::from_stable_name(method_name.ident.name.as_str()); if let Some(slice_type) = is_slice_of_primitives(cx, slice); then { - let args_str = args.iter().skip(1).map(|arg| Sugg::hir(cx, arg, "..").to_string()).collect::>().join(", "); + let args_str = args.iter().map(|arg| Sugg::hir(cx, arg, "..").to_string()).collect::>().join(", "); Some(LintDetection { slice_name: Sugg::hir(cx, slice, "..").to_string(), method, method_args: args_str, slice_type }) } else { None diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index fe29bf29d0caf..b6738e2891d3e 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -59,17 +59,17 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { ExprKind::Ret(Some(e)) | ExprKind::Break(_, Some(e)) => e, _ => return, }; - if let ExprKind::Call(_, args) = e.kind { - self.try_desugar_arm.push(args[0].hir_id); + if let ExprKind::Call(_, [arg, ..]) = e.kind { + self.try_desugar_arm.push(arg.hir_id); } }, - ExprKind::MethodCall(name, .., args, _) => { + ExprKind::MethodCall(name, .., [recv, ..], _) => { if is_trait_method(cx, e, sym::Into) && name.ident.as_str() == "into" { let a = cx.typeck_results().expr_ty(e); - let b = cx.typeck_results().expr_ty(&args[0]); + let b = cx.typeck_results().expr_ty(recv); if same_type_and_consts(a, b) { - let sugg = snippet_with_macro_callsite(cx, args[0].span, "").to_string(); + let sugg = snippet_with_macro_callsite(cx, recv.span, "").to_string(); span_lint_and_sugg( cx, USELESS_CONVERSION, @@ -90,9 +90,9 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { } } let a = cx.typeck_results().expr_ty(e); - let b = cx.typeck_results().expr_ty(&args[0]); + let b = cx.typeck_results().expr_ty(recv); if same_type_and_consts(a, b) { - let sugg = snippet(cx, args[0].span, "").into_owned(); + let sugg = snippet(cx, recv.span, "").into_owned(); span_lint_and_sugg( cx, USELESS_CONVERSION, @@ -107,7 +107,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { if_chain! { if is_trait_method(cx, e, sym::TryInto) && name.ident.name == sym::try_into; let a = cx.typeck_results().expr_ty(e); - let b = cx.typeck_results().expr_ty(&args[0]); + let b = cx.typeck_results().expr_ty(recv); if is_type_diagnostic_item(cx, a, sym::Result); if let ty::Adt(_, substs) = a.kind(); if let Some(a_type) = substs.types().next(); @@ -126,14 +126,13 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { } }, - ExprKind::Call(path, args) => { + ExprKind::Call(path, [arg]) => { if_chain! { - if args.len() == 1; if let ExprKind::Path(ref qpath) = path.kind; if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id(); then { let a = cx.typeck_results().expr_ty(e); - let b = cx.typeck_results().expr_ty(&args[0]); + let b = cx.typeck_results().expr_ty(arg); if_chain! { if match_def_path(cx, def_id, &paths::TRY_FROM); if is_type_diagnostic_item(cx, a, sym::Result); @@ -159,7 +158,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { if same_type_and_consts(a, b); then { - let sugg = Sugg::hir_with_macro_callsite(cx, &args[0], "").maybe_par(); + let sugg = Sugg::hir_with_macro_callsite(cx, arg, "").maybe_par(); let sugg_msg = format!("consider removing `{}()`", snippet(cx, path.span, "From::from")); span_lint_and_sugg( diff --git a/clippy_lints/src/verbose_file_reads.rs b/clippy_lints/src/verbose_file_reads.rs index 8e2ddd225fdb3..afd0077a65804 100644 --- a/clippy_lints/src/verbose_file_reads.rs +++ b/clippy_lints/src/verbose_file_reads.rs @@ -61,10 +61,10 @@ impl<'tcx> LateLintPass<'tcx> for VerboseFileReads { fn is_file_read_to_end<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { if_chain! { - if let ExprKind::MethodCall(method_name, exprs, _) = expr.kind; + if let ExprKind::MethodCall(method_name, [recv, ..], _) = expr.kind; if method_name.ident.as_str() == "read_to_end"; - if let ExprKind::Path(QPath::Resolved(None, _)) = &exprs[0].kind; - let ty = cx.typeck_results().expr_ty(&exprs[0]); + if let ExprKind::Path(QPath::Resolved(None, _)) = &recv.kind; + let ty = cx.typeck_results().expr_ty(recv); if match_type(cx, ty, &paths::FILE); then { return true From 145ebb1cd723e34dc5a940ec3e498de814e6293d Mon Sep 17 00:00:00 2001 From: Daniel Macovei Date: Tue, 2 Aug 2022 10:39:35 -0500 Subject: [PATCH 36/62] add paren before '?' when suggesting deref --- clippy_lints/src/methods/clone_on_copy.rs | 6 +++++- tests/ui/clone_on_copy.fixed | 6 +++++- tests/ui/clone_on_copy.rs | 6 +++++- tests/ui/clone_on_copy.stderr | 8 +++++++- 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/methods/clone_on_copy.rs b/clippy_lints/src/methods/clone_on_copy.rs index 0b38a07204e86..a813d39441b54 100644 --- a/clippy_lints/src/methods/clone_on_copy.rs +++ b/clippy_lints/src/methods/clone_on_copy.rs @@ -4,7 +4,7 @@ use clippy_utils::source::snippet_with_context; use clippy_utils::sugg; use clippy_utils::ty::is_copy; use rustc_errors::Applicability; -use rustc_hir::{BindingAnnotation, Expr, ExprKind, MatchSource, Node, PatKind}; +use rustc_hir::{BindingAnnotation, Expr, ExprKind, MatchSource, Node, PatKind, QPath}; use rustc_lint::LateContext; use rustc_middle::ty::{self, adjustment::Adjust}; use rustc_span::symbol::{sym, Symbol}; @@ -86,6 +86,10 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, { return; }, + ExprKind::Call(hir_callee, _) => match hir_callee.kind { + ExprKind::Path(QPath::LangItem(rustc_hir::LangItem::TryTraitBranch, _, _)) => true, + _ => false, + }, ExprKind::MethodCall(_, [self_arg, ..], _) if expr.hir_id == self_arg.hir_id => true, ExprKind::Match(_, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar) | ExprKind::Field(..) diff --git a/tests/ui/clone_on_copy.fixed b/tests/ui/clone_on_copy.fixed index dc062762604e0..43849121b0433 100644 --- a/tests/ui/clone_on_copy.fixed +++ b/tests/ui/clone_on_copy.fixed @@ -21,7 +21,7 @@ fn is_ascii(ch: char) -> bool { ch.is_ascii() } -fn clone_on_copy() { +fn clone_on_copy() -> Option<(i32)> { 42; vec![1].clone(); // ok, not a Copy type @@ -71,4 +71,8 @@ fn clone_on_copy() { // Issue #5436 let mut vec = Vec::new(); vec.push(42); + + let opt: &Option = &None; + let value = (*opt)?; + None } diff --git a/tests/ui/clone_on_copy.rs b/tests/ui/clone_on_copy.rs index 8c39d0d55dd8b..1f10599da2283 100644 --- a/tests/ui/clone_on_copy.rs +++ b/tests/ui/clone_on_copy.rs @@ -21,7 +21,7 @@ fn is_ascii(ch: char) -> bool { ch.is_ascii() } -fn clone_on_copy() { +fn clone_on_copy() -> Option<(i32)> { 42.clone(); vec![1].clone(); // ok, not a Copy type @@ -71,4 +71,8 @@ fn clone_on_copy() { // Issue #5436 let mut vec = Vec::new(); vec.push(42.clone()); + + let opt: &Option = &None; + let value = opt.clone()?; + None } diff --git a/tests/ui/clone_on_copy.stderr b/tests/ui/clone_on_copy.stderr index 861543d0aa904..483ea35af2a0b 100644 --- a/tests/ui/clone_on_copy.stderr +++ b/tests/ui/clone_on_copy.stderr @@ -48,5 +48,11 @@ error: using `clone` on type `i32` which implements the `Copy` trait LL | vec.push(42.clone()); | ^^^^^^^^^^ help: try removing the `clone` call: `42` -error: aborting due to 8 previous errors +error: using `clone` on type `std::option::Option` which implements the `Copy` trait + --> $DIR/clone_on_copy.rs:76:17 + | +LL | let value = opt.clone()?; + | ^^^^^^^^^^^ help: try dereferencing it: `(*opt)` + +error: aborting due to 9 previous errors From 503c03c5584bb697071f3585953ed6e5b16d2e10 Mon Sep 17 00:00:00 2001 From: Daniel Macovei Date: Tue, 2 Aug 2022 12:06:22 -0500 Subject: [PATCH 37/62] clean up --- clippy_lints/src/methods/clone_on_copy.rs | 9 +++++---- tests/ui/clone_on_copy.fixed | 3 ++- tests/ui/clone_on_copy.rs | 3 ++- tests/ui/clone_on_copy.stderr | 4 ++-- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/methods/clone_on_copy.rs b/clippy_lints/src/methods/clone_on_copy.rs index a813d39441b54..60e1355f9b92d 100644 --- a/clippy_lints/src/methods/clone_on_copy.rs +++ b/clippy_lints/src/methods/clone_on_copy.rs @@ -86,10 +86,11 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, { return; }, - ExprKind::Call(hir_callee, _) => match hir_callee.kind { - ExprKind::Path(QPath::LangItem(rustc_hir::LangItem::TryTraitBranch, _, _)) => true, - _ => false, - }, + // ? is a Call, makes sure not to rec *x?, but rather (*x)? + ExprKind::Call(hir_callee, _) => matches!( + hir_callee.kind, + ExprKind::Path(QPath::LangItem(rustc_hir::LangItem::TryTraitBranch, _, _)) + ), ExprKind::MethodCall(_, [self_arg, ..], _) if expr.hir_id == self_arg.hir_id => true, ExprKind::Match(_, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar) | ExprKind::Field(..) diff --git a/tests/ui/clone_on_copy.fixed b/tests/ui/clone_on_copy.fixed index 43849121b0433..72b1222709819 100644 --- a/tests/ui/clone_on_copy.fixed +++ b/tests/ui/clone_on_copy.fixed @@ -72,7 +72,8 @@ fn clone_on_copy() -> Option<(i32)> { let mut vec = Vec::new(); vec.push(42); + // Issue #9277 let opt: &Option = &None; - let value = (*opt)?; + let value = (*opt)?; // operator precedence needed (*opt)? None } diff --git a/tests/ui/clone_on_copy.rs b/tests/ui/clone_on_copy.rs index 1f10599da2283..03e210ebad98c 100644 --- a/tests/ui/clone_on_copy.rs +++ b/tests/ui/clone_on_copy.rs @@ -72,7 +72,8 @@ fn clone_on_copy() -> Option<(i32)> { let mut vec = Vec::new(); vec.push(42.clone()); + // Issue #9277 let opt: &Option = &None; - let value = opt.clone()?; + let value = opt.clone()?; // operator precedence needed (*opt)? None } diff --git a/tests/ui/clone_on_copy.stderr b/tests/ui/clone_on_copy.stderr index 483ea35af2a0b..42ae227777c70 100644 --- a/tests/ui/clone_on_copy.stderr +++ b/tests/ui/clone_on_copy.stderr @@ -49,9 +49,9 @@ LL | vec.push(42.clone()); | ^^^^^^^^^^ help: try removing the `clone` call: `42` error: using `clone` on type `std::option::Option` which implements the `Copy` trait - --> $DIR/clone_on_copy.rs:76:17 + --> $DIR/clone_on_copy.rs:77:17 | -LL | let value = opt.clone()?; +LL | let value = opt.clone()?; // operator precedence needed (*opt)? | ^^^^^^^^^^^ help: try dereferencing it: `(*opt)` error: aborting due to 9 previous errors From b50ba06a83981633b9c1e192fd8a3fc46c3a2226 Mon Sep 17 00:00:00 2001 From: lengyijun Date: Wed, 3 Aug 2022 03:56:59 +0000 Subject: [PATCH 38/62] fix typo in tests/ui/redundant_allocation.rs --- tests/ui/redundant_allocation.rs | 12 +-------- tests/ui/redundant_allocation.stderr | 40 ++++++++++++++-------------- 2 files changed, 21 insertions(+), 31 deletions(-) diff --git a/tests/ui/redundant_allocation.rs b/tests/ui/redundant_allocation.rs index 9f2b1f4a2819f..574d34aed2d87 100644 --- a/tests/ui/redundant_allocation.rs +++ b/tests/ui/redundant_allocation.rs @@ -1,7 +1,5 @@ #![warn(clippy::all)] -#![allow(clippy::boxed_local, clippy::needless_pass_by_value)] -#![allow(clippy::disallowed_names, unused_variables, dead_code)] -#![allow(unused_imports)] +#![allow(clippy::boxed_local, clippy::disallowed_names)] pub struct MyStruct; @@ -9,13 +7,7 @@ pub struct SubT { foo: T, } -pub enum MyEnum { - One, - Two, -} - mod outer_box { - use crate::MyEnum; use crate::MyStruct; use crate::SubT; use std::boxed::Box; @@ -36,7 +28,6 @@ mod outer_box { } mod outer_rc { - use crate::MyEnum; use crate::MyStruct; use crate::SubT; use std::boxed::Box; @@ -57,7 +48,6 @@ mod outer_rc { } mod outer_arc { - use crate::MyEnum; use crate::MyStruct; use crate::SubT; use std::boxed::Box; diff --git a/tests/ui/redundant_allocation.stderr b/tests/ui/redundant_allocation.stderr index fab1b069fcbc7..54d4d88dba819 100644 --- a/tests/ui/redundant_allocation.stderr +++ b/tests/ui/redundant_allocation.stderr @@ -1,5 +1,5 @@ error: usage of `Box>` - --> $DIR/redundant_allocation.rs:25:30 + --> $DIR/redundant_allocation.rs:17:30 | LL | pub fn box_test6(foo: Box>) {} | ^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | pub fn box_test6(foo: Box>) {} = help: consider using just `Box` or `Rc` error: usage of `Box>` - --> $DIR/redundant_allocation.rs:27:30 + --> $DIR/redundant_allocation.rs:19:30 | LL | pub fn box_test7(foo: Box>) {} | ^^^^^^^^^^^ @@ -18,7 +18,7 @@ LL | pub fn box_test7(foo: Box>) {} = help: consider using just `Box` or `Arc` error: usage of `Box>>` - --> $DIR/redundant_allocation.rs:29:27 + --> $DIR/redundant_allocation.rs:21:27 | LL | pub fn box_test8() -> Box>> { | ^^^^^^^^^^^^^^^^^^^^ @@ -27,7 +27,7 @@ LL | pub fn box_test8() -> Box>> { = help: consider using just `Box>` or `Rc>` error: usage of `Box>` - --> $DIR/redundant_allocation.rs:33:30 + --> $DIR/redundant_allocation.rs:25:30 | LL | pub fn box_test9(foo: Box>) -> Box>> { | ^^^^^^^^^^^ @@ -36,7 +36,7 @@ LL | pub fn box_test9(foo: Box>) -> Box>> { = help: consider using just `Box` or `Arc` error: usage of `Box>>` - --> $DIR/redundant_allocation.rs:33:46 + --> $DIR/redundant_allocation.rs:25:46 | LL | pub fn box_test9(foo: Box>) -> Box>> { | ^^^^^^^^^^^^^^^^^ @@ -45,7 +45,7 @@ LL | pub fn box_test9(foo: Box>) -> Box>> { = help: consider using just `Box>` or `Arc>` error: usage of `Rc>` - --> $DIR/redundant_allocation.rs:46:24 + --> $DIR/redundant_allocation.rs:37:24 | LL | pub fn rc_test5(a: Rc>) {} | ^^^^^^^^^^^^^ @@ -54,7 +54,7 @@ LL | pub fn rc_test5(a: Rc>) {} = help: consider using just `Rc` or `Box` error: usage of `Rc>` - --> $DIR/redundant_allocation.rs:48:24 + --> $DIR/redundant_allocation.rs:39:24 | LL | pub fn rc_test7(a: Rc>) {} | ^^^^^^^^^^^^^ @@ -63,7 +63,7 @@ LL | pub fn rc_test7(a: Rc>) {} = help: consider using just `Rc` or `Arc` error: usage of `Rc>>` - --> $DIR/redundant_allocation.rs:50:26 + --> $DIR/redundant_allocation.rs:41:26 | LL | pub fn rc_test8() -> Rc>> { | ^^^^^^^^^^^^^^^^^^^^ @@ -72,7 +72,7 @@ LL | pub fn rc_test8() -> Rc>> { = help: consider using just `Rc>` or `Box>` error: usage of `Rc>` - --> $DIR/redundant_allocation.rs:54:29 + --> $DIR/redundant_allocation.rs:45:29 | LL | pub fn rc_test9(foo: Rc>) -> Rc>> { | ^^^^^^^^^^ @@ -81,7 +81,7 @@ LL | pub fn rc_test9(foo: Rc>) -> Rc>> { = help: consider using just `Rc` or `Arc` error: usage of `Rc>>` - --> $DIR/redundant_allocation.rs:54:44 + --> $DIR/redundant_allocation.rs:45:44 | LL | pub fn rc_test9(foo: Rc>) -> Rc>> { | ^^^^^^^^^^^^^^^^ @@ -90,7 +90,7 @@ LL | pub fn rc_test9(foo: Rc>) -> Rc>> { = help: consider using just `Rc>` or `Arc>` error: usage of `Arc>` - --> $DIR/redundant_allocation.rs:67:25 + --> $DIR/redundant_allocation.rs:57:25 | LL | pub fn arc_test5(a: Arc>) {} | ^^^^^^^^^^^^^^ @@ -99,7 +99,7 @@ LL | pub fn arc_test5(a: Arc>) {} = help: consider using just `Arc` or `Box` error: usage of `Arc>` - --> $DIR/redundant_allocation.rs:69:25 + --> $DIR/redundant_allocation.rs:59:25 | LL | pub fn arc_test6(a: Arc>) {} | ^^^^^^^^^^^^^ @@ -108,7 +108,7 @@ LL | pub fn arc_test6(a: Arc>) {} = help: consider using just `Arc` or `Rc` error: usage of `Arc>>` - --> $DIR/redundant_allocation.rs:71:27 + --> $DIR/redundant_allocation.rs:61:27 | LL | pub fn arc_test8() -> Arc>> { | ^^^^^^^^^^^^^^^^^^^^^ @@ -117,7 +117,7 @@ LL | pub fn arc_test8() -> Arc>> { = help: consider using just `Arc>` or `Box>` error: usage of `Arc>` - --> $DIR/redundant_allocation.rs:75:30 + --> $DIR/redundant_allocation.rs:65:30 | LL | pub fn arc_test9(foo: Arc>) -> Arc>> { | ^^^^^^^^^^ @@ -126,7 +126,7 @@ LL | pub fn arc_test9(foo: Arc>) -> Arc>> { = help: consider using just `Arc` or `Rc` error: usage of `Arc>>` - --> $DIR/redundant_allocation.rs:75:45 + --> $DIR/redundant_allocation.rs:65:45 | LL | pub fn arc_test9(foo: Arc>) -> Arc>> { | ^^^^^^^^^^^^^^^^ @@ -135,7 +135,7 @@ LL | pub fn arc_test9(foo: Arc>) -> Arc>> { = help: consider using just `Arc>` or `Rc>` error: usage of `Rc>>` - --> $DIR/redundant_allocation.rs:97:27 + --> $DIR/redundant_allocation.rs:87:27 | LL | pub fn test_rc_box(_: Rc>>) {} | ^^^^^^^^^^^^^^^^^^^ @@ -144,7 +144,7 @@ LL | pub fn test_rc_box(_: Rc>>) {} = help: consider using just `Rc>` or `Box>` error: usage of `Rc>>` - --> $DIR/redundant_allocation.rs:129:31 + --> $DIR/redundant_allocation.rs:119:31 | LL | pub fn test_rc_box_str(_: Rc>>) {} | ^^^^^^^^^^^^^^^^^ @@ -153,7 +153,7 @@ LL | pub fn test_rc_box_str(_: Rc>>) {} = help: consider using just `Rc>` or `Box>` error: usage of `Rc>>` - --> $DIR/redundant_allocation.rs:130:33 + --> $DIR/redundant_allocation.rs:120:33 | LL | pub fn test_rc_box_slice(_: Rc>>) {} | ^^^^^^^^^^^^^^^^^^^^^ @@ -162,7 +162,7 @@ LL | pub fn test_rc_box_slice(_: Rc>>) {} = help: consider using just `Rc>` or `Box>` error: usage of `Rc>>` - --> $DIR/redundant_allocation.rs:131:32 + --> $DIR/redundant_allocation.rs:121:32 | LL | pub fn test_rc_box_path(_: Rc>>) {} | ^^^^^^^^^^^^^^^^^^ @@ -171,7 +171,7 @@ LL | pub fn test_rc_box_path(_: Rc>>) {} = help: consider using just `Rc>` or `Box>` error: usage of `Rc>>` - --> $DIR/redundant_allocation.rs:132:34 + --> $DIR/redundant_allocation.rs:122:34 | LL | pub fn test_rc_box_custom(_: Rc>>) {} | ^^^^^^^^^^^^^^^^^^^^^^ From f232402057dd2f2fd947811ce72fd7abd8b5869f Mon Sep 17 00:00:00 2001 From: Fabian Wolff Date: Mon, 25 Jul 2022 22:36:03 +0200 Subject: [PATCH 39/62] Warn about dead tuple struct fields --- .../auxiliary/helper.rs | 1 + tests/ui/format.fixed | 1 + tests/ui/format.rs | 1 + tests/ui/format.stderr | 38 +++++++++---------- tests/ui/from_iter_instead_of_collect.fixed | 2 +- tests/ui/from_iter_instead_of_collect.rs | 2 +- tests/ui/must_use_candidates.fixed | 2 +- tests/ui/must_use_candidates.rs | 2 +- tests/ui/numbered_fields.fixed | 1 + tests/ui/numbered_fields.rs | 1 + tests/ui/numbered_fields.stderr | 4 +- tests/ui/option_if_let_else.fixed | 1 + tests/ui/option_if_let_else.rs | 1 + tests/ui/option_if_let_else.stderr | 30 +++++++-------- tests/ui/unreadable_literal.fixed | 1 + tests/ui/unreadable_literal.rs | 1 + tests/ui/unreadable_literal.stderr | 22 +++++------ 17 files changed, 60 insertions(+), 51 deletions(-) diff --git a/tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs b/tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs index 2289f7875f04c..f13733af3d0d1 100644 --- a/tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs +++ b/tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs @@ -2,6 +2,7 @@ // As the most common case is the `http` crate, it replicates `http::HeadewrName`'s structure. #![allow(clippy::declare_interior_mutable_const)] +#![allow(unused_tuple_struct_fields)] use std::sync::atomic::AtomicUsize; diff --git a/tests/ui/format.fixed b/tests/ui/format.fixed index f4db2d20c713c..6b754f3bd7103 100644 --- a/tests/ui/format.fixed +++ b/tests/ui/format.fixed @@ -1,6 +1,7 @@ // run-rustfix #![allow( + unused_tuple_struct_fields, clippy::print_literal, clippy::redundant_clone, clippy::to_string_in_format_args, diff --git a/tests/ui/format.rs b/tests/ui/format.rs index bf687cb1e96c7..ca9826b356ec8 100644 --- a/tests/ui/format.rs +++ b/tests/ui/format.rs @@ -1,6 +1,7 @@ // run-rustfix #![allow( + unused_tuple_struct_fields, clippy::print_literal, clippy::redundant_clone, clippy::to_string_in_format_args, diff --git a/tests/ui/format.stderr b/tests/ui/format.stderr index a0f8e7d193791..6c35caeb034d0 100644 --- a/tests/ui/format.stderr +++ b/tests/ui/format.stderr @@ -1,5 +1,5 @@ error: useless use of `format!` - --> $DIR/format.rs:18:5 + --> $DIR/format.rs:19:5 | LL | format!("foo"); | ^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()` @@ -7,19 +7,19 @@ LL | format!("foo"); = note: `-D clippy::useless-format` implied by `-D warnings` error: useless use of `format!` - --> $DIR/format.rs:19:5 + --> $DIR/format.rs:20:5 | LL | format!("{{}}"); | ^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"{}".to_string()` error: useless use of `format!` - --> $DIR/format.rs:20:5 + --> $DIR/format.rs:21:5 | LL | format!("{{}} abc {{}}"); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"{} abc {}".to_string()` error: useless use of `format!` - --> $DIR/format.rs:21:5 + --> $DIR/format.rs:22:5 | LL | / format!( LL | | r##"foo {{}} @@ -34,91 +34,91 @@ LL ~ " bar"##.to_string(); | error: useless use of `format!` - --> $DIR/format.rs:26:13 + --> $DIR/format.rs:27:13 | LL | let _ = format!(""); | ^^^^^^^^^^^ help: consider using `String::new()`: `String::new()` error: useless use of `format!` - --> $DIR/format.rs:28:5 + --> $DIR/format.rs:29:5 | LL | format!("{}", "foo"); | ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()` error: useless use of `format!` - --> $DIR/format.rs:32:5 + --> $DIR/format.rs:33:5 | LL | format!("{:+}", "foo"); // Warn when the format makes no difference. | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()` error: useless use of `format!` - --> $DIR/format.rs:33:5 + --> $DIR/format.rs:34:5 | LL | format!("{:<}", "foo"); // Warn when the format makes no difference. | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()` error: useless use of `format!` - --> $DIR/format.rs:38:5 + --> $DIR/format.rs:39:5 | LL | format!("{}", arg); | ^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()` error: useless use of `format!` - --> $DIR/format.rs:42:5 + --> $DIR/format.rs:43:5 | LL | format!("{:+}", arg); // Warn when the format makes no difference. | ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()` error: useless use of `format!` - --> $DIR/format.rs:43:5 + --> $DIR/format.rs:44:5 | LL | format!("{:<}", arg); // Warn when the format makes no difference. | ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()` error: useless use of `format!` - --> $DIR/format.rs:70:5 + --> $DIR/format.rs:71:5 | LL | format!("{}", 42.to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `42.to_string()` error: useless use of `format!` - --> $DIR/format.rs:72:5 + --> $DIR/format.rs:73:5 | LL | format!("{}", x.display().to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.display().to_string()` error: useless use of `format!` - --> $DIR/format.rs:76:18 + --> $DIR/format.rs:77:18 | LL | let _ = Some(format!("{}", a + "bar")); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `a + "bar"` error: useless use of `format!` - --> $DIR/format.rs:80:22 + --> $DIR/format.rs:81:22 | LL | let _s: String = format!("{}", &*v.join("/n")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `(&*v.join("/n")).to_string()` error: useless use of `format!` - --> $DIR/format.rs:86:13 + --> $DIR/format.rs:87:13 | LL | let _ = format!("{x}"); | ^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()` error: useless use of `format!` - --> $DIR/format.rs:88:13 + --> $DIR/format.rs:89:13 | LL | let _ = format!("{y}", y = x); | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()` error: useless use of `format!` - --> $DIR/format.rs:92:13 + --> $DIR/format.rs:93:13 | LL | let _ = format!("{abc}"); | ^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `abc.to_string()` error: useless use of `format!` - --> $DIR/format.rs:94:13 + --> $DIR/format.rs:95:13 | LL | let _ = format!("{xx}"); | ^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `xx.to_string()` diff --git a/tests/ui/from_iter_instead_of_collect.fixed b/tests/ui/from_iter_instead_of_collect.fixed index 403c3b3e44380..48f8093311cbd 100644 --- a/tests/ui/from_iter_instead_of_collect.fixed +++ b/tests/ui/from_iter_instead_of_collect.fixed @@ -1,7 +1,7 @@ // run-rustfix #![warn(clippy::from_iter_instead_of_collect)] -#![allow(unused_imports)] +#![allow(unused_imports, unused_tuple_struct_fields)] use std::collections::{BTreeMap, BTreeSet, HashMap, VecDeque}; diff --git a/tests/ui/from_iter_instead_of_collect.rs b/tests/ui/from_iter_instead_of_collect.rs index fefc7b01a65bb..ebe0ad278be30 100644 --- a/tests/ui/from_iter_instead_of_collect.rs +++ b/tests/ui/from_iter_instead_of_collect.rs @@ -1,7 +1,7 @@ // run-rustfix #![warn(clippy::from_iter_instead_of_collect)] -#![allow(unused_imports)] +#![allow(unused_imports, unused_tuple_struct_fields)] use std::collections::{BTreeMap, BTreeSet, HashMap, VecDeque}; diff --git a/tests/ui/must_use_candidates.fixed b/tests/ui/must_use_candidates.fixed index 9556f6f82cc63..04a74a009e092 100644 --- a/tests/ui/must_use_candidates.fixed +++ b/tests/ui/must_use_candidates.fixed @@ -1,6 +1,6 @@ // run-rustfix #![feature(never_type)] -#![allow(unused_mut, clippy::redundant_allocation)] +#![allow(unused_mut, unused_tuple_struct_fields, clippy::redundant_allocation)] #![warn(clippy::must_use_candidate)] use std::rc::Rc; use std::sync::atomic::{AtomicBool, Ordering}; diff --git a/tests/ui/must_use_candidates.rs b/tests/ui/must_use_candidates.rs index 3732422017104..f04122f4eeab6 100644 --- a/tests/ui/must_use_candidates.rs +++ b/tests/ui/must_use_candidates.rs @@ -1,6 +1,6 @@ // run-rustfix #![feature(never_type)] -#![allow(unused_mut, clippy::redundant_allocation)] +#![allow(unused_mut, unused_tuple_struct_fields, clippy::redundant_allocation)] #![warn(clippy::must_use_candidate)] use std::rc::Rc; use std::sync::atomic::{AtomicBool, Ordering}; diff --git a/tests/ui/numbered_fields.fixed b/tests/ui/numbered_fields.fixed index 3710b3e9c81e0..68c987eb4c677 100644 --- a/tests/ui/numbered_fields.fixed +++ b/tests/ui/numbered_fields.fixed @@ -1,5 +1,6 @@ //run-rustfix #![warn(clippy::init_numbered_fields)] +#![allow(unused_tuple_struct_fields)] #[derive(Default)] struct TupleStruct(u32, u32, u8); diff --git a/tests/ui/numbered_fields.rs b/tests/ui/numbered_fields.rs index 2af84bc0642a5..2ef4fb4de5370 100644 --- a/tests/ui/numbered_fields.rs +++ b/tests/ui/numbered_fields.rs @@ -1,5 +1,6 @@ //run-rustfix #![warn(clippy::init_numbered_fields)] +#![allow(unused_tuple_struct_fields)] #[derive(Default)] struct TupleStruct(u32, u32, u8); diff --git a/tests/ui/numbered_fields.stderr b/tests/ui/numbered_fields.stderr index 01691c8b141e8..60c0d7898063f 100644 --- a/tests/ui/numbered_fields.stderr +++ b/tests/ui/numbered_fields.stderr @@ -1,5 +1,5 @@ error: used a field initializer for a tuple struct - --> $DIR/numbered_fields.rs:18:13 + --> $DIR/numbered_fields.rs:19:13 | LL | let _ = TupleStruct { | _____________^ @@ -12,7 +12,7 @@ LL | | }; = note: `-D clippy::init-numbered-fields` implied by `-D warnings` error: used a field initializer for a tuple struct - --> $DIR/numbered_fields.rs:25:13 + --> $DIR/numbered_fields.rs:26:13 | LL | let _ = TupleStruct { | _____________^ diff --git a/tests/ui/option_if_let_else.fixed b/tests/ui/option_if_let_else.fixed index e12e13a57f1f0..b6d5e106f057a 100644 --- a/tests/ui/option_if_let_else.fixed +++ b/tests/ui/option_if_let_else.fixed @@ -1,6 +1,7 @@ // run-rustfix #![warn(clippy::option_if_let_else)] #![allow( + unused_tuple_struct_fields, clippy::redundant_closure, clippy::ref_option_ref, clippy::equatable_if_let, diff --git a/tests/ui/option_if_let_else.rs b/tests/ui/option_if_let_else.rs index b5206fc26a9e1..35bae15934358 100644 --- a/tests/ui/option_if_let_else.rs +++ b/tests/ui/option_if_let_else.rs @@ -1,6 +1,7 @@ // run-rustfix #![warn(clippy::option_if_let_else)] #![allow( + unused_tuple_struct_fields, clippy::redundant_closure, clippy::ref_option_ref, clippy::equatable_if_let, diff --git a/tests/ui/option_if_let_else.stderr b/tests/ui/option_if_let_else.stderr index 40aef977b989b..daba606004e11 100644 --- a/tests/ui/option_if_let_else.stderr +++ b/tests/ui/option_if_let_else.stderr @@ -1,5 +1,5 @@ error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:11:5 + --> $DIR/option_if_let_else.rs:12:5 | LL | / if let Some(x) = string { LL | | (true, x) @@ -11,19 +11,19 @@ LL | | } = note: `-D clippy::option-if-let-else` implied by `-D warnings` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:29:13 + --> $DIR/option_if_let_else.rs:30:13 | LL | let _ = if let Some(s) = *string { s.len() } else { 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `string.map_or(0, |s| s.len())` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:30:13 + --> $DIR/option_if_let_else.rs:31:13 | LL | let _ = if let Some(s) = &num { s } else { &0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:31:13 + --> $DIR/option_if_let_else.rs:32:13 | LL | let _ = if let Some(s) = &mut num { | _____________^ @@ -43,13 +43,13 @@ LL ~ }); | error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:37:13 + --> $DIR/option_if_let_else.rs:38:13 | LL | let _ = if let Some(ref s) = num { s } else { &0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:38:13 + --> $DIR/option_if_let_else.rs:39:13 | LL | let _ = if let Some(mut s) = num { | _____________^ @@ -69,7 +69,7 @@ LL ~ }); | error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:44:13 + --> $DIR/option_if_let_else.rs:45:13 | LL | let _ = if let Some(ref mut s) = num { | _____________^ @@ -89,7 +89,7 @@ LL ~ }); | error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:53:5 + --> $DIR/option_if_let_else.rs:54:5 | LL | / if let Some(x) = arg { LL | | let y = x * x; @@ -108,7 +108,7 @@ LL + }) | error: use Option::map_or_else instead of an if let/else - --> $DIR/option_if_let_else.rs:66:13 + --> $DIR/option_if_let_else.rs:67:13 | LL | let _ = if let Some(x) = arg { | _____________^ @@ -120,7 +120,7 @@ LL | | }; | |_____^ help: try: `arg.map_or_else(|| side_effect(), |x| x)` error: use Option::map_or_else instead of an if let/else - --> $DIR/option_if_let_else.rs:75:13 + --> $DIR/option_if_let_else.rs:76:13 | LL | let _ = if let Some(x) = arg { | _____________^ @@ -143,7 +143,7 @@ LL ~ }, |x| x * x * x * x); | error: use Option::map_or_else instead of an if let/else - --> $DIR/option_if_let_else.rs:108:13 + --> $DIR/option_if_let_else.rs:109:13 | LL | / if let Some(idx) = s.find('.') { LL | | vec![s[..idx].to_string(), s[idx..].to_string()] @@ -153,13 +153,13 @@ LL | | } | |_____________^ help: try: `s.find('.').map_or_else(|| vec![s.to_string()], |idx| vec![s[..idx].to_string(), s[idx..].to_string()])` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:132:13 + --> $DIR/option_if_let_else.rs:133:13 | LL | let _ = if let Some(x) = optional { x + 2 } else { 5 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `optional.map_or(5, |x| x + 2)` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:141:13 + --> $DIR/option_if_let_else.rs:142:13 | LL | let _ = if let Some(x) = Some(0) { | _____________^ @@ -181,13 +181,13 @@ LL ~ }); | error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:169:13 + --> $DIR/option_if_let_else.rs:170:13 | LL | let _ = if let Some(x) = Some(0) { s.len() + x } else { s.len() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(0).map_or(s.len(), |x| s.len() + x)` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:173:13 + --> $DIR/option_if_let_else.rs:174:13 | LL | let _ = if let Some(x) = Some(0) { | _____________^ diff --git a/tests/ui/unreadable_literal.fixed b/tests/ui/unreadable_literal.fixed index e726b652ef1ed..a67363b09ea5a 100644 --- a/tests/ui/unreadable_literal.fixed +++ b/tests/ui/unreadable_literal.fixed @@ -1,6 +1,7 @@ // run-rustfix #![warn(clippy::unreadable_literal)] +#![allow(unused_tuple_struct_fields)] struct Foo(u64); diff --git a/tests/ui/unreadable_literal.rs b/tests/ui/unreadable_literal.rs index 5bbb2fc9dc137..82f04e7ced527 100644 --- a/tests/ui/unreadable_literal.rs +++ b/tests/ui/unreadable_literal.rs @@ -1,6 +1,7 @@ // run-rustfix #![warn(clippy::unreadable_literal)] +#![allow(unused_tuple_struct_fields)] struct Foo(u64); diff --git a/tests/ui/unreadable_literal.stderr b/tests/ui/unreadable_literal.stderr index ee5466fd517fd..b51130c6a6aba 100644 --- a/tests/ui/unreadable_literal.stderr +++ b/tests/ui/unreadable_literal.stderr @@ -1,5 +1,5 @@ error: digits of hex or binary literal not grouped by four - --> $DIR/unreadable_literal.rs:25:9 + --> $DIR/unreadable_literal.rs:26:9 | LL | 0x1_234_567, | ^^^^^^^^^^^ help: consider: `0x0123_4567` @@ -7,7 +7,7 @@ LL | 0x1_234_567, = note: `-D clippy::unusual-byte-groupings` implied by `-D warnings` error: long literal lacking separators - --> $DIR/unreadable_literal.rs:33:17 + --> $DIR/unreadable_literal.rs:34:17 | LL | let _bad = (0b110110_i64, 0x12345678_usize, 123456_f32, 1.234567_f32); | ^^^^^^^^^^^^ help: consider: `0b11_0110_i64` @@ -15,55 +15,55 @@ LL | let _bad = (0b110110_i64, 0x12345678_usize, 123456_f32, 1.234567_f32); = note: `-D clippy::unreadable-literal` implied by `-D warnings` error: long literal lacking separators - --> $DIR/unreadable_literal.rs:33:31 + --> $DIR/unreadable_literal.rs:34:31 | LL | let _bad = (0b110110_i64, 0x12345678_usize, 123456_f32, 1.234567_f32); | ^^^^^^^^^^^^^^^^ help: consider: `0x1234_5678_usize` error: long literal lacking separators - --> $DIR/unreadable_literal.rs:33:49 + --> $DIR/unreadable_literal.rs:34:49 | LL | let _bad = (0b110110_i64, 0x12345678_usize, 123456_f32, 1.234567_f32); | ^^^^^^^^^^ help: consider: `123_456_f32` error: long literal lacking separators - --> $DIR/unreadable_literal.rs:33:61 + --> $DIR/unreadable_literal.rs:34:61 | LL | let _bad = (0b110110_i64, 0x12345678_usize, 123456_f32, 1.234567_f32); | ^^^^^^^^^^^^ help: consider: `1.234_567_f32` error: long literal lacking separators - --> $DIR/unreadable_literal.rs:35:20 + --> $DIR/unreadable_literal.rs:36:20 | LL | let _bad_sci = 1.123456e1; | ^^^^^^^^^^ help: consider: `1.123_456e1` error: long literal lacking separators - --> $DIR/unreadable_literal.rs:37:18 + --> $DIR/unreadable_literal.rs:38:18 | LL | let _fail1 = 0xabcdef; | ^^^^^^^^ help: consider: `0x00ab_cdef` error: long literal lacking separators - --> $DIR/unreadable_literal.rs:38:23 + --> $DIR/unreadable_literal.rs:39:23 | LL | let _fail2: u32 = 0xBAFEBAFE; | ^^^^^^^^^^ help: consider: `0xBAFE_BAFE` error: long literal lacking separators - --> $DIR/unreadable_literal.rs:39:18 + --> $DIR/unreadable_literal.rs:40:18 | LL | let _fail3 = 0xabcdeff; | ^^^^^^^^^ help: consider: `0x0abc_deff` error: long literal lacking separators - --> $DIR/unreadable_literal.rs:40:24 + --> $DIR/unreadable_literal.rs:41:24 | LL | let _fail4: i128 = 0xabcabcabcabcabcabc; | ^^^^^^^^^^^^^^^^^^^^ help: consider: `0x00ab_cabc_abca_bcab_cabc` error: long literal lacking separators - --> $DIR/unreadable_literal.rs:41:18 + --> $DIR/unreadable_literal.rs:42:18 | LL | let _fail5 = 1.100300400; | ^^^^^^^^^^^ help: consider: `1.100_300_400` From ccbc96508a5ff373f960ec0d904e1be41ad8c978 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 2 Aug 2022 06:02:04 +0000 Subject: [PATCH 40/62] Add `traits::fully_solve_obligation` that acts like `traits::fully_normalize` It spawns up a trait engine, registers the single obligation, then fully solves it --- clippy_lints/src/future_not_send.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/future_not_send.rs b/clippy_lints/src/future_not_send.rs index 5c46d6c7df705..ef7d75aa8ed9b 100644 --- a/clippy_lints/src/future_not_send.rs +++ b/clippy_lints/src/future_not_send.rs @@ -9,7 +9,7 @@ use rustc_middle::ty::{EarlyBinder, Opaque, PredicateKind::Trait}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{sym, Span}; use rustc_trait_selection::traits::error_reporting::suggestions::InferCtxtExt; -use rustc_trait_selection::traits::{self, FulfillmentError, TraitEngine}; +use rustc_trait_selection::traits::{self, FulfillmentError}; declare_clippy_lint! { /// ### What it does @@ -80,9 +80,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { let span = decl.output.span(); let send_errors = cx.tcx.infer_ctxt().enter(|infcx| { let cause = traits::ObligationCause::misc(span, hir_id); - let mut fulfillment_cx = traits::FulfillmentContext::new(); - fulfillment_cx.register_bound(&infcx, cx.param_env, ret_ty, send_trait, cause); - fulfillment_cx.select_all_or_error(&infcx) + traits::fully_solve_bound(&infcx, cause, cx.param_env, ret_ty, send_trait) }); if !send_errors.is_empty() { span_lint_and_then( From 7062a013e73a9571470cfe4df9940f7c47c6cbf3 Mon Sep 17 00:00:00 2001 From: alex-semenyuk Date: Thu, 4 Aug 2022 19:53:07 +0300 Subject: [PATCH 41/62] Fix some typos --- clippy_lints/src/missing_const_for_fn.rs | 4 ++-- clippy_lints/src/utils/internal_lints.rs | 2 +- tests/ui-internal/check_clippy_version_attribute.stderr | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index 16d65966c1009..2bd920db3025d 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -124,7 +124,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { FnKind::Method(_, sig, ..) => { if trait_ref_of_method(cx, def_id).is_some() || already_const(sig.header) - || method_accepts_dropable(cx, sig.decl.inputs) + || method_accepts_droppable(cx, sig.decl.inputs) { return; } @@ -159,7 +159,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { /// Returns true if any of the method parameters is a type that implements `Drop`. The method /// can't be made const then, because `drop` can't be const-evaluated. -fn method_accepts_dropable(cx: &LateContext<'_>, param_tys: &[hir::Ty<'_>]) -> bool { +fn method_accepts_droppable(cx: &LateContext<'_>, param_tys: &[hir::Ty<'_>]) -> bool { // If any of the params are droppable, return true param_tys.iter().any(|hir_ty| { let ty_ty = hir_ty_to_ty(cx.tcx, hir_ty); diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index b309653291b11..3de96f72bbcdd 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -569,7 +569,7 @@ fn check_invalid_clippy_version_attribute(cx: &LateContext<'_>, item: &'_ Item<' item.span, "this item has an invalid `clippy::version` attribute", None, - "please use a valid sematic version, see `doc/adding_lints.md`", + "please use a valid semantic version, see `doc/adding_lints.md`", ); } } else { diff --git a/tests/ui-internal/check_clippy_version_attribute.stderr b/tests/ui-internal/check_clippy_version_attribute.stderr index 5331075885c1d..ab7c8d5930713 100644 --- a/tests/ui-internal/check_clippy_version_attribute.stderr +++ b/tests/ui-internal/check_clippy_version_attribute.stderr @@ -16,7 +16,7 @@ note: the lint level is defined here LL | #![deny(clippy::internal)] | ^^^^^^^^^^^^^^^^ = note: `#[deny(clippy::invalid_clippy_version_attribute)]` implied by `#[deny(clippy::internal)]` - = help: please use a valid sematic version, see `doc/adding_lints.md` + = help: please use a valid senmatic version, see `doc/adding_lints.md` = note: this error originates in the macro `$crate::declare_tool_lint` which comes from the expansion of the macro `declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info) error: this item has an invalid `clippy::version` attribute @@ -31,7 +31,7 @@ LL | | report_in_external_macro: true LL | | } | |_^ | - = help: please use a valid sematic version, see `doc/adding_lints.md` + = help: please use a valid semantic version, see `doc/adding_lints.md` = note: this error originates in the macro `$crate::declare_tool_lint` which comes from the expansion of the macro `declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info) error: this lint is missing the `clippy::version` attribute or version value From 0e1d65850afd9ebf894526c75ddf7d6dcabf4097 Mon Sep 17 00:00:00 2001 From: alex-semenyuk Date: Sat, 30 Jul 2022 17:21:37 +0300 Subject: [PATCH 42/62] Fix cast_abs_to_unsigned generates non-compiling code when original code is in parens --- clippy_lints/src/casts/cast_abs_to_unsigned.rs | 2 +- tests/ui/cast_abs_to_unsigned.fixed | 2 ++ tests/ui/cast_abs_to_unsigned.rs | 2 ++ tests/ui/cast_abs_to_unsigned.stderr | 8 +++++++- 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/casts/cast_abs_to_unsigned.rs b/clippy_lints/src/casts/cast_abs_to_unsigned.rs index 64ea326b75a0d..6426e8c25ac1c 100644 --- a/clippy_lints/src/casts/cast_abs_to_unsigned.rs +++ b/clippy_lints/src/casts/cast_abs_to_unsigned.rs @@ -37,7 +37,7 @@ pub(super) fn check( span, &format!("casting the result of `{cast_from}::abs()` to {cast_to}"), "replace with", - format!("{}.unsigned_abs()", Sugg::hir(cx, &args[0], "..")), + format!("{}.unsigned_abs()", Sugg::hir(cx, &args[0], "..").maybe_par()), Applicability::MachineApplicable, ); } diff --git a/tests/ui/cast_abs_to_unsigned.fixed b/tests/ui/cast_abs_to_unsigned.fixed index a68b32b097e85..7ecefd7b13439 100644 --- a/tests/ui/cast_abs_to_unsigned.fixed +++ b/tests/ui/cast_abs_to_unsigned.fixed @@ -26,4 +26,6 @@ fn main() { let _ = a.unsigned_abs() as u32; let _ = a.unsigned_abs() as u64; let _ = a.unsigned_abs() as u128; + + let _ = (x as i64 - y as i64).unsigned_abs() as u32; } diff --git a/tests/ui/cast_abs_to_unsigned.rs b/tests/ui/cast_abs_to_unsigned.rs index 110fbc6c2dfb6..30c603fca9a14 100644 --- a/tests/ui/cast_abs_to_unsigned.rs +++ b/tests/ui/cast_abs_to_unsigned.rs @@ -26,4 +26,6 @@ fn main() { let _ = a.abs() as u32; let _ = a.abs() as u64; let _ = a.abs() as u128; + + let _ = (x as i64 - y as i64).abs() as u32; } diff --git a/tests/ui/cast_abs_to_unsigned.stderr b/tests/ui/cast_abs_to_unsigned.stderr index 02c24e10659ac..0455377452676 100644 --- a/tests/ui/cast_abs_to_unsigned.stderr +++ b/tests/ui/cast_abs_to_unsigned.stderr @@ -96,5 +96,11 @@ error: casting the result of `isize::abs()` to u128 LL | let _ = a.abs() as u128; | ^^^^^^^ help: replace with: `a.unsigned_abs()` -error: aborting due to 16 previous errors +error: casting the result of `i64::abs()` to u32 + --> $DIR/cast_abs_to_unsigned.rs:30:13 + | +LL | let _ = (x as i64 - y as i64).abs() as u32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `(x as i64 - y as i64).unsigned_abs()` + +error: aborting due to 17 previous errors From f63b324ab1f37c6238af3070eb0c7c33230e43a8 Mon Sep 17 00:00:00 2001 From: alex-semenyuk Date: Fri, 5 Aug 2022 00:59:21 +0300 Subject: [PATCH 43/62] Fix some typos --- tests/ui-internal/check_clippy_version_attribute.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui-internal/check_clippy_version_attribute.stderr b/tests/ui-internal/check_clippy_version_attribute.stderr index ab7c8d5930713..2aa4de490bcf6 100644 --- a/tests/ui-internal/check_clippy_version_attribute.stderr +++ b/tests/ui-internal/check_clippy_version_attribute.stderr @@ -16,7 +16,7 @@ note: the lint level is defined here LL | #![deny(clippy::internal)] | ^^^^^^^^^^^^^^^^ = note: `#[deny(clippy::invalid_clippy_version_attribute)]` implied by `#[deny(clippy::internal)]` - = help: please use a valid senmatic version, see `doc/adding_lints.md` + = help: please use a valid semantic version, see `doc/adding_lints.md` = note: this error originates in the macro `$crate::declare_tool_lint` which comes from the expansion of the macro `declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info) error: this item has an invalid `clippy::version` attribute From 1e1193f4faa0338e41b7a77814bdbe3098c8fe33 Mon Sep 17 00:00:00 2001 From: alex-semenyuk Date: Fri, 5 Aug 2022 23:24:50 +0300 Subject: [PATCH 44/62] Enable test for def_id_nocore for windows --- tests/ui/def_id_nocore.rs | 1 - tests/ui/def_id_nocore.stderr | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/ui/def_id_nocore.rs b/tests/ui/def_id_nocore.rs index 156c88e2e45b7..a7da8f89aa3d4 100644 --- a/tests/ui/def_id_nocore.rs +++ b/tests/ui/def_id_nocore.rs @@ -1,4 +1,3 @@ -// ignore-windows // ignore-macos #![feature(no_core, lang_items, start)] diff --git a/tests/ui/def_id_nocore.stderr b/tests/ui/def_id_nocore.stderr index 40d355e9a2e3e..6210d7c6cfd80 100644 --- a/tests/ui/def_id_nocore.stderr +++ b/tests/ui/def_id_nocore.stderr @@ -1,5 +1,5 @@ error: methods called `as_*` usually take `self` by reference or `self` by mutable reference - --> $DIR/def_id_nocore.rs:28:19 + --> $DIR/def_id_nocore.rs:27:19 | LL | pub fn as_ref(self) -> &'static str { | ^^^^ From aa0b0af3ba170ab6d502ae19ce64124a4ee70017 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 7 Aug 2022 21:01:27 -0400 Subject: [PATCH 45/62] Move `significant_drop_in_scrutinee` into `nursey` --- clippy_lints/src/lib.register_all.rs | 1 - clippy_lints/src/lib.register_nursery.rs | 1 + clippy_lints/src/lib.register_suspicious.rs | 1 - clippy_lints/src/matches/mod.rs | 2 +- 4 files changed, 2 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index b9cc9fc1e85b0..ab08e65d6081b 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -144,7 +144,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(matches::MATCH_STR_CASE_MISMATCH), LintId::of(matches::NEEDLESS_MATCH), LintId::of(matches::REDUNDANT_PATTERN_MATCHING), - LintId::of(matches::SIGNIFICANT_DROP_IN_SCRUTINEE), LintId::of(matches::SINGLE_MATCH), LintId::of(matches::WILDCARD_IN_OR_PATTERNS), LintId::of(mem_replace::MEM_REPLACE_OPTION_WITH_NONE), diff --git a/clippy_lints/src/lib.register_nursery.rs b/clippy_lints/src/lib.register_nursery.rs index f961952991f54..7d731d52dbbd2 100644 --- a/clippy_lints/src/lib.register_nursery.rs +++ b/clippy_lints/src/lib.register_nursery.rs @@ -13,6 +13,7 @@ store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![ LintId::of(future_not_send::FUTURE_NOT_SEND), LintId::of(index_refutable_slice::INDEX_REFUTABLE_SLICE), LintId::of(let_if_seq::USELESS_LET_IF_SEQ), + LintId::of(matches::SIGNIFICANT_DROP_IN_SCRUTINEE), LintId::of(methods::ITER_WITH_DRAIN), LintId::of(missing_const_for_fn::MISSING_CONST_FOR_FN), LintId::of(mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL), diff --git a/clippy_lints/src/lib.register_suspicious.rs b/clippy_lints/src/lib.register_suspicious.rs index f7558f8709810..964992bd94fe2 100644 --- a/clippy_lints/src/lib.register_suspicious.rs +++ b/clippy_lints/src/lib.register_suspicious.rs @@ -22,7 +22,6 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec! LintId::of(loops::EMPTY_LOOP), LintId::of(loops::FOR_LOOPS_OVER_FALLIBLES), LintId::of(loops::MUT_RANGE_BOUND), - LintId::of(matches::SIGNIFICANT_DROP_IN_SCRUTINEE), LintId::of(methods::NO_EFFECT_REPLACE), LintId::of(methods::SUSPICIOUS_MAP), LintId::of(mut_key::MUTABLE_KEY_TYPE), diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs index b638f27160282..97cfdf3e2d20c 100644 --- a/clippy_lints/src/matches/mod.rs +++ b/clippy_lints/src/matches/mod.rs @@ -835,7 +835,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.60.0"] pub SIGNIFICANT_DROP_IN_SCRUTINEE, - suspicious, + nursery, "warns when a temporary of a type with a drop with a significant side-effect might have a surprising lifetime" } From 2ae8b300a7f55f5cf132b640ad6a5727ba282d1e Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 13 Apr 2022 00:36:13 -0400 Subject: [PATCH 46/62] Don't lint `unit_arg` when expanded from a proc-macro --- clippy_lints/src/matches/mod.rs | 6 +- clippy_lints/src/unit_types/unit_arg.rs | 3 +- clippy_utils/src/check_proc_macro.rs | 167 ++++++++++++++++++++++++ clippy_utils/src/lib.rs | 2 + clippy_utils/src/source.rs | 18 --- tests/ui/unit_arg.rs | 12 +- tests/ui/unit_arg.stderr | 20 +-- 7 files changed, 195 insertions(+), 33 deletions(-) create mode 100644 clippy_utils/src/check_proc_macro.rs diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs index b638f27160282..a74166c32d17c 100644 --- a/clippy_lints/src/matches/mod.rs +++ b/clippy_lints/src/matches/mod.rs @@ -21,8 +21,8 @@ mod single_match; mod try_err; mod wild_in_or_pats; -use clippy_utils::source::{snippet_opt, span_starts_with, walk_span_to_context}; -use clippy_utils::{higher, in_constant, meets_msrv, msrvs}; +use clippy_utils::source::{snippet_opt, walk_span_to_context}; +use clippy_utils::{higher, in_constant, is_span_match, meets_msrv, msrvs}; use rustc_hir::{Arm, Expr, ExprKind, Local, MatchSource, Pat}; use rustc_lexer::{tokenize, TokenKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -949,7 +949,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches { let from_expansion = expr.span.from_expansion(); if let ExprKind::Match(ex, arms, source) = expr.kind { - if source == MatchSource::Normal && !span_starts_with(cx, expr.span, "match") { + if source == MatchSource::Normal && !is_span_match(cx, expr.span) { return; } if matches!(source, MatchSource::Normal | MatchSource::ForLoopDesugar) { diff --git a/clippy_lints/src/unit_types/unit_arg.rs b/clippy_lints/src/unit_types/unit_arg.rs index 97d92f10e1cb2..cd38720f72235 100644 --- a/clippy_lints/src/unit_types/unit_arg.rs +++ b/clippy_lints/src/unit_types/unit_arg.rs @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::is_expr_from_proc_macro; use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; use if_chain::if_chain; use rustc_errors::Applicability; @@ -44,7 +45,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { } }) .collect::>(); - if !args_to_recover.is_empty() { + if !args_to_recover.is_empty() && !is_expr_from_proc_macro(cx, expr) { lint_unit_args(cx, expr, &args_to_recover); } }, diff --git a/clippy_utils/src/check_proc_macro.rs b/clippy_utils/src/check_proc_macro.rs new file mode 100644 index 0000000000000..387bf72000848 --- /dev/null +++ b/clippy_utils/src/check_proc_macro.rs @@ -0,0 +1,167 @@ +//! This module handles checking if the span given is from a proc-macro or not. +//! +//! Proc-macros are capable of setting the span of every token they output to a few possible spans. +//! This includes spans we can detect easily as coming from a proc-macro (e.g. the call site +//! or the def site), and spans we can't easily detect as such (e.g. the span of any token +//! passed into the proc macro). This capability means proc-macros are capable of generating code +//! with a span that looks like it was written by the user, but which should not be linted by clippy +//! as it was generated by an external macro. +//! +//! That brings us to this module. The current approach is to determine a small bit of text which +//! must exist at both the start and the end of an item (e.g. an expression or a path) assuming the +//! code was written, and check if the span contains that text. Note this will only work correctly +//! if the span is not from a `macro_rules` based macro. + +use rustc_ast::ast::{IntTy, LitIntType, LitKind, StrStyle, UintTy}; +use rustc_hir::{ + Block, BlockCheckMode, Closure, Destination, Expr, ExprKind, LoopSource, MatchSource, QPath, UnOp, UnsafeSource, + YieldSource, +}; +use rustc_lint::{LateContext, LintContext}; +use rustc_middle::ty::TyCtxt; +use rustc_session::Session; +use rustc_span::{Span, Symbol}; + +#[derive(Clone, Copy)] +enum Pat { + Str(&'static str), + Sym(Symbol), + Num, +} + +/// Checks if the start and the end of the span's text matches the patterns. This will return false +/// if the span crosses multiple files or if source is not available. +fn span_matches_pat(sess: &Session, span: Span, start_pat: Pat, end_pat: Pat) -> bool { + let pos = sess.source_map().lookup_byte_offset(span.lo()); + let Some(ref src) = pos.sf.src else { + return false; + }; + let end = span.hi() - pos.sf.start_pos; + src.get(pos.pos.0 as usize..end.0 as usize).map_or(false, |s| { + // Spans can be wrapped in a mixture or parenthesis, whitespace, and trailing commas. + let start_str = s.trim_start_matches(|c: char| c.is_whitespace() || c == '('); + let end_str = s.trim_end_matches(|c: char| c.is_whitespace() || c == ')' || c == ','); + (match start_pat { + Pat::Str(text) => start_str.starts_with(text), + Pat::Sym(sym) => start_str.starts_with(sym.as_str()), + Pat::Num => start_str.as_bytes().first().map_or(false, u8::is_ascii_digit), + } && match end_pat { + Pat::Str(text) => end_str.ends_with(text), + Pat::Sym(sym) => end_str.ends_with(sym.as_str()), + Pat::Num => end_str.as_bytes().last().map_or(false, u8::is_ascii_hexdigit), + }) + }) +} + +/// Get the search patterns to use for the given literal +fn lit_search_pat(lit: &LitKind) -> (Pat, Pat) { + match lit { + LitKind::Str(_, StrStyle::Cooked) => (Pat::Str("\""), Pat::Str("\"")), + LitKind::Str(_, StrStyle::Raw(0)) => (Pat::Str("r"), Pat::Str("\"")), + LitKind::Str(_, StrStyle::Raw(_)) => (Pat::Str("r#"), Pat::Str("#")), + LitKind::ByteStr(_) => (Pat::Str("b\""), Pat::Str("\"")), + LitKind::Byte(_) => (Pat::Str("b'"), Pat::Str("'")), + LitKind::Char(_) => (Pat::Str("'"), Pat::Str("'")), + LitKind::Int(_, LitIntType::Signed(IntTy::Isize)) => (Pat::Num, Pat::Str("isize")), + LitKind::Int(_, LitIntType::Unsigned(UintTy::Usize)) => (Pat::Num, Pat::Str("usize")), + LitKind::Int(..) => (Pat::Num, Pat::Num), + LitKind::Float(..) => (Pat::Num, Pat::Str("")), + LitKind::Bool(true) => (Pat::Str("true"), Pat::Str("true")), + LitKind::Bool(false) => (Pat::Str("false"), Pat::Str("false")), + _ => (Pat::Str(""), Pat::Str("")), + } +} + +/// Get the search patterns to use for the given path +fn qpath_search_pat(path: &QPath<'_>) -> (Pat, Pat) { + match path { + QPath::Resolved(ty, path) => { + let start = if ty.is_some() { + Pat::Str("<") + } else { + path.segments + .first() + .map_or(Pat::Str(""), |seg| Pat::Sym(seg.ident.name)) + }; + let end = path.segments.last().map_or(Pat::Str(""), |seg| { + if seg.args.is_some() { + Pat::Str(">") + } else { + Pat::Sym(seg.ident.name) + } + }); + (start, end) + }, + QPath::TypeRelative(_, name) => (Pat::Str(""), Pat::Sym(name.ident.name)), + QPath::LangItem(..) => (Pat::Str(""), Pat::Str("")), + } +} + +/// Get the search patterns to use for the given expression +fn expr_search_pat(tcx: TyCtxt<'_>, e: &Expr<'_>) -> (Pat, Pat) { + match e.kind { + ExprKind::Box(e) => (Pat::Str("box"), expr_search_pat(tcx, e).1), + ExprKind::ConstBlock(_) => (Pat::Str("const"), Pat::Str("}")), + ExprKind::Tup([]) => (Pat::Str(")"), Pat::Str("(")), + ExprKind::Unary(UnOp::Deref, _) => (Pat::Str("*"), expr_search_pat(tcx, e).1), + ExprKind::Unary(UnOp::Not, _) => (Pat::Str("!"), expr_search_pat(tcx, e).1), + ExprKind::Unary(UnOp::Neg, _) => (Pat::Str("-"), expr_search_pat(tcx, e).1), + ExprKind::Lit(ref lit) => lit_search_pat(&lit.node), + ExprKind::Array(_) | ExprKind::Repeat(..) => (Pat::Str("["), Pat::Str("]")), + ExprKind::Call(e, []) | ExprKind::MethodCall(_, [e], _) => (expr_search_pat(tcx, e).0, Pat::Str("(")), + ExprKind::Call(first, [.., last]) + | ExprKind::MethodCall(_, [first, .., last], _) + | ExprKind::Binary(_, first, last) + | ExprKind::Tup([first, .., last]) + | ExprKind::Assign(first, last, _) + | ExprKind::AssignOp(_, first, last) => (expr_search_pat(tcx, first).0, expr_search_pat(tcx, last).1), + ExprKind::Tup([e]) | ExprKind::DropTemps(e) => expr_search_pat(tcx, e), + ExprKind::Cast(e, _) | ExprKind::Type(e, _) => (expr_search_pat(tcx, e).0, Pat::Str("")), + ExprKind::Let(let_expr) => (Pat::Str("let"), expr_search_pat(tcx, let_expr.init).1), + ExprKind::If(..) => (Pat::Str("if"), Pat::Str("}")), + ExprKind::Loop(_, Some(_), _, _) | ExprKind::Block(_, Some(_)) => (Pat::Str("'"), Pat::Str("}")), + ExprKind::Loop(_, None, LoopSource::Loop, _) => (Pat::Str("loop"), Pat::Str("}")), + ExprKind::Loop(_, None, LoopSource::While, _) => (Pat::Str("while"), Pat::Str("}")), + ExprKind::Loop(_, None, LoopSource::ForLoop, _) | ExprKind::Match(_, _, MatchSource::ForLoopDesugar) => { + (Pat::Str("for"), Pat::Str("}")) + }, + ExprKind::Match(_, _, MatchSource::Normal) => (Pat::Str("match"), Pat::Str("}")), + ExprKind::Match(e, _, MatchSource::TryDesugar) => (expr_search_pat(tcx, e).0, Pat::Str("?")), + ExprKind::Match(e, _, MatchSource::AwaitDesugar) | ExprKind::Yield(e, YieldSource::Await { .. }) => { + (expr_search_pat(tcx, e).0, Pat::Str("await")) + }, + ExprKind::Closure(&Closure { body, .. }) => (Pat::Str(""), expr_search_pat(tcx, &tcx.hir().body(body).value).1), + ExprKind::Block( + Block { + rules: BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided), + .. + }, + None, + ) => (Pat::Str("unsafe"), Pat::Str("}")), + ExprKind::Block(_, None) => (Pat::Str("{"), Pat::Str("}")), + ExprKind::Field(e, name) => (expr_search_pat(tcx, e).0, Pat::Sym(name.name)), + ExprKind::Index(e, _) => (expr_search_pat(tcx, e).0, Pat::Str("]")), + ExprKind::Path(ref path) => qpath_search_pat(path), + ExprKind::AddrOf(_, _, e) => (Pat::Str("&"), expr_search_pat(tcx, e).1), + ExprKind::Break(Destination { label: None, .. }, None) => (Pat::Str("break"), Pat::Str("break")), + ExprKind::Break(Destination { label: Some(name), .. }, None) => (Pat::Str("break"), Pat::Sym(name.ident.name)), + ExprKind::Break(_, Some(e)) => (Pat::Str("break"), expr_search_pat(tcx, e).1), + ExprKind::Continue(Destination { label: None, .. }) => (Pat::Str("continue"), Pat::Str("continue")), + ExprKind::Continue(Destination { label: Some(name), .. }) => (Pat::Str("continue"), Pat::Sym(name.ident.name)), + ExprKind::Ret(None) => (Pat::Str("return"), Pat::Str("return")), + ExprKind::Struct(path, _, _) => (qpath_search_pat(path).0, Pat::Str("}")), + ExprKind::Yield(e, YieldSource::Yield) => (Pat::Str("yield"), expr_search_pat(tcx, e).1), + _ => (Pat::Str(""), Pat::Str("")), + } +} + +/// Checks if the expression likely came from a proc-macro +pub fn is_expr_from_proc_macro(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { + let (start_pat, end_pat) = expr_search_pat(cx.tcx, e); + !span_matches_pat(cx.sess(), e.span, start_pat, end_pat) +} + +/// Checks if the span actually refers to a match expression +pub fn is_span_match(cx: &LateContext<'_>, span: Span) -> bool { + span_matches_pat(cx.sess(), span, Pat::Str("match"), Pat::Str("}")) +} diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 9ffbc73dc62c7..2d051e3a8157c 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -38,6 +38,7 @@ pub mod sym_helper; pub mod ast_utils; pub mod attrs; +mod check_proc_macro; pub mod comparisons; pub mod consts; pub mod diagnostics; @@ -58,6 +59,7 @@ pub mod usage; pub mod visitors; pub use self::attrs::*; +pub use self::check_proc_macro::{is_expr_from_proc_macro, is_span_match}; pub use self::hir_utils::{ both, count_eq, eq_expr_value, hash_expr, hash_stmt, over, HirEqInterExpr, SpanlessEq, SpanlessHash, }; diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs index 1197fe914de46..d85f591fb9a42 100644 --- a/clippy_utils/src/source.rs +++ b/clippy_utils/src/source.rs @@ -11,24 +11,6 @@ use rustc_span::source_map::SourceMap; use rustc_span::{BytePos, Pos, Span, SpanData, SyntaxContext}; use std::borrow::Cow; -/// Checks if the span starts with the given text. This will return false if the span crosses -/// multiple files or if source is not available. -/// -/// This is used to check for proc macros giving unhelpful spans to things. -pub fn span_starts_with(cx: &T, span: Span, text: &str) -> bool { - fn helper(sm: &SourceMap, span: Span, text: &str) -> bool { - let pos = sm.lookup_byte_offset(span.lo()); - let Some(ref src) = pos.sf.src else { - return false; - }; - let end = span.hi() - pos.sf.start_pos; - src.get(pos.pos.0 as usize..end.0 as usize) - // Expression spans can include wrapping parenthesis. Remove them first. - .map_or(false, |s| s.trim_start_matches('(').starts_with(text)) - } - helper(cx.sess().source_map(), span, text) -} - /// Like `snippet_block`, but add braces if the expr is not an `ExprKind::Block`. /// Also takes an `Option` which can be put inside the braces. pub fn expr_block<'a, T: LintContext>( diff --git a/tests/ui/unit_arg.rs b/tests/ui/unit_arg.rs index 38be87bddf198..7bf3adc07ac56 100644 --- a/tests/ui/unit_arg.rs +++ b/tests/ui/unit_arg.rs @@ -1,3 +1,5 @@ +// aux-build: proc_macro_with_span.rs + #![warn(clippy::unit_arg)] #![allow( clippy::no_effect, @@ -8,9 +10,13 @@ clippy::or_fun_call, clippy::needless_question_mark, clippy::self_named_constructors, - clippy::let_unit_value + clippy::let_unit_value, + clippy::never_loop )] +extern crate proc_macro_with_span; + +use proc_macro_with_span::with_span; use std::fmt::Debug; fn foo(t: T) { @@ -127,6 +133,10 @@ fn returning_expr() -> Option<()> { fn taking_multiple_units(a: (), b: ()) {} +fn proc_macro() { + with_span!(span taking_multiple_units(unsafe { (); }, 'x: loop { break 'x (); })); +} + fn main() { bad(); ok(); diff --git a/tests/ui/unit_arg.stderr b/tests/ui/unit_arg.stderr index 11cfe66a30e85..1de9d44bb0d6e 100644 --- a/tests/ui/unit_arg.stderr +++ b/tests/ui/unit_arg.stderr @@ -1,5 +1,5 @@ error: passing a unit value to a function - --> $DIR/unit_arg.rs:57:5 + --> $DIR/unit_arg.rs:63:5 | LL | / foo({ LL | | 1; @@ -20,7 +20,7 @@ LL ~ foo(()); | error: passing a unit value to a function - --> $DIR/unit_arg.rs:60:5 + --> $DIR/unit_arg.rs:66:5 | LL | foo(foo(1)); | ^^^^^^^^^^^ @@ -32,7 +32,7 @@ LL ~ foo(()); | error: passing a unit value to a function - --> $DIR/unit_arg.rs:61:5 + --> $DIR/unit_arg.rs:67:5 | LL | / foo({ LL | | foo(1); @@ -54,7 +54,7 @@ LL ~ foo(()); | error: passing a unit value to a function - --> $DIR/unit_arg.rs:66:5 + --> $DIR/unit_arg.rs:72:5 | LL | / b.bar({ LL | | 1; @@ -74,7 +74,7 @@ LL ~ b.bar(()); | error: passing unit values to a function - --> $DIR/unit_arg.rs:69:5 + --> $DIR/unit_arg.rs:75:5 | LL | taking_multiple_units(foo(0), foo(1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -87,7 +87,7 @@ LL ~ taking_multiple_units((), ()); | error: passing unit values to a function - --> $DIR/unit_arg.rs:70:5 + --> $DIR/unit_arg.rs:76:5 | LL | / taking_multiple_units(foo(0), { LL | | foo(1); @@ -110,7 +110,7 @@ LL ~ taking_multiple_units((), ()); | error: passing unit values to a function - --> $DIR/unit_arg.rs:74:5 + --> $DIR/unit_arg.rs:80:5 | LL | / taking_multiple_units( LL | | { @@ -146,7 +146,7 @@ LL ~ ); | error: passing a unit value to a function - --> $DIR/unit_arg.rs:85:13 + --> $DIR/unit_arg.rs:91:13 | LL | None.or(Some(foo(2))); | ^^^^^^^^^^^^ @@ -160,7 +160,7 @@ LL ~ }); | error: passing a unit value to a function - --> $DIR/unit_arg.rs:88:5 + --> $DIR/unit_arg.rs:94:5 | LL | foo(foo(())); | ^^^^^^^^^^^^ @@ -172,7 +172,7 @@ LL ~ foo(()); | error: passing a unit value to a function - --> $DIR/unit_arg.rs:125:5 + --> $DIR/unit_arg.rs:131:5 | LL | Some(foo(1)) | ^^^^^^^^^^^^ From 37e838f759b99dd3ac042a61f60a4f14272b99c2 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 13 Apr 2022 01:13:47 -0400 Subject: [PATCH 47/62] Use new util function in `suspicious_else_formatting` --- clippy_lints/src/formatting.rs | 6 +++--- clippy_utils/src/check_proc_macro.rs | 7 ++++++- clippy_utils/src/lib.rs | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index db0166da57f0e..01cefe4af8532 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note}; +use clippy_utils::is_span_if; use clippy_utils::source::snippet_opt; use if_chain::if_chain; use rustc_ast::ast::{BinOpKind, Block, Expr, ExprKind, StmtKind, UnOp}; @@ -297,12 +298,11 @@ fn check_array(cx: &EarlyContext<'_>, expr: &Expr) { fn check_missing_else(cx: &EarlyContext<'_>, first: &Expr, second: &Expr) { if_chain! { if !first.span.from_expansion() && !second.span.from_expansion(); - if let ExprKind::If(cond_expr, ..) = &first.kind; + if matches!(first.kind, ExprKind::If(..)); if is_block(second) || is_if(second); // Proc-macros can give weird spans. Make sure this is actually an `if`. - if let Some(if_snip) = snippet_opt(cx, first.span.until(cond_expr.span)); - if if_snip.starts_with("if"); + if is_span_if(cx, first.span); // If there is a line break between the two expressions, don't lint. // If there is a non-whitespace character, this span came from a proc-macro. diff --git a/clippy_utils/src/check_proc_macro.rs b/clippy_utils/src/check_proc_macro.rs index 387bf72000848..51cd70f5e7c8f 100644 --- a/clippy_utils/src/check_proc_macro.rs +++ b/clippy_utils/src/check_proc_macro.rs @@ -162,6 +162,11 @@ pub fn is_expr_from_proc_macro(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { } /// Checks if the span actually refers to a match expression -pub fn is_span_match(cx: &LateContext<'_>, span: Span) -> bool { +pub fn is_span_match(cx: &impl LintContext, span: Span) -> bool { span_matches_pat(cx.sess(), span, Pat::Str("match"), Pat::Str("}")) } + +/// Checks if the span actually refers to an if expression +pub fn is_span_if(cx: &impl LintContext, span: Span) -> bool { + span_matches_pat(cx.sess(), span, Pat::Str("if"), Pat::Str("}")) +} diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 2d051e3a8157c..086e6d6e3a2b7 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -59,7 +59,7 @@ pub mod usage; pub mod visitors; pub use self::attrs::*; -pub use self::check_proc_macro::{is_expr_from_proc_macro, is_span_match}; +pub use self::check_proc_macro::{is_expr_from_proc_macro, is_span_if, is_span_match}; pub use self::hir_utils::{ both, count_eq, eq_expr_value, hash_expr, hash_stmt, over, HirEqInterExpr, SpanlessEq, SpanlessHash, }; From 4ae582ef88adbdcd3a01686a7a61120efd7a208b Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 13 Apr 2022 09:23:12 -0400 Subject: [PATCH 48/62] Don't lint `missing_docs_in_private_items` on proc-macro output --- clippy_lints/src/missing_doc.rs | 21 ++- clippy_lints/src/unit_types/mod.rs | 2 +- clippy_lints/src/unit_types/unit_arg.rs | 6 +- clippy_utils/src/check_proc_macro.rs | 130 +++++++++++++++++- clippy_utils/src/lib.rs | 2 +- tests/ui/{missing-doc.rs => missing_doc.rs} | 13 ++ ...{missing-doc.stderr => missing_doc.stderr} | 48 +++---- ...sing-doc-crate.rs => missing_doc_crate.rs} | 0 ...issing.rs => missing_doc_crate_missing.rs} | 0 ...tderr => missing_doc_crate_missing.stderr} | 2 +- ...issing-doc-impl.rs => missing_doc_impl.rs} | 15 ++ ...oc-impl.stderr => missing_doc_impl.stderr} | 30 ++-- 12 files changed, 212 insertions(+), 57 deletions(-) rename tests/ui/{missing-doc.rs => missing_doc.rs} (82%) rename tests/ui/{missing-doc.stderr => missing_doc.stderr} (79%) rename tests/ui/{missing-doc-crate.rs => missing_doc_crate.rs} (100%) rename tests/ui/{missing-doc-crate-missing.rs => missing_doc_crate_missing.rs} (100%) rename tests/ui/{missing-doc-crate-missing.stderr => missing_doc_crate_missing.stderr} (86%) rename tests/ui/{missing-doc-impl.rs => missing_doc_impl.rs} (83%) rename tests/ui/{missing-doc-impl.stderr => missing_doc_impl.stderr} (78%) diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index b99052e66ba57..7ef80b1a5960e 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -7,6 +7,7 @@ use clippy_utils::attrs::is_doc_hidden; use clippy_utils::diagnostics::span_lint; +use clippy_utils::is_from_proc_macro; use if_chain::if_chain; use rustc_ast::ast::{self, MetaItem, MetaItemKind}; use rustc_hir as hir; @@ -158,14 +159,18 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { let (article, desc) = cx.tcx.article_and_description(it.def_id.to_def_id()); let attrs = cx.tcx.hir().attrs(it.hir_id()); - self.check_missing_docs_attrs(cx, attrs, it.span, article, desc); + if !is_from_proc_macro(cx, it) { + self.check_missing_docs_attrs(cx, attrs, it.span, article, desc); + } } fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx hir::TraitItem<'_>) { let (article, desc) = cx.tcx.article_and_description(trait_item.def_id.to_def_id()); let attrs = cx.tcx.hir().attrs(trait_item.hir_id()); - self.check_missing_docs_attrs(cx, attrs, trait_item.span, article, desc); + if !is_from_proc_macro(cx, trait_item) { + self.check_missing_docs_attrs(cx, attrs, trait_item.span, article, desc); + } } fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) { @@ -181,18 +186,24 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { let (article, desc) = cx.tcx.article_and_description(impl_item.def_id.to_def_id()); let attrs = cx.tcx.hir().attrs(impl_item.hir_id()); - self.check_missing_docs_attrs(cx, attrs, impl_item.span, article, desc); + if !is_from_proc_macro(cx, impl_item) { + self.check_missing_docs_attrs(cx, attrs, impl_item.span, article, desc); + } } fn check_field_def(&mut self, cx: &LateContext<'tcx>, sf: &'tcx hir::FieldDef<'_>) { if !sf.is_positional() { let attrs = cx.tcx.hir().attrs(sf.hir_id); - self.check_missing_docs_attrs(cx, attrs, sf.span, "a", "struct field"); + if !is_from_proc_macro(cx, sf) { + self.check_missing_docs_attrs(cx, attrs, sf.span, "a", "struct field"); + } } } fn check_variant(&mut self, cx: &LateContext<'tcx>, v: &'tcx hir::Variant<'_>) { let attrs = cx.tcx.hir().attrs(v.id); - self.check_missing_docs_attrs(cx, attrs, v.span, "a", "variant"); + if !is_from_proc_macro(cx, v) { + self.check_missing_docs_attrs(cx, attrs, v.span, "a", "variant"); + } } } diff --git a/clippy_lints/src/unit_types/mod.rs b/clippy_lints/src/unit_types/mod.rs index 6aa86a57c9bdf..546242ebd9a47 100644 --- a/clippy_lints/src/unit_types/mod.rs +++ b/clippy_lints/src/unit_types/mod.rs @@ -103,7 +103,7 @@ impl<'tcx> LateLintPass<'tcx> for UnitTypes { let_unit_value::check(cx, local); } - fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { unit_cmp::check(cx, expr); unit_arg::check(cx, expr); } diff --git a/clippy_lints/src/unit_types/unit_arg.rs b/clippy_lints/src/unit_types/unit_arg.rs index cd38720f72235..16da2f11b81a6 100644 --- a/clippy_lints/src/unit_types/unit_arg.rs +++ b/clippy_lints/src/unit_types/unit_arg.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::is_expr_from_proc_macro; +use clippy_utils::is_from_proc_macro; use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; use if_chain::if_chain; use rustc_errors::Applicability; @@ -8,7 +8,7 @@ use rustc_lint::LateContext; use super::{utils, UNIT_ARG}; -pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if expr.span.from_expansion() { return; } @@ -45,7 +45,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { } }) .collect::>(); - if !args_to_recover.is_empty() && !is_expr_from_proc_macro(cx, expr) { + if !args_to_recover.is_empty() && !is_from_proc_macro(cx, expr) { lint_unit_args(cx, expr, &args_to_recover); } }, diff --git a/clippy_utils/src/check_proc_macro.rs b/clippy_utils/src/check_proc_macro.rs index 51cd70f5e7c8f..4dd0ec6b6d05e 100644 --- a/clippy_utils/src/check_proc_macro.rs +++ b/clippy_utils/src/check_proc_macro.rs @@ -14,17 +14,20 @@ use rustc_ast::ast::{IntTy, LitIntType, LitKind, StrStyle, UintTy}; use rustc_hir::{ - Block, BlockCheckMode, Closure, Destination, Expr, ExprKind, LoopSource, MatchSource, QPath, UnOp, UnsafeSource, - YieldSource, + Block, BlockCheckMode, Closure, Destination, Expr, ExprKind, FieldDef, FnHeader, Impl, ImplItem, ImplItemKind, + IsAuto, Item, ItemKind, LoopSource, MatchSource, QPath, TraitItem, TraitItemKind, UnOp, UnsafeSource, Unsafety, + Variant, VariantData, VisibilityKind, YieldSource, }; use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_span::{Span, Symbol}; +use rustc_target::spec::abi::Abi; #[derive(Clone, Copy)] -enum Pat { +pub enum Pat { Str(&'static str), + MultiStr(&'static [&'static str]), Sym(Symbol), Num, } @@ -43,10 +46,12 @@ fn span_matches_pat(sess: &Session, span: Span, start_pat: Pat, end_pat: Pat) -> let end_str = s.trim_end_matches(|c: char| c.is_whitespace() || c == ')' || c == ','); (match start_pat { Pat::Str(text) => start_str.starts_with(text), + Pat::MultiStr(texts) => texts.iter().any(|s| start_str.starts_with(s)), Pat::Sym(sym) => start_str.starts_with(sym.as_str()), Pat::Num => start_str.as_bytes().first().map_or(false, u8::is_ascii_digit), } && match end_pat { Pat::Str(text) => end_str.ends_with(text), + Pat::MultiStr(texts) => texts.iter().any(|s| start_str.ends_with(s)), Pat::Sym(sym) => end_str.ends_with(sym.as_str()), Pat::Num => end_str.as_bytes().last().map_or(false, u8::is_ascii_hexdigit), }) @@ -155,10 +160,121 @@ fn expr_search_pat(tcx: TyCtxt<'_>, e: &Expr<'_>) -> (Pat, Pat) { } } -/// Checks if the expression likely came from a proc-macro -pub fn is_expr_from_proc_macro(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { - let (start_pat, end_pat) = expr_search_pat(cx.tcx, e); - !span_matches_pat(cx.sess(), e.span, start_pat, end_pat) +fn fn_header_search_pat(header: FnHeader) -> Pat { + if header.is_async() { + Pat::Str("async") + } else if header.is_const() { + Pat::Str("const") + } else if header.is_unsafe() { + Pat::Str("unsafe") + } else if header.abi != Abi::Rust { + Pat::Str("extern") + } else { + Pat::MultiStr(&["fn", "extern"]) + } +} + +fn item_search_pat(item: &Item<'_>) -> (Pat, Pat) { + let (start_pat, end_pat) = match &item.kind { + ItemKind::ExternCrate(_) => (Pat::Str("extern"), Pat::Str(";")), + ItemKind::Static(..) => (Pat::Str("static"), Pat::Str(";")), + ItemKind::Const(..) => (Pat::Str("const"), Pat::Str(";")), + ItemKind::Fn(sig, ..) => (fn_header_search_pat(sig.header), Pat::Str("")), + ItemKind::ForeignMod { .. } => (Pat::Str("extern"), Pat::Str("}")), + ItemKind::TyAlias(..) | ItemKind::OpaqueTy(_) => (Pat::Str("type"), Pat::Str(";")), + ItemKind::Enum(..) => (Pat::Str("enum"), Pat::Str("}")), + ItemKind::Struct(VariantData::Struct(..), _) => (Pat::Str("struct"), Pat::Str("}")), + ItemKind::Struct(..) => (Pat::Str("struct"), Pat::Str(";")), + ItemKind::Union(..) => (Pat::Str("union"), Pat::Str("}")), + ItemKind::Trait(_, Unsafety::Unsafe, ..) + | ItemKind::Impl(Impl { + unsafety: Unsafety::Unsafe, + .. + }) => (Pat::Str("unsafe"), Pat::Str("}")), + ItemKind::Trait(IsAuto::Yes, ..) => (Pat::Str("auto"), Pat::Str("}")), + ItemKind::Trait(..) => (Pat::Str("trait"), Pat::Str("}")), + ItemKind::Impl(_) => (Pat::Str("impl"), Pat::Str("}")), + _ => return (Pat::Str(""), Pat::Str("")), + }; + if matches!(item.vis.node, VisibilityKind::Inherited) { + (start_pat, end_pat) + } else { + (Pat::Str("pub"), end_pat) + } +} + +fn trait_item_search_pat(item: &TraitItem<'_>) -> (Pat, Pat) { + match &item.kind { + TraitItemKind::Const(..) => (Pat::Str("const"), Pat::Str(";")), + TraitItemKind::Type(..) => (Pat::Str("type"), Pat::Str(";")), + TraitItemKind::Fn(sig, ..) => (fn_header_search_pat(sig.header), Pat::Str("")), + } +} + +fn impl_item_search_pat(item: &ImplItem<'_>) -> (Pat, Pat) { + let (start_pat, end_pat) = match &item.kind { + ImplItemKind::Const(..) => (Pat::Str("const"), Pat::Str(";")), + ImplItemKind::TyAlias(..) => (Pat::Str("type"), Pat::Str(";")), + ImplItemKind::Fn(sig, ..) => (fn_header_search_pat(sig.header), Pat::Str("")), + }; + if matches!(item.vis.node, VisibilityKind::Inherited) { + (start_pat, end_pat) + } else { + (Pat::Str("pub"), end_pat) + } +} + +fn field_def_search_pat(def: &FieldDef<'_>) -> (Pat, Pat) { + if matches!(def.vis.node, VisibilityKind::Inherited) { + if def.is_positional() { + (Pat::Str(""), Pat::Str("")) + } else { + (Pat::Sym(def.ident.name), Pat::Str("")) + } + } else { + (Pat::Str("pub"), Pat::Str("")) + } +} + +fn variant_search_pat(v: &Variant<'_>) -> (Pat, Pat) { + match v.data { + VariantData::Struct(..) => (Pat::Sym(v.ident.name), Pat::Str("}")), + VariantData::Tuple(..) => (Pat::Sym(v.ident.name), Pat::Str("")), + VariantData::Unit(..) => (Pat::Sym(v.ident.name), Pat::Sym(v.ident.name)), + } +} + +pub trait WithSearchPat { + type Context: LintContext; + fn search_pat(&self, cx: &Self::Context) -> (Pat, Pat); + fn span(&self) -> Span; +} +macro_rules! impl_with_search_pat { + ($cx:ident: $ty:ident with $fn:ident $(($tcx:ident))?) => { + impl<'cx> WithSearchPat for $ty<'cx> { + type Context = $cx<'cx>; + #[allow(unused_variables)] + fn search_pat(&self, cx: &Self::Context) -> (Pat, Pat) { + $(let $tcx = cx.tcx;)? + $fn($($tcx,)? self) + } + fn span(&self) -> Span { + self.span + } + } + }; +} +impl_with_search_pat!(LateContext: Expr with expr_search_pat(tcx)); +impl_with_search_pat!(LateContext: Item with item_search_pat); +impl_with_search_pat!(LateContext: TraitItem with trait_item_search_pat); +impl_with_search_pat!(LateContext: ImplItem with impl_item_search_pat); +impl_with_search_pat!(LateContext: FieldDef with field_def_search_pat); +impl_with_search_pat!(LateContext: Variant with variant_search_pat); + +/// Checks if the item likely came from a proc-macro +pub fn is_from_proc_macro(cx: &T::Context, item: &T) -> bool { + let (start_pat, end_pat) = item.search_pat(cx); + !span_matches_pat(cx.sess(), item.span(), start_pat, end_pat) } /// Checks if the span actually refers to a match expression diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 086e6d6e3a2b7..dcfc03475b423 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -59,7 +59,7 @@ pub mod usage; pub mod visitors; pub use self::attrs::*; -pub use self::check_proc_macro::{is_expr_from_proc_macro, is_span_if, is_span_match}; +pub use self::check_proc_macro::{is_from_proc_macro, is_span_if, is_span_match}; pub use self::hir_utils::{ both, count_eq, eq_expr_value, hash_expr, hash_stmt, over, HirEqInterExpr, SpanlessEq, SpanlessHash, }; diff --git a/tests/ui/missing-doc.rs b/tests/ui/missing_doc.rs similarity index 82% rename from tests/ui/missing-doc.rs rename to tests/ui/missing_doc.rs index 6e2e710e21c84..29cc026a8fd39 100644 --- a/tests/ui/missing-doc.rs +++ b/tests/ui/missing_doc.rs @@ -1,3 +1,5 @@ +// aux-build: proc_macro_with_span.rs + #![warn(clippy::missing_docs_in_private_items)] // When denying at the crate level, be sure to not get random warnings from the // injected intrinsics by the compiler. @@ -5,6 +7,9 @@ //! Some garbage docs for the crate here #![doc = "More garbage"] +extern crate proc_macro_with_span; + +use proc_macro_with_span::with_span; use std::arch::global_asm; type Typedef = String; @@ -100,3 +105,11 @@ fn main() {} // Ensure global asm doesn't require documentation. global_asm! { "" } + +// Don't lint proc macro output with an unexpected span. +with_span!(span pub struct FooPm { pub field: u32}); +with_span!(span pub struct FooPm2;); +with_span!(span pub enum FooPm3 { A, B(u32), C { field: u32 }}); +with_span!(span pub fn foo_pm() {}); +with_span!(span pub static FOO_PM: u32 = 0;); +with_span!(span pub const FOO2_PM: u32 = 0;); diff --git a/tests/ui/missing-doc.stderr b/tests/ui/missing_doc.stderr similarity index 79% rename from tests/ui/missing-doc.stderr rename to tests/ui/missing_doc.stderr index a876dc078ebff..6c8e66f464377 100644 --- a/tests/ui/missing-doc.stderr +++ b/tests/ui/missing_doc.stderr @@ -1,5 +1,5 @@ error: missing documentation for a type alias - --> $DIR/missing-doc.rs:10:1 + --> $DIR/missing_doc.rs:15:1 | LL | type Typedef = String; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -7,37 +7,37 @@ LL | type Typedef = String; = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings` error: missing documentation for a type alias - --> $DIR/missing-doc.rs:11:1 + --> $DIR/missing_doc.rs:16:1 | LL | pub type PubTypedef = String; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a module - --> $DIR/missing-doc.rs:13:1 + --> $DIR/missing_doc.rs:18:1 | LL | mod module_no_dox {} | ^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a module - --> $DIR/missing-doc.rs:14:1 + --> $DIR/missing_doc.rs:19:1 | LL | pub mod pub_module_no_dox {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> $DIR/missing-doc.rs:18:1 + --> $DIR/missing_doc.rs:23:1 | LL | pub fn foo2() {} | ^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> $DIR/missing-doc.rs:19:1 + --> $DIR/missing_doc.rs:24:1 | LL | fn foo3() {} | ^^^^^^^^^^^^ error: missing documentation for an enum - --> $DIR/missing-doc.rs:33:1 + --> $DIR/missing_doc.rs:38:1 | LL | / enum Baz { LL | | BazA { a: isize, b: isize }, @@ -46,31 +46,31 @@ LL | | } | |_^ error: missing documentation for a variant - --> $DIR/missing-doc.rs:34:5 + --> $DIR/missing_doc.rs:39:5 | LL | BazA { a: isize, b: isize }, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a struct field - --> $DIR/missing-doc.rs:34:12 + --> $DIR/missing_doc.rs:39:12 | LL | BazA { a: isize, b: isize }, | ^^^^^^^^ error: missing documentation for a struct field - --> $DIR/missing-doc.rs:34:22 + --> $DIR/missing_doc.rs:39:22 | LL | BazA { a: isize, b: isize }, | ^^^^^^^^ error: missing documentation for a variant - --> $DIR/missing-doc.rs:35:5 + --> $DIR/missing_doc.rs:40:5 | LL | BarB, | ^^^^ error: missing documentation for an enum - --> $DIR/missing-doc.rs:38:1 + --> $DIR/missing_doc.rs:43:1 | LL | / pub enum PubBaz { LL | | PubBazA { a: isize }, @@ -78,43 +78,43 @@ LL | | } | |_^ error: missing documentation for a variant - --> $DIR/missing-doc.rs:39:5 + --> $DIR/missing_doc.rs:44:5 | LL | PubBazA { a: isize }, | ^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a struct field - --> $DIR/missing-doc.rs:39:15 + --> $DIR/missing_doc.rs:44:15 | LL | PubBazA { a: isize }, | ^^^^^^^^ error: missing documentation for a constant - --> $DIR/missing-doc.rs:59:1 + --> $DIR/missing_doc.rs:64:1 | LL | const FOO: u32 = 0; | ^^^^^^^^^^^^^^^^^^^ error: missing documentation for a constant - --> $DIR/missing-doc.rs:66:1 + --> $DIR/missing_doc.rs:71:1 | LL | pub const FOO4: u32 = 0; | ^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a static - --> $DIR/missing-doc.rs:68:1 + --> $DIR/missing_doc.rs:73:1 | LL | static BAR: u32 = 0; | ^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a static - --> $DIR/missing-doc.rs:75:1 + --> $DIR/missing_doc.rs:80:1 | LL | pub static BAR4: u32 = 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a module - --> $DIR/missing-doc.rs:77:1 + --> $DIR/missing_doc.rs:82:1 | LL | / mod internal_impl { LL | | /// dox @@ -126,31 +126,31 @@ LL | | } | |_^ error: missing documentation for a function - --> $DIR/missing-doc.rs:80:5 + --> $DIR/missing_doc.rs:85:5 | LL | pub fn undocumented1() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> $DIR/missing-doc.rs:81:5 + --> $DIR/missing_doc.rs:86:5 | LL | pub fn undocumented2() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> $DIR/missing-doc.rs:82:5 + --> $DIR/missing_doc.rs:87:5 | LL | fn undocumented3() {} | ^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> $DIR/missing-doc.rs:87:9 + --> $DIR/missing_doc.rs:92:9 | LL | pub fn also_undocumented1() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> $DIR/missing-doc.rs:88:9 + --> $DIR/missing_doc.rs:93:9 | LL | fn also_undocumented2() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/missing-doc-crate.rs b/tests/ui/missing_doc_crate.rs similarity index 100% rename from tests/ui/missing-doc-crate.rs rename to tests/ui/missing_doc_crate.rs diff --git a/tests/ui/missing-doc-crate-missing.rs b/tests/ui/missing_doc_crate_missing.rs similarity index 100% rename from tests/ui/missing-doc-crate-missing.rs rename to tests/ui/missing_doc_crate_missing.rs diff --git a/tests/ui/missing-doc-crate-missing.stderr b/tests/ui/missing_doc_crate_missing.stderr similarity index 86% rename from tests/ui/missing-doc-crate-missing.stderr rename to tests/ui/missing_doc_crate_missing.stderr index d56c5cc4c3ae2..19516bf5fab0e 100644 --- a/tests/ui/missing-doc-crate-missing.stderr +++ b/tests/ui/missing_doc_crate_missing.stderr @@ -1,5 +1,5 @@ error: missing documentation for the crate - --> $DIR/missing-doc-crate-missing.rs:1:1 + --> $DIR/missing_doc_crate_missing.rs:1:1 | LL | / #![warn(clippy::missing_docs_in_private_items)] LL | | diff --git a/tests/ui/missing-doc-impl.rs b/tests/ui/missing_doc_impl.rs similarity index 83% rename from tests/ui/missing-doc-impl.rs rename to tests/ui/missing_doc_impl.rs index d5724bf661c63..0396d1193ff5c 100644 --- a/tests/ui/missing-doc-impl.rs +++ b/tests/ui/missing_doc_impl.rs @@ -1,3 +1,5 @@ +// aux-build: proc_macro_with_span.rs + #![warn(clippy::missing_docs_in_private_items)] #![allow(dead_code)] #![feature(associated_type_defaults)] @@ -5,6 +7,9 @@ //! Some garbage docs for the crate here #![doc = "More garbage"] +extern crate proc_macro_with_span; +use proc_macro_with_span::with_span; + struct Foo { a: isize, b: isize, @@ -90,3 +95,13 @@ impl F for Foo { } fn main() {} + +// don't lint proc macro output +with_span!(span + pub struct FooPm; + impl FooPm { + pub fn foo() {} + pub const fn bar() {} + pub const X: u32 = 0; + } +); diff --git a/tests/ui/missing-doc-impl.stderr b/tests/ui/missing_doc_impl.stderr similarity index 78% rename from tests/ui/missing-doc-impl.stderr rename to tests/ui/missing_doc_impl.stderr index bda63d66a174a..f22fa19dbcabc 100644 --- a/tests/ui/missing-doc-impl.stderr +++ b/tests/ui/missing_doc_impl.stderr @@ -1,5 +1,5 @@ error: missing documentation for a struct - --> $DIR/missing-doc-impl.rs:8:1 + --> $DIR/missing_doc_impl.rs:13:1 | LL | / struct Foo { LL | | a: isize, @@ -10,19 +10,19 @@ LL | | } = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings` error: missing documentation for a struct field - --> $DIR/missing-doc-impl.rs:9:5 + --> $DIR/missing_doc_impl.rs:14:5 | LL | a: isize, | ^^^^^^^^ error: missing documentation for a struct field - --> $DIR/missing-doc-impl.rs:10:5 + --> $DIR/missing_doc_impl.rs:15:5 | LL | b: isize, | ^^^^^^^^ error: missing documentation for a struct - --> $DIR/missing-doc-impl.rs:13:1 + --> $DIR/missing_doc_impl.rs:18:1 | LL | / pub struct PubFoo { LL | | pub a: isize, @@ -31,19 +31,19 @@ LL | | } | |_^ error: missing documentation for a struct field - --> $DIR/missing-doc-impl.rs:14:5 + --> $DIR/missing_doc_impl.rs:19:5 | LL | pub a: isize, | ^^^^^^^^^^^^ error: missing documentation for a struct field - --> $DIR/missing-doc-impl.rs:15:5 + --> $DIR/missing_doc_impl.rs:20:5 | LL | b: isize, | ^^^^^^^^ error: missing documentation for a trait - --> $DIR/missing-doc-impl.rs:38:1 + --> $DIR/missing_doc_impl.rs:43:1 | LL | / pub trait C { LL | | fn foo(&self); @@ -52,31 +52,31 @@ LL | | } | |_^ error: missing documentation for an associated function - --> $DIR/missing-doc-impl.rs:39:5 + --> $DIR/missing_doc_impl.rs:44:5 | LL | fn foo(&self); | ^^^^^^^^^^^^^^ error: missing documentation for an associated function - --> $DIR/missing-doc-impl.rs:40:5 + --> $DIR/missing_doc_impl.rs:45:5 | LL | fn foo_with_impl(&self) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for an associated type - --> $DIR/missing-doc-impl.rs:50:5 + --> $DIR/missing_doc_impl.rs:55:5 | LL | type AssociatedType; | ^^^^^^^^^^^^^^^^^^^^ error: missing documentation for an associated type - --> $DIR/missing-doc-impl.rs:51:5 + --> $DIR/missing_doc_impl.rs:56:5 | LL | type AssociatedTypeDef = Self; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for an associated function - --> $DIR/missing-doc-impl.rs:62:5 + --> $DIR/missing_doc_impl.rs:67:5 | LL | / pub fn new() -> Self { LL | | Foo { a: 0, b: 0 } @@ -84,19 +84,19 @@ LL | | } | |_____^ error: missing documentation for an associated function - --> $DIR/missing-doc-impl.rs:65:5 + --> $DIR/missing_doc_impl.rs:70:5 | LL | fn bar() {} | ^^^^^^^^^^^ error: missing documentation for an associated function - --> $DIR/missing-doc-impl.rs:69:5 + --> $DIR/missing_doc_impl.rs:74:5 | LL | pub fn foo() {} | ^^^^^^^^^^^^^^^ error: missing documentation for an associated function - --> $DIR/missing-doc-impl.rs:73:5 + --> $DIR/missing_doc_impl.rs:78:5 | LL | / fn foo2() -> u32 { LL | | 1 From 670efd5720b31e235c8e97f49f612e685db97b93 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 13 Apr 2022 10:13:39 -0400 Subject: [PATCH 49/62] Don't lint `default_trait_access` in proc-macro expansions --- clippy_lints/src/default.rs | 5 ++++- clippy_utils/src/check_proc_macro.rs | 8 ++++---- tests/ui/default_trait_access.fixed | 6 ++++++ tests/ui/default_trait_access.rs | 6 ++++++ tests/ui/default_trait_access.stderr | 18 +++++++++--------- 5 files changed, 29 insertions(+), 14 deletions(-) diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs index d99a1aa296946..74f7df611778e 100644 --- a/clippy_lints/src/default.rs +++ b/clippy_lints/src/default.rs @@ -1,7 +1,9 @@ use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg}; use clippy_utils::source::snippet_with_macro_callsite; use clippy_utils::ty::{has_drop, is_copy}; -use clippy_utils::{any_parent_is_automatically_derived, contains_name, get_parent_expr, match_def_path, paths}; +use clippy_utils::{ + any_parent_is_automatically_derived, contains_name, get_parent_expr, is_from_proc_macro, match_def_path, paths, +}; use if_chain::if_chain; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; @@ -94,6 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { if let QPath::Resolved(None, _path) = qpath; let expr_ty = cx.typeck_results().expr_ty(expr); if let ty::Adt(def, ..) = expr_ty.kind(); + if !is_from_proc_macro(cx, expr); then { // TODO: Work out a way to put "whatever the imported way of referencing // this type in this file" rather than a fully-qualified type. diff --git a/clippy_utils/src/check_proc_macro.rs b/clippy_utils/src/check_proc_macro.rs index 4dd0ec6b6d05e..f546a788c5d39 100644 --- a/clippy_utils/src/check_proc_macro.rs +++ b/clippy_utils/src/check_proc_macro.rs @@ -16,7 +16,7 @@ use rustc_ast::ast::{IntTy, LitIntType, LitKind, StrStyle, UintTy}; use rustc_hir::{ Block, BlockCheckMode, Closure, Destination, Expr, ExprKind, FieldDef, FnHeader, Impl, ImplItem, ImplItemKind, IsAuto, Item, ItemKind, LoopSource, MatchSource, QPath, TraitItem, TraitItemKind, UnOp, UnsafeSource, Unsafety, - Variant, VariantData, VisibilityKind, YieldSource, + Variant, VariantData, YieldSource, }; use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty::TyCtxt; @@ -196,7 +196,7 @@ fn item_search_pat(item: &Item<'_>) -> (Pat, Pat) { ItemKind::Impl(_) => (Pat::Str("impl"), Pat::Str("}")), _ => return (Pat::Str(""), Pat::Str("")), }; - if matches!(item.vis.node, VisibilityKind::Inherited) { + if item.vis_span.is_empty() { (start_pat, end_pat) } else { (Pat::Str("pub"), end_pat) @@ -217,7 +217,7 @@ fn impl_item_search_pat(item: &ImplItem<'_>) -> (Pat, Pat) { ImplItemKind::TyAlias(..) => (Pat::Str("type"), Pat::Str(";")), ImplItemKind::Fn(sig, ..) => (fn_header_search_pat(sig.header), Pat::Str("")), }; - if matches!(item.vis.node, VisibilityKind::Inherited) { + if item.vis_span.is_empty() { (start_pat, end_pat) } else { (Pat::Str("pub"), end_pat) @@ -225,7 +225,7 @@ fn impl_item_search_pat(item: &ImplItem<'_>) -> (Pat, Pat) { } fn field_def_search_pat(def: &FieldDef<'_>) -> (Pat, Pat) { - if matches!(def.vis.node, VisibilityKind::Inherited) { + if def.vis_span.is_empty() { if def.is_positional() { (Pat::Str(""), Pat::Str("")) } else { diff --git a/tests/ui/default_trait_access.fixed b/tests/ui/default_trait_access.fixed index 264dd4efaeb86..fce66eb175963 100644 --- a/tests/ui/default_trait_access.fixed +++ b/tests/ui/default_trait_access.fixed @@ -1,8 +1,12 @@ // run-rustfix +// aux-build: proc_macro_with_span.rs #![allow(unused_imports, dead_code)] #![deny(clippy::default_trait_access)] +extern crate proc_macro_with_span; + +use proc_macro_with_span::with_span; use std::default; use std::default::Default as D2; use std::string; @@ -51,6 +55,8 @@ fn main() { ..Default::default() }; + let _s21: String = with_span!(s Default::default()); + println!( "[{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}]", s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15, s16, s17, s18, s19, s20, diff --git a/tests/ui/default_trait_access.rs b/tests/ui/default_trait_access.rs index a0930fab8e7c8..3e8e898b7bc61 100644 --- a/tests/ui/default_trait_access.rs +++ b/tests/ui/default_trait_access.rs @@ -1,8 +1,12 @@ // run-rustfix +// aux-build: proc_macro_with_span.rs #![allow(unused_imports, dead_code)] #![deny(clippy::default_trait_access)] +extern crate proc_macro_with_span; + +use proc_macro_with_span::with_span; use std::default; use std::default::Default as D2; use std::string; @@ -51,6 +55,8 @@ fn main() { ..Default::default() }; + let _s21: String = with_span!(s Default::default()); + println!( "[{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}]", s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15, s16, s17, s18, s19, s20, diff --git a/tests/ui/default_trait_access.stderr b/tests/ui/default_trait_access.stderr index df8a5b94ddcf3..3493de37a55be 100644 --- a/tests/ui/default_trait_access.stderr +++ b/tests/ui/default_trait_access.stderr @@ -1,53 +1,53 @@ error: calling `std::string::String::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:11:22 + --> $DIR/default_trait_access.rs:15:22 | LL | let s1: String = Default::default(); | ^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()` | note: the lint level is defined here - --> $DIR/default_trait_access.rs:4:9 + --> $DIR/default_trait_access.rs:5:9 | LL | #![deny(clippy::default_trait_access)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: calling `std::string::String::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:15:22 + --> $DIR/default_trait_access.rs:19:22 | LL | let s3: String = D2::default(); | ^^^^^^^^^^^^^ help: try: `std::string::String::default()` error: calling `std::string::String::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:17:22 + --> $DIR/default_trait_access.rs:21:22 | LL | let s4: String = std::default::Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()` error: calling `std::string::String::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:21:22 + --> $DIR/default_trait_access.rs:25:22 | LL | let s6: String = default::Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()` error: calling `GenericDerivedDefault::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:31:46 + --> $DIR/default_trait_access.rs:35:46 | LL | let s11: GenericDerivedDefault = Default::default(); | ^^^^^^^^^^^^^^^^^^ help: try: `GenericDerivedDefault::default()` error: calling `TupleDerivedDefault::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:37:36 + --> $DIR/default_trait_access.rs:41:36 | LL | let s14: TupleDerivedDefault = Default::default(); | ^^^^^^^^^^^^^^^^^^ help: try: `TupleDerivedDefault::default()` error: calling `ArrayDerivedDefault::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:39:36 + --> $DIR/default_trait_access.rs:43:36 | LL | let s15: ArrayDerivedDefault = Default::default(); | ^^^^^^^^^^^^^^^^^^ help: try: `ArrayDerivedDefault::default()` error: calling `TupleStructDerivedDefault::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:43:42 + --> $DIR/default_trait_access.rs:47:42 | LL | let s17: TupleStructDerivedDefault = Default::default(); | ^^^^^^^^^^^^^^^^^^ help: try: `TupleStructDerivedDefault::default()` From 8dda974a2753c0cf4d552e6054303376bc62c7bb Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 24 Apr 2022 10:04:33 -0400 Subject: [PATCH 50/62] Add note to the docs on `is_from_proc_macro` --- clippy_utils/src/check_proc_macro.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/clippy_utils/src/check_proc_macro.rs b/clippy_utils/src/check_proc_macro.rs index f546a788c5d39..9f2c412eb8553 100644 --- a/clippy_utils/src/check_proc_macro.rs +++ b/clippy_utils/src/check_proc_macro.rs @@ -271,7 +271,10 @@ impl_with_search_pat!(LateContext: ImplItem with impl_item_search_pat); impl_with_search_pat!(LateContext: FieldDef with field_def_search_pat); impl_with_search_pat!(LateContext: Variant with variant_search_pat); -/// Checks if the item likely came from a proc-macro +/// Checks if the item likely came from a proc-macro. +/// +/// This should be called after `in_external_macro` and the initial pattern matching of the ast as +/// it is significantly slower than both of those. pub fn is_from_proc_macro(cx: &T::Context, item: &T) -> bool { let (start_pat, end_pat) = item.search_pat(cx); !span_matches_pat(cx.sess(), item.span(), start_pat, end_pat) From 745b1942925c53156389f3ea731c360e507f71eb Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 7 Aug 2022 21:44:32 -0400 Subject: [PATCH 51/62] Small cleanup for `check_proc_macro.rs` --- clippy_utils/src/check_proc_macro.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/clippy_utils/src/check_proc_macro.rs b/clippy_utils/src/check_proc_macro.rs index 9f2c412eb8553..0f00a1cdf0fa2 100644 --- a/clippy_utils/src/check_proc_macro.rs +++ b/clippy_utils/src/check_proc_macro.rs @@ -24,11 +24,16 @@ use rustc_session::Session; use rustc_span::{Span, Symbol}; use rustc_target::spec::abi::Abi; +/// The search pattern to look for. Used by `span_matches_pat` #[derive(Clone, Copy)] pub enum Pat { + /// A single string. Str(&'static str), + /// Any of the given strings. MultiStr(&'static [&'static str]), + /// The string representation of the symbol. Sym(Symbol), + /// Any decimal or hexadecimal digit depending on the location. Num, } @@ -108,9 +113,9 @@ fn expr_search_pat(tcx: TyCtxt<'_>, e: &Expr<'_>) -> (Pat, Pat) { ExprKind::Box(e) => (Pat::Str("box"), expr_search_pat(tcx, e).1), ExprKind::ConstBlock(_) => (Pat::Str("const"), Pat::Str("}")), ExprKind::Tup([]) => (Pat::Str(")"), Pat::Str("(")), - ExprKind::Unary(UnOp::Deref, _) => (Pat::Str("*"), expr_search_pat(tcx, e).1), - ExprKind::Unary(UnOp::Not, _) => (Pat::Str("!"), expr_search_pat(tcx, e).1), - ExprKind::Unary(UnOp::Neg, _) => (Pat::Str("-"), expr_search_pat(tcx, e).1), + ExprKind::Unary(UnOp::Deref, e) => (Pat::Str("*"), expr_search_pat(tcx, e).1), + ExprKind::Unary(UnOp::Not, e) => (Pat::Str("!"), expr_search_pat(tcx, e).1), + ExprKind::Unary(UnOp::Neg, e) => (Pat::Str("-"), expr_search_pat(tcx, e).1), ExprKind::Lit(ref lit) => lit_search_pat(&lit.node), ExprKind::Array(_) | ExprKind::Repeat(..) => (Pat::Str("["), Pat::Str("]")), ExprKind::Call(e, []) | ExprKind::MethodCall(_, [e], _) => (expr_search_pat(tcx, e).0, Pat::Str("(")), @@ -154,6 +159,7 @@ fn expr_search_pat(tcx: TyCtxt<'_>, e: &Expr<'_>) -> (Pat, Pat) { ExprKind::Continue(Destination { label: None, .. }) => (Pat::Str("continue"), Pat::Str("continue")), ExprKind::Continue(Destination { label: Some(name), .. }) => (Pat::Str("continue"), Pat::Sym(name.ident.name)), ExprKind::Ret(None) => (Pat::Str("return"), Pat::Str("return")), + ExprKind::Ret(Some(e)) => (Pat::Str("return"), expr_search_pat(tcx, e).1), ExprKind::Struct(path, _, _) => (qpath_search_pat(path).0, Pat::Str("}")), ExprKind::Yield(e, YieldSource::Yield) => (Pat::Str("yield"), expr_search_pat(tcx, e).1), _ => (Pat::Str(""), Pat::Str("")), From 99abd4a9f605fbc80acc2cfd44cfaf62d54c557a Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 7 Aug 2022 22:22:17 -0400 Subject: [PATCH 52/62] Fix ICE when reading literals with weird proc-macro spans --- clippy_utils/src/numeric_literal.rs | 10 ++++---- tests/ui/mistyped_literal_suffix.fixed | 6 +++++ tests/ui/mistyped_literal_suffix.rs | 6 +++++ tests/ui/mistyped_literal_suffix.stderr | 32 ++++++++++++------------- 4 files changed, 34 insertions(+), 20 deletions(-) diff --git a/clippy_utils/src/numeric_literal.rs b/clippy_utils/src/numeric_literal.rs index 3fb5415ce0299..80098d9766c67 100644 --- a/clippy_utils/src/numeric_literal.rs +++ b/clippy_utils/src/numeric_literal.rs @@ -223,10 +223,12 @@ impl<'a> NumericLiteral<'a> { fn split_suffix<'a>(src: &'a str, lit_kind: &LitKind) -> (&'a str, Option<&'a str>) { debug_assert!(lit_kind.is_numeric()); - lit_suffix_length(lit_kind).map_or((src, None), |suffix_length| { - let (unsuffixed, suffix) = src.split_at(src.len() - suffix_length); - (unsuffixed, Some(suffix)) - }) + lit_suffix_length(lit_kind) + .and_then(|suffix_length| src.len().checked_sub(suffix_length)) + .map_or((src, None), |split_pos| { + let (unsuffixed, suffix) = src.split_at(split_pos); + (unsuffixed, Some(suffix)) + }) } fn lit_suffix_length(lit_kind: &LitKind) -> Option { diff --git a/tests/ui/mistyped_literal_suffix.fixed b/tests/ui/mistyped_literal_suffix.fixed index a7b36d53cd26c..becb9562a8497 100644 --- a/tests/ui/mistyped_literal_suffix.fixed +++ b/tests/ui/mistyped_literal_suffix.fixed @@ -1,4 +1,5 @@ // run-rustfix +// aux-build: proc_macro_with_span.rs #![allow( dead_code, @@ -9,6 +10,9 @@ clippy::unusual_byte_groupings )] +extern crate proc_macro_with_span; +use proc_macro_with_span::with_span; + fn main() { let fail14 = 2_i32; let fail15 = 4_i64; @@ -40,4 +44,6 @@ fn main() { let ok38 = 124_64.0; let _ = 1.123_45E1_f32; + + let _ = with_span!(1 2_u32); } diff --git a/tests/ui/mistyped_literal_suffix.rs b/tests/ui/mistyped_literal_suffix.rs index c97b31965c75a..ee841bcd7e4e9 100644 --- a/tests/ui/mistyped_literal_suffix.rs +++ b/tests/ui/mistyped_literal_suffix.rs @@ -1,4 +1,5 @@ // run-rustfix +// aux-build: proc_macro_with_span.rs #![allow( dead_code, @@ -9,6 +10,9 @@ clippy::unusual_byte_groupings )] +extern crate proc_macro_with_span; +use proc_macro_with_span::with_span; + fn main() { let fail14 = 2_32; let fail15 = 4_64; @@ -40,4 +44,6 @@ fn main() { let ok38 = 124_64.0; let _ = 1.12345E1_32; + + let _ = with_span!(1 2_u32); } diff --git a/tests/ui/mistyped_literal_suffix.stderr b/tests/ui/mistyped_literal_suffix.stderr index fb761d9bde452..ef8e6a33d28f5 100644 --- a/tests/ui/mistyped_literal_suffix.stderr +++ b/tests/ui/mistyped_literal_suffix.stderr @@ -1,5 +1,5 @@ error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:13:18 + --> $DIR/mistyped_literal_suffix.rs:17:18 | LL | let fail14 = 2_32; | ^^^^ help: did you mean to write: `2_i32` @@ -7,91 +7,91 @@ LL | let fail14 = 2_32; = note: `#[deny(clippy::mistyped_literal_suffixes)]` on by default error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:14:18 + --> $DIR/mistyped_literal_suffix.rs:18:18 | LL | let fail15 = 4_64; | ^^^^ help: did you mean to write: `4_i64` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:15:18 + --> $DIR/mistyped_literal_suffix.rs:19:18 | LL | let fail16 = 7_8; // | ^^^ help: did you mean to write: `7_i8` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:16:18 + --> $DIR/mistyped_literal_suffix.rs:20:18 | LL | let fail17 = 23_16; // | ^^^^^ help: did you mean to write: `23_i16` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:19:18 + --> $DIR/mistyped_literal_suffix.rs:23:18 | LL | let fail20 = 2__8; // | ^^^^ help: did you mean to write: `2_i8` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:20:18 + --> $DIR/mistyped_literal_suffix.rs:24:18 | LL | let fail21 = 4___16; // | ^^^^^^ help: did you mean to write: `4_i16` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:23:18 + --> $DIR/mistyped_literal_suffix.rs:27:18 | LL | let fail25 = 1E2_32; | ^^^^^^ help: did you mean to write: `1E2_f32` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:24:18 + --> $DIR/mistyped_literal_suffix.rs:28:18 | LL | let fail26 = 43E7_64; | ^^^^^^^ help: did you mean to write: `43E7_f64` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:25:18 + --> $DIR/mistyped_literal_suffix.rs:29:18 | LL | let fail27 = 243E17_32; | ^^^^^^^^^ help: did you mean to write: `243E17_f32` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:26:18 + --> $DIR/mistyped_literal_suffix.rs:30:18 | LL | let fail28 = 241251235E723_64; | ^^^^^^^^^^^^^^^^ help: did you mean to write: `241_251_235E723_f64` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:30:18 + --> $DIR/mistyped_literal_suffix.rs:34:18 | LL | let fail30 = 127_8; // should be i8 | ^^^^^ help: did you mean to write: `127_i8` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:31:18 + --> $DIR/mistyped_literal_suffix.rs:35:18 | LL | let fail31 = 240_8; // should be u8 | ^^^^^ help: did you mean to write: `240_u8` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:33:18 + --> $DIR/mistyped_literal_suffix.rs:37:18 | LL | let fail33 = 0x1234_16; | ^^^^^^^^^ help: did you mean to write: `0x1234_i16` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:34:18 + --> $DIR/mistyped_literal_suffix.rs:38:18 | LL | let fail34 = 0xABCD_16; | ^^^^^^^^^ help: did you mean to write: `0xABCD_u16` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:36:18 + --> $DIR/mistyped_literal_suffix.rs:40:18 | LL | let fail36 = 0xFFFF_FFFF_FFFF_FFFF_64; // u64 | ^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean to write: `0xFFFF_FFFF_FFFF_FFFF_u64` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:42:13 + --> $DIR/mistyped_literal_suffix.rs:46:13 | LL | let _ = 1.12345E1_32; | ^^^^^^^^^^^^ help: did you mean to write: `1.123_45E1_f32` From 5285928bc0190efb54495d8126b68778873884b9 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Mon, 8 Aug 2022 10:09:05 -0400 Subject: [PATCH 53/62] Fix ICE when checking the HIR ty of closure args. --- clippy_lints/src/dereference.rs | 67 +++++++++++++--------- tests/ui/explicit_auto_deref.fixed | 11 ++++ tests/ui/explicit_auto_deref.rs | 11 ++++ tests/ui/explicit_auto_deref.stderr | 86 ++++++++++++++++------------- 4 files changed, 112 insertions(+), 63 deletions(-) diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 05dbc7434855c..821528d7ab948 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -15,7 +15,7 @@ use rustc_hir::{ use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable, TypeckResults}; +use rustc_middle::ty::{self, Binder, BoundVariableKind, List, Ty, TyCtxt, TypeVisitable, TypeckResults}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP}; use rustc_trait_selection::infer::InferCtxtExt; @@ -651,7 +651,7 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & } match parent { Node::Local(Local { ty: Some(ty), span, .. }) if span.ctxt() == ctxt => { - Some(binding_ty_auto_deref_stability(cx, ty, precedence)) + Some(binding_ty_auto_deref_stability(cx, ty, precedence, List::empty())) }, Node::Item(&Item { kind: ItemKind::Static(..) | ItemKind::Const(..), @@ -703,13 +703,23 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & ExprKind::Ret(_) => { let owner_id = cx.tcx.hir().body_owner(cx.enclosing_body.unwrap()); Some( - if let Node::Expr(Expr { - kind: ExprKind::Closure(&Closure { fn_decl, .. }), - .. - }) = cx.tcx.hir().get(owner_id) + if let Node::Expr( + closure @ Expr { + kind: ExprKind::Closure(&Closure { fn_decl, .. }), + .. + }, + ) = cx.tcx.hir().get(owner_id) { match fn_decl.output { - FnRetTy::Return(ty) => binding_ty_auto_deref_stability(cx, ty, precedence), + FnRetTy::Return(ty) => { + if let Some(sig) = expr_sig(cx, closure) + && let Some(output) = sig.output() + { + binding_ty_auto_deref_stability(cx, ty, precedence, output.bound_vars()) + } else { + Position::Other(precedence) + } + }, FnRetTy::DefaultReturn(_) => Position::Other(precedence), } } else { @@ -731,7 +741,7 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & .map(|(hir_ty, ty)| match hir_ty { // Type inference for closures can depend on how they're called. Only go by the explicit // types here. - Some(ty) => binding_ty_auto_deref_stability(cx, ty, precedence), + Some(hir_ty) => binding_ty_auto_deref_stability(cx, hir_ty, precedence, ty.bound_vars()), None => ty_auto_deref_stability(cx, cx.tcx.erase_late_bound_regions(ty), precedence) .position_for_arg(), }), @@ -824,7 +834,12 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & // // Here `y1` and `y2` would resolve to different types, so the type `&Box<_>` is not stable when // switching to auto-dereferencing. -fn binding_ty_auto_deref_stability(cx: &LateContext<'_>, ty: &hir::Ty<'_>, precedence: i8) -> Position { +fn binding_ty_auto_deref_stability<'tcx>( + cx: &LateContext<'tcx>, + ty: &'tcx hir::Ty<'_>, + precedence: i8, + binder_args: &'tcx List, +) -> Position { let TyKind::Rptr(_, ty) = &ty.kind else { return Position::Other(precedence); }; @@ -856,31 +871,31 @@ fn binding_ty_auto_deref_stability(cx: &LateContext<'_>, ty: &hir::Ty<'_>, prece } else { Position::DerefStable( precedence, - cx - .typeck_results() - .node_type(ty.ty.hir_id) + cx.tcx + .erase_late_bound_regions(Binder::bind_with_vars( + cx.typeck_results().node_type(ty.ty.hir_id), + binder_args, + )) .is_sized(cx.tcx.at(DUMMY_SP), cx.param_env.without_caller_bounds()), ) } }, - TyKind::Slice(_) - | TyKind::Array(..) - | TyKind::BareFn(_) - | TyKind::Never + TyKind::Slice(_) => Position::DerefStable(precedence, false), + TyKind::Array(..) | TyKind::Ptr(_) | TyKind::BareFn(_) => Position::DerefStable(precedence, true), + TyKind::Never | TyKind::Tup(_) - | TyKind::Ptr(_) | TyKind::Path(_) => Position::DerefStable( precedence, - cx - .typeck_results() - .node_type(ty.ty.hir_id) - .is_sized(cx.tcx.at(DUMMY_SP), cx.param_env.without_caller_bounds()), + cx.tcx + .erase_late_bound_regions(Binder::bind_with_vars( + cx.typeck_results().node_type(ty.ty.hir_id), + binder_args, + )) + .is_sized(cx.tcx.at(DUMMY_SP), cx.param_env.without_caller_bounds()), ), - TyKind::OpaqueDef(..) - | TyKind::Infer - | TyKind::Typeof(..) - | TyKind::TraitObject(..) - | TyKind::Err => Position::ReborrowStable(precedence), + TyKind::OpaqueDef(..) | TyKind::Infer | TyKind::Typeof(..) | TyKind::TraitObject(..) | TyKind::Err => { + Position::ReborrowStable(precedence) + }, }; } } diff --git a/tests/ui/explicit_auto_deref.fixed b/tests/ui/explicit_auto_deref.fixed index 1e868af87cb80..27bc7fbfae3c7 100644 --- a/tests/ui/explicit_auto_deref.fixed +++ b/tests/ui/explicit_auto_deref.fixed @@ -1,5 +1,6 @@ // run-rustfix +#![feature(closure_lifetime_binder)] #![warn(clippy::explicit_auto_deref)] #![allow( dead_code, @@ -255,4 +256,14 @@ fn main() { } let x = S7([0]); let _: &[u32] = &*x; + + let c1 = |x: &Vec<&u32>| {}; + let x = &&vec![&1u32]; + c1(x); + let _ = for<'a, 'b> |x: &'a &'a Vec<&'b u32>, b: bool| -> &'a Vec<&'b u32> { + if b { + return x; + } + *x + }; } diff --git a/tests/ui/explicit_auto_deref.rs b/tests/ui/explicit_auto_deref.rs index a2157d9b4f05a..64aea9f464e48 100644 --- a/tests/ui/explicit_auto_deref.rs +++ b/tests/ui/explicit_auto_deref.rs @@ -1,5 +1,6 @@ // run-rustfix +#![feature(closure_lifetime_binder)] #![warn(clippy::explicit_auto_deref)] #![allow( dead_code, @@ -255,4 +256,14 @@ fn main() { } let x = S7([0]); let _: &[u32] = &*x; + + let c1 = |x: &Vec<&u32>| {}; + let x = &&vec![&1u32]; + c1(*x); + let _ = for<'a, 'b> |x: &'a &'a Vec<&'b u32>, b: bool| -> &'a Vec<&'b u32> { + if b { + return *x; + } + *x + }; } diff --git a/tests/ui/explicit_auto_deref.stderr b/tests/ui/explicit_auto_deref.stderr index f2933390fb95c..12db0c6f87fc3 100644 --- a/tests/ui/explicit_auto_deref.stderr +++ b/tests/ui/explicit_auto_deref.stderr @@ -1,5 +1,5 @@ error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:69:19 + --> $DIR/explicit_auto_deref.rs:70:19 | LL | let _: &str = &*s; | ^^^ help: try this: `&s` @@ -7,214 +7,226 @@ LL | let _: &str = &*s; = note: `-D clippy::explicit-auto-deref` implied by `-D warnings` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:70:19 + --> $DIR/explicit_auto_deref.rs:71:19 | LL | let _: &str = &*{ String::new() }; | ^^^^^^^^^^^^^^^^^^^ help: try this: `&{ String::new() }` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:71:19 + --> $DIR/explicit_auto_deref.rs:72:19 | LL | let _: &str = &mut *{ String::new() }; | ^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&mut { String::new() }` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:75:11 + --> $DIR/explicit_auto_deref.rs:76:11 | LL | f_str(&*s); | ^^^ help: try this: `&s` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:79:13 + --> $DIR/explicit_auto_deref.rs:80:13 | LL | f_str_t(&*s, &*s); // Don't lint second param. | ^^^ help: try this: `&s` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:82:24 + --> $DIR/explicit_auto_deref.rs:83:24 | LL | let _: &Box = &**b; | ^^^^ help: try this: `&b` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:88:7 + --> $DIR/explicit_auto_deref.rs:89:7 | LL | c(&*s); | ^^^ help: try this: `&s` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:94:9 + --> $DIR/explicit_auto_deref.rs:95:9 | LL | &**x | ^^^^ help: try this: `x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:98:11 + --> $DIR/explicit_auto_deref.rs:99:11 | LL | { &**x } | ^^^^ help: try this: `x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:102:9 + --> $DIR/explicit_auto_deref.rs:103:9 | LL | &**{ x } | ^^^^^^^^ help: try this: `{ x }` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:106:9 + --> $DIR/explicit_auto_deref.rs:107:9 | LL | &***x | ^^^^^ help: try this: `x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:123:12 + --> $DIR/explicit_auto_deref.rs:124:12 | LL | f1(&*x); | ^^^ help: try this: `&x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:124:12 + --> $DIR/explicit_auto_deref.rs:125:12 | LL | f2(&*x); | ^^^ help: try this: `&x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:125:12 + --> $DIR/explicit_auto_deref.rs:126:12 | LL | f3(&*x); | ^^^ help: try this: `&x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:126:27 + --> $DIR/explicit_auto_deref.rs:127:27 | LL | f4.callable_str()(&*x); | ^^^ help: try this: `&x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:127:12 + --> $DIR/explicit_auto_deref.rs:128:12 | LL | f5(&*x); | ^^^ help: try this: `&x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:128:12 + --> $DIR/explicit_auto_deref.rs:129:12 | LL | f6(&*x); | ^^^ help: try this: `&x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:129:27 + --> $DIR/explicit_auto_deref.rs:130:27 | LL | f7.callable_str()(&*x); | ^^^ help: try this: `&x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:130:25 + --> $DIR/explicit_auto_deref.rs:131:25 | LL | f8.callable_t()(&*x); | ^^^ help: try this: `&x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:131:12 + --> $DIR/explicit_auto_deref.rs:132:12 | LL | f9(&*x); | ^^^ help: try this: `&x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:132:13 + --> $DIR/explicit_auto_deref.rs:133:13 | LL | f10(&*x); | ^^^ help: try this: `&x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:133:26 + --> $DIR/explicit_auto_deref.rs:134:26 | LL | f11.callable_t()(&*x); | ^^^ help: try this: `&x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:137:16 + --> $DIR/explicit_auto_deref.rs:138:16 | LL | let _ = S1(&*s); | ^^^ help: try this: `&s` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:142:21 + --> $DIR/explicit_auto_deref.rs:143:21 | LL | let _ = S2 { s: &*s }; | ^^^ help: try this: `&s` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:158:30 + --> $DIR/explicit_auto_deref.rs:159:30 | LL | let _ = Self::S1(&**s); | ^^^^ help: try this: `s` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:159:35 + --> $DIR/explicit_auto_deref.rs:160:35 | LL | let _ = Self::S2 { s: &**s }; | ^^^^ help: try this: `s` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:162:20 + --> $DIR/explicit_auto_deref.rs:163:20 | LL | let _ = E1::S1(&*s); | ^^^ help: try this: `&s` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:163:25 + --> $DIR/explicit_auto_deref.rs:164:25 | LL | let _ = E1::S2 { s: &*s }; | ^^^ help: try this: `&s` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:181:13 + --> $DIR/explicit_auto_deref.rs:182:13 | LL | let _ = (*b).foo; | ^^^^ help: try this: `b` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:182:13 + --> $DIR/explicit_auto_deref.rs:183:13 | LL | let _ = (**b).foo; | ^^^^^ help: try this: `b` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:197:19 + --> $DIR/explicit_auto_deref.rs:198:19 | LL | let _ = f_str(*ref_str); | ^^^^^^^^ help: try this: `ref_str` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:199:19 + --> $DIR/explicit_auto_deref.rs:200:19 | LL | let _ = f_str(**ref_ref_str); | ^^^^^^^^^^^^^ help: try this: `ref_ref_str` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:209:13 + --> $DIR/explicit_auto_deref.rs:210:13 | LL | f_str(&&*ref_str); // `needless_borrow` will suggest removing both references | ^^^^^^^^ help: try this: `ref_str` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:210:12 + --> $DIR/explicit_auto_deref.rs:211:12 | LL | f_str(&&**ref_str); // `needless_borrow` will suggest removing only one reference | ^^^^^^^^^^ help: try this: `ref_str` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:219:41 + --> $DIR/explicit_auto_deref.rs:220:41 | LL | let _ = || -> &'static str { return *s }; | ^^ help: try this: `s` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:238:9 + --> $DIR/explicit_auto_deref.rs:239:9 | LL | &**x | ^^^^ help: try this: `x` -error: aborting due to 36 previous errors +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:262:8 + | +LL | c1(*x); + | ^^ help: try this: `x` + +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:265:20 + | +LL | return *x; + | ^^ help: try this: `x` + +error: aborting due to 38 previous errors From ecb51fe6a55f975f2d3bfd65d3568c263c248460 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Mon, 8 Aug 2022 10:25:05 -0400 Subject: [PATCH 54/62] Lint `explicit_auto_deref` in implicit return positions for closures --- clippy_lints/src/dereference.rs | 45 +++++++++++++++++++---------- clippy_utils/src/ty.rs | 3 +- tests/ui/explicit_auto_deref.fixed | 4 +-- tests/ui/explicit_auto_deref.rs | 2 +- tests/ui/explicit_auto_deref.stderr | 8 ++++- 5 files changed, 42 insertions(+), 20 deletions(-) diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 821528d7ab948..1c19a9e0e60ee 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::{expr_sig, peel_mid_ty_refs, variant_of_res}; +use clippy_utils::ty::{expr_sig, peel_mid_ty_refs, ty_sig, variant_of_res}; use clippy_utils::{get_parent_expr, is_lint_allowed, path_to_local, walk_to_expr_usage}; use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX}; use rustc_data_structures::fx::FxIndexMap; @@ -704,24 +704,13 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & let owner_id = cx.tcx.hir().body_owner(cx.enclosing_body.unwrap()); Some( if let Node::Expr( - closure @ Expr { - kind: ExprKind::Closure(&Closure { fn_decl, .. }), + closure_expr @ Expr { + kind: ExprKind::Closure(closure), .. }, ) = cx.tcx.hir().get(owner_id) { - match fn_decl.output { - FnRetTy::Return(ty) => { - if let Some(sig) = expr_sig(cx, closure) - && let Some(output) = sig.output() - { - binding_ty_auto_deref_stability(cx, ty, precedence, output.bound_vars()) - } else { - Position::Other(precedence) - } - }, - FnRetTy::DefaultReturn(_) => Position::Other(precedence), - } + closure_result_position(cx, closure, cx.typeck_results().expr_ty(closure_expr), precedence) } else { let output = cx .tcx @@ -730,6 +719,12 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & }, ) }, + ExprKind::Closure(closure) => Some(closure_result_position( + cx, + closure, + cx.typeck_results().expr_ty(parent), + precedence, + )), ExprKind::Call(func, _) if func.hir_id == child_id => { (child_id == e.hir_id).then_some(Position::Callee) }, @@ -825,6 +820,26 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & (position, adjustments) } +fn closure_result_position<'tcx>( + cx: &LateContext<'tcx>, + closure: &'tcx Closure<'_>, + ty: Ty<'tcx>, + precedence: i8, +) -> Position { + match closure.fn_decl.output { + FnRetTy::Return(hir_ty) => { + if let Some(sig) = ty_sig(cx, ty) + && let Some(output) = sig.output() + { + binding_ty_auto_deref_stability(cx, hir_ty, precedence, output.bound_vars()) + } else { + Position::Other(precedence) + } + }, + FnRetTy::DefaultReturn(_) => Position::Other(precedence), + } +} + // Checks the stability of auto-deref when assigned to a binding with the given explicit type. // // e.g. diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index d394360fc678b..e7d670766a050 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -572,7 +572,8 @@ pub fn expr_sig<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option> { +/// If the type is function like, get the signature for it. +pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option> { if ty.is_box() { return ty_sig(cx, ty.boxed_ty()); } diff --git a/tests/ui/explicit_auto_deref.fixed b/tests/ui/explicit_auto_deref.fixed index 27bc7fbfae3c7..d1d35e5c0eb46 100644 --- a/tests/ui/explicit_auto_deref.fixed +++ b/tests/ui/explicit_auto_deref.fixed @@ -257,13 +257,13 @@ fn main() { let x = S7([0]); let _: &[u32] = &*x; - let c1 = |x: &Vec<&u32>| {}; + let c1 = |_: &Vec<&u32>| {}; let x = &&vec![&1u32]; c1(x); let _ = for<'a, 'b> |x: &'a &'a Vec<&'b u32>, b: bool| -> &'a Vec<&'b u32> { if b { return x; } - *x + x }; } diff --git a/tests/ui/explicit_auto_deref.rs b/tests/ui/explicit_auto_deref.rs index 64aea9f464e48..deedafad153b9 100644 --- a/tests/ui/explicit_auto_deref.rs +++ b/tests/ui/explicit_auto_deref.rs @@ -257,7 +257,7 @@ fn main() { let x = S7([0]); let _: &[u32] = &*x; - let c1 = |x: &Vec<&u32>| {}; + let c1 = |_: &Vec<&u32>| {}; let x = &&vec![&1u32]; c1(*x); let _ = for<'a, 'b> |x: &'a &'a Vec<&'b u32>, b: bool| -> &'a Vec<&'b u32> { diff --git a/tests/ui/explicit_auto_deref.stderr b/tests/ui/explicit_auto_deref.stderr index 12db0c6f87fc3..91863abcc5d24 100644 --- a/tests/ui/explicit_auto_deref.stderr +++ b/tests/ui/explicit_auto_deref.stderr @@ -228,5 +228,11 @@ error: deref which would be done by auto-deref LL | return *x; | ^^ help: try this: `x` -error: aborting due to 38 previous errors +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:267:9 + | +LL | *x + | ^^ help: try this: `x` + +error: aborting due to 39 previous errors From f6cab94bd073c9b5103605c67006808d874ee5c1 Mon Sep 17 00:00:00 2001 From: Federico Guerinoni Date: Mon, 8 Aug 2022 18:12:24 +0200 Subject: [PATCH 55/62] Rename `logic_bug` to `overly_complex_bool_expr` Closes #1916 --- CHANGELOG.md | 1 + clippy_lints/src/booleans.rs | 6 +- clippy_lints/src/lib.register_all.rs | 2 +- clippy_lints/src/lib.register_correctness.rs | 2 +- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/renamed_lints.rs | 3 +- tests/ui/diverging_sub_expression.rs | 2 +- tests/ui/expect_tool_lint_rfc_2383.rs | 4 +- tests/ui/expect_tool_lint_rfc_2383.stderr | 4 +- ...gic_bug.rs => overly_complex_bool_expr.rs} | 4 +- ...stderr => overly_complex_bool_expr.stderr} | 22 ++--- tests/ui/rename.fixed | 6 +- tests/ui/rename.rs | 6 +- tests/ui/rename.stderr | 94 ++++++++++--------- 14 files changed, 85 insertions(+), 73 deletions(-) rename tests/ui/{logic_bug.rs => overly_complex_bool_expr.rs} (90%) rename tests/ui/{logic_bug.stderr => overly_complex_bool_expr.stderr} (76%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 84f06d9887997..7ea7e76ee1082 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3818,6 +3818,7 @@ Released 2018-09-13 [`or_then_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#or_then_unwrap [`out_of_bounds_indexing`]: https://rust-lang.github.io/rust-clippy/master/index.html#out_of_bounds_indexing [`overflow_check_conditional`]: https://rust-lang.github.io/rust-clippy/master/index.html#overflow_check_conditional +[`overly_complex_bool_expr`]: https://rust-lang.github.io/rust-clippy/master/index.html#overly_complex_bool_expr [`panic`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic [`panic_in_result_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_in_result_fn [`panic_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_params diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 526ee2f891a16..6eb78d21e8266 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -64,7 +64,7 @@ declare_clippy_lint! { /// if a {} /// ``` #[clippy::version = "pre 1.29.0"] - pub LOGIC_BUG, + pub OVERLY_COMPLEX_BOOL_EXPR, correctness, "boolean expressions that contain terminals which can be eliminated" } @@ -72,7 +72,7 @@ declare_clippy_lint! { // For each pairs, both orders are considered. const METHODS_WITH_NEGATION: [(&str, &str); 2] = [("is_some", "is_none"), ("is_err", "is_ok")]; -declare_lint_pass!(NonminimalBool => [NONMINIMAL_BOOL, LOGIC_BUG]); +declare_lint_pass!(NonminimalBool => [NONMINIMAL_BOOL, OVERLY_COMPLEX_BOOL_EXPR]); impl<'tcx> LateLintPass<'tcx> for NonminimalBool { fn check_fn( @@ -396,7 +396,7 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> { if stats.terminals[i] != 0 && simplified_stats.terminals[i] == 0 { span_lint_hir_and_then( self.cx, - LOGIC_BUG, + OVERLY_COMPLEX_BOOL_EXPR, e.hir_id, e.span, "this boolean expression contains a logic bug", diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index ab08e65d6081b..3caee50322c99 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -17,8 +17,8 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(await_holding_invalid::AWAIT_HOLDING_REFCELL_REF), LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS), LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON), - LintId::of(booleans::LOGIC_BUG), LintId::of(booleans::NONMINIMAL_BOOL), + LintId::of(booleans::OVERLY_COMPLEX_BOOL_EXPR), LintId::of(borrow_deref_ref::BORROW_DEREF_REF), LintId::of(bytes_count_to_len::BYTES_COUNT_TO_LEN), LintId::of(casts::CAST_ABS_TO_UNSIGNED), diff --git a/clippy_lints/src/lib.register_correctness.rs b/clippy_lints/src/lib.register_correctness.rs index 9975859c54fea..006275d1383ff 100644 --- a/clippy_lints/src/lib.register_correctness.rs +++ b/clippy_lints/src/lib.register_correctness.rs @@ -8,7 +8,7 @@ store.register_group(true, "clippy::correctness", Some("clippy_correctness"), ve LintId::of(attrs::DEPRECATED_SEMVER), LintId::of(attrs::MISMATCHED_TARGET_OS), LintId::of(attrs::USELESS_ATTRIBUTE), - LintId::of(booleans::LOGIC_BUG), + LintId::of(booleans::OVERLY_COMPLEX_BOOL_EXPR), LintId::of(casts::CAST_REF_TO_MUT), LintId::of(casts::CAST_SLICE_DIFFERENT_SIZES), LintId::of(copies::IFS_SAME_COND), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index c2bc4badc43cc..d83508a2d6cae 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -57,8 +57,8 @@ store.register_lints(&[ await_holding_invalid::AWAIT_HOLDING_REFCELL_REF, blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS, bool_assert_comparison::BOOL_ASSERT_COMPARISON, - booleans::LOGIC_BUG, booleans::NONMINIMAL_BOOL, + booleans::OVERLY_COMPLEX_BOOL_EXPR, borrow_as_ptr::BORROW_AS_PTR, borrow_deref_ref::BORROW_DEREF_REF, bytecount::NAIVE_BYTECOUNT, diff --git a/clippy_lints/src/renamed_lints.rs b/clippy_lints/src/renamed_lints.rs index be16bd6413225..6bea6dc0773d5 100644 --- a/clippy_lints/src/renamed_lints.rs +++ b/clippy_lints/src/renamed_lints.rs @@ -2,10 +2,10 @@ #[rustfmt::skip] pub static RENAMED_LINTS: &[(&str, &str)] = &[ + ("clippy::blacklisted_name", "clippy::disallowed_names"), ("clippy::block_in_if_condition_expr", "clippy::blocks_in_if_conditions"), ("clippy::block_in_if_condition_stmt", "clippy::blocks_in_if_conditions"), ("clippy::box_vec", "clippy::box_collection"), - ("clippy::blacklisted_name", "clippy::disallowed_names"), ("clippy::const_static_lifetime", "clippy::redundant_static_lifetimes"), ("clippy::cyclomatic_complexity", "clippy::cognitive_complexity"), ("clippy::disallowed_method", "clippy::disallowed_methods"), @@ -15,6 +15,7 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[ ("clippy::for_loop_over_result", "clippy::for_loops_over_fallibles"), ("clippy::identity_conversion", "clippy::useless_conversion"), ("clippy::if_let_some_result", "clippy::match_result_ok"), + ("clippy::logic_bug", "clippy::overly_complex_bool_expr"), ("clippy::new_without_default_derive", "clippy::new_without_default"), ("clippy::option_and_then_some", "clippy::bind_instead_of_map"), ("clippy::option_expect_used", "clippy::expect_used"), diff --git a/tests/ui/diverging_sub_expression.rs b/tests/ui/diverging_sub_expression.rs index e27f9fea708ee..e8f992e6ddedb 100644 --- a/tests/ui/diverging_sub_expression.rs +++ b/tests/ui/diverging_sub_expression.rs @@ -1,5 +1,5 @@ #![warn(clippy::diverging_sub_expression)] -#![allow(clippy::match_same_arms, clippy::logic_bug)] +#![allow(clippy::match_same_arms, clippy::overly_complex_bool_expr)] #[allow(clippy::empty_loop)] fn diverge() -> ! { loop {} diff --git a/tests/ui/expect_tool_lint_rfc_2383.rs b/tests/ui/expect_tool_lint_rfc_2383.rs index 985835ffa6533..018f875d60bfa 100644 --- a/tests/ui/expect_tool_lint_rfc_2383.rs +++ b/tests/ui/expect_tool_lint_rfc_2383.rs @@ -98,7 +98,7 @@ mod clippy_ok { let _ = if true { 42 } else { 42 }; } - #[expect(clippy::logic_bug)] + #[expect(clippy::overly_complex_bool_expr)] fn burger() { let a = false; let b = true; @@ -127,7 +127,7 @@ mod clippy_warn { let _ = if true { 33 } else { 42 }; } - #[expect(clippy::logic_bug)] + #[expect(clippy::overly_complex_bool_expr)] fn burger() { let a = false; let b = true; diff --git a/tests/ui/expect_tool_lint_rfc_2383.stderr b/tests/ui/expect_tool_lint_rfc_2383.stderr index db29e85a82191..7ce9e855b5e05 100644 --- a/tests/ui/expect_tool_lint_rfc_2383.stderr +++ b/tests/ui/expect_tool_lint_rfc_2383.stderr @@ -33,8 +33,8 @@ LL | #[expect(clippy::if_same_then_else)] error: this lint expectation is unfulfilled --> $DIR/expect_tool_lint_rfc_2383.rs:130:14 | -LL | #[expect(clippy::logic_bug)] - | ^^^^^^^^^^^^^^^^^ +LL | #[expect(clippy::overly_complex_bool_expr)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 6 previous errors diff --git a/tests/ui/logic_bug.rs b/tests/ui/overly_complex_bool_expr.rs similarity index 90% rename from tests/ui/logic_bug.rs rename to tests/ui/overly_complex_bool_expr.rs index dd6b1db5f70a0..04a30a83250e1 100644 --- a/tests/ui/logic_bug.rs +++ b/tests/ui/overly_complex_bool_expr.rs @@ -1,6 +1,6 @@ #![feature(lint_reasons)] #![allow(unused, clippy::diverging_sub_expression)] -#![warn(clippy::logic_bug)] +#![warn(clippy::overly_complex_bool_expr)] fn main() { let a: bool = unimplemented!(); @@ -29,6 +29,6 @@ fn equality_stuff() { fn check_expect() { let a: i32 = unimplemented!(); let b: i32 = unimplemented!(); - #[expect(clippy::logic_bug)] + #[expect(clippy::overly_complex_bool_expr)] let _ = a < b && a >= b; } diff --git a/tests/ui/logic_bug.stderr b/tests/ui/overly_complex_bool_expr.stderr similarity index 76% rename from tests/ui/logic_bug.stderr rename to tests/ui/overly_complex_bool_expr.stderr index 4021fbf457053..158cae8b8f373 100644 --- a/tests/ui/logic_bug.stderr +++ b/tests/ui/overly_complex_bool_expr.stderr @@ -1,60 +1,60 @@ error: this boolean expression contains a logic bug - --> $DIR/logic_bug.rs:11:13 + --> $DIR/overly_complex_bool_expr.rs:11:13 | LL | let _ = a && b || a; | ^^^^^^^^^^^ help: it would look like the following: `a` | - = note: `-D clippy::logic-bug` implied by `-D warnings` + = note: `-D clippy::overly-complex-bool-expr` implied by `-D warnings` help: this expression can be optimized out by applying boolean operations to the outer expression - --> $DIR/logic_bug.rs:11:18 + --> $DIR/overly_complex_bool_expr.rs:11:18 | LL | let _ = a && b || a; | ^ error: this boolean expression contains a logic bug - --> $DIR/logic_bug.rs:13:13 + --> $DIR/overly_complex_bool_expr.rs:13:13 | LL | let _ = false && a; | ^^^^^^^^^^ help: it would look like the following: `false` | help: this expression can be optimized out by applying boolean operations to the outer expression - --> $DIR/logic_bug.rs:13:22 + --> $DIR/overly_complex_bool_expr.rs:13:22 | LL | let _ = false && a; | ^ error: this boolean expression contains a logic bug - --> $DIR/logic_bug.rs:23:13 + --> $DIR/overly_complex_bool_expr.rs:23:13 | LL | let _ = a == b && a != b; | ^^^^^^^^^^^^^^^^ help: it would look like the following: `false` | help: this expression can be optimized out by applying boolean operations to the outer expression - --> $DIR/logic_bug.rs:23:13 + --> $DIR/overly_complex_bool_expr.rs:23:13 | LL | let _ = a == b && a != b; | ^^^^^^ error: this boolean expression contains a logic bug - --> $DIR/logic_bug.rs:24:13 + --> $DIR/overly_complex_bool_expr.rs:24:13 | LL | let _ = a < b && a >= b; | ^^^^^^^^^^^^^^^ help: it would look like the following: `false` | help: this expression can be optimized out by applying boolean operations to the outer expression - --> $DIR/logic_bug.rs:24:13 + --> $DIR/overly_complex_bool_expr.rs:24:13 | LL | let _ = a < b && a >= b; | ^^^^^ error: this boolean expression contains a logic bug - --> $DIR/logic_bug.rs:25:13 + --> $DIR/overly_complex_bool_expr.rs:25:13 | LL | let _ = a > b && a <= b; | ^^^^^^^^^^^^^^^ help: it would look like the following: `false` | help: this expression can be optimized out by applying boolean operations to the outer expression - --> $DIR/logic_bug.rs:25:13 + --> $DIR/overly_complex_bool_expr.rs:25:13 | LL | let _ = a > b && a <= b; | ^^^^^ diff --git a/tests/ui/rename.fixed b/tests/ui/rename.fixed index 2a74c6e54f46e..9cbad2269a099 100644 --- a/tests/ui/rename.fixed +++ b/tests/ui/rename.fixed @@ -4,9 +4,9 @@ // run-rustfix +#![allow(clippy::disallowed_names)] #![allow(clippy::blocks_in_if_conditions)] #![allow(clippy::box_collection)] -#![allow(clippy::disallowed_names)] #![allow(clippy::redundant_static_lifetimes)] #![allow(clippy::cognitive_complexity)] #![allow(clippy::disallowed_methods)] @@ -15,6 +15,7 @@ #![allow(clippy::for_loops_over_fallibles)] #![allow(clippy::useless_conversion)] #![allow(clippy::match_result_ok)] +#![allow(clippy::overly_complex_bool_expr)] #![allow(clippy::new_without_default)] #![allow(clippy::bind_instead_of_map)] #![allow(clippy::expect_used)] @@ -34,10 +35,10 @@ #![allow(temporary_cstring_as_ptr)] #![allow(unknown_lints)] #![allow(unused_labels)] +#![warn(clippy::disallowed_names)] #![warn(clippy::blocks_in_if_conditions)] #![warn(clippy::blocks_in_if_conditions)] #![warn(clippy::box_collection)] -#![warn(clippy::disallowed_names)] #![warn(clippy::redundant_static_lifetimes)] #![warn(clippy::cognitive_complexity)] #![warn(clippy::disallowed_methods)] @@ -47,6 +48,7 @@ #![warn(clippy::for_loops_over_fallibles)] #![warn(clippy::useless_conversion)] #![warn(clippy::match_result_ok)] +#![warn(clippy::overly_complex_bool_expr)] #![warn(clippy::new_without_default)] #![warn(clippy::bind_instead_of_map)] #![warn(clippy::expect_used)] diff --git a/tests/ui/rename.rs b/tests/ui/rename.rs index fa88af959743a..9153c0dab0290 100644 --- a/tests/ui/rename.rs +++ b/tests/ui/rename.rs @@ -4,9 +4,9 @@ // run-rustfix +#![allow(clippy::disallowed_names)] #![allow(clippy::blocks_in_if_conditions)] #![allow(clippy::box_collection)] -#![allow(clippy::disallowed_names)] #![allow(clippy::redundant_static_lifetimes)] #![allow(clippy::cognitive_complexity)] #![allow(clippy::disallowed_methods)] @@ -15,6 +15,7 @@ #![allow(clippy::for_loops_over_fallibles)] #![allow(clippy::useless_conversion)] #![allow(clippy::match_result_ok)] +#![allow(clippy::overly_complex_bool_expr)] #![allow(clippy::new_without_default)] #![allow(clippy::bind_instead_of_map)] #![allow(clippy::expect_used)] @@ -34,10 +35,10 @@ #![allow(temporary_cstring_as_ptr)] #![allow(unknown_lints)] #![allow(unused_labels)] +#![warn(clippy::blacklisted_name)] #![warn(clippy::block_in_if_condition_expr)] #![warn(clippy::block_in_if_condition_stmt)] #![warn(clippy::box_vec)] -#![warn(clippy::blacklisted_name)] #![warn(clippy::const_static_lifetime)] #![warn(clippy::cyclomatic_complexity)] #![warn(clippy::disallowed_method)] @@ -47,6 +48,7 @@ #![warn(clippy::for_loop_over_result)] #![warn(clippy::identity_conversion)] #![warn(clippy::if_let_some_result)] +#![warn(clippy::logic_bug)] #![warn(clippy::new_without_default_derive)] #![warn(clippy::option_and_then_some)] #![warn(clippy::option_expect_used)] diff --git a/tests/ui/rename.stderr b/tests/ui/rename.stderr index d510951b1217b..9c03ea914bb65 100644 --- a/tests/ui/rename.stderr +++ b/tests/ui/rename.stderr @@ -1,220 +1,226 @@ +error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names` + --> $DIR/rename.rs:38:9 + | +LL | #![warn(clippy::blacklisted_name)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names` + | + = note: `-D renamed-and-removed-lints` implied by `-D warnings` + error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions` - --> $DIR/rename.rs:37:9 + --> $DIR/rename.rs:39:9 | LL | #![warn(clippy::block_in_if_condition_expr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` - | - = note: `-D renamed-and-removed-lints` implied by `-D warnings` error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions` - --> $DIR/rename.rs:38:9 + --> $DIR/rename.rs:40:9 | LL | #![warn(clippy::block_in_if_condition_stmt)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` error: lint `clippy::box_vec` has been renamed to `clippy::box_collection` - --> $DIR/rename.rs:39:9 + --> $DIR/rename.rs:41:9 | LL | #![warn(clippy::box_vec)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection` -error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names` - --> $DIR/rename.rs:40:9 - | -LL | #![warn(clippy::blacklisted_name)] - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names` - error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes` - --> $DIR/rename.rs:41:9 + --> $DIR/rename.rs:42:9 | LL | #![warn(clippy::const_static_lifetime)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes` error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity` - --> $DIR/rename.rs:42:9 + --> $DIR/rename.rs:43:9 | LL | #![warn(clippy::cyclomatic_complexity)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity` error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods` - --> $DIR/rename.rs:43:9 + --> $DIR/rename.rs:44:9 | LL | #![warn(clippy::disallowed_method)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods` error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types` - --> $DIR/rename.rs:44:9 + --> $DIR/rename.rs:45:9 | LL | #![warn(clippy::disallowed_type)] | ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types` error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression` - --> $DIR/rename.rs:45:9 + --> $DIR/rename.rs:46:9 | LL | #![warn(clippy::eval_order_dependence)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression` error: lint `clippy::for_loop_over_option` has been renamed to `clippy::for_loops_over_fallibles` - --> $DIR/rename.rs:46:9 + --> $DIR/rename.rs:47:9 | LL | #![warn(clippy::for_loop_over_option)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles` error: lint `clippy::for_loop_over_result` has been renamed to `clippy::for_loops_over_fallibles` - --> $DIR/rename.rs:47:9 + --> $DIR/rename.rs:48:9 | LL | #![warn(clippy::for_loop_over_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles` error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion` - --> $DIR/rename.rs:48:9 + --> $DIR/rename.rs:49:9 | LL | #![warn(clippy::identity_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion` error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok` - --> $DIR/rename.rs:49:9 + --> $DIR/rename.rs:50:9 | LL | #![warn(clippy::if_let_some_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok` +error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr` + --> $DIR/rename.rs:51:9 + | +LL | #![warn(clippy::logic_bug)] + | ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr` + error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default` - --> $DIR/rename.rs:50:9 + --> $DIR/rename.rs:52:9 | LL | #![warn(clippy::new_without_default_derive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default` error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map` - --> $DIR/rename.rs:51:9 + --> $DIR/rename.rs:53:9 | LL | #![warn(clippy::option_and_then_some)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map` error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used` - --> $DIR/rename.rs:52:9 + --> $DIR/rename.rs:54:9 | LL | #![warn(clippy::option_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:53:9 + --> $DIR/rename.rs:55:9 | LL | #![warn(clippy::option_map_unwrap_or)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:54:9 + --> $DIR/rename.rs:56:9 | LL | #![warn(clippy::option_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used` - --> $DIR/rename.rs:55:9 + --> $DIR/rename.rs:57:9 | LL | #![warn(clippy::option_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow` - --> $DIR/rename.rs:56:9 + --> $DIR/rename.rs:58:9 | LL | #![warn(clippy::ref_in_deref)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow` error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used` - --> $DIR/rename.rs:57:9 + --> $DIR/rename.rs:59:9 | LL | #![warn(clippy::result_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:58:9 + --> $DIR/rename.rs:60:9 | LL | #![warn(clippy::result_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used` - --> $DIR/rename.rs:59:9 + --> $DIR/rename.rs:61:9 | LL | #![warn(clippy::result_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str` - --> $DIR/rename.rs:60:9 + --> $DIR/rename.rs:62:9 | LL | #![warn(clippy::single_char_push_str)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str` error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions` - --> $DIR/rename.rs:61:9 + --> $DIR/rename.rs:63:9 | LL | #![warn(clippy::stutter)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions` error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl` - --> $DIR/rename.rs:62:9 + --> $DIR/rename.rs:64:9 | LL | #![warn(clippy::to_string_in_display)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl` error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters` - --> $DIR/rename.rs:63:9 + --> $DIR/rename.rs:65:9 | LL | #![warn(clippy::zero_width_space)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters` error: lint `clippy::drop_bounds` has been renamed to `drop_bounds` - --> $DIR/rename.rs:64:9 + --> $DIR/rename.rs:66:9 | LL | #![warn(clippy::drop_bounds)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds` error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter` - --> $DIR/rename.rs:65:9 + --> $DIR/rename.rs:67:9 | LL | #![warn(clippy::into_iter_on_array)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter` error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering` - --> $DIR/rename.rs:66:9 + --> $DIR/rename.rs:68:9 | LL | #![warn(clippy::invalid_atomic_ordering)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering` error: lint `clippy::invalid_ref` has been renamed to `invalid_value` - --> $DIR/rename.rs:67:9 + --> $DIR/rename.rs:69:9 | LL | #![warn(clippy::invalid_ref)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value` error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums` - --> $DIR/rename.rs:68:9 + --> $DIR/rename.rs:70:9 | LL | #![warn(clippy::mem_discriminant_non_enum)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums` error: lint `clippy::panic_params` has been renamed to `non_fmt_panics` - --> $DIR/rename.rs:69:9 + --> $DIR/rename.rs:71:9 | LL | #![warn(clippy::panic_params)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics` error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr` - --> $DIR/rename.rs:70:9 + --> $DIR/rename.rs:72:9 | LL | #![warn(clippy::temporary_cstring_as_ptr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr` error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints` - --> $DIR/rename.rs:71:9 + --> $DIR/rename.rs:73:9 | LL | #![warn(clippy::unknown_clippy_lints)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints` error: lint `clippy::unused_label` has been renamed to `unused_labels` - --> $DIR/rename.rs:72:9 + --> $DIR/rename.rs:74:9 | LL | #![warn(clippy::unused_label)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels` -error: aborting due to 36 previous errors +error: aborting due to 37 previous errors From 657b0da912f0281aa11fe61df7fa273bf9be1d5b Mon Sep 17 00:00:00 2001 From: Lukas Lueg Date: Wed, 3 Aug 2022 22:13:06 +0200 Subject: [PATCH 56/62] Add partialeq_to_none lint Fixes #9275 --- CHANGELOG.md | 1 + clippy_lints/src/lib.register_all.rs | 1 + clippy_lints/src/lib.register_lints.rs | 1 + clippy_lints/src/lib.register_style.rs | 1 + clippy_lints/src/lib.rs | 2 + clippy_lints/src/partialeq_to_none.rs | 104 +++++++++++++++++ tests/ui/ifs_same_cond.rs | 4 +- tests/ui/manual_assert.edition2018.fixed | 2 +- tests/ui/manual_assert.edition2021.fixed | 2 +- tests/ui/manual_assert.fixed | 2 +- tests/ui/manual_assert.rs | 2 +- tests/ui/partialeq_to_none.fixed | 62 ++++++++++ tests/ui/partialeq_to_none.rs | 62 ++++++++++ tests/ui/partialeq_to_none.stderr | 110 ++++++++++++++++++ tests/ui/same_functions_in_if_condition.rs | 4 +- .../ui/same_functions_in_if_condition.stderr | 8 +- 16 files changed, 356 insertions(+), 12 deletions(-) create mode 100644 clippy_lints/src/partialeq_to_none.rs create mode 100644 tests/ui/partialeq_to_none.fixed create mode 100644 tests/ui/partialeq_to_none.rs create mode 100644 tests/ui/partialeq_to_none.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 84f06d9887997..ecac6086ffc44 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3823,6 +3823,7 @@ Released 2018-09-13 [`panic_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_params [`panicking_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#panicking_unwrap [`partialeq_ne_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_ne_impl +[`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 [`pattern_type_mismatch`]: https://rust-lang.github.io/rust-clippy/master/index.html#pattern_type_mismatch [`possible_missing_comma`]: https://rust-lang.github.io/rust-clippy/master/index.html#possible_missing_comma diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index b9cc9fc1e85b0..5b10061052df8 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -267,6 +267,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP), LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL), LintId::of(partialeq_ne_impl::PARTIALEQ_NE_IMPL), + LintId::of(partialeq_to_none::PARTIALEQ_TO_NONE), LintId::of(precedence::PRECEDENCE), LintId::of(ptr::CMP_NULL), LintId::of(ptr::INVALID_NULL_PTR_USAGE), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index c2bc4badc43cc..7468fc8b47b9a 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -454,6 +454,7 @@ store.register_lints(&[ panic_unimplemented::UNIMPLEMENTED, panic_unimplemented::UNREACHABLE, partialeq_ne_impl::PARTIALEQ_NE_IMPL, + partialeq_to_none::PARTIALEQ_TO_NONE, pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE, pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF, path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE, diff --git a/clippy_lints/src/lib.register_style.rs b/clippy_lints/src/lib.register_style.rs index ebc0933e31d27..bfa654238f130 100644 --- a/clippy_lints/src/lib.register_style.rs +++ b/clippy_lints/src/lib.register_style.rs @@ -100,6 +100,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(operators::ASSIGN_OP_PATTERN), LintId::of(operators::OP_REF), LintId::of(operators::PTR_EQ), + LintId::of(partialeq_to_none::PARTIALEQ_TO_NONE), LintId::of(ptr::CMP_NULL), LintId::of(ptr::PTR_ARG), LintId::of(question_mark::QUESTION_MARK), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 88c1a727f8dc3..e6a405f8170d8 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -332,6 +332,7 @@ mod overflow_check_conditional; mod panic_in_result_fn; mod panic_unimplemented; mod partialeq_ne_impl; +mod partialeq_to_none; mod pass_by_ref_or_value; mod path_buf_push_overwrite; mod pattern_type_mismatch; @@ -931,6 +932,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(invalid_utf8_in_unchecked::InvalidUtf8InUnchecked)); store.register_late_pass(|| Box::new(std_instead_of_core::StdReexports::default())); store.register_late_pass(|| Box::new(manual_instant_elapsed::ManualInstantElapsed)); + store.register_late_pass(|| Box::new(partialeq_to_none::PartialeqToNone)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/partialeq_to_none.rs b/clippy_lints/src/partialeq_to_none.rs new file mode 100644 index 0000000000000..eee7642068d62 --- /dev/null +++ b/clippy_lints/src/partialeq_to_none.rs @@ -0,0 +1,104 @@ +use clippy_utils::{ + diagnostics::span_lint_and_sugg, is_lang_ctor, peel_hir_expr_refs, peel_ref_operators, sugg, + ty::is_type_diagnostic_item, +}; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Expr, ExprKind, LangItem}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; + +declare_clippy_lint! { + /// ### What it does + /// + /// Checks for binary comparisons to a literal `Option::None`. + /// + /// ### Why is this bad? + /// + /// A programmer checking if some `foo` is `None` via a comparison `foo == None` + /// is usually inspired from other programming languages (e.g. `foo is None` + /// in Python). + /// Checking if a value of type `Option` is (not) equal to `None` in that + /// way relies on `T: PartialEq` to do the comparison, which is unneeded. + /// + /// ### Example + /// ```rust + /// fn foo(f: Option) -> &'static str { + /// if f != None { "yay" } else { "nay" } + /// } + /// ``` + /// Use instead: + /// ```rust + /// fn foo(f: Option) -> &'static str { + /// if f.is_some() { "yay" } else { "nay" } + /// } + /// ``` + #[clippy::version = "1.64.0"] + pub PARTIALEQ_TO_NONE, + style, + "Binary comparison to `Option::None` relies on `T: PartialEq`, which is unneeded" +} +declare_lint_pass!(PartialeqToNone => [PARTIALEQ_TO_NONE]); + +impl<'tcx> LateLintPass<'tcx> for PartialeqToNone { + fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { + // Skip expanded code, as we have no control over it anyway... + if e.span.from_expansion() { + return; + } + + // If the expression is of type `Option` + let is_ty_option = + |expr: &Expr<'_>| is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr).peel_refs(), sym::Option); + + // If the expression is a literal `Option::None` + let is_none_ctor = |expr: &Expr<'_>| { + matches!(&peel_hir_expr_refs(expr).0.kind, + ExprKind::Path(p) if is_lang_ctor(cx, p, LangItem::OptionNone)) + }; + + let mut applicability = Applicability::MachineApplicable; + + if let ExprKind::Binary(op, left_side, right_side) = e.kind { + // All other comparisons (e.g. `>= None`) have special meaning wrt T + let is_eq = match op.node { + BinOpKind::Eq => true, + BinOpKind::Ne => false, + _ => return, + }; + + // We are only interested in comparisons between `Option` and a literal `Option::None` + let scrutinee = match ( + is_none_ctor(left_side) && is_ty_option(right_side), + is_none_ctor(right_side) && is_ty_option(left_side), + ) { + (true, false) => right_side, + (false, true) => left_side, + _ => return, + }; + + // Peel away refs/derefs (as long as we don't cross manual deref impls), as + // autoref/autoderef will take care of those + let sugg = format!( + "{}.{}", + sugg::Sugg::hir_with_applicability(cx, peel_ref_operators(cx, scrutinee), "..", &mut applicability) + .maybe_par(), + if is_eq { "is_none()" } else { "is_some()" } + ); + + span_lint_and_sugg( + cx, + PARTIALEQ_TO_NONE, + e.span, + "binary comparison to literal `Option::None`", + if is_eq { + "use `Option::is_none()` instead" + } else { + "use `Option::is_some()` instead" + }, + sugg, + applicability, + ); + } + } +} diff --git a/tests/ui/ifs_same_cond.rs b/tests/ui/ifs_same_cond.rs index 80e9839ff40bd..9850fc0919e12 100644 --- a/tests/ui/ifs_same_cond.rs +++ b/tests/ui/ifs_same_cond.rs @@ -32,9 +32,9 @@ fn ifs_same_cond() { }; let mut v = vec![1]; - if v.pop() == None { + if v.pop().is_none() { // ok, functions - } else if v.pop() == None { + } else if v.pop().is_none() { } if v.len() == 42 { diff --git a/tests/ui/manual_assert.edition2018.fixed b/tests/ui/manual_assert.edition2018.fixed index d0bc640db8899..65598f1eaccc5 100644 --- a/tests/ui/manual_assert.edition2018.fixed +++ b/tests/ui/manual_assert.edition2018.fixed @@ -17,7 +17,7 @@ fn main() { let c = Some(2); if !a.is_empty() && a.len() == 3 - && c != None + && c.is_some() && !a.is_empty() && a.len() == 3 && !a.is_empty() diff --git a/tests/ui/manual_assert.edition2021.fixed b/tests/ui/manual_assert.edition2021.fixed index d0bc640db8899..65598f1eaccc5 100644 --- a/tests/ui/manual_assert.edition2021.fixed +++ b/tests/ui/manual_assert.edition2021.fixed @@ -17,7 +17,7 @@ fn main() { let c = Some(2); if !a.is_empty() && a.len() == 3 - && c != None + && c.is_some() && !a.is_empty() && a.len() == 3 && !a.is_empty() diff --git a/tests/ui/manual_assert.fixed b/tests/ui/manual_assert.fixed index 6c2a25c37d8d7..a2393674fe612 100644 --- a/tests/ui/manual_assert.fixed +++ b/tests/ui/manual_assert.fixed @@ -11,7 +11,7 @@ fn main() { let c = Some(2); if !a.is_empty() && a.len() == 3 - && c != None + && c.is_some() && !a.is_empty() && a.len() == 3 && !a.is_empty() diff --git a/tests/ui/manual_assert.rs b/tests/ui/manual_assert.rs index 027747d838631..4d2706dd62113 100644 --- a/tests/ui/manual_assert.rs +++ b/tests/ui/manual_assert.rs @@ -17,7 +17,7 @@ fn main() { let c = Some(2); if !a.is_empty() && a.len() == 3 - && c != None + && c.is_some() && !a.is_empty() && a.len() == 3 && !a.is_empty() diff --git a/tests/ui/partialeq_to_none.fixed b/tests/ui/partialeq_to_none.fixed new file mode 100644 index 0000000000000..f3e4c58d69492 --- /dev/null +++ b/tests/ui/partialeq_to_none.fixed @@ -0,0 +1,62 @@ +// run-rustfix +#![warn(clippy::partialeq_to_none)] + +struct Foobar; + +impl PartialEq> for Foobar { + fn eq(&self, _: &Option<()>) -> bool { + false + } +} + +#[allow(dead_code)] +fn foo(f: Option) -> &'static str { + if f.is_some() { "yay" } else { "nay" } +} + +fn foobar() -> Option<()> { + None +} + +fn bar() -> Result<(), ()> { + Ok(()) +} + +fn optref() -> &'static &'static Option<()> { + &&None +} + +fn main() { + let x = Some(0); + + let _ = x.is_none(); + let _ = x.is_some(); + let _ = x.is_none(); + let _ = x.is_some(); + + if foobar().is_none() {} + + if bar().ok().is_some() {} + + let _ = Some(1 + 2).is_some(); + + let _ = { Some(0) }.is_none(); + + let _ = { + /* + This comment runs long + */ + Some(1) + }.is_some(); + + // Should not trigger, as `Foobar` is not an `Option` and has no `is_none` + let _ = Foobar == None; + + let _ = optref().is_none(); + let _ = optref().is_some(); + let _ = optref().is_none(); + let _ = optref().is_some(); + + let x = Box::new(Option::<()>::None); + let _ = (*x).is_some(); +} diff --git a/tests/ui/partialeq_to_none.rs b/tests/ui/partialeq_to_none.rs new file mode 100644 index 0000000000000..767b2a38bcc17 --- /dev/null +++ b/tests/ui/partialeq_to_none.rs @@ -0,0 +1,62 @@ +// run-rustfix +#![warn(clippy::partialeq_to_none)] + +struct Foobar; + +impl PartialEq> for Foobar { + fn eq(&self, _: &Option<()>) -> bool { + false + } +} + +#[allow(dead_code)] +fn foo(f: Option) -> &'static str { + if f != None { "yay" } else { "nay" } +} + +fn foobar() -> Option<()> { + None +} + +fn bar() -> Result<(), ()> { + Ok(()) +} + +fn optref() -> &'static &'static Option<()> { + &&None +} + +fn main() { + let x = Some(0); + + let _ = x == None; + let _ = x != None; + let _ = None == x; + let _ = None != x; + + if foobar() == None {} + + if bar().ok() != None {} + + let _ = Some(1 + 2) != None; + + let _ = { Some(0) } == None; + + let _ = { + /* + This comment runs long + */ + Some(1) + } != None; + + // Should not trigger, as `Foobar` is not an `Option` and has no `is_none` + let _ = Foobar == None; + + let _ = optref() == &&None; + let _ = &&None != optref(); + let _ = **optref() == None; + let _ = &None != *optref(); + + let x = Box::new(Option::<()>::None); + let _ = None != *x; +} diff --git a/tests/ui/partialeq_to_none.stderr b/tests/ui/partialeq_to_none.stderr new file mode 100644 index 0000000000000..de15a9f7baaf0 --- /dev/null +++ b/tests/ui/partialeq_to_none.stderr @@ -0,0 +1,110 @@ +error: binary comparison to literal `Option::None` + --> $DIR/partialeq_to_none.rs:14:8 + | +LL | if f != None { "yay" } else { "nay" } + | ^^^^^^^^^ help: use `Option::is_some()` instead: `f.is_some()` + | + = note: `-D clippy::partialeq-to-none` implied by `-D warnings` + +error: binary comparison to literal `Option::None` + --> $DIR/partialeq_to_none.rs:32:13 + | +LL | let _ = x == None; + | ^^^^^^^^^ help: use `Option::is_none()` instead: `x.is_none()` + +error: binary comparison to literal `Option::None` + --> $DIR/partialeq_to_none.rs:33:13 + | +LL | let _ = x != None; + | ^^^^^^^^^ help: use `Option::is_some()` instead: `x.is_some()` + +error: binary comparison to literal `Option::None` + --> $DIR/partialeq_to_none.rs:34:13 + | +LL | let _ = None == x; + | ^^^^^^^^^ help: use `Option::is_none()` instead: `x.is_none()` + +error: binary comparison to literal `Option::None` + --> $DIR/partialeq_to_none.rs:35:13 + | +LL | let _ = None != x; + | ^^^^^^^^^ help: use `Option::is_some()` instead: `x.is_some()` + +error: binary comparison to literal `Option::None` + --> $DIR/partialeq_to_none.rs:37:8 + | +LL | if foobar() == None {} + | ^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `foobar().is_none()` + +error: binary comparison to literal `Option::None` + --> $DIR/partialeq_to_none.rs:39:8 + | +LL | if bar().ok() != None {} + | ^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `bar().ok().is_some()` + +error: binary comparison to literal `Option::None` + --> $DIR/partialeq_to_none.rs:41:13 + | +LL | let _ = Some(1 + 2) != None; + | ^^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `Some(1 + 2).is_some()` + +error: binary comparison to literal `Option::None` + --> $DIR/partialeq_to_none.rs:43:13 + | +LL | let _ = { Some(0) } == None; + | ^^^^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `{ Some(0) }.is_none()` + +error: binary comparison to literal `Option::None` + --> $DIR/partialeq_to_none.rs:45:13 + | +LL | let _ = { + | _____________^ +LL | | /* +LL | | This comment runs long +LL | | */ +LL | | Some(1) +LL | | } != None; + | |_____________^ + | +help: use `Option::is_some()` instead + | +LL ~ let _ = { +LL + /* +LL + This comment runs long +LL + */ +LL + Some(1) +LL ~ }.is_some(); + | + +error: binary comparison to literal `Option::None` + --> $DIR/partialeq_to_none.rs:55:13 + | +LL | let _ = optref() == &&None; + | ^^^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `optref().is_none()` + +error: binary comparison to literal `Option::None` + --> $DIR/partialeq_to_none.rs:56:13 + | +LL | let _ = &&None != optref(); + | ^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `optref().is_some()` + +error: binary comparison to literal `Option::None` + --> $DIR/partialeq_to_none.rs:57:13 + | +LL | let _ = **optref() == None; + | ^^^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `optref().is_none()` + +error: binary comparison to literal `Option::None` + --> $DIR/partialeq_to_none.rs:58:13 + | +LL | let _ = &None != *optref(); + | ^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `optref().is_some()` + +error: binary comparison to literal `Option::None` + --> $DIR/partialeq_to_none.rs:61:13 + | +LL | let _ = None != *x; + | ^^^^^^^^^^ help: use `Option::is_some()` instead: `(*x).is_some()` + +error: aborting due to 15 previous errors + diff --git a/tests/ui/same_functions_in_if_condition.rs b/tests/ui/same_functions_in_if_condition.rs index 3d2295912c9fd..a48829caac019 100644 --- a/tests/ui/same_functions_in_if_condition.rs +++ b/tests/ui/same_functions_in_if_condition.rs @@ -48,9 +48,9 @@ fn ifs_same_cond_fn() { } let mut v = vec![1]; - if v.pop() == None { + if v.pop().is_none() { //~ ERROR ifs same condition - } else if v.pop() == None { + } else if v.pop().is_none() { } if v.len() == 42 { diff --git a/tests/ui/same_functions_in_if_condition.stderr b/tests/ui/same_functions_in_if_condition.stderr index 71e82910ef752..cd438b830401d 100644 --- a/tests/ui/same_functions_in_if_condition.stderr +++ b/tests/ui/same_functions_in_if_condition.stderr @@ -50,14 +50,14 @@ LL | if obj.method_arg(a) { error: this `if` has the same function call as a previous `if` --> $DIR/same_functions_in_if_condition.rs:53:15 | -LL | } else if v.pop() == None { - | ^^^^^^^^^^^^^^^ +LL | } else if v.pop().is_none() { + | ^^^^^^^^^^^^^^^^^ | note: same as this --> $DIR/same_functions_in_if_condition.rs:51:8 | -LL | if v.pop() == None { - | ^^^^^^^^^^^^^^^ +LL | if v.pop().is_none() { + | ^^^^^^^^^^^^^^^^^ error: this `if` has the same function call as a previous `if` --> $DIR/same_functions_in_if_condition.rs:58:15 From 8d4f2ac38195567ee8eca0123d428951821db507 Mon Sep 17 00:00:00 2001 From: dAxpeDDa Date: Tue, 9 Aug 2022 03:26:08 +0200 Subject: [PATCH 57/62] Use `check_proc_macro` for `missing_const_for_fn` --- clippy_lints/src/missing_const_for_fn.rs | 14 +++++-- clippy_utils/src/check_proc_macro.rs | 39 +++++++++++++++++-- .../ui/missing_const_for_fn/cant_be_const.rs | 9 +++++ 3 files changed, 55 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index 2bd920db3025d..bc304c081b906 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -1,7 +1,9 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::qualify_min_const_fn::is_min_const_fn; use clippy_utils::ty::has_drop; -use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, meets_msrv, msrvs, trait_ref_of_method}; +use clippy_utils::{ + fn_has_unsatisfiable_preds, is_entrypoint_fn, is_from_proc_macro, meets_msrv, msrvs, trait_ref_of_method, +}; use rustc_hir as hir; use rustc_hir::def_id::CRATE_DEF_ID; use rustc_hir::intravisit::FnKind; @@ -86,10 +88,10 @@ impl MissingConstForFn { impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { fn check_fn( &mut self, - cx: &LateContext<'_>, - kind: FnKind<'_>, + cx: &LateContext<'tcx>, + kind: FnKind<'tcx>, _: &FnDecl<'_>, - _: &Body<'_>, + body: &Body<'tcx>, span: Span, hir_id: HirId, ) { @@ -144,6 +146,10 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { } } + if is_from_proc_macro(cx, &(&kind, body, hir_id, span)) { + return; + } + let mir = cx.tcx.optimized_mir(def_id); if let Err((span, err)) = is_min_const_fn(cx.tcx, mir, self.msrv) { diff --git a/clippy_utils/src/check_proc_macro.rs b/clippy_utils/src/check_proc_macro.rs index 0f00a1cdf0fa2..1062f223912f5 100644 --- a/clippy_utils/src/check_proc_macro.rs +++ b/clippy_utils/src/check_proc_macro.rs @@ -14,9 +14,9 @@ use rustc_ast::ast::{IntTy, LitIntType, LitKind, StrStyle, UintTy}; use rustc_hir::{ - Block, BlockCheckMode, Closure, Destination, Expr, ExprKind, FieldDef, FnHeader, Impl, ImplItem, ImplItemKind, - IsAuto, Item, ItemKind, LoopSource, MatchSource, QPath, TraitItem, TraitItemKind, UnOp, UnsafeSource, Unsafety, - Variant, VariantData, YieldSource, + intravisit::FnKind, Block, BlockCheckMode, Body, Closure, Destination, Expr, ExprKind, FieldDef, FnHeader, HirId, + Impl, ImplItem, ImplItemKind, IsAuto, Item, ItemKind, LoopSource, MatchSource, QPath, TraitItem, TraitItemKind, + UnOp, UnsafeSource, Unsafety, Variant, VariantData, YieldSource, }; use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty::TyCtxt; @@ -250,6 +250,27 @@ fn variant_search_pat(v: &Variant<'_>) -> (Pat, Pat) { } } +fn fn_kind_pat(tcx: TyCtxt<'_>, kind: &FnKind<'_>, body: &Body<'_>, hir_id: HirId) -> (Pat, Pat) { + let (start_pat, end_pat, visibility) = match kind { + FnKind::ItemFn(.., header) => ( + fn_header_search_pat(*header), + Pat::Str(""), + tcx.visibility(tcx.hir().local_def_id(hir_id)), + ), + FnKind::Method(.., sig) => ( + fn_header_search_pat(sig.header), + Pat::Str(""), + tcx.visibility(tcx.hir().local_def_id(hir_id)), + ), + FnKind::Closure => return (Pat::Str(""), expr_search_pat(tcx, &body.value).1), + }; + if visibility.is_public() { + (Pat::Str("pub"), end_pat) + } else { + (start_pat, end_pat) + } +} + pub trait WithSearchPat { type Context: LintContext; fn search_pat(&self, cx: &Self::Context) -> (Pat, Pat); @@ -277,6 +298,18 @@ impl_with_search_pat!(LateContext: ImplItem with impl_item_search_pat); impl_with_search_pat!(LateContext: FieldDef with field_def_search_pat); impl_with_search_pat!(LateContext: Variant with variant_search_pat); +impl<'cx> WithSearchPat for (&FnKind<'cx>, &Body<'cx>, HirId, Span) { + type Context = LateContext<'cx>; + + fn search_pat(&self, cx: &Self::Context) -> (Pat, Pat) { + fn_kind_pat(cx.tcx, self.0, self.1, self.2) + } + + fn span(&self) -> Span { + self.3 + } +} + /// Checks if the item likely came from a proc-macro. /// /// This should be called after `in_external_macro` and the initial pattern matching of the ast as diff --git a/tests/ui/missing_const_for_fn/cant_be_const.rs b/tests/ui/missing_const_for_fn/cant_be_const.rs index aa60d0504e5e6..b950248ef9420 100644 --- a/tests/ui/missing_const_for_fn/cant_be_const.rs +++ b/tests/ui/missing_const_for_fn/cant_be_const.rs @@ -3,12 +3,16 @@ //! The .stderr output of this test should be empty. Otherwise it's a bug somewhere. // aux-build:helper.rs +// aux-build:../../auxiliary/proc_macro_with_span.rs #![warn(clippy::missing_const_for_fn)] #![feature(start)] #![feature(custom_inner_attributes)] extern crate helper; +extern crate proc_macro_with_span; + +use proc_macro_with_span::with_span; struct Game; @@ -119,3 +123,8 @@ mod const_fn_stabilized_after_msrv { byte.is_ascii_digit(); } } + +with_span! { + span + fn dont_check_in_proc_macro() {} +} From 6f5d64842bfce445cbe251bec492c80481bca7f3 Mon Sep 17 00:00:00 2001 From: dAxpeDDa Date: Tue, 9 Aug 2022 04:48:05 +0200 Subject: [PATCH 58/62] Address review --- clippy_utils/src/check_proc_macro.rs | 29 +++++++++++++--------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/clippy_utils/src/check_proc_macro.rs b/clippy_utils/src/check_proc_macro.rs index 1062f223912f5..da3db9230a0c5 100644 --- a/clippy_utils/src/check_proc_macro.rs +++ b/clippy_utils/src/check_proc_macro.rs @@ -15,8 +15,8 @@ use rustc_ast::ast::{IntTy, LitIntType, LitKind, StrStyle, UintTy}; use rustc_hir::{ intravisit::FnKind, Block, BlockCheckMode, Body, Closure, Destination, Expr, ExprKind, FieldDef, FnHeader, HirId, - Impl, ImplItem, ImplItemKind, IsAuto, Item, ItemKind, LoopSource, MatchSource, QPath, TraitItem, TraitItemKind, - UnOp, UnsafeSource, Unsafety, Variant, VariantData, YieldSource, + Impl, ImplItem, ImplItemKind, IsAuto, Item, ItemKind, LoopSource, MatchSource, Node, QPath, TraitItem, + TraitItemKind, UnOp, UnsafeSource, Unsafety, Variant, VariantData, YieldSource, }; use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty::TyCtxt; @@ -251,23 +251,20 @@ fn variant_search_pat(v: &Variant<'_>) -> (Pat, Pat) { } fn fn_kind_pat(tcx: TyCtxt<'_>, kind: &FnKind<'_>, body: &Body<'_>, hir_id: HirId) -> (Pat, Pat) { - let (start_pat, end_pat, visibility) = match kind { - FnKind::ItemFn(.., header) => ( - fn_header_search_pat(*header), - Pat::Str(""), - tcx.visibility(tcx.hir().local_def_id(hir_id)), - ), - FnKind::Method(.., sig) => ( - fn_header_search_pat(sig.header), - Pat::Str(""), - tcx.visibility(tcx.hir().local_def_id(hir_id)), - ), + let (start_pat, end_pat) = match kind { + FnKind::ItemFn(.., header) => (fn_header_search_pat(*header), Pat::Str("")), + FnKind::Method(.., sig) => (fn_header_search_pat(sig.header), Pat::Str("")), FnKind::Closure => return (Pat::Str(""), expr_search_pat(tcx, &body.value).1), }; - if visibility.is_public() { - (Pat::Str("pub"), end_pat) - } else { + let vis_span = match tcx.hir().get(hir_id) { + Node::Item(Item { vis_span, .. }) | Node::ImplItem(ImplItem { vis_span, .. }) => Some(vis_span), + Node::TraitItem(_) => None, + _ => unreachable!(), + }; + if matches!(vis_span, Some(span) if span.is_empty()) { (start_pat, end_pat) + } else { + (Pat::Str("pub"), end_pat) } } From fd605816287de96486066accf4e3a10e412ff055 Mon Sep 17 00:00:00 2001 From: dAxpeDDa Date: Tue, 9 Aug 2022 05:14:03 +0200 Subject: [PATCH 59/62] Address review take 2 --- clippy_utils/src/check_proc_macro.rs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/clippy_utils/src/check_proc_macro.rs b/clippy_utils/src/check_proc_macro.rs index da3db9230a0c5..8335ffae81eb7 100644 --- a/clippy_utils/src/check_proc_macro.rs +++ b/clippy_utils/src/check_proc_macro.rs @@ -256,16 +256,18 @@ fn fn_kind_pat(tcx: TyCtxt<'_>, kind: &FnKind<'_>, body: &Body<'_>, hir_id: HirI FnKind::Method(.., sig) => (fn_header_search_pat(sig.header), Pat::Str("")), FnKind::Closure => return (Pat::Str(""), expr_search_pat(tcx, &body.value).1), }; - let vis_span = match tcx.hir().get(hir_id) { - Node::Item(Item { vis_span, .. }) | Node::ImplItem(ImplItem { vis_span, .. }) => Some(vis_span), - Node::TraitItem(_) => None, - _ => unreachable!(), + let start_pat = match tcx.hir().get(hir_id) { + Node::Item(Item { vis_span, .. }) | Node::ImplItem(ImplItem { vis_span, .. }) => { + if vis_span.is_empty() { + start_pat + } else { + Pat::Str("pub") + } + }, + Node::TraitItem(_) => start_pat, + _ => Pat::Str(""), }; - if matches!(vis_span, Some(span) if span.is_empty()) { - (start_pat, end_pat) - } else { - (Pat::Str("pub"), end_pat) - } + (start_pat, end_pat) } pub trait WithSearchPat { From eda0b001e87f55f991b14a0073877616f1c12ffb Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 11 Aug 2022 19:26:26 +0200 Subject: [PATCH 60/62] Bump nightly version -> 2022-08-11 --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 23ba7c712779e..7e14df4feea66 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2022-07-28" +channel = "nightly-2022-08-11" components = ["cargo", "llvm-tools-preview", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] From 280b527821c0d598bfd82df18490704f89d012e8 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 11 Aug 2022 19:26:38 +0200 Subject: [PATCH 61/62] Bump Clippy version -> 0.1.65 --- Cargo.toml | 2 +- clippy_lints/Cargo.toml | 2 +- clippy_utils/Cargo.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 69deaca0b4b8e..d648cd7945ef2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.1.64" +version = "0.1.65" 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/Cargo.toml b/clippy_lints/Cargo.toml index 9a3f042ffc034..badd391302b6f 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_lints" -version = "0.1.64" +version = "0.1.65" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" diff --git a/clippy_utils/Cargo.toml b/clippy_utils/Cargo.toml index bb443bdc1168f..a688050f63a6a 100644 --- a/clippy_utils/Cargo.toml +++ b/clippy_utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_utils" -version = "0.1.64" +version = "0.1.65" edition = "2021" publish = false From ea90d4bce509f0c44d2d6de71fd6f85429733843 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 11 Aug 2022 19:42:37 +0200 Subject: [PATCH 62/62] Update Cargo.lock --- Cargo.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f6627424d57a5..ffbe3b5998a1c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -661,7 +661,7 @@ dependencies = [ [[package]] name = "clippy" -version = "0.1.64" +version = "0.1.65" dependencies = [ "clippy_lints", "clippy_utils", @@ -704,7 +704,7 @@ dependencies = [ [[package]] name = "clippy_lints" -version = "0.1.64" +version = "0.1.65" dependencies = [ "cargo_metadata 0.14.0", "clippy_utils", @@ -726,7 +726,7 @@ dependencies = [ [[package]] name = "clippy_utils" -version = "0.1.64" +version = "0.1.65" dependencies = [ "arrayvec", "if_chain",