From 0cd9b06125c5a4ffce659bc92328946be94ccc2b Mon Sep 17 00:00:00 2001 From: Niki4tap Date: Fri, 23 Dec 2022 00:56:50 +0300 Subject: [PATCH 01/51] Small code style adjustments --- clippy_lints/src/returns.rs | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index d4d506605206b..0da50450512c2 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -210,22 +210,25 @@ fn check_final_expr<'tcx>( // if desugar of `do yeet`, don't lint if let Some(inner_expr) = inner && let ExprKind::Call(path_expr, _) = inner_expr.kind - && let ExprKind::Path(QPath::LangItem(LangItem::TryTraitFromYeet, _, _)) = path_expr.kind { - return; + && let ExprKind::Path(QPath::LangItem(LangItem::TryTraitFromYeet, _, _)) = path_expr.kind + { + return; } - if cx.tcx.hir().attrs(expr.hir_id).is_empty() { - let borrows = inner.map_or(false, |inner| last_statement_borrows(cx, inner)); - if !borrows { - // check if expr return nothing - let ret_span = if inner.is_none() && replacement == RetReplacement::Empty { - extend_span_to_previous_non_ws(cx, peeled_drop_expr.span) - } else { - peeled_drop_expr.span - }; - - emit_return_lint(cx, ret_span, semi_spans, inner.as_ref().map(|i| i.span), replacement); - } + if !cx.tcx.hir().attrs(expr.hir_id).is_empty() { + return; + } + let borrows = inner.map_or(false, |inner| last_statement_borrows(cx, inner)); + if borrows { + return; } + // check if expr return nothing + let ret_span = if inner.is_none() && replacement == RetReplacement::Empty { + extend_span_to_previous_non_ws(cx, peeled_drop_expr.span) + } else { + peeled_drop_expr.span + }; + + emit_return_lint(cx, ret_span, semi_spans, inner.as_ref().map(|i| i.span), replacement); }, ExprKind::If(_, then, else_clause_opt) => { check_block_return(cx, &then.kind, semi_spans.clone()); From a9358260717e55c367f16bc033990bac77cfb5a1 Mon Sep 17 00:00:00 2001 From: Niki4tap Date: Fri, 23 Dec 2022 00:57:28 +0300 Subject: [PATCH 02/51] Fix the actual bug --- clippy_lints/src/returns.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index 0da50450512c2..bbbd9e4989e97 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -295,7 +295,7 @@ fn last_statement_borrows<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { ControlFlow::Break(()) } else { - ControlFlow::Continue(Descend::from(!expr.span.from_expansion())) + ControlFlow::Continue(Descend::from(!e.span.from_expansion())) } }) .is_some() From 9ff868c4ae90f2b94d086cf8cf6302118c29f2ee Mon Sep 17 00:00:00 2001 From: Niki4tap Date: Fri, 23 Dec 2022 01:14:07 +0300 Subject: [PATCH 03/51] test test test --- tests/ui/needless_return.fixed | 10 ++++++++++ tests/ui/needless_return.rs | 10 ++++++++++ tests/ui/needless_return.stderr | 18 +++++++++++++++++- 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/tests/ui/needless_return.fixed b/tests/ui/needless_return.fixed index d451be1f389a7..ab1c0e590bbc7 100644 --- a/tests/ui/needless_return.fixed +++ b/tests/ui/needless_return.fixed @@ -277,4 +277,14 @@ fn issue9947() -> Result<(), String> { do yeet "hello"; } +// without anyhow, but triggers the same bug I believe +#[expect(clippy::useless_format)] +fn issue10051() -> Result { + if true { + Ok(format!("ok!")) + } else { + Err(format!("err!")) + } +} + fn main() {} diff --git a/tests/ui/needless_return.rs b/tests/ui/needless_return.rs index e1a1bea2c0b85..abed338bb9b29 100644 --- a/tests/ui/needless_return.rs +++ b/tests/ui/needless_return.rs @@ -287,4 +287,14 @@ fn issue9947() -> Result<(), String> { do yeet "hello"; } +// without anyhow, but triggers the same bug I believe +#[expect(clippy::useless_format)] +fn issue10051() -> Result { + if true { + return Ok(format!("ok!")); + } else { + return Err(format!("err!")); + } +} + fn main() {} diff --git a/tests/ui/needless_return.stderr b/tests/ui/needless_return.stderr index ca2253e658637..52eabf6e1370d 100644 --- a/tests/ui/needless_return.stderr +++ b/tests/ui/needless_return.stderr @@ -386,5 +386,21 @@ LL | let _ = 42; return; | = help: remove `return` -error: aborting due to 46 previous errors +error: unneeded `return` statement + --> $DIR/needless_return.rs:294:9 + | +LL | return Ok(format!("ok!")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: remove `return` + +error: unneeded `return` statement + --> $DIR/needless_return.rs:296:9 + | +LL | return Err(format!("err!")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: remove `return` + +error: aborting due to 48 previous errors From 0e5fcb7b7f13c30668637568e9eb11ce0672a5ed Mon Sep 17 00:00:00 2001 From: Ray Redondo Date: Sat, 24 Dec 2022 23:47:14 -0600 Subject: [PATCH 04/51] move mutex_atomic to clippy::restriction --- clippy_lints/src/mutex_atomic.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/mutex_atomic.rs b/clippy_lints/src/mutex_atomic.rs index 09cb53331763d..45bb217979aae 100644 --- a/clippy_lints/src/mutex_atomic.rs +++ b/clippy_lints/src/mutex_atomic.rs @@ -39,7 +39,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "pre 1.29.0"] pub MUTEX_ATOMIC, - nursery, + restriction, "using a mutex where an atomic value could be used instead" } From c617a8e01cf3ac7c4b69a473be038a80e7219371 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Wed, 28 Dec 2022 18:06:11 +0100 Subject: [PATCH 05/51] Rename `Rptr` to `Ref` in AST and HIR The name makes a lot more sense, and `ty::TyKind` calls it `Ref` already as well. --- clippy_lints/src/dereference.rs | 4 ++-- clippy_lints/src/manual_async_fn.rs | 2 +- clippy_lints/src/methods/mod.rs | 2 +- clippy_lints/src/mut_mut.rs | 4 ++-- clippy_lints/src/needless_arbitrary_self_type.rs | 2 +- clippy_lints/src/pass_by_ref_or_value.rs | 2 +- clippy_lints/src/ptr.rs | 10 +++++----- clippy_lints/src/redundant_static_lifetimes.rs | 2 +- clippy_lints/src/ref_option_ref.rs | 4 ++-- clippy_lints/src/transmute/transmute_ptr_to_ref.rs | 2 +- clippy_lints/src/types/mod.rs | 2 +- clippy_lints/src/types/type_complexity.rs | 2 +- clippy_lints/src/types/utils.rs | 2 +- .../src/utils/internal_lints/lint_without_lint_pass.rs | 2 +- clippy_utils/src/ast_utils.rs | 2 +- clippy_utils/src/hir_utils.rs | 4 ++-- clippy_utils/src/lib.rs | 2 +- clippy_utils/src/sugg.rs | 4 ++-- clippy_utils/src/ty.rs | 2 +- 19 files changed, 28 insertions(+), 28 deletions(-) diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 7b43d8ccc67d1..05f2b92c03709 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -969,14 +969,14 @@ fn binding_ty_auto_deref_stability<'tcx>( precedence: i8, binder_args: &'tcx List, ) -> Position { - let TyKind::Rptr(_, ty) = &ty.kind else { + let TyKind::Ref(_, ty) = &ty.kind else { return Position::Other(precedence); }; let mut ty = ty; loop { break match ty.ty.kind { - TyKind::Rptr(_, ref ref_ty) => { + TyKind::Ref(_, ref ref_ty) => { ty = ref_ty; continue; }, diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index 075ecbe7eded3..676a37e04f602 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -152,7 +152,7 @@ fn captures_all_lifetimes(inputs: &[Ty<'_>], output_lifetimes: &[LifetimeName]) let input_lifetimes: Vec = inputs .iter() .filter_map(|ty| { - if let TyKind::Rptr(lt, _) = ty.kind { + if let TyKind::Ref(lt, _) = ty.kind { Some(lt.res) } else { None diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 561e4336593b0..77be61b479340 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3986,7 +3986,7 @@ impl OutType { (Self::Unit, &hir::FnRetTy::Return(ty)) if is_unit(ty) => true, (Self::Bool, &hir::FnRetTy::Return(ty)) if is_bool(ty) => true, (Self::Any, &hir::FnRetTy::Return(ty)) if !is_unit(ty) => true, - (Self::Ref, &hir::FnRetTy::Return(ty)) => matches!(ty.kind, hir::TyKind::Rptr(_, _)), + (Self::Ref, &hir::FnRetTy::Return(ty)) => matches!(ty.kind, hir::TyKind::Ref(_, _)), _ => false, } } diff --git a/clippy_lints/src/mut_mut.rs b/clippy_lints/src/mut_mut.rs index bc90e131b7f3b..64d8333a093b1 100644 --- a/clippy_lints/src/mut_mut.rs +++ b/clippy_lints/src/mut_mut.rs @@ -86,7 +86,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for MutVisitor<'a, 'tcx> { return; } - if let hir::TyKind::Rptr( + if let hir::TyKind::Ref( _, hir::MutTy { ty: pty, @@ -94,7 +94,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for MutVisitor<'a, 'tcx> { }, ) = ty.kind { - if let hir::TyKind::Rptr( + if let hir::TyKind::Ref( _, hir::MutTy { mutbl: hir::Mutability::Mut, diff --git a/clippy_lints/src/needless_arbitrary_self_type.rs b/clippy_lints/src/needless_arbitrary_self_type.rs index f2ffac85bf402..5457eeec4eacf 100644 --- a/clippy_lints/src/needless_arbitrary_self_type.rs +++ b/clippy_lints/src/needless_arbitrary_self_type.rs @@ -124,7 +124,7 @@ impl EarlyLintPass for NeedlessArbitrarySelfType { check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Value, mutbl); } }, - TyKind::Rptr(lifetime, mut_ty) => { + TyKind::Ref(lifetime, mut_ty) => { if_chain! { if let TyKind::Path(None, path) = &mut_ty.ty.kind; if let PatKind::Ident(BindingAnnotation::NONE, _, _) = p.pat.kind; diff --git a/clippy_lints/src/pass_by_ref_or_value.rs b/clippy_lints/src/pass_by_ref_or_value.rs index f9fd3645668a9..75add4ee4aade 100644 --- a/clippy_lints/src/pass_by_ref_or_value.rs +++ b/clippy_lints/src/pass_by_ref_or_value.rs @@ -184,7 +184,7 @@ impl<'tcx> PassByRefOrValue { if is_copy(cx, ty) && let Some(size) = cx.layout_of(ty).ok().map(|l| l.size.bytes()) && size <= self.ref_min_size - && let hir::TyKind::Rptr(_, MutTy { ty: decl_ty, .. }) = input.kind + && let hir::TyKind::Ref(_, MutTy { ty: decl_ty, .. }) = input.kind { if let Some(typeck) = cx.maybe_typeck_results() { // Don't lint if an unsafe pointer is created. diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index e395ff54cb15a..262953042581a 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -421,7 +421,7 @@ fn check_fn_args<'cx, 'tcx: 'cx>( if let ty::Ref(_, ty, mutability) = *ty.kind(); if let ty::Adt(adt, substs) = *ty.kind(); - if let TyKind::Rptr(lt, ref ty) = hir_ty.kind; + if let TyKind::Ref(lt, ref ty) = hir_ty.kind; if let TyKind::Path(QPath::Resolved(None, path)) = ty.ty.kind; // Check that the name as typed matches the actual name of the type. @@ -503,14 +503,14 @@ fn check_fn_args<'cx, 'tcx: 'cx>( fn check_mut_from_ref<'tcx>(cx: &LateContext<'tcx>, sig: &FnSig<'_>, body: Option<&'tcx Body<'_>>) { if let FnRetTy::Return(ty) = sig.decl.output - && let Some((out, Mutability::Mut, _)) = get_rptr_lm(ty) + && let Some((out, Mutability::Mut, _)) = get_ref_lm(ty) { let out_region = cx.tcx.named_region(out.hir_id); let args: Option> = sig .decl .inputs .iter() - .filter_map(get_rptr_lm) + .filter_map(get_ref_lm) .filter(|&(lt, _, _)| cx.tcx.named_region(lt.hir_id) == out_region) .map(|(_, mutability, span)| (mutability == Mutability::Not).then_some(span)) .collect(); @@ -704,8 +704,8 @@ fn matches_preds<'tcx>( }) } -fn get_rptr_lm<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> Option<(&'tcx Lifetime, Mutability, Span)> { - if let TyKind::Rptr(lt, ref m) = ty.kind { +fn get_ref_lm<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> Option<(&'tcx Lifetime, Mutability, Span)> { + if let TyKind::Ref(lt, ref m) = ty.kind { Some((lt, m.mutbl, ty.span)) } else { None diff --git a/clippy_lints/src/redundant_static_lifetimes.rs b/clippy_lints/src/redundant_static_lifetimes.rs index 41f991a967bfd..44bf824aa0e2d 100644 --- a/clippy_lints/src/redundant_static_lifetimes.rs +++ b/clippy_lints/src/redundant_static_lifetimes.rs @@ -59,7 +59,7 @@ impl RedundantStaticLifetimes { } }, // This is what we are looking for ! - TyKind::Rptr(ref optional_lifetime, ref borrow_type) => { + TyKind::Ref(ref optional_lifetime, ref borrow_type) => { // Match the 'static lifetime if let Some(lifetime) = *optional_lifetime { match borrow_type.ty.kind { diff --git a/clippy_lints/src/ref_option_ref.rs b/clippy_lints/src/ref_option_ref.rs index f21b3ea6c3b05..448a32b77c036 100644 --- a/clippy_lints/src/ref_option_ref.rs +++ b/clippy_lints/src/ref_option_ref.rs @@ -39,7 +39,7 @@ declare_lint_pass!(RefOptionRef => [REF_OPTION_REF]); impl<'tcx> LateLintPass<'tcx> for RefOptionRef { fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx>) { if_chain! { - if let TyKind::Rptr(_, ref mut_ty) = ty.kind; + if let TyKind::Ref(_, ref mut_ty) = ty.kind; if mut_ty.mutbl == Mutability::Not; if let TyKind::Path(ref qpath) = &mut_ty.ty.kind; let last = last_path_segment(qpath); @@ -52,7 +52,7 @@ impl<'tcx> LateLintPass<'tcx> for RefOptionRef { GenericArg::Type(inner_ty) => Some(inner_ty), _ => None, }); - if let TyKind::Rptr(_, ref inner_mut_ty) = inner_ty.kind; + if let TyKind::Ref(_, ref inner_mut_ty) = inner_ty.kind; if inner_mut_ty.mutbl == Mutability::Not; then { diff --git a/clippy_lints/src/transmute/transmute_ptr_to_ref.rs b/clippy_lints/src/transmute/transmute_ptr_to_ref.rs index 3dde4eee67179..54ac04df1c12a 100644 --- a/clippy_lints/src/transmute/transmute_ptr_to_ref.rs +++ b/clippy_lints/src/transmute/transmute_ptr_to_ref.rs @@ -71,7 +71,7 @@ pub(super) fn check<'tcx>( /// Gets the type `Bar` in `…::transmute`. fn get_explicit_type<'tcx>(path: &'tcx Path<'tcx>) -> Option<&'tcx hir::Ty<'tcx>> { if let GenericArg::Type(ty) = path.segments.last()?.args?.args.get(1)? - && let TyKind::Rptr(_, ty) = &ty.kind + && let TyKind::Ref(_, ty) = &ty.kind { Some(ty.ty) } else { diff --git a/clippy_lints/src/types/mod.rs b/clippy_lints/src/types/mod.rs index 20978e81dc584..c14f056a1f2de 100644 --- a/clippy_lints/src/types/mod.rs +++ b/clippy_lints/src/types/mod.rs @@ -539,7 +539,7 @@ impl Types { QPath::LangItem(..) => {}, } }, - TyKind::Rptr(lt, ref mut_ty) => { + TyKind::Ref(lt, ref mut_ty) => { context.is_nested_call = true; if !borrowed_box::check(cx, hir_ty, lt, mut_ty) { self.check_ty(cx, mut_ty.ty, context); diff --git a/clippy_lints/src/types/type_complexity.rs b/clippy_lints/src/types/type_complexity.rs index 5ca4023aa5c19..0aa50c99c1690 100644 --- a/clippy_lints/src/types/type_complexity.rs +++ b/clippy_lints/src/types/type_complexity.rs @@ -44,7 +44,7 @@ impl<'tcx> Visitor<'tcx> for TypeComplexityVisitor { fn visit_ty(&mut self, ty: &'tcx hir::Ty<'_>) { let (add_score, sub_nest) = match ty.kind { // _, &x and *x have only small overhead; don't mess with nesting level - TyKind::Infer | TyKind::Ptr(..) | TyKind::Rptr(..) => (1, 0), + TyKind::Infer | TyKind::Ptr(..) | TyKind::Ref(..) => (1, 0), // the "normal" components of a type: named types, arrays/tuples TyKind::Path(..) | TyKind::Slice(..) | TyKind::Tup(..) | TyKind::Array(..) => (10 * self.nest, 1), diff --git a/clippy_lints/src/types/utils.rs b/clippy_lints/src/types/utils.rs index 0fa75f8f0a9be..7f43b7841ff33 100644 --- a/clippy_lints/src/types/utils.rs +++ b/clippy_lints/src/types/utils.rs @@ -13,7 +13,7 @@ pub(super) fn match_borrows_parameter(_cx: &LateContext<'_>, qpath: &QPath<'_>) GenericArg::Type(ty) => Some(ty), _ => None, }); - if let TyKind::Rptr(..) = ty.kind; + if let TyKind::Ref(..) = ty.kind; then { return Some(ty.span); } diff --git a/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs b/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs index 786d9608c851e..4c3b1b131fd4c 100644 --- a/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs +++ b/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs @@ -257,7 +257,7 @@ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass { } pub(super) fn is_lint_ref_type(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool { - if let TyKind::Rptr( + if let TyKind::Ref( _, MutTy { ty: inner, diff --git a/clippy_utils/src/ast_utils.rs b/clippy_utils/src/ast_utils.rs index 49e5f283db089..9d0263e93be75 100644 --- a/clippy_utils/src/ast_utils.rs +++ b/clippy_utils/src/ast_utils.rs @@ -625,7 +625,7 @@ pub fn eq_ty(l: &Ty, r: &Ty) -> bool { (Slice(l), Slice(r)) => eq_ty(l, r), (Array(le, ls), Array(re, rs)) => eq_ty(le, re) && eq_expr(&ls.value, &rs.value), (Ptr(l), Ptr(r)) => l.mutbl == r.mutbl && eq_ty(&l.ty, &r.ty), - (Rptr(ll, l), Rptr(rl, r)) => { + (Ref(ll, l), Ref(rl, r)) => { both(ll, rl, |l, r| eq_id(l.ident, r.ident)) && l.mutbl == r.mutbl && eq_ty(&l.ty, &r.ty) }, (BareFn(l), BareFn(r)) => { diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index 07fb6af91ba04..2bbe1a19b625a 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -430,7 +430,7 @@ impl HirEqInterExpr<'_, '_, '_> { (&TyKind::Slice(l_vec), &TyKind::Slice(r_vec)) => self.eq_ty(l_vec, r_vec), (&TyKind::Array(lt, ll), &TyKind::Array(rt, rl)) => self.eq_ty(lt, rt) && self.eq_array_length(ll, rl), (TyKind::Ptr(l_mut), TyKind::Ptr(r_mut)) => l_mut.mutbl == r_mut.mutbl && self.eq_ty(l_mut.ty, r_mut.ty), - (TyKind::Rptr(_, l_rmut), TyKind::Rptr(_, r_rmut)) => { + (TyKind::Ref(_, l_rmut), TyKind::Ref(_, r_rmut)) => { l_rmut.mutbl == r_rmut.mutbl && self.eq_ty(l_rmut.ty, r_rmut.ty) }, (TyKind::Path(l), TyKind::Path(r)) => self.eq_qpath(l, r), @@ -950,7 +950,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_ty(mut_ty.ty); mut_ty.mutbl.hash(&mut self.s); }, - TyKind::Rptr(lifetime, ref mut_ty) => { + TyKind::Ref(lifetime, ref mut_ty) => { self.hash_lifetime(lifetime); self.hash_ty(mut_ty.ty); mut_ty.mutbl.hash(&mut self.s); diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 43e2d1ec826c2..d863609b6a726 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -2264,7 +2264,7 @@ pub fn peel_hir_ty_refs<'a>(mut ty: &'a hir::Ty<'a>) -> (&'a hir::Ty<'a>, usize) let mut count = 0; loop { match &ty.kind { - TyKind::Rptr(_, ref_ty) => { + TyKind::Ref(_, ref_ty) => { ty = ref_ty.ty; count += 1; }, diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index b66604f33db17..a203a7afddf88 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -813,9 +813,9 @@ pub fn deref_closure_args(cx: &LateContext<'_>, closure: &hir::Expr<'_>) -> Opti let closure_body = cx.tcx.hir().body(body); // is closure arg a type annotated double reference (i.e.: `|x: &&i32| ...`) // a type annotation is present if param `kind` is different from `TyKind::Infer` - let closure_arg_is_type_annotated_double_ref = if let TyKind::Rptr(_, MutTy { ty, .. }) = fn_decl.inputs[0].kind + let closure_arg_is_type_annotated_double_ref = if let TyKind::Ref(_, MutTy { ty, .. }) = fn_decl.inputs[0].kind { - matches!(ty.kind, TyKind::Rptr(_, MutTy { .. })) + matches!(ty.kind, TyKind::Ref(_, MutTy { .. })) } else { false }; diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 2773da70d7880..c8d56a3be5cf3 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -496,7 +496,7 @@ pub fn type_is_unsafe_function<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bo /// Returns the base type for HIR references and pointers. pub fn walk_ptrs_hir_ty<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> { match ty.kind { - TyKind::Ptr(ref mut_ty) | TyKind::Rptr(_, ref mut_ty) => walk_ptrs_hir_ty(mut_ty.ty), + TyKind::Ptr(ref mut_ty) | TyKind::Ref(_, ref mut_ty) => walk_ptrs_hir_ty(mut_ty.ty), _ => ty, } } From 4ccafea92d00fe35c71fb1ab419df7b4f264d25f Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 29 Dec 2022 14:28:34 +0100 Subject: [PATCH 06/51] Merge commit '4f3ab69ea0a0908260944443c739426cc384ae1a' into clippyup --- CHANGELOG.md | 4 + .../src/casts/cast_slice_different_sizes.rs | 2 +- clippy_lints/src/declared_lints.rs | 4 + clippy_lints/src/dereference.rs | 8 +- clippy_lints/src/floating_point_arithmetic.rs | 2 +- clippy_lints/src/fn_null_check.rs | 106 +++++++ clippy_lints/src/format_args.rs | 2 +- clippy_lints/src/functions/mod.rs | 33 ++- clippy_lints/src/large_const_arrays.rs | 6 +- clippy_lints/src/large_enum_variant.rs | 2 +- clippy_lints/src/large_stack_arrays.rs | 6 +- clippy_lints/src/len_zero.rs | 2 +- clippy_lints/src/lib.rs | 8 +- .../src/loops/explicit_counter_loop.rs | 2 +- clippy_lints/src/manual_async_fn.rs | 2 +- clippy_lints/src/manual_clamp.rs | 5 +- clippy_lints/src/manual_strip.rs | 2 +- clippy_lints/src/matches/manual_filter.rs | 17 +- .../src/matches/match_single_binding.rs | 18 +- clippy_lints/src/matches/match_wild_enum.rs | 2 +- .../src/methods/inefficient_to_string.rs | 2 +- clippy_lints/src/methods/iter_skip_next.rs | 2 +- .../src/methods/option_map_unwrap_or.rs | 2 +- clippy_lints/src/methods/str_splitn.rs | 2 +- .../src/methods/unnecessary_lazy_eval.rs | 2 +- clippy_lints/src/needless_late_init.rs | 6 +- clippy_lints/src/octal_escapes.rs | 4 +- .../src/operators/misrefactored_assign_op.rs | 2 +- .../src/permissions_set_readonly_false.rs | 52 ++++ clippy_lints/src/redundant_clone.rs | 4 +- clippy_lints/src/returns.rs | 8 +- clippy_lints/src/same_name_method.rs | 4 +- clippy_lints/src/size_of_ref.rs | 73 +++++ clippy_lints/src/swap.rs | 4 +- clippy_lints/src/transmute/mod.rs | 31 ++ .../src/transmute/transmute_null_to_fn.rs | 64 ++++ .../src/transmute/transmute_undefined_repr.rs | 14 +- .../transmutes_expressible_as_ptr_casts.rs | 2 +- .../src/transmute/transmuting_null.rs | 3 +- .../src/transmute/useless_transmute.rs | 2 +- .../src/types/redundant_allocation.rs | 8 +- clippy_lints/src/unit_types/unit_arg.rs | 4 +- clippy_lints/src/useless_conversion.rs | 28 +- clippy_lints/src/utils/conf.rs | 2 +- .../internal_lints/metadata_collector.rs | 4 +- clippy_lints/src/write.rs | 4 +- clippy_utils/src/consts.rs | 7 +- clippy_utils/src/diagnostics.rs | 2 +- clippy_utils/src/mir/maybe_storage_live.rs | 52 ---- clippy_utils/src/mir/mod.rs | 2 - clippy_utils/src/mir/possible_borrower.rs | 274 +++++++++++------- clippy_utils/src/sugg.rs | 1 - rust-toolchain | 2 +- tests/ui/crashes/ice-10044.rs | 3 + tests/ui/crashes/ice-10044.stderr | 10 + tests/ui/floating_point_powi.fixed | 9 + tests/ui/floating_point_powi.rs | 9 + tests/ui/floating_point_powi.stderr | 44 ++- tests/ui/fn_null_check.rs | 21 ++ tests/ui/fn_null_check.stderr | 43 +++ tests/ui/manual_filter.fixed | 41 +++ tests/ui/manual_filter.rs | 41 +++ tests/ui/manual_retain.fixed | 2 +- tests/ui/manual_retain.rs | 2 +- tests/ui/match_single_binding.fixed | 13 + tests/ui/match_single_binding.rs | 14 + tests/ui/match_single_binding.stderr | 27 +- .../match_wildcard_for_single_variants.fixed | 22 ++ .../ui/match_wildcard_for_single_variants.rs | 22 ++ .../match_wildcard_for_single_variants.stderr | 8 +- tests/ui/needless_borrow.fixed | 13 +- tests/ui/needless_borrow.rs | 13 +- tests/ui/needless_borrow.stderr | 8 +- tests/ui/needless_return.fixed | 5 + tests/ui/needless_return.rs | 5 + tests/ui/needless_return.stderr | 92 +++--- tests/ui/permissions_set_readonly_false.rs | 29 ++ .../ui/permissions_set_readonly_false.stderr | 13 + tests/ui/redundant_clone.fixed | 6 + tests/ui/redundant_clone.rs | 6 + tests/ui/redundant_clone.stderr | 14 +- tests/ui/size_of_ref.rs | 27 ++ tests/ui/size_of_ref.stderr | 27 ++ tests/ui/transmute_null_to_fn.rs | 28 ++ tests/ui/transmute_null_to_fn.stderr | 27 ++ tests/ui/useless_conversion.fixed | 73 ++++- tests/ui/useless_conversion.rs | 73 ++++- tests/ui/useless_conversion.stderr | 54 +++- tests/ui/wildcard_imports.fixed | 1 - tests/ui/wildcard_imports.rs | 1 - tests/ui/wildcard_imports.stderr | 42 +-- .../wildcard_imports_2021.edition2018.fixed | 240 +++++++++++++++ .../wildcard_imports_2021.edition2018.stderr | 132 +++++++++ .../wildcard_imports_2021.edition2021.fixed | 240 +++++++++++++++ .../wildcard_imports_2021.edition2021.stderr | 132 +++++++++ tests/ui/wildcard_imports_2021.rs | 241 +++++++++++++++ tests/ui/wildcard_imports_2021.stderr | 132 +++++++++ 97 files changed, 2555 insertions(+), 356 deletions(-) create mode 100644 clippy_lints/src/fn_null_check.rs create mode 100644 clippy_lints/src/permissions_set_readonly_false.rs create mode 100644 clippy_lints/src/size_of_ref.rs create mode 100644 clippy_lints/src/transmute/transmute_null_to_fn.rs delete mode 100644 clippy_utils/src/mir/maybe_storage_live.rs create mode 100644 tests/ui/crashes/ice-10044.rs create mode 100644 tests/ui/crashes/ice-10044.stderr create mode 100644 tests/ui/fn_null_check.rs create mode 100644 tests/ui/fn_null_check.stderr create mode 100644 tests/ui/permissions_set_readonly_false.rs create mode 100644 tests/ui/permissions_set_readonly_false.stderr create mode 100644 tests/ui/size_of_ref.rs create mode 100644 tests/ui/size_of_ref.stderr create mode 100644 tests/ui/transmute_null_to_fn.rs create mode 100644 tests/ui/transmute_null_to_fn.stderr create mode 100644 tests/ui/wildcard_imports_2021.edition2018.fixed create mode 100644 tests/ui/wildcard_imports_2021.edition2018.stderr create mode 100644 tests/ui/wildcard_imports_2021.edition2021.fixed create mode 100644 tests/ui/wildcard_imports_2021.edition2021.stderr create mode 100644 tests/ui/wildcard_imports_2021.rs create mode 100644 tests/ui/wildcard_imports_2021.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 903ee938d9d2d..02f3188f8be08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4203,6 +4203,7 @@ Released 2018-09-13 [`float_cmp_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_cmp_const [`float_equality_without_abs`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_equality_without_abs [`fn_address_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_address_comparisons +[`fn_null_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_null_check [`fn_params_excessive_bools`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_params_excessive_bools [`fn_to_numeric_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast [`fn_to_numeric_cast_any`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast_any @@ -4460,6 +4461,7 @@ Released 2018-09-13 [`partialeq_to_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_to_none [`path_buf_push_overwrite`]: https://rust-lang.github.io/rust-clippy/master/index.html#path_buf_push_overwrite [`pattern_type_mismatch`]: https://rust-lang.github.io/rust-clippy/master/index.html#pattern_type_mismatch +[`permissions_set_readonly_false`]: https://rust-lang.github.io/rust-clippy/master/index.html#permissions_set_readonly_false [`positional_named_format_parameters`]: https://rust-lang.github.io/rust-clippy/master/index.html#positional_named_format_parameters [`possible_missing_comma`]: https://rust-lang.github.io/rust-clippy/master/index.html#possible_missing_comma [`precedence`]: https://rust-lang.github.io/rust-clippy/master/index.html#precedence @@ -4545,6 +4547,7 @@ Released 2018-09-13 [`single_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match [`single_match_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match_else [`size_of_in_element_count`]: https://rust-lang.github.io/rust-clippy/master/index.html#size_of_in_element_count +[`size_of_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#size_of_ref [`skip_while_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#skip_while_next [`slow_vector_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#slow_vector_initialization [`stable_sort_primitive`]: https://rust-lang.github.io/rust-clippy/master/index.html#stable_sort_primitive @@ -4590,6 +4593,7 @@ Released 2018-09-13 [`transmute_int_to_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_bool [`transmute_int_to_char`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_char [`transmute_int_to_float`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_float +[`transmute_null_to_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_null_to_fn [`transmute_num_to_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_num_to_bytes [`transmute_ptr_to_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ptr [`transmute_ptr_to_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ref diff --git a/clippy_lints/src/casts/cast_slice_different_sizes.rs b/clippy_lints/src/casts/cast_slice_different_sizes.rs index e862f13e69fc7..c8e54d7b8e0c3 100644 --- a/clippy_lints/src/casts/cast_slice_different_sizes.rs +++ b/clippy_lints/src/casts/cast_slice_different_sizes.rs @@ -54,7 +54,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: &Msrv diag.span_suggestion( expr.span, - &format!("replace with `ptr::slice_from_raw_parts{mutbl_fn_str}`"), + format!("replace with `ptr::slice_from_raw_parts{mutbl_fn_str}`"), sugg, rustc_errors::Applicability::HasPlaceholders, ); diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 3cd7d1d7e7228..2982460c9cfa4 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -161,6 +161,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::float_literal::LOSSY_FLOAT_LITERAL_INFO, crate::floating_point_arithmetic::IMPRECISE_FLOPS_INFO, crate::floating_point_arithmetic::SUBOPTIMAL_FLOPS_INFO, + crate::fn_null_check::FN_NULL_CHECK_INFO, crate::format::USELESS_FORMAT_INFO, crate::format_args::FORMAT_IN_FORMAT_ARGS_INFO, crate::format_args::TO_STRING_IN_FORMAT_ARGS_INFO, @@ -494,6 +495,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE_INFO, crate::pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF_INFO, crate::pattern_type_mismatch::PATTERN_TYPE_MISMATCH_INFO, + crate::permissions_set_readonly_false::PERMISSIONS_SET_READONLY_FALSE_INFO, crate::precedence::PRECEDENCE_INFO, crate::ptr::CMP_NULL_INFO, crate::ptr::INVALID_NULL_PTR_USAGE_INFO, @@ -535,6 +537,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::single_char_lifetime_names::SINGLE_CHAR_LIFETIME_NAMES_INFO, crate::single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS_INFO, crate::size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT_INFO, + crate::size_of_ref::SIZE_OF_REF_INFO, crate::slow_vector_initialization::SLOW_VECTOR_INITIALIZATION_INFO, crate::std_instead_of_core::ALLOC_INSTEAD_OF_CORE_INFO, crate::std_instead_of_core::STD_INSTEAD_OF_ALLOC_INFO, @@ -568,6 +571,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::transmute::TRANSMUTE_INT_TO_BOOL_INFO, crate::transmute::TRANSMUTE_INT_TO_CHAR_INFO, crate::transmute::TRANSMUTE_INT_TO_FLOAT_INFO, + crate::transmute::TRANSMUTE_NULL_TO_FN_INFO, crate::transmute::TRANSMUTE_NUM_TO_BYTES_INFO, crate::transmute::TRANSMUTE_PTR_TO_PTR_INFO, crate::transmute::TRANSMUTE_PTR_TO_REF_INFO, diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 7b43d8ccc67d1..728941b8b3d9a 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -1282,10 +1282,10 @@ fn referent_used_exactly_once<'tcx>( possible_borrowers.push((body_owner_local_def_id, PossibleBorrowerMap::new(cx, mir))); } let possible_borrower = &mut possible_borrowers.last_mut().unwrap().1; - // If `only_borrowers` were used here, the `copyable_iterator::warn` test would fail. The reason is - // that `PossibleBorrowerVisitor::visit_terminator` considers `place.local` a possible borrower of - // itself. See the comment in that method for an explanation as to why. - possible_borrower.bounded_borrowers(&[local], &[local, place.local], place.local, location) + // If `place.local` were not included here, the `copyable_iterator::warn` test would fail. The + // reason is that `PossibleBorrowerVisitor::visit_terminator` considers `place.local` a possible + // borrower of itself. See the comment in that method for an explanation as to why. + possible_borrower.at_most_borrowers(cx, &[local, place.local], place.local, location) && used_exactly_once(mir, place.local).unwrap_or(false) } else { false diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index 0ed301964758e..f95b628e6c31e 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -324,7 +324,7 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: let maybe_neg_sugg = |expr, hir_id| { let sugg = Sugg::hir(cx, expr, ".."); if matches!(op, BinOpKind::Sub) && hir_id == rhs.hir_id { - format!("-{sugg}") + format!("-{}", sugg.maybe_par()) } else { sugg.to_string() } diff --git a/clippy_lints/src/fn_null_check.rs b/clippy_lints/src/fn_null_check.rs new file mode 100644 index 0000000000000..91c8c340ce28f --- /dev/null +++ b/clippy_lints/src/fn_null_check.rs @@ -0,0 +1,106 @@ +use clippy_utils::consts::{constant, Constant}; +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::{is_integer_literal, is_path_diagnostic_item}; +use rustc_hir::{BinOpKind, Expr, ExprKind, TyKind}; +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 comparing a function pointer to null. + /// + /// ### Why is this bad? + /// Function pointers are assumed to not be null. + /// + /// ### Example + /// ```rust,ignore + /// let fn_ptr: fn() = /* somehow obtained nullable function pointer */ + /// + /// if (fn_ptr as *const ()).is_null() { ... } + /// ``` + /// Use instead: + /// ```rust,ignore + /// let fn_ptr: Option = /* somehow obtained nullable function pointer */ + /// + /// if fn_ptr.is_none() { ... } + /// ``` + #[clippy::version = "1.67.0"] + pub FN_NULL_CHECK, + correctness, + "`fn()` type assumed to be nullable" +} +declare_lint_pass!(FnNullCheck => [FN_NULL_CHECK]); + +fn lint_expr(cx: &LateContext<'_>, expr: &Expr<'_>) { + span_lint_and_help( + cx, + FN_NULL_CHECK, + expr.span, + "function pointer assumed to be nullable, even though it isn't", + None, + "try wrapping your function pointer type in `Option` instead, and using `is_none` to check for null pointer value", + ); +} + +fn is_fn_ptr_cast(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + if let ExprKind::Cast(cast_expr, cast_ty) = expr.kind + && let TyKind::Ptr(_) = cast_ty.kind + { + cx.typeck_results().expr_ty_adjusted(cast_expr).is_fn() + } else { + false + } +} + +impl<'tcx> LateLintPass<'tcx> for FnNullCheck { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + match expr.kind { + // Catching: + // (fn_ptr as * ).is_null() + ExprKind::MethodCall(method_name, receiver, _, _) + if method_name.ident.as_str() == "is_null" && is_fn_ptr_cast(cx, receiver) => + { + lint_expr(cx, expr); + }, + + ExprKind::Binary(op, left, right) if matches!(op.node, BinOpKind::Eq) => { + let to_check: &Expr<'_>; + if is_fn_ptr_cast(cx, left) { + to_check = right; + } else if is_fn_ptr_cast(cx, right) { + to_check = left; + } else { + return; + } + + match to_check.kind { + // Catching: + // (fn_ptr as * ) == (0 as ) + ExprKind::Cast(cast_expr, _) if is_integer_literal(cast_expr, 0) => { + lint_expr(cx, expr); + }, + + // Catching: + // (fn_ptr as * ) == std::ptr::null() + ExprKind::Call(func, []) if is_path_diagnostic_item(cx, func, sym::ptr_null) => { + lint_expr(cx, expr); + }, + + // Catching: + // (fn_ptr as * ) == + _ if matches!( + constant(cx, cx.typeck_results(), to_check), + Some((Constant::RawPtr(0), _)) + ) => + { + lint_expr(cx, expr); + }, + + _ => {}, + } + }, + _ => {}, + } + } +} diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index 69f7c152fc4af..043112bbc9596 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -382,7 +382,7 @@ fn check_format_in_format_args( call_site, &format!("`format!` in `{name}!` args"), |diag| { - diag.help(&format!( + diag.help(format!( "combine the `format!(..)` arguments with the outer `{name}!(..)` call" )); diag.help("or consider changing `format!` to `format_args!`"); diff --git a/clippy_lints/src/functions/mod.rs b/clippy_lints/src/functions/mod.rs index 91e6ffe644790..9dbce3f889bef 100644 --- a/clippy_lints/src/functions/mod.rs +++ b/clippy_lints/src/functions/mod.rs @@ -63,23 +63,40 @@ declare_clippy_lint! { /// arguments but are not marked `unsafe`. /// /// ### Why is this bad? - /// The function should probably be marked `unsafe`, since - /// for an arbitrary raw pointer, there is no way of telling for sure if it is - /// valid. + /// The function should almost definitely be marked `unsafe`, since for an + /// arbitrary raw pointer, there is no way of telling for sure if it is valid. + /// + /// In general, this lint should **never be disabled** unless it is definitely a + /// false positive (please submit an issue if so) since it breaks Rust's + /// soundness guarantees, directly exposing API users to potentially dangerous + /// program behavior. This is also true for internal APIs, as it is easy to leak + /// unsoundness. + /// + /// ### Context + /// In Rust, an `unsafe {...}` block is used to indicate that the code in that + /// section has been verified in some way that the compiler can not. For a + /// function that accepts a raw pointer then accesses the pointer's data, this is + /// generally impossible as the incoming pointer could point anywhere, valid or + /// not. So, the signature should be marked `unsafe fn`: this indicates that the + /// function's caller must provide some verification that the arguments it sends + /// are valid (and then call the function within an `unsafe` block). /// /// ### Known problems /// * It does not check functions recursively so if the pointer is passed to a /// private non-`unsafe` function which does the dereferencing, the lint won't - /// trigger. + /// trigger (false negative). /// * It only checks for arguments whose type are raw pointers, not raw pointers /// got from an argument in some other way (`fn foo(bar: &[*const u8])` or - /// `some_argument.get_raw_ptr()`). + /// `some_argument.get_raw_ptr()`) (false negative). /// /// ### Example /// ```rust,ignore /// pub fn foo(x: *const u8) { /// println!("{}", unsafe { *x }); /// } + /// + /// // this call "looks" safe but will segfault or worse! + /// // foo(invalid_ptr); /// ``` /// /// Use instead: @@ -87,6 +104,12 @@ declare_clippy_lint! { /// pub unsafe fn foo(x: *const u8) { /// println!("{}", unsafe { *x }); /// } + /// + /// // this would cause a compiler error for calling without `unsafe` + /// // foo(invalid_ptr); + /// + /// // sound call if the caller knows the pointer is valid + /// unsafe { foo(valid_ptr); } /// ``` #[clippy::version = "pre 1.29.0"] pub NOT_UNSAFE_PTR_ARG_DEREF, diff --git a/clippy_lints/src/large_const_arrays.rs b/clippy_lints/src/large_const_arrays.rs index 76c83ab47d095..db637dfc068d4 100644 --- a/clippy_lints/src/large_const_arrays.rs +++ b/clippy_lints/src/large_const_arrays.rs @@ -34,12 +34,12 @@ declare_clippy_lint! { } pub struct LargeConstArrays { - maximum_allowed_size: u64, + maximum_allowed_size: u128, } impl LargeConstArrays { #[must_use] - pub fn new(maximum_allowed_size: u64) -> Self { + pub fn new(maximum_allowed_size: u128) -> Self { Self { maximum_allowed_size } } } @@ -56,7 +56,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeConstArrays { if let ConstKind::Value(ty::ValTree::Leaf(element_count)) = cst.kind(); if let Ok(element_count) = element_count.try_to_machine_usize(cx.tcx); if let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes()); - if self.maximum_allowed_size < element_count * element_size; + if self.maximum_allowed_size < u128::from(element_count) * u128::from(element_size); then { let hi_pos = item.ident.span.lo() - BytePos::from_usize(1); diff --git a/clippy_lints/src/large_enum_variant.rs b/clippy_lints/src/large_enum_variant.rs index b18456ee52340..b8d4abdbb781a 100644 --- a/clippy_lints/src/large_enum_variant.rs +++ b/clippy_lints/src/large_enum_variant.rs @@ -111,7 +111,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant { ); diag.span_label( def.variants[variants_size[1].ind].span, - &if variants_size[1].fields_size.is_empty() { + if variants_size[1].fields_size.is_empty() { "the second-largest variant carries no data at all".to_owned() } else { format!( diff --git a/clippy_lints/src/large_stack_arrays.rs b/clippy_lints/src/large_stack_arrays.rs index 5857d81ab1f20..89ae83d48f536 100644 --- a/clippy_lints/src/large_stack_arrays.rs +++ b/clippy_lints/src/large_stack_arrays.rs @@ -24,12 +24,12 @@ declare_clippy_lint! { } pub struct LargeStackArrays { - maximum_allowed_size: u64, + maximum_allowed_size: u128, } impl LargeStackArrays { #[must_use] - pub fn new(maximum_allowed_size: u64) -> Self { + pub fn new(maximum_allowed_size: u128) -> Self { Self { maximum_allowed_size } } } @@ -45,7 +45,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackArrays { && let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes()) && !cx.tcx.hir().parent_iter(expr.hir_id) .any(|(_, node)| matches!(node, Node::Item(Item { kind: ItemKind::Static(..), .. }))) - && self.maximum_allowed_size < element_count * element_size { + && self.maximum_allowed_size < u128::from(element_count) * u128::from(element_size) { span_lint_and_help( cx, LARGE_STACK_ARRAYS, diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index e88d1764a2489..9eba46756299c 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -361,7 +361,7 @@ fn check_for_is_empty<'tcx>( db.span_note(span, "`is_empty` defined here"); } if let Some(self_kind) = self_kind { - db.note(&output.expected_sig(self_kind)); + db.note(output.expected_sig(self_kind)); } }); } diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 39850d598038f..dcd8ca81ae872 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -125,6 +125,7 @@ mod explicit_write; mod fallible_impl_from; mod float_literal; mod floating_point_arithmetic; +mod fn_null_check; mod format; mod format_args; mod format_impl; @@ -234,6 +235,7 @@ mod partialeq_ne_impl; mod partialeq_to_none; mod pass_by_ref_or_value; mod pattern_type_mismatch; +mod permissions_set_readonly_false; mod precedence; mod ptr; mod ptr_offset_with_cast; @@ -263,6 +265,7 @@ mod shadow; mod single_char_lifetime_names; mod single_component_path_imports; mod size_of_in_element_count; +mod size_of_ref; mod slow_vector_initialization; mod std_instead_of_core; mod strings; @@ -334,7 +337,7 @@ pub fn read_conf(sess: &Session, path: &io::Result>) -> Conf { Ok(Some(path)) => path, Ok(None) => return Conf::default(), Err(error) => { - sess.struct_err(&format!("error finding Clippy's configuration file: {error}")) + sess.struct_err(format!("error finding Clippy's configuration file: {error}")) .emit(); return Conf::default(); }, @@ -902,6 +905,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(suspicious_xor_used_as_pow::ConfusingXorAndPow)); store.register_late_pass(move |_| Box::new(manual_is_ascii_check::ManualIsAsciiCheck::new(msrv()))); store.register_late_pass(|_| Box::new(semicolon_block::SemicolonBlock)); + store.register_late_pass(|_| Box::new(fn_null_check::FnNullCheck)); + store.register_late_pass(|_| Box::new(permissions_set_readonly_false::PermissionsSetReadonlyFalse)); + store.register_late_pass(|_| Box::new(size_of_ref::SizeOfRef)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/loops/explicit_counter_loop.rs b/clippy_lints/src/loops/explicit_counter_loop.rs index 14f2234813277..1953ee8a71752 100644 --- a/clippy_lints/src/loops/explicit_counter_loop.rs +++ b/clippy_lints/src/loops/explicit_counter_loop.rs @@ -77,7 +77,7 @@ pub(super) fn check<'tcx>( applicability, ); - diag.note(&format!( + diag.note(format!( "`{name}` is of type `{int_name}`, making it ineligible for `Iterator::enumerate`" )); }, diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index 075ecbe7eded3..af7c056355579 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -76,7 +76,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn { let help = format!("make the function `async` and {ret_sugg}"); diag.span_suggestion( header_span, - &help, + help, format!("async {}{ret_snip}", &header_snip[..ret_pos]), Applicability::MachineApplicable ); diff --git a/clippy_lints/src/manual_clamp.rs b/clippy_lints/src/manual_clamp.rs index bb6d628af3b50..f239736d38a4c 100644 --- a/clippy_lints/src/manual_clamp.rs +++ b/clippy_lints/src/manual_clamp.rs @@ -35,6 +35,9 @@ declare_clippy_lint! { /// Some may consider panicking in these situations to be desirable, but it also may /// introduce panicking where there wasn't any before. /// + /// See also [the discussion in the + /// PR](https://github.com/rust-lang/rust-clippy/pull/9484#issuecomment-1278922613). + /// /// ### Examples /// ```rust /// # let (input, min, max) = (0, -2, 1); @@ -78,7 +81,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.66.0"] pub MANUAL_CLAMP, - complexity, + nursery, "using a clamp pattern instead of the clamp function" } impl_lint_pass!(ManualClamp => [MANUAL_CLAMP]); diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index de166b9765f41..c795c1d9a16c3 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -109,7 +109,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip { let test_span = expr.span.until(then.span); span_lint_and_then(cx, MANUAL_STRIP, strippings[0], &format!("stripping a {kind_word} manually"), |diag| { - diag.span_note(test_span, &format!("the {kind_word} was tested here")); + diag.span_note(test_span, format!("the {kind_word} was tested here")); multispan_sugg( diag, &format!("try using the `strip_{kind_word}` method"), diff --git a/clippy_lints/src/matches/manual_filter.rs b/clippy_lints/src/matches/manual_filter.rs index d521a529e0d64..f6bf0e7aa1ad9 100644 --- a/clippy_lints/src/matches/manual_filter.rs +++ b/clippy_lints/src/matches/manual_filter.rs @@ -3,7 +3,7 @@ use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::contains_unsafe_block; use clippy_utils::{is_res_lang_ctor, path_res, path_to_local_id}; -use rustc_hir::LangItem::OptionSome; +use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_hir::{Arm, Expr, ExprKind, HirId, Pat, PatKind}; use rustc_lint::LateContext; use rustc_span::{sym, SyntaxContext}; @@ -25,15 +25,13 @@ fn get_cond_expr<'tcx>( if let Some(block_expr) = peels_blocks_incl_unsafe_opt(expr); if let ExprKind::If(cond, then_expr, Some(else_expr)) = block_expr.kind; if let PatKind::Binding(_,target, ..) = pat.kind; - if let (then_visitor, else_visitor) - = (is_some_expr(cx, target, ctxt, then_expr), - is_some_expr(cx, target, ctxt, else_expr)); - if then_visitor != else_visitor; // check that one expr resolves to `Some(x)`, the other to `None` + if is_some_expr(cx, target, ctxt, then_expr) && is_none_expr(cx, else_expr) + || is_none_expr(cx, then_expr) && is_some_expr(cx, target, ctxt, else_expr); // check that one expr resolves to `Some(x)`, the other to `None` then { return Some(SomeExpr { expr: peels_blocks_incl_unsafe(cond.peel_drop_temps()), needs_unsafe_block: contains_unsafe_block(cx, expr), - needs_negated: !then_visitor // if the `then_expr` resolves to `None`, need to negate the cond + needs_negated: is_none_expr(cx, then_expr) // if the `then_expr` resolves to `None`, need to negate the cond }) } }; @@ -74,6 +72,13 @@ fn is_some_expr(cx: &LateContext<'_>, target: HirId, ctxt: SyntaxContext, expr: false } +fn is_none_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + if let Some(inner_expr) = peels_blocks_incl_unsafe_opt(expr) { + return is_res_lang_ctor(cx, path_res(cx, inner_expr), OptionNone); + }; + false +} + // given the closure: `|| ` // returns `|&| ` fn add_ampersand_if_copy(body_str: String, has_copy_trait: bool) -> String { diff --git a/clippy_lints/src/matches/match_single_binding.rs b/clippy_lints/src/matches/match_single_binding.rs index 1bf8d4e96ad49..c94a1f763306e 100644 --- a/clippy_lints/src/matches/match_single_binding.rs +++ b/clippy_lints/src/matches/match_single_binding.rs @@ -31,19 +31,11 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e }; // Do we need to add ';' to suggestion ? - match match_body.kind { - ExprKind::Block(block, _) => { - // macro + expr_ty(body) == () - if block.span.from_expansion() && cx.typeck_results().expr_ty(match_body).is_unit() { - snippet_body.push(';'); - } - }, - _ => { - // expr_ty(body) == () - if cx.typeck_results().expr_ty(match_body).is_unit() { - snippet_body.push(';'); - } - }, + if let ExprKind::Block(block, _) = match_body.kind { + // macro + expr_ty(body) == () + if block.span.from_expansion() && cx.typeck_results().expr_ty(match_body).is_unit() { + snippet_body.push(';'); + } } let mut applicability = Applicability::MaybeIncorrect; diff --git a/clippy_lints/src/matches/match_wild_enum.rs b/clippy_lints/src/matches/match_wild_enum.rs index 7f8d124838cb8..59de8c0384ba0 100644 --- a/clippy_lints/src/matches/match_wild_enum.rs +++ b/clippy_lints/src/matches/match_wild_enum.rs @@ -30,7 +30,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) { let mut has_non_wild = false; for arm in arms { match peel_hir_pat_refs(arm.pat).0.kind { - PatKind::Wild => wildcard_span = Some(arm.pat.span), + PatKind::Wild if arm.guard.is_none() => wildcard_span = Some(arm.pat.span), PatKind::Binding(_, _, ident, None) => { wildcard_span = Some(arm.pat.span); wildcard_ident = Some(ident); diff --git a/clippy_lints/src/methods/inefficient_to_string.rs b/clippy_lints/src/methods/inefficient_to_string.rs index d8c821bc9eeee..424482859ee87 100644 --- a/clippy_lints/src/methods/inefficient_to_string.rs +++ b/clippy_lints/src/methods/inefficient_to_string.rs @@ -36,7 +36,7 @@ pub fn check( expr.span, &format!("calling `to_string` on `{arg_ty}`"), |diag| { - diag.help(&format!( + diag.help(format!( "`{self_ty}` implements `ToString` through a slower blanket impl, but `{deref_self_ty}` has a fast specialization of `ToString`" )); let mut applicability = Applicability::MachineApplicable; diff --git a/clippy_lints/src/methods/iter_skip_next.rs b/clippy_lints/src/methods/iter_skip_next.rs index beb772100affc..279175e20c37f 100644 --- a/clippy_lints/src/methods/iter_skip_next.rs +++ b/clippy_lints/src/methods/iter_skip_next.rs @@ -29,7 +29,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr application = Applicability::Unspecified; diag.span_help( pat.span, - &format!("for this change `{}` has to be mutable", snippet(cx, pat.span, "..")), + format!("for this change `{}` has to be mutable", snippet(cx, pat.span, "..")), ); } } diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs index 910ee14855e23..4c6328481e438 100644 --- a/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -84,7 +84,7 @@ pub(super) fn check<'tcx>( suggestion.push((map_arg_span.with_hi(map_arg_span.lo()), format!("{unwrap_snippet}, "))); } - diag.multipart_suggestion(&format!("use `{suggest}` instead"), suggestion, applicability); + diag.multipart_suggestion(format!("use `{suggest}` instead"), suggestion, applicability); }); } } diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs index 3c01ce1fecd3a..d00708e828eae 100644 --- a/clippy_lints/src/methods/str_splitn.rs +++ b/clippy_lints/src/methods/str_splitn.rs @@ -167,7 +167,7 @@ fn check_manual_split_once_indirect( }; diag.span_suggestion_verbose( local.span, - &format!("try `{r}split_once`"), + format!("try `{r}split_once`"), format!("let ({lhs}, {rhs}) = {self_snip}.{r}split_once({pat_snip}){unwrap};"), app, ); diff --git a/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/clippy_lints/src/methods/unnecessary_lazy_eval.rs index 0e73459ad65f7..47e2e744112c5 100644 --- a/clippy_lints/src/methods/unnecessary_lazy_eval.rs +++ b/clippy_lints/src/methods/unnecessary_lazy_eval.rs @@ -62,7 +62,7 @@ pub(super) fn check<'tcx>( span_lint_and_then(cx, UNNECESSARY_LAZY_EVALUATIONS, expr.span, msg, |diag| { diag.span_suggestion( span, - &format!("use `{simplify_using}(..)` instead"), + format!("use `{simplify_using}(..)` instead"), format!("{simplify_using}({})", snippet(cx, body_expr.span, "..")), applicability, ); diff --git a/clippy_lints/src/needless_late_init.rs b/clippy_lints/src/needless_late_init.rs index 67debe7e08af6..5a9387b34cc19 100644 --- a/clippy_lints/src/needless_late_init.rs +++ b/clippy_lints/src/needless_late_init.rs @@ -284,7 +284,7 @@ fn check<'tcx>( diag.span_suggestion( assign.lhs_span, - &format!("declare `{binding_name}` here"), + format!("declare `{binding_name}` here"), let_snippet, Applicability::MachineApplicable, ); @@ -304,7 +304,7 @@ fn check<'tcx>( diag.span_suggestion_verbose( usage.stmt.span.shrink_to_lo(), - &format!("declare `{binding_name}` here"), + format!("declare `{binding_name}` here"), format!("{let_snippet} = "), applicability, ); @@ -335,7 +335,7 @@ fn check<'tcx>( diag.span_suggestion_verbose( usage.stmt.span.shrink_to_lo(), - &format!("declare `{binding_name}` here"), + format!("declare `{binding_name}` here"), format!("{let_snippet} = "), applicability, ); diff --git a/clippy_lints/src/octal_escapes.rs b/clippy_lints/src/octal_escapes.rs index ae0a41db918a3..7376ab0c846d9 100644 --- a/clippy_lints/src/octal_escapes.rs +++ b/clippy_lints/src/octal_escapes.rs @@ -125,7 +125,7 @@ fn check_lit(cx: &EarlyContext<'_>, lit: &Lit, span: Span, is_string: bool) { if is_string { "string" } else { "byte string" } ), |diag| { - diag.help(&format!( + diag.help(format!( "octal escapes are not supported, `\\0` is always a null {}", if is_string { "character" } else { "byte" } )); @@ -139,7 +139,7 @@ fn check_lit(cx: &EarlyContext<'_>, lit: &Lit, span: Span, is_string: bool) { // suggestion 2: unambiguous null byte diag.span_suggestion( span, - &format!( + format!( "if the null {} is intended, disambiguate using", if is_string { "character" } else { "byte" } ), diff --git a/clippy_lints/src/operators/misrefactored_assign_op.rs b/clippy_lints/src/operators/misrefactored_assign_op.rs index ae805147f07a2..015f6c14e7612 100644 --- a/clippy_lints/src/operators/misrefactored_assign_op.rs +++ b/clippy_lints/src/operators/misrefactored_assign_op.rs @@ -50,7 +50,7 @@ fn lint_misrefactored_assign_op( let long = format!("{snip_a} = {}", sugg::make_binop(op.into(), a, r)); diag.span_suggestion( expr.span, - &format!( + format!( "did you mean `{snip_a} = {snip_a} {} {snip_r}` or `{long}`? Consider replacing it with", op.as_str() ), diff --git a/clippy_lints/src/permissions_set_readonly_false.rs b/clippy_lints/src/permissions_set_readonly_false.rs new file mode 100644 index 0000000000000..e7095ec191f7d --- /dev/null +++ b/clippy_lints/src/permissions_set_readonly_false.rs @@ -0,0 +1,52 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::paths; +use clippy_utils::ty::match_type; +use rustc_ast::ast::LitKind; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// ### What it does + /// Checks for calls to `std::fs::Permissions.set_readonly` with argument `false`. + /// + /// ### Why is this bad? + /// On Unix platforms this results in the file being world writable, + /// equivalent to `chmod a+w `. + /// ### Example + /// ```rust + /// use std::fs::File; + /// let f = File::create("foo.txt").unwrap(); + /// let metadata = f.metadata().unwrap(); + /// let mut permissions = metadata.permissions(); + /// permissions.set_readonly(false); + /// ``` + #[clippy::version = "1.66.0"] + pub PERMISSIONS_SET_READONLY_FALSE, + suspicious, + "Checks for calls to `std::fs::Permissions.set_readonly` with argument `false`" +} +declare_lint_pass!(PermissionsSetReadonlyFalse => [PERMISSIONS_SET_READONLY_FALSE]); + +impl<'tcx> LateLintPass<'tcx> for PermissionsSetReadonlyFalse { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { + if let ExprKind::MethodCall(path, receiver, [arg], _) = &expr.kind + && match_type(cx, cx.typeck_results().expr_ty(receiver), &paths::PERMISSIONS) + && path.ident.name == sym!(set_readonly) + && let ExprKind::Lit(lit) = &arg.kind + && LitKind::Bool(false) == lit.node + { + span_lint_and_then( + cx, + PERMISSIONS_SET_READONLY_FALSE, + expr.span, + "call to `set_readonly` with argument `false`", + |diag| { + diag.note("on Unix platforms this results in the file being world writable"); + diag.help("you can set the desired permissions using `PermissionsExt`. For more information, see\n\ + https://doc.rust-lang.org/std/os/unix/fs/trait.PermissionsExt.html"); + } + ); + } + } +} diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index c1677fb3da1c4..0e7c5cca7240b 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -131,7 +131,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone { // `res = clone(arg)` can be turned into `res = move arg;` // if `arg` is the only borrow of `cloned` at this point. - if cannot_move_out || !possible_borrower.only_borrowers(&[arg], cloned, loc) { + if cannot_move_out || !possible_borrower.at_most_borrowers(cx, &[arg], cloned, loc) { continue; } @@ -178,7 +178,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone { // StorageDead(pred_arg); // res = to_path_buf(cloned); // ``` - if cannot_move_out || !possible_borrower.only_borrowers(&[arg, cloned], local, loc) { + if cannot_move_out || !possible_borrower.at_most_borrowers(cx, &[arg, cloned], local, loc) { continue; } diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index 81143d7799ea8..d4d506605206b 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -6,7 +6,7 @@ use core::ops::ControlFlow; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; -use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, HirId, MatchSource, PatKind, StmtKind}; +use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, HirId, LangItem, MatchSource, PatKind, QPath, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::subst::GenericArgKind; @@ -207,6 +207,12 @@ fn check_final_expr<'tcx>( match &peeled_drop_expr.kind { // simple return is always "bad" ExprKind::Ret(ref inner) => { + // if desugar of `do yeet`, don't lint + if let Some(inner_expr) = inner + && let ExprKind::Call(path_expr, _) = inner_expr.kind + && let ExprKind::Path(QPath::LangItem(LangItem::TryTraitFromYeet, _, _)) = path_expr.kind { + return; + } if cx.tcx.hir().attrs(expr.hir_id).is_empty() { let borrows = inner.map_or(false, |inner| last_statement_borrows(cx, inner)); if !borrows { diff --git a/clippy_lints/src/same_name_method.rs b/clippy_lints/src/same_name_method.rs index caab5851bafc9..17763128cd143 100644 --- a/clippy_lints/src/same_name_method.rs +++ b/clippy_lints/src/same_name_method.rs @@ -108,7 +108,7 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod { |diag| { diag.span_note( trait_method_span, - &format!("existing `{method_name}` defined here"), + format!("existing `{method_name}` defined here"), ); }, ); @@ -151,7 +151,7 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod { // iterate on trait_spans? diag.span_note( trait_spans[0], - &format!("existing `{method_name}` defined here"), + format!("existing `{method_name}` defined here"), ); }, ); diff --git a/clippy_lints/src/size_of_ref.rs b/clippy_lints/src/size_of_ref.rs new file mode 100644 index 0000000000000..3fcdb4288ce6d --- /dev/null +++ b/clippy_lints/src/size_of_ref.rs @@ -0,0 +1,73 @@ +use clippy_utils::{diagnostics::span_lint_and_help, path_def_id, ty::peel_mid_ty_refs}; +use rustc_hir::{Expr, ExprKind}; +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 calls to `std::mem::size_of_val()` where the argument is + /// a reference to a reference. + /// + /// ### Why is this bad? + /// + /// Calling `size_of_val()` with a reference to a reference as the argument + /// yields the size of the reference-type, not the size of the value behind + /// the reference. + /// + /// ### Example + /// ```rust + /// struct Foo { + /// buffer: [u8], + /// } + /// + /// impl Foo { + /// fn size(&self) -> usize { + /// // Note that `&self` as an argument is a `&&Foo`: Because `self` + /// // is already a reference, `&self` is a double-reference. + /// // The return value of `size_of_val()` therefor is the + /// // size of the reference-type, not the size of `self`. + /// std::mem::size_of_val(&self) + /// } + /// } + /// ``` + /// Use instead: + /// ```rust + /// struct Foo { + /// buffer: [u8], + /// } + /// + /// impl Foo { + /// fn size(&self) -> usize { + /// // Correct + /// std::mem::size_of_val(self) + /// } + /// } + /// ``` + #[clippy::version = "1.67.0"] + pub SIZE_OF_REF, + suspicious, + "Argument to `std::mem::size_of_val()` is a double-reference, which is almost certainly unintended" +} +declare_lint_pass!(SizeOfRef => [SIZE_OF_REF]); + +impl LateLintPass<'_> for SizeOfRef { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) { + if let ExprKind::Call(path, [arg]) = expr.kind + && let Some(def_id) = path_def_id(cx, path) + && cx.tcx.is_diagnostic_item(sym::mem_size_of_val, def_id) + && let arg_ty = cx.typeck_results().expr_ty(arg) + && peel_mid_ty_refs(arg_ty).1 > 1 + { + span_lint_and_help( + cx, + SIZE_OF_REF, + expr.span, + "argument to `std::mem::size_of_val()` is a reference to a reference", + None, + "dereference the argument to `std::mem::size_of_val()` to get the size of the value instead of the size of the reference-type", + ); + } + } +} diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index c374529d1ea9f..17e9cc5f6b7c7 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -132,7 +132,7 @@ fn generate_swap_warning(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>, spa applicability, ); if !is_xor_based { - diag.note(&format!("or maybe you should use `{sugg}::mem::replace`?")); + diag.note(format!("or maybe you should use `{sugg}::mem::replace`?")); } }, ); @@ -214,7 +214,7 @@ fn check_suspicious_swap(cx: &LateContext<'_>, block: &Block<'_>) { Applicability::MaybeIncorrect, ); diag.note( - &format!("or maybe you should use `{sugg}::mem::replace`?") + format!("or maybe you should use `{sugg}::mem::replace`?") ); } }); diff --git a/clippy_lints/src/transmute/mod.rs b/clippy_lints/src/transmute/mod.rs index 83e651aba8e89..691d759d7739d 100644 --- a/clippy_lints/src/transmute/mod.rs +++ b/clippy_lints/src/transmute/mod.rs @@ -3,6 +3,7 @@ mod transmute_float_to_int; mod transmute_int_to_bool; mod transmute_int_to_char; mod transmute_int_to_float; +mod transmute_null_to_fn; mod transmute_num_to_bytes; mod transmute_ptr_to_ptr; mod transmute_ptr_to_ref; @@ -409,6 +410,34 @@ declare_clippy_lint! { "transmutes from a null pointer to a reference, which is undefined behavior" } +declare_clippy_lint! { + /// ### What it does + /// Checks for null function pointer creation through transmute. + /// + /// ### Why is this bad? + /// Creating a null function pointer is undefined behavior. + /// + /// More info: https://doc.rust-lang.org/nomicon/ffi.html#the-nullable-pointer-optimization + /// + /// ### Known problems + /// Not all cases can be detected at the moment of this writing. + /// For example, variables which hold a null pointer and are then fed to a `transmute` + /// call, aren't detectable yet. + /// + /// ### Example + /// ```rust + /// let null_fn: fn() = unsafe { std::mem::transmute( std::ptr::null::<()>() ) }; + /// ``` + /// Use instead: + /// ```rust + /// let null_fn: Option = None; + /// ``` + #[clippy::version = "1.67.0"] + pub TRANSMUTE_NULL_TO_FN, + correctness, + "transmute results in a null function pointer, which is undefined behavior" +} + pub struct Transmute { msrv: Msrv, } @@ -428,6 +457,7 @@ impl_lint_pass!(Transmute => [ TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS, TRANSMUTE_UNDEFINED_REPR, TRANSMUTING_NULL, + TRANSMUTE_NULL_TO_FN, ]); impl Transmute { #[must_use] @@ -461,6 +491,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute { let linted = wrong_transmute::check(cx, e, from_ty, to_ty) | crosspointer_transmute::check(cx, e, from_ty, to_ty) | transmuting_null::check(cx, e, arg, to_ty) + | transmute_null_to_fn::check(cx, e, arg, to_ty) | transmute_ptr_to_ref::check(cx, e, from_ty, to_ty, arg, path, &self.msrv) | transmute_int_to_char::check(cx, e, from_ty, to_ty, arg, const_context) | transmute_ref_to_ref::check(cx, e, from_ty, to_ty, arg, const_context) diff --git a/clippy_lints/src/transmute/transmute_null_to_fn.rs b/clippy_lints/src/transmute/transmute_null_to_fn.rs new file mode 100644 index 0000000000000..e75d7f6bf1d52 --- /dev/null +++ b/clippy_lints/src/transmute/transmute_null_to_fn.rs @@ -0,0 +1,64 @@ +use clippy_utils::consts::{constant, Constant}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::{is_integer_literal, is_path_diagnostic_item}; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_middle::ty::Ty; +use rustc_span::symbol::sym; + +use super::TRANSMUTE_NULL_TO_FN; + +fn lint_expr(cx: &LateContext<'_>, expr: &Expr<'_>) { + span_lint_and_then( + cx, + TRANSMUTE_NULL_TO_FN, + expr.span, + "transmuting a known null pointer into a function pointer", + |diag| { + diag.span_label(expr.span, "this transmute results in undefined behavior"); + diag.help( + "try wrapping your function pointer type in `Option` instead, and using `None` as a null pointer value" + ); + }, + ); +} + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'tcx Expr<'_>, to_ty: Ty<'tcx>) -> bool { + if !to_ty.is_fn() { + return false; + } + + match arg.kind { + // Catching: + // transmute over constants that resolve to `null`. + ExprKind::Path(ref _qpath) + if matches!(constant(cx, cx.typeck_results(), arg), Some((Constant::RawPtr(0), _))) => + { + lint_expr(cx, expr); + true + }, + + // Catching: + // `std::mem::transmute(0 as *const i32)` + ExprKind::Cast(inner_expr, _cast_ty) if is_integer_literal(inner_expr, 0) => { + lint_expr(cx, expr); + true + }, + + // Catching: + // `std::mem::transmute(std::ptr::null::())` + ExprKind::Call(func1, []) if is_path_diagnostic_item(cx, func1, sym::ptr_null) => { + lint_expr(cx, expr); + true + }, + + _ => { + // FIXME: + // Also catch transmutations of variables which are known nulls. + // To do this, MIR const propagation seems to be the better tool. + // Whenever MIR const prop routines are more developed, this will + // become available. As of this writing (25/03/19) it is not yet. + false + }, + } +} diff --git a/clippy_lints/src/transmute/transmute_undefined_repr.rs b/clippy_lints/src/transmute/transmute_undefined_repr.rs index 34642f4b122f2..af0242348ac29 100644 --- a/clippy_lints/src/transmute/transmute_undefined_repr.rs +++ b/clippy_lints/src/transmute/transmute_undefined_repr.rs @@ -77,7 +77,7 @@ pub(super) fn check<'tcx>( &format!("transmute from `{from_ty_orig}` which has an undefined layout"), |diag| { if from_ty_orig.peel_refs() != from_ty.peel_refs() { - diag.note(&format!("the contained type `{from_ty}` has an undefined layout")); + diag.note(format!("the contained type `{from_ty}` has an undefined layout")); } }, ); @@ -91,7 +91,7 @@ pub(super) fn check<'tcx>( &format!("transmute to `{to_ty_orig}` which has an undefined layout"), |diag| { if to_ty_orig.peel_refs() != to_ty.peel_refs() { - diag.note(&format!("the contained type `{to_ty}` has an undefined layout")); + diag.note(format!("the contained type `{to_ty}` has an undefined layout")); } }, ); @@ -119,16 +119,16 @@ pub(super) fn check<'tcx>( ), |diag| { if let Some(same_adt_did) = same_adt_did { - diag.note(&format!( + diag.note(format!( "two instances of the same generic type (`{}`) may have different layouts", cx.tcx.item_name(same_adt_did) )); } else { if from_ty_orig.peel_refs() != from_ty { - diag.note(&format!("the contained type `{from_ty}` has an undefined layout")); + diag.note(format!("the contained type `{from_ty}` has an undefined layout")); } if to_ty_orig.peel_refs() != to_ty { - diag.note(&format!("the contained type `{to_ty}` has an undefined layout")); + diag.note(format!("the contained type `{to_ty}` has an undefined layout")); } } }, @@ -146,7 +146,7 @@ pub(super) fn check<'tcx>( &format!("transmute from `{from_ty_orig}` which has an undefined layout"), |diag| { if from_ty_orig.peel_refs() != from_ty { - diag.note(&format!("the contained type `{from_ty}` has an undefined layout")); + diag.note(format!("the contained type `{from_ty}` has an undefined layout")); } }, ); @@ -163,7 +163,7 @@ pub(super) fn check<'tcx>( &format!("transmute into `{to_ty_orig}` which has an undefined layout"), |diag| { if to_ty_orig.peel_refs() != to_ty { - diag.note(&format!("the contained type `{to_ty}` has an undefined layout")); + diag.note(format!("the contained type `{to_ty}` has an undefined layout")); } }, ); diff --git a/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs b/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs index 6b444922a7cc7..b79d4e915a271 100644 --- a/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs +++ b/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs @@ -24,7 +24,7 @@ pub(super) fn check<'tcx>( &format!("transmute from `{from_ty}` to `{to_ty}` which could be expressed as a pointer cast instead"), |diag| { if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) { - let sugg = arg.as_ty(&to_ty.to_string()).to_string(); + let sugg = arg.as_ty(to_ty.to_string()).to_string(); diag.span_suggestion(e.span, "try", sugg, Applicability::MachineApplicable); } }, diff --git a/clippy_lints/src/transmute/transmuting_null.rs b/clippy_lints/src/transmute/transmuting_null.rs index 19ce5ae72c24e..1e407fc4138c1 100644 --- a/clippy_lints/src/transmute/transmuting_null.rs +++ b/clippy_lints/src/transmute/transmuting_null.rs @@ -18,8 +18,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t // Catching transmute over constants that resolve to `null`. let mut const_eval_context = constant_context(cx, cx.typeck_results()); if let ExprKind::Path(ref _qpath) = arg.kind && - let Some(Constant::RawPtr(x)) = const_eval_context.expr(arg) && - x == 0 + let Some(Constant::RawPtr(0)) = const_eval_context.expr(arg) { span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG); return true; diff --git a/clippy_lints/src/transmute/useless_transmute.rs b/clippy_lints/src/transmute/useless_transmute.rs index f919bbd5afca3..871c3fadbba71 100644 --- a/clippy_lints/src/transmute/useless_transmute.rs +++ b/clippy_lints/src/transmute/useless_transmute.rs @@ -61,7 +61,7 @@ pub(super) fn check<'tcx>( "transmute from an integer to a pointer", |diag| { if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) { - diag.span_suggestion(e.span, "try", arg.as_ty(&to_ty.to_string()), Applicability::Unspecified); + diag.span_suggestion(e.span, "try", arg.as_ty(to_ty.to_string()), Applicability::Unspecified); } }, ); diff --git a/clippy_lints/src/types/redundant_allocation.rs b/clippy_lints/src/types/redundant_allocation.rs index fae5385ffc848..f9b9a66b5fa46 100644 --- a/clippy_lints/src/types/redundant_allocation.rs +++ b/clippy_lints/src/types/redundant_allocation.rs @@ -31,7 +31,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_ &format!("usage of `{outer_sym}<{generic_snippet}>`"), |diag| { diag.span_suggestion(hir_ty.span, "try", format!("{generic_snippet}"), applicability); - diag.note(&format!( + diag.note(format!( "`{generic_snippet}` is already a pointer, `{outer_sym}<{generic_snippet}>` allocates a pointer on the heap" )); }, @@ -78,7 +78,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_ format!("{outer_sym}<{generic_snippet}>"), applicability, ); - diag.note(&format!( + diag.note(format!( "`{inner_sym}<{generic_snippet}>` is already on the heap, `{outer_sym}<{inner_sym}<{generic_snippet}>>` makes an extra allocation" )); }, @@ -91,10 +91,10 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_ hir_ty.span, &format!("usage of `{outer_sym}<{inner_sym}<{generic_snippet}>>`"), |diag| { - diag.note(&format!( + diag.note(format!( "`{inner_sym}<{generic_snippet}>` is already on the heap, `{outer_sym}<{inner_sym}<{generic_snippet}>>` makes an extra allocation" )); - diag.help(&format!( + diag.help(format!( "consider using just `{outer_sym}<{generic_snippet}>` or `{inner_sym}<{generic_snippet}>`" )); }, diff --git a/clippy_lints/src/unit_types/unit_arg.rs b/clippy_lints/src/unit_types/unit_arg.rs index f6d3fb00f4ee5..ef9f740f7047c 100644 --- a/clippy_lints/src/unit_types/unit_arg.rs +++ b/clippy_lints/src/unit_types/unit_arg.rs @@ -129,7 +129,7 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp if arg_snippets_without_empty_blocks.is_empty() { db.multipart_suggestion( - &format!("use {singular}unit literal{plural} instead"), + format!("use {singular}unit literal{plural} instead"), args_to_recover .iter() .map(|arg| (arg.span, "()".to_string())) @@ -142,7 +142,7 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp let it_or_them = if plural { "them" } else { "it" }; db.span_suggestion( expr.span, - &format!( + format!( "{or}move the expression{empty_or_s} in front of the call and replace {it_or_them} with the unit literal `()`" ), sugg, diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index 3743d5d97a735..a95e7b613746d 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -1,11 +1,11 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; use clippy_utils::source::{snippet, snippet_with_macro_callsite}; use clippy_utils::sugg::Sugg; -use clippy_utils::ty::{is_type_diagnostic_item, same_type_and_consts}; -use clippy_utils::{get_parent_expr, is_trait_method, match_def_path, paths}; +use clippy_utils::ty::{is_copy, is_type_diagnostic_item, same_type_and_consts}; +use clippy_utils::{get_parent_expr, is_trait_method, match_def_path, path_to_local, paths}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, HirId, MatchSource}; +use rustc_hir::{BindingAnnotation, Expr, ExprKind, HirId, MatchSource, Node, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::{declare_tool_lint, impl_lint_pass}; @@ -81,16 +81,24 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { } } if is_trait_method(cx, e, sym::IntoIterator) && name.ident.name == sym::into_iter { - if let Some(parent_expr) = get_parent_expr(cx, e) { - if let ExprKind::MethodCall(parent_name, ..) = parent_expr.kind { - if parent_name.ident.name != sym::into_iter { - return; - } - } + if get_parent_expr(cx, e).is_some() && + let Some(id) = path_to_local(recv) && + let Node::Pat(pat) = cx.tcx.hir().get(id) && + let PatKind::Binding(ann, ..) = pat.kind && + ann != BindingAnnotation::MUT + { + // Do not remove .into_iter() applied to a non-mutable local variable used in + // a larger expression context as it would differ in mutability. + return; } + let a = cx.typeck_results().expr_ty(e); let b = cx.typeck_results().expr_ty(recv); - if same_type_and_consts(a, b) { + + // If the types are identical then .into_iter() can be removed, unless the type + // implements Copy, in which case .into_iter() returns a copy of the receiver and + // cannot be safely omitted. + if same_type_and_consts(a, b) && !is_copy(cx, b) { let sugg = snippet(cx, recv.span, "").into_owned(); span_lint_and_sugg( cx, diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 3e7d0028c0fbd..c1589c771c462 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -333,7 +333,7 @@ define_Conf! { /// Lint: LARGE_STACK_ARRAYS, LARGE_CONST_ARRAYS. /// /// The maximum allowed size for arrays on the stack - (array_size_threshold: u64 = 512_000), + (array_size_threshold: u128 = 512_000), /// Lint: VEC_BOX. /// /// The size of the boxed type in bytes, where boxing in a `Vec` is allowed diff --git a/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/clippy_lints/src/utils/internal_lints/metadata_collector.rs index 857abe77e21f2..929544cd69d5b 100644 --- a/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ b/clippy_lints/src/utils/internal_lints/metadata_collector.rs @@ -558,8 +558,8 @@ impl fmt::Display for ClippyConfiguration { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> fmt::Result { writeln!( f, - "* `{}`: `{}`: {} (defaults to `{}`)", - self.name, self.config_type, self.doc, self.default + "* `{}`: `{}`(defaults to `{}`): {}", + self.name, self.config_type, self.default, self.doc ) } } diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index 6b321765bc082..df3350388817e 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -377,7 +377,7 @@ fn check_newline(cx: &LateContext<'_>, format_args: &FormatArgsExpn<'_>, macro_c // print!("\n"), write!(f, "\n") diag.multipart_suggestion( - &format!("use `{name}ln!` instead"), + format!("use `{name}ln!` instead"), vec![(name_span, format!("{name}ln")), (format_string_span, String::new())], Applicability::MachineApplicable, ); @@ -388,7 +388,7 @@ fn check_newline(cx: &LateContext<'_>, format_args: &FormatArgsExpn<'_>, macro_c let newline_span = format_string_span.with_lo(hi - BytePos(3)).with_hi(hi - BytePos(1)); diag.multipart_suggestion( - &format!("use `{name}ln!` instead"), + format!("use `{name}ln!` instead"), vec![(name_span, format!("{name}ln")), (newline_span, String::new())], Applicability::MachineApplicable, ); diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 7a637d32babec..a67bd8d46006b 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -620,12 +620,7 @@ pub fn miri_to_const<'tcx>(tcx: TyCtxt<'tcx>, result: mir::ConstantKind<'tcx>) - ty::Float(FloatTy::F64) => Some(Constant::F64(f64::from_bits( int.try_into().expect("invalid f64 bit representation"), ))), - ty::RawPtr(type_and_mut) => { - if let ty::Uint(_) = type_and_mut.ty.kind() { - return Some(Constant::RawPtr(int.assert_bits(int.size()))); - } - None - }, + ty::RawPtr(_) => Some(Constant::RawPtr(int.assert_bits(int.size()))), // FIXME: implement other conversions. _ => None, } diff --git a/clippy_utils/src/diagnostics.rs b/clippy_utils/src/diagnostics.rs index 16b160b6fd27e..812f6fe71a0a0 100644 --- a/clippy_utils/src/diagnostics.rs +++ b/clippy_utils/src/diagnostics.rs @@ -17,7 +17,7 @@ use std::env; fn docs_link(diag: &mut Diagnostic, lint: &'static Lint) { if env::var("CLIPPY_DISABLE_DOCS_LINKS").is_err() { if let Some(lint) = lint.name_lower().strip_prefix("clippy::") { - diag.help(&format!( + diag.help(format!( "for further information visit https://rust-lang.github.io/rust-clippy/{}/index.html#{lint}", &option_env!("RUST_RELEASE_NUM").map_or("master".to_string(), |n| { // extract just major + minor version and ignore patch versions diff --git a/clippy_utils/src/mir/maybe_storage_live.rs b/clippy_utils/src/mir/maybe_storage_live.rs deleted file mode 100644 index d262b335d99d3..0000000000000 --- a/clippy_utils/src/mir/maybe_storage_live.rs +++ /dev/null @@ -1,52 +0,0 @@ -use rustc_index::bit_set::BitSet; -use rustc_middle::mir; -use rustc_mir_dataflow::{AnalysisDomain, CallReturnPlaces, GenKill, GenKillAnalysis}; - -/// Determines liveness of each local purely based on `StorageLive`/`Dead`. -#[derive(Copy, Clone)] -pub(super) struct MaybeStorageLive; - -impl<'tcx> AnalysisDomain<'tcx> for MaybeStorageLive { - type Domain = BitSet; - const NAME: &'static str = "maybe_storage_live"; - - fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain { - // bottom = dead - BitSet::new_empty(body.local_decls.len()) - } - - fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut Self::Domain) { - for arg in body.args_iter() { - state.insert(arg); - } - } -} - -impl<'tcx> GenKillAnalysis<'tcx> for MaybeStorageLive { - type Idx = mir::Local; - - fn statement_effect(&self, trans: &mut impl GenKill, stmt: &mir::Statement<'tcx>, _: mir::Location) { - match stmt.kind { - mir::StatementKind::StorageLive(l) => trans.gen(l), - mir::StatementKind::StorageDead(l) => trans.kill(l), - _ => (), - } - } - - fn terminator_effect( - &self, - _trans: &mut impl GenKill, - _terminator: &mir::Terminator<'tcx>, - _loc: mir::Location, - ) { - } - - fn call_return_effect( - &self, - _trans: &mut impl GenKill, - _block: mir::BasicBlock, - _return_places: CallReturnPlaces<'_, 'tcx>, - ) { - // Nothing to do when a call returns successfully - } -} diff --git a/clippy_utils/src/mir/mod.rs b/clippy_utils/src/mir/mod.rs index 818e603f665e7..26c0015e87e0f 100644 --- a/clippy_utils/src/mir/mod.rs +++ b/clippy_utils/src/mir/mod.rs @@ -5,8 +5,6 @@ use rustc_middle::mir::{ }; use rustc_middle::ty::TyCtxt; -mod maybe_storage_live; - mod possible_borrower; pub use possible_borrower::PossibleBorrowerMap; diff --git a/clippy_utils/src/mir/possible_borrower.rs b/clippy_utils/src/mir/possible_borrower.rs index 25717bf3d2fee..395d46e7a2f8a 100644 --- a/clippy_utils/src/mir/possible_borrower.rs +++ b/clippy_utils/src/mir/possible_borrower.rs @@ -1,92 +1,137 @@ -use super::{ - maybe_storage_live::MaybeStorageLive, possible_origin::PossibleOriginVisitor, - transitive_relation::TransitiveRelation, -}; +use super::possible_origin::PossibleOriginVisitor; use crate::ty::is_copy; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_index::bit_set::{BitSet, HybridBitSet}; use rustc_lint::LateContext; -use rustc_middle::mir::{self, visit::Visitor as _, Mutability}; -use rustc_middle::ty::{self, visit::TypeVisitor}; -use rustc_mir_dataflow::{Analysis, ResultsCursor}; +use rustc_middle::mir::{ + self, visit::Visitor as _, BasicBlock, Local, Location, Mutability, Statement, StatementKind, Terminator, +}; +use rustc_middle::ty::{self, visit::TypeVisitor, TyCtxt}; +use rustc_mir_dataflow::{ + fmt::DebugWithContext, impls::MaybeStorageLive, lattice::JoinSemiLattice, Analysis, AnalysisDomain, + CallReturnPlaces, ResultsCursor, +}; +use std::borrow::Cow; use std::ops::ControlFlow; /// Collects the possible borrowers of each local. /// For example, `b = &a; c = &a;` will make `b` and (transitively) `c` /// possible borrowers of `a`. #[allow(clippy::module_name_repetitions)] -struct PossibleBorrowerVisitor<'a, 'b, 'tcx> { - possible_borrower: TransitiveRelation, +struct PossibleBorrowerAnalysis<'b, 'tcx> { + tcx: TyCtxt<'tcx>, body: &'b mir::Body<'tcx>, - cx: &'a LateContext<'tcx>, possible_origin: FxHashMap>, } -impl<'a, 'b, 'tcx> PossibleBorrowerVisitor<'a, 'b, 'tcx> { - fn new( - cx: &'a LateContext<'tcx>, - body: &'b mir::Body<'tcx>, - possible_origin: FxHashMap>, - ) -> Self { +#[derive(Clone, Debug, Eq, PartialEq)] +struct PossibleBorrowerState { + map: FxIndexMap>, + domain_size: usize, +} + +impl PossibleBorrowerState { + fn new(domain_size: usize) -> Self { Self { - possible_borrower: TransitiveRelation::default(), - cx, - body, - possible_origin, + map: FxIndexMap::default(), + domain_size, } } - fn into_map( - self, - cx: &'a LateContext<'tcx>, - maybe_live: ResultsCursor<'b, 'tcx, MaybeStorageLive>, - ) -> PossibleBorrowerMap<'b, 'tcx> { - let mut map = FxHashMap::default(); - for row in (1..self.body.local_decls.len()).map(mir::Local::from_usize) { - if is_copy(cx, self.body.local_decls[row].ty) { - continue; - } + #[allow(clippy::similar_names)] + fn add(&mut self, borrowed: Local, borrower: Local) { + self.map + .entry(borrowed) + .or_insert(BitSet::new_empty(self.domain_size)) + .insert(borrower); + } +} - let mut borrowers = self.possible_borrower.reachable_from(row, self.body.local_decls.len()); - borrowers.remove(mir::Local::from_usize(0)); +impl DebugWithContext for PossibleBorrowerState { + fn fmt_with(&self, _ctxt: &C, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + <_ as std::fmt::Debug>::fmt(self, f) + } + fn fmt_diff_with(&self, _old: &Self, _ctxt: &C, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + unimplemented!() + } +} + +impl JoinSemiLattice for PossibleBorrowerState { + fn join(&mut self, other: &Self) -> bool { + let mut changed = false; + for (&borrowed, borrowers) in other.map.iter() { if !borrowers.is_empty() { - map.insert(row, borrowers); + changed |= self + .map + .entry(borrowed) + .or_insert(BitSet::new_empty(self.domain_size)) + .union(borrowers); } } + changed + } +} - let bs = BitSet::new_empty(self.body.local_decls.len()); - PossibleBorrowerMap { - map, - maybe_live, - bitset: (bs.clone(), bs), +impl<'b, 'tcx> AnalysisDomain<'tcx> for PossibleBorrowerAnalysis<'b, 'tcx> { + type Domain = PossibleBorrowerState; + + const NAME: &'static str = "possible_borrower"; + + fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain { + PossibleBorrowerState::new(body.local_decls.len()) + } + + fn initialize_start_block(&self, _body: &mir::Body<'tcx>, _entry_set: &mut Self::Domain) {} +} + +impl<'b, 'tcx> PossibleBorrowerAnalysis<'b, 'tcx> { + fn new( + tcx: TyCtxt<'tcx>, + body: &'b mir::Body<'tcx>, + possible_origin: FxHashMap>, + ) -> Self { + Self { + tcx, + body, + possible_origin, } } } -impl<'a, 'b, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'b, 'tcx> { - fn visit_assign(&mut self, place: &mir::Place<'tcx>, rvalue: &mir::Rvalue<'_>, _location: mir::Location) { - let lhs = place.local; - match rvalue { - mir::Rvalue::Ref(_, _, borrowed) => { - self.possible_borrower.add(borrowed.local, lhs); - }, - other => { - if ContainsRegion - .visit_ty(place.ty(&self.body.local_decls, self.cx.tcx).ty) - .is_continue() - { - return; - } - rvalue_locals(other, |rhs| { - if lhs != rhs { - self.possible_borrower.add(rhs, lhs); +impl<'b, 'tcx> Analysis<'tcx> for PossibleBorrowerAnalysis<'b, 'tcx> { + fn apply_call_return_effect( + &self, + _state: &mut Self::Domain, + _block: BasicBlock, + _return_places: CallReturnPlaces<'_, 'tcx>, + ) { + } + + fn apply_statement_effect(&self, state: &mut Self::Domain, statement: &Statement<'tcx>, _location: Location) { + if let StatementKind::Assign(box (place, rvalue)) = &statement.kind { + let lhs = place.local; + match rvalue { + mir::Rvalue::Ref(_, _, borrowed) => { + state.add(borrowed.local, lhs); + }, + other => { + if ContainsRegion + .visit_ty(place.ty(&self.body.local_decls, self.tcx).ty) + .is_continue() + { + return; } - }); - }, + rvalue_locals(other, |rhs| { + if lhs != rhs { + state.add(rhs, lhs); + } + }); + }, + } } } - fn visit_terminator(&mut self, terminator: &mir::Terminator<'_>, _loc: mir::Location) { + fn apply_terminator_effect(&self, state: &mut Self::Domain, terminator: &Terminator<'tcx>, _location: Location) { if let mir::TerminatorKind::Call { args, destination: mir::Place { local: dest, .. }, @@ -126,10 +171,10 @@ impl<'a, 'b, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'b, for y in mutable_variables { for x in &immutable_borrowers { - self.possible_borrower.add(*x, y); + state.add(*x, y); } for x in &mutable_borrowers { - self.possible_borrower.add(*x, y); + state.add(*x, y); } } } @@ -165,73 +210,98 @@ fn rvalue_locals(rvalue: &mir::Rvalue<'_>, mut visit: impl FnMut(mir::Local)) { } } -/// Result of `PossibleBorrowerVisitor`. +/// Result of `PossibleBorrowerAnalysis`. #[allow(clippy::module_name_repetitions)] pub struct PossibleBorrowerMap<'b, 'tcx> { - /// Mapping `Local -> its possible borrowers` - pub map: FxHashMap>, - maybe_live: ResultsCursor<'b, 'tcx, MaybeStorageLive>, - // Caches to avoid allocation of `BitSet` on every query - pub bitset: (BitSet, BitSet), + body: &'b mir::Body<'tcx>, + possible_borrower: ResultsCursor<'b, 'tcx, PossibleBorrowerAnalysis<'b, 'tcx>>, + maybe_live: ResultsCursor<'b, 'tcx, MaybeStorageLive<'b>>, + pushed: BitSet, + stack: Vec, } -impl<'a, 'b, 'tcx> PossibleBorrowerMap<'b, 'tcx> { - pub fn new(cx: &'a LateContext<'tcx>, mir: &'b mir::Body<'tcx>) -> Self { +impl<'b, 'tcx> PossibleBorrowerMap<'b, 'tcx> { + pub fn new(cx: &LateContext<'tcx>, mir: &'b mir::Body<'tcx>) -> Self { let possible_origin = { let mut vis = PossibleOriginVisitor::new(mir); vis.visit_body(mir); vis.into_map(cx) }; - let maybe_storage_live_result = MaybeStorageLive + let possible_borrower = PossibleBorrowerAnalysis::new(cx.tcx, mir, possible_origin) .into_engine(cx.tcx, mir) - .pass_name("redundant_clone") + .pass_name("possible_borrower") .iterate_to_fixpoint() .into_results_cursor(mir); - let mut vis = PossibleBorrowerVisitor::new(cx, mir, possible_origin); - vis.visit_body(mir); - vis.into_map(cx, maybe_storage_live_result) - } - - /// Returns true if the set of borrowers of `borrowed` living at `at` matches with `borrowers`. - pub fn only_borrowers(&mut self, borrowers: &[mir::Local], borrowed: mir::Local, at: mir::Location) -> bool { - self.bounded_borrowers(borrowers, borrowers, borrowed, at) + let maybe_live = MaybeStorageLive::new(Cow::Owned(BitSet::new_empty(mir.local_decls.len()))) + .into_engine(cx.tcx, mir) + .pass_name("possible_borrower") + .iterate_to_fixpoint() + .into_results_cursor(mir); + PossibleBorrowerMap { + body: mir, + possible_borrower, + maybe_live, + pushed: BitSet::new_empty(mir.local_decls.len()), + stack: Vec::with_capacity(mir.local_decls.len()), + } } - /// Returns true if the set of borrowers of `borrowed` living at `at` includes at least `below` - /// but no more than `above`. - pub fn bounded_borrowers( + /// Returns true if the set of borrowers of `borrowed` living at `at` includes no more than + /// `borrowers`. + /// Notes: + /// 1. It would be nice if `PossibleBorrowerMap` could store `cx` so that `at_most_borrowers` + /// would not require it to be passed in. But a `PossibleBorrowerMap` is stored in `LintPass` + /// `Dereferencing`, which outlives any `LateContext`. + /// 2. In all current uses of `at_most_borrowers`, `borrowers` is a slice of at most two + /// elements. Thus, `borrowers.contains(...)` is effectively a constant-time operation. If + /// `at_most_borrowers`'s uses were to expand beyond this, its implementation might have to be + /// adjusted. + pub fn at_most_borrowers( &mut self, - below: &[mir::Local], - above: &[mir::Local], + cx: &LateContext<'tcx>, + borrowers: &[mir::Local], borrowed: mir::Local, at: mir::Location, ) -> bool { - self.maybe_live.seek_after_primary_effect(at); + if is_copy(cx, self.body.local_decls[borrowed].ty) { + return true; + } - self.bitset.0.clear(); - let maybe_live = &mut self.maybe_live; - if let Some(bitset) = self.map.get(&borrowed) { - for b in bitset.iter().filter(move |b| maybe_live.contains(*b)) { - self.bitset.0.insert(b); + self.possible_borrower.seek_before_primary_effect(at); + self.maybe_live.seek_before_primary_effect(at); + + let possible_borrower = &self.possible_borrower.get().map; + let maybe_live = &self.maybe_live; + + self.pushed.clear(); + self.stack.clear(); + + if let Some(borrowers) = possible_borrower.get(&borrowed) { + for b in borrowers.iter() { + if self.pushed.insert(b) { + self.stack.push(b); + } } } else { - return false; + // Nothing borrows `borrowed` at `at`. + return true; } - self.bitset.1.clear(); - for b in below { - self.bitset.1.insert(*b); - } - - if !self.bitset.0.superset(&self.bitset.1) { - return false; - } + while let Some(borrower) = self.stack.pop() { + if maybe_live.contains(borrower) && !borrowers.contains(&borrower) { + return false; + } - for b in above { - self.bitset.0.remove(*b); + if let Some(borrowers) = possible_borrower.get(&borrower) { + for b in borrowers.iter() { + if self.pushed.insert(b) { + self.stack.push(b); + } + } + } } - self.bitset.0.is_empty() + true } pub fn local_is_alive_at(&mut self, local: mir::Local, at: mir::Location) -> bool { diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index b66604f33db17..4c4c077d771f9 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -185,7 +185,6 @@ impl<'a> Sugg<'a> { ) -> Self { use rustc_ast::ast::RangeLimits; - #[expect(clippy::match_wildcard_for_single_variants)] match expr.kind { _ if expr.span.ctxt() != ctxt => Sugg::NonParen(snippet_with_context(cx, expr.span, ctxt, default, app).0), ast::ExprKind::AddrOf(..) diff --git a/rust-toolchain b/rust-toolchain index 8e21cef32abb6..9399d422036d4 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2022-12-17" +channel = "nightly-2022-12-29" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] diff --git a/tests/ui/crashes/ice-10044.rs b/tests/ui/crashes/ice-10044.rs new file mode 100644 index 0000000000000..65f38fe71188e --- /dev/null +++ b/tests/ui/crashes/ice-10044.rs @@ -0,0 +1,3 @@ +fn main() { + [0; usize::MAX]; +} diff --git a/tests/ui/crashes/ice-10044.stderr b/tests/ui/crashes/ice-10044.stderr new file mode 100644 index 0000000000000..731f8265ad6c9 --- /dev/null +++ b/tests/ui/crashes/ice-10044.stderr @@ -0,0 +1,10 @@ +error: statement with no effect + --> $DIR/ice-10044.rs:2:5 + | +LL | [0; usize::MAX]; + | ^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::no-effect` implied by `-D warnings` + +error: aborting due to previous error + diff --git a/tests/ui/floating_point_powi.fixed b/tests/ui/floating_point_powi.fixed index 884d05fed71ba..8ffd4cc513790 100644 --- a/tests/ui/floating_point_powi.fixed +++ b/tests/ui/floating_point_powi.fixed @@ -14,6 +14,15 @@ fn main() { let _ = (y as f32).mul_add(y as f32, x); let _ = x.mul_add(x, y).sqrt(); let _ = y.mul_add(y, x).sqrt(); + + let _ = (x - 1.0).mul_add(x - 1.0, -y); + let _ = (x - 1.0).mul_add(x - 1.0, -y) + 3.0; + let _ = (x - 1.0).mul_add(x - 1.0, -(y + 3.0)); + let _ = (y + 1.0).mul_add(-(y + 1.0), x); + let _ = (3.0 * y).mul_add(-(3.0 * y), x); + let _ = (y + 1.0 + x).mul_add(-(y + 1.0 + x), x); + let _ = (y + 1.0 + 2.0).mul_add(-(y + 1.0 + 2.0), x); + // Cases where the lint shouldn't be applied let _ = x.powi(2); let _ = x.powi(1 + 1); diff --git a/tests/ui/floating_point_powi.rs b/tests/ui/floating_point_powi.rs index e6a1c895371b6..9ae3455a1346a 100644 --- a/tests/ui/floating_point_powi.rs +++ b/tests/ui/floating_point_powi.rs @@ -14,6 +14,15 @@ fn main() { let _ = x + (y as f32).powi(2); let _ = (x.powi(2) + y).sqrt(); let _ = (x + y.powi(2)).sqrt(); + + let _ = (x - 1.0).powi(2) - y; + let _ = (x - 1.0).powi(2) - y + 3.0; + let _ = (x - 1.0).powi(2) - (y + 3.0); + let _ = x - (y + 1.0).powi(2); + let _ = x - (3.0 * y).powi(2); + let _ = x - (y + 1.0 + x).powi(2); + let _ = x - (y + 1.0 + 2.0).powi(2); + // Cases where the lint shouldn't be applied let _ = x.powi(2); let _ = x.powi(1 + 1); diff --git a/tests/ui/floating_point_powi.stderr b/tests/ui/floating_point_powi.stderr index 5df0de1fef22e..fdf6d088052ea 100644 --- a/tests/ui/floating_point_powi.stderr +++ b/tests/ui/floating_point_powi.stderr @@ -42,5 +42,47 @@ error: multiply and add expressions can be calculated more efficiently and accur LL | let _ = (x + y.powi(2)).sqrt(); | ^^^^^^^^^^^^^^^ help: consider using: `y.mul_add(y, x)` -error: aborting due to 7 previous errors +error: multiply and add expressions can be calculated more efficiently and accurately + --> $DIR/floating_point_powi.rs:18:13 + | +LL | let _ = (x - 1.0).powi(2) - y; + | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x - 1.0).mul_add(x - 1.0, -y)` + +error: multiply and add expressions can be calculated more efficiently and accurately + --> $DIR/floating_point_powi.rs:19:13 + | +LL | let _ = (x - 1.0).powi(2) - y + 3.0; + | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x - 1.0).mul_add(x - 1.0, -y)` + +error: multiply and add expressions can be calculated more efficiently and accurately + --> $DIR/floating_point_powi.rs:20:13 + | +LL | let _ = (x - 1.0).powi(2) - (y + 3.0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x - 1.0).mul_add(x - 1.0, -(y + 3.0))` + +error: multiply and add expressions can be calculated more efficiently and accurately + --> $DIR/floating_point_powi.rs:21:13 + | +LL | let _ = x - (y + 1.0).powi(2); + | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(y + 1.0).mul_add(-(y + 1.0), x)` + +error: multiply and add expressions can be calculated more efficiently and accurately + --> $DIR/floating_point_powi.rs:22:13 + | +LL | let _ = x - (3.0 * y).powi(2); + | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(3.0 * y).mul_add(-(3.0 * y), x)` + +error: multiply and add expressions can be calculated more efficiently and accurately + --> $DIR/floating_point_powi.rs:23:13 + | +LL | let _ = x - (y + 1.0 + x).powi(2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(y + 1.0 + x).mul_add(-(y + 1.0 + x), x)` + +error: multiply and add expressions can be calculated more efficiently and accurately + --> $DIR/floating_point_powi.rs:24:13 + | +LL | let _ = x - (y + 1.0 + 2.0).powi(2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(y + 1.0 + 2.0).mul_add(-(y + 1.0 + 2.0), x)` + +error: aborting due to 14 previous errors diff --git a/tests/ui/fn_null_check.rs b/tests/ui/fn_null_check.rs new file mode 100644 index 0000000000000..df5bc8420d57b --- /dev/null +++ b/tests/ui/fn_null_check.rs @@ -0,0 +1,21 @@ +#![allow(unused)] +#![warn(clippy::fn_null_check)] +#![allow(clippy::cmp_null)] +#![allow(clippy::ptr_eq)] +#![allow(clippy::zero_ptr)] + +pub const ZPTR: *const () = 0 as *const _; +pub const NOT_ZPTR: *const () = 1 as *const _; + +fn main() { + let fn_ptr = main; + + if (fn_ptr as *mut ()).is_null() {} + if (fn_ptr as *const u8).is_null() {} + if (fn_ptr as *const ()) == std::ptr::null() {} + if (fn_ptr as *const ()) == (0 as *const ()) {} + if (fn_ptr as *const ()) == ZPTR {} + + // no lint + if (fn_ptr as *const ()) == NOT_ZPTR {} +} diff --git a/tests/ui/fn_null_check.stderr b/tests/ui/fn_null_check.stderr new file mode 100644 index 0000000000000..660dd32397922 --- /dev/null +++ b/tests/ui/fn_null_check.stderr @@ -0,0 +1,43 @@ +error: function pointer assumed to be nullable, even though it isn't + --> $DIR/fn_null_check.rs:13:8 + | +LL | if (fn_ptr as *mut ()).is_null() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: try wrapping your function pointer type in `Option` instead, and using `is_none` to check for null pointer value + = note: `-D clippy::fn-null-check` implied by `-D warnings` + +error: function pointer assumed to be nullable, even though it isn't + --> $DIR/fn_null_check.rs:14:8 + | +LL | if (fn_ptr as *const u8).is_null() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: try wrapping your function pointer type in `Option` instead, and using `is_none` to check for null pointer value + +error: function pointer assumed to be nullable, even though it isn't + --> $DIR/fn_null_check.rs:15:8 + | +LL | if (fn_ptr as *const ()) == std::ptr::null() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: try wrapping your function pointer type in `Option` instead, and using `is_none` to check for null pointer value + +error: function pointer assumed to be nullable, even though it isn't + --> $DIR/fn_null_check.rs:16:8 + | +LL | if (fn_ptr as *const ()) == (0 as *const ()) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: try wrapping your function pointer type in `Option` instead, and using `is_none` to check for null pointer value + +error: function pointer assumed to be nullable, even though it isn't + --> $DIR/fn_null_check.rs:17:8 + | +LL | if (fn_ptr as *const ()) == ZPTR {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: try wrapping your function pointer type in `Option` instead, and using `is_none` to check for null pointer value + +error: aborting due to 5 previous errors + diff --git a/tests/ui/manual_filter.fixed b/tests/ui/manual_filter.fixed index 3553291b87df6..ef6780dc96d9c 100644 --- a/tests/ui/manual_filter.fixed +++ b/tests/ui/manual_filter.fixed @@ -116,4 +116,45 @@ fn main() { }, None => None, }; + + match Some(20) { + // Don't Lint, because `Some(3*x)` is not `None` + None => None, + Some(x) => { + if x > 0 { + Some(3 * x) + } else { + Some(x) + } + }, + }; + + // Don't lint: https://github.com/rust-lang/rust-clippy/issues/10088 + let result = if let Some(a) = maybe_some() { + if let Some(b) = maybe_some() { + Some(a + b) + } else { + Some(a) + } + } else { + None + }; + + let allowed_integers = vec![3, 4, 5, 6]; + // Don't lint, since there's a side effect in the else branch + match Some(21) { + Some(x) => { + if allowed_integers.contains(&x) { + Some(x) + } else { + println!("Invalid integer: {x:?}"); + None + } + }, + None => None, + }; +} + +fn maybe_some() -> Option { + Some(0) } diff --git a/tests/ui/manual_filter.rs b/tests/ui/manual_filter.rs index aa9f90f752b17..ea0ce83172b7d 100644 --- a/tests/ui/manual_filter.rs +++ b/tests/ui/manual_filter.rs @@ -240,4 +240,45 @@ fn main() { }, None => None, }; + + match Some(20) { + // Don't Lint, because `Some(3*x)` is not `None` + None => None, + Some(x) => { + if x > 0 { + Some(3 * x) + } else { + Some(x) + } + }, + }; + + // Don't lint: https://github.com/rust-lang/rust-clippy/issues/10088 + let result = if let Some(a) = maybe_some() { + if let Some(b) = maybe_some() { + Some(a + b) + } else { + Some(a) + } + } else { + None + }; + + let allowed_integers = vec![3, 4, 5, 6]; + // Don't lint, since there's a side effect in the else branch + match Some(21) { + Some(x) => { + if allowed_integers.contains(&x) { + Some(x) + } else { + println!("Invalid integer: {x:?}"); + None + } + }, + None => None, + }; +} + +fn maybe_some() -> Option { + Some(0) } diff --git a/tests/ui/manual_retain.fixed b/tests/ui/manual_retain.fixed index e5ae3cf3e5033..8f25fea678f19 100644 --- a/tests/ui/manual_retain.fixed +++ b/tests/ui/manual_retain.fixed @@ -1,6 +1,6 @@ // run-rustfix #![warn(clippy::manual_retain)] -#![allow(unused)] +#![allow(unused, clippy::redundant_clone)] use std::collections::BTreeMap; use std::collections::BTreeSet; use std::collections::BinaryHeap; diff --git a/tests/ui/manual_retain.rs b/tests/ui/manual_retain.rs index 1021f15edd1ea..e6b3995a689b3 100644 --- a/tests/ui/manual_retain.rs +++ b/tests/ui/manual_retain.rs @@ -1,6 +1,6 @@ // run-rustfix #![warn(clippy::manual_retain)] -#![allow(unused)] +#![allow(unused, clippy::redundant_clone)] use std::collections::BTreeMap; use std::collections::BTreeSet; use std::collections::BinaryHeap; diff --git a/tests/ui/match_single_binding.fixed b/tests/ui/match_single_binding.fixed index a6e315e4773a2..6cfb6661a0394 100644 --- a/tests/ui/match_single_binding.fixed +++ b/tests/ui/match_single_binding.fixed @@ -133,3 +133,16 @@ fn issue_9575() { println!("Needs curlies"); }; } + +#[allow(dead_code)] +fn issue_9725(r: Option) { + let x = r; + match x { + Some(_) => { + println!("Some"); + }, + None => { + println!("None"); + }, + }; +} diff --git a/tests/ui/match_single_binding.rs b/tests/ui/match_single_binding.rs index cecbd703e5669..f188aeb5f2ff5 100644 --- a/tests/ui/match_single_binding.rs +++ b/tests/ui/match_single_binding.rs @@ -148,3 +148,17 @@ fn issue_9575() { _ => println!("Needs curlies"), }; } + +#[allow(dead_code)] +fn issue_9725(r: Option) { + match r { + x => match x { + Some(_) => { + println!("Some"); + }, + None => { + println!("None"); + }, + }, + }; +} diff --git a/tests/ui/match_single_binding.stderr b/tests/ui/match_single_binding.stderr index 2b9ec7ee7026e..e960d64ad2b03 100644 --- a/tests/ui/match_single_binding.stderr +++ b/tests/ui/match_single_binding.stderr @@ -213,5 +213,30 @@ LL + println!("Needs curlies"); LL ~ }; | -error: aborting due to 14 previous errors +error: this match could be written as a `let` statement + --> $DIR/match_single_binding.rs:154:5 + | +LL | / match r { +LL | | x => match x { +LL | | Some(_) => { +LL | | println!("Some"); +... | +LL | | }, +LL | | }; + | |_____^ + | +help: consider using a `let` statement + | +LL ~ let x = r; +LL + match x { +LL + Some(_) => { +LL + println!("Some"); +LL + }, +LL + None => { +LL + println!("None"); +LL + }, +LL ~ }; + | + +error: aborting due to 15 previous errors diff --git a/tests/ui/match_wildcard_for_single_variants.fixed b/tests/ui/match_wildcard_for_single_variants.fixed index e675c183ea711..fc252cdd35294 100644 --- a/tests/ui/match_wildcard_for_single_variants.fixed +++ b/tests/ui/match_wildcard_for_single_variants.fixed @@ -132,3 +132,25 @@ fn main() { } } } + +mod issue9993 { + enum Foo { + A(bool), + B, + } + + fn test() { + let _ = match Foo::A(true) { + _ if false => 0, + Foo::A(true) => 1, + Foo::A(false) => 2, + Foo::B => 3, + }; + + let _ = match Foo::B { + _ if false => 0, + Foo::A(_) => 1, + Foo::B => 2, + }; + } +} diff --git a/tests/ui/match_wildcard_for_single_variants.rs b/tests/ui/match_wildcard_for_single_variants.rs index 38c3ffc00c71b..9a5c849e6ec9a 100644 --- a/tests/ui/match_wildcard_for_single_variants.rs +++ b/tests/ui/match_wildcard_for_single_variants.rs @@ -132,3 +132,25 @@ fn main() { } } } + +mod issue9993 { + enum Foo { + A(bool), + B, + } + + fn test() { + let _ = match Foo::A(true) { + _ if false => 0, + Foo::A(true) => 1, + Foo::A(false) => 2, + Foo::B => 3, + }; + + let _ = match Foo::B { + _ if false => 0, + Foo::A(_) => 1, + _ => 2, + }; + } +} diff --git a/tests/ui/match_wildcard_for_single_variants.stderr b/tests/ui/match_wildcard_for_single_variants.stderr index 34538dea8e5f4..6fa313dc91114 100644 --- a/tests/ui/match_wildcard_for_single_variants.stderr +++ b/tests/ui/match_wildcard_for_single_variants.stderr @@ -48,5 +48,11 @@ error: wildcard matches only a single variant and will also match any future add LL | _ => (), | ^ help: try this: `Color::Blue` -error: aborting due to 8 previous errors +error: wildcard matches only a single variant and will also match any future added variants + --> $DIR/match_wildcard_for_single_variants.rs:153:13 + | +LL | _ => 2, + | ^ help: try this: `Foo::B` + +error: aborting due to 9 previous errors diff --git a/tests/ui/needless_borrow.fixed b/tests/ui/needless_borrow.fixed index 4cb7f6b687f11..31e1cb6c3d7f7 100644 --- a/tests/ui/needless_borrow.fixed +++ b/tests/ui/needless_borrow.fixed @@ -1,5 +1,5 @@ // run-rustfix -#![feature(lint_reasons)] +#![feature(custom_inner_attributes, lint_reasons, rustc_private)] #![allow( unused, clippy::uninlined_format_args, @@ -491,3 +491,14 @@ mod issue_9782_method_variant { S.foo::<&[u8; 100]>(&a); } } + +extern crate rustc_lint; +extern crate rustc_span; + +#[allow(dead_code)] +mod span_lint { + use rustc_lint::{LateContext, Lint, LintContext}; + fn foo(cx: &LateContext<'_>, lint: &'static Lint) { + cx.struct_span_lint(lint, rustc_span::Span::default(), "", |diag| diag.note(String::new())); + } +} diff --git a/tests/ui/needless_borrow.rs b/tests/ui/needless_borrow.rs index 9a01190ed8dbd..55c2738fcf273 100644 --- a/tests/ui/needless_borrow.rs +++ b/tests/ui/needless_borrow.rs @@ -1,5 +1,5 @@ // run-rustfix -#![feature(lint_reasons)] +#![feature(custom_inner_attributes, lint_reasons, rustc_private)] #![allow( unused, clippy::uninlined_format_args, @@ -491,3 +491,14 @@ mod issue_9782_method_variant { S.foo::<&[u8; 100]>(&a); } } + +extern crate rustc_lint; +extern crate rustc_span; + +#[allow(dead_code)] +mod span_lint { + use rustc_lint::{LateContext, Lint, LintContext}; + fn foo(cx: &LateContext<'_>, lint: &'static Lint) { + cx.struct_span_lint(lint, rustc_span::Span::default(), "", |diag| diag.note(&String::new())); + } +} diff --git a/tests/ui/needless_borrow.stderr b/tests/ui/needless_borrow.stderr index d26c317124b8d..98a48d68317b4 100644 --- a/tests/ui/needless_borrow.stderr +++ b/tests/ui/needless_borrow.stderr @@ -216,5 +216,11 @@ error: the borrowed expression implements the required traits LL | foo(&a); | ^^ help: change this to: `a` -error: aborting due to 36 previous errors +error: the borrowed expression implements the required traits + --> $DIR/needless_borrow.rs:502:85 + | +LL | cx.struct_span_lint(lint, rustc_span::Span::default(), "", |diag| diag.note(&String::new())); + | ^^^^^^^^^^^^^^ help: change this to: `String::new()` + +error: aborting due to 37 previous errors diff --git a/tests/ui/needless_return.fixed b/tests/ui/needless_return.fixed index 4386aaec49e24..d451be1f389a7 100644 --- a/tests/ui/needless_return.fixed +++ b/tests/ui/needless_return.fixed @@ -1,6 +1,7 @@ // run-rustfix #![feature(lint_reasons)] +#![feature(yeet_expr)] #![allow(unused)] #![allow( clippy::if_same_then_else, @@ -272,4 +273,8 @@ mod issue9416 { } } +fn issue9947() -> Result<(), String> { + do yeet "hello"; +} + fn main() {} diff --git a/tests/ui/needless_return.rs b/tests/ui/needless_return.rs index 666dc54b76b41..e1a1bea2c0b85 100644 --- a/tests/ui/needless_return.rs +++ b/tests/ui/needless_return.rs @@ -1,6 +1,7 @@ // run-rustfix #![feature(lint_reasons)] +#![feature(yeet_expr)] #![allow(unused)] #![allow( clippy::if_same_then_else, @@ -282,4 +283,8 @@ mod issue9416 { } } +fn issue9947() -> Result<(), String> { + do yeet "hello"; +} + fn main() {} diff --git a/tests/ui/needless_return.stderr b/tests/ui/needless_return.stderr index a8b5d86cd5581..ca2253e658637 100644 --- a/tests/ui/needless_return.stderr +++ b/tests/ui/needless_return.stderr @@ -1,5 +1,5 @@ error: unneeded `return` statement - --> $DIR/needless_return.rs:26:5 + --> $DIR/needless_return.rs:27:5 | LL | return true; | ^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | return true; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:30:5 + --> $DIR/needless_return.rs:31:5 | LL | return true; | ^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | return true; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:35:9 + --> $DIR/needless_return.rs:36:9 | LL | return true; | ^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL | return true; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:37:9 + --> $DIR/needless_return.rs:38:9 | LL | return false; | ^^^^^^^^^^^^ @@ -32,7 +32,7 @@ LL | return false; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:43:17 + --> $DIR/needless_return.rs:44:17 | LL | true => return false, | ^^^^^^^^^^^^ @@ -40,7 +40,7 @@ LL | true => return false, = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:45:13 + --> $DIR/needless_return.rs:46:13 | LL | return true; | ^^^^^^^^^^^ @@ -48,7 +48,7 @@ LL | return true; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:52:9 + --> $DIR/needless_return.rs:53:9 | LL | return true; | ^^^^^^^^^^^ @@ -56,7 +56,7 @@ LL | return true; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:54:16 + --> $DIR/needless_return.rs:55:16 | LL | let _ = || return true; | ^^^^^^^^^^^ @@ -64,7 +64,7 @@ LL | let _ = || return true; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:58:5 + --> $DIR/needless_return.rs:59:5 | LL | return the_answer!(); | ^^^^^^^^^^^^^^^^^^^^ @@ -72,7 +72,7 @@ LL | return the_answer!(); = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:61:21 + --> $DIR/needless_return.rs:62:21 | LL | fn test_void_fun() { | _____________________^ @@ -82,7 +82,7 @@ LL | | return; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:66:11 + --> $DIR/needless_return.rs:67:11 | LL | if b { | ___________^ @@ -92,7 +92,7 @@ LL | | return; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:68:13 + --> $DIR/needless_return.rs:69:13 | LL | } else { | _____________^ @@ -102,7 +102,7 @@ LL | | return; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:76:14 + --> $DIR/needless_return.rs:77:14 | LL | _ => return, | ^^^^^^ @@ -110,7 +110,7 @@ LL | _ => return, = help: replace `return` with a unit value error: unneeded `return` statement - --> $DIR/needless_return.rs:84:24 + --> $DIR/needless_return.rs:85:24 | LL | let _ = 42; | ________________________^ @@ -120,7 +120,7 @@ LL | | return; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:87:14 + --> $DIR/needless_return.rs:88:14 | LL | _ => return, | ^^^^^^ @@ -128,7 +128,7 @@ LL | _ => return, = help: replace `return` with a unit value error: unneeded `return` statement - --> $DIR/needless_return.rs:100:9 + --> $DIR/needless_return.rs:101:9 | LL | return String::from("test"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -136,7 +136,7 @@ LL | return String::from("test"); = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:102:9 + --> $DIR/needless_return.rs:103:9 | LL | return String::new(); | ^^^^^^^^^^^^^^^^^^^^ @@ -144,7 +144,7 @@ LL | return String::new(); = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:124:32 + --> $DIR/needless_return.rs:125:32 | LL | bar.unwrap_or_else(|_| return) | ^^^^^^ @@ -152,7 +152,7 @@ LL | bar.unwrap_or_else(|_| return) = help: replace `return` with an empty block error: unneeded `return` statement - --> $DIR/needless_return.rs:128:21 + --> $DIR/needless_return.rs:129:21 | LL | let _ = || { | _____________________^ @@ -162,7 +162,7 @@ LL | | return; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:131:20 + --> $DIR/needless_return.rs:132:20 | LL | let _ = || return; | ^^^^^^ @@ -170,7 +170,7 @@ LL | let _ = || return; = help: replace `return` with an empty block error: unneeded `return` statement - --> $DIR/needless_return.rs:137:32 + --> $DIR/needless_return.rs:138:32 | LL | res.unwrap_or_else(|_| return Foo) | ^^^^^^^^^^ @@ -178,7 +178,7 @@ LL | res.unwrap_or_else(|_| return Foo) = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:146:5 + --> $DIR/needless_return.rs:147:5 | LL | return true; | ^^^^^^^^^^^ @@ -186,7 +186,7 @@ LL | return true; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:150:5 + --> $DIR/needless_return.rs:151:5 | LL | return true; | ^^^^^^^^^^^ @@ -194,7 +194,7 @@ LL | return true; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:155:9 + --> $DIR/needless_return.rs:156:9 | LL | return true; | ^^^^^^^^^^^ @@ -202,7 +202,7 @@ LL | return true; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:157:9 + --> $DIR/needless_return.rs:158:9 | LL | return false; | ^^^^^^^^^^^^ @@ -210,7 +210,7 @@ LL | return false; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:163:17 + --> $DIR/needless_return.rs:164:17 | LL | true => return false, | ^^^^^^^^^^^^ @@ -218,7 +218,7 @@ LL | true => return false, = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:165:13 + --> $DIR/needless_return.rs:166:13 | LL | return true; | ^^^^^^^^^^^ @@ -226,7 +226,7 @@ LL | return true; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:172:9 + --> $DIR/needless_return.rs:173:9 | LL | return true; | ^^^^^^^^^^^ @@ -234,7 +234,7 @@ LL | return true; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:174:16 + --> $DIR/needless_return.rs:175:16 | LL | let _ = || return true; | ^^^^^^^^^^^ @@ -242,7 +242,7 @@ LL | let _ = || return true; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:178:5 + --> $DIR/needless_return.rs:179:5 | LL | return the_answer!(); | ^^^^^^^^^^^^^^^^^^^^ @@ -250,7 +250,7 @@ LL | return the_answer!(); = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:181:33 + --> $DIR/needless_return.rs:182:33 | LL | async fn async_test_void_fun() { | _________________________________^ @@ -260,7 +260,7 @@ LL | | return; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:186:11 + --> $DIR/needless_return.rs:187:11 | LL | if b { | ___________^ @@ -270,7 +270,7 @@ LL | | return; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:188:13 + --> $DIR/needless_return.rs:189:13 | LL | } else { | _____________^ @@ -280,7 +280,7 @@ LL | | return; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:196:14 + --> $DIR/needless_return.rs:197:14 | LL | _ => return, | ^^^^^^ @@ -288,7 +288,7 @@ LL | _ => return, = help: replace `return` with a unit value error: unneeded `return` statement - --> $DIR/needless_return.rs:209:9 + --> $DIR/needless_return.rs:210:9 | LL | return String::from("test"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -296,7 +296,7 @@ LL | return String::from("test"); = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:211:9 + --> $DIR/needless_return.rs:212:9 | LL | return String::new(); | ^^^^^^^^^^^^^^^^^^^^ @@ -304,7 +304,7 @@ LL | return String::new(); = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:227:5 + --> $DIR/needless_return.rs:228:5 | LL | return format!("Hello {}", "world!"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -312,7 +312,7 @@ LL | return format!("Hello {}", "world!"); = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:238:9 + --> $DIR/needless_return.rs:239:9 | LL | return true; | ^^^^^^^^^^^ @@ -320,7 +320,7 @@ LL | return true; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:240:9 + --> $DIR/needless_return.rs:241:9 | LL | return false; | ^^^^^^^^^^^^ @@ -328,7 +328,7 @@ LL | return false; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:247:13 + --> $DIR/needless_return.rs:248:13 | LL | return 10; | ^^^^^^^^^ @@ -336,7 +336,7 @@ LL | return 10; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:250:13 + --> $DIR/needless_return.rs:251:13 | LL | return 100; | ^^^^^^^^^^ @@ -344,7 +344,7 @@ LL | return 100; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:258:9 + --> $DIR/needless_return.rs:259:9 | LL | return 0; | ^^^^^^^^ @@ -352,7 +352,7 @@ LL | return 0; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:265:13 + --> $DIR/needless_return.rs:266:13 | LL | return *(x as *const isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -360,7 +360,7 @@ LL | return *(x as *const isize); = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:267:13 + --> $DIR/needless_return.rs:268:13 | LL | return !*(x as *const isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -368,7 +368,7 @@ LL | return !*(x as *const isize); = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:274:20 + --> $DIR/needless_return.rs:275:20 | LL | let _ = 42; | ____________________^ @@ -379,7 +379,7 @@ LL | | return; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:281:20 + --> $DIR/needless_return.rs:282:20 | LL | let _ = 42; return; | ^^^^^^^ diff --git a/tests/ui/permissions_set_readonly_false.rs b/tests/ui/permissions_set_readonly_false.rs new file mode 100644 index 0000000000000..28c00d100942c --- /dev/null +++ b/tests/ui/permissions_set_readonly_false.rs @@ -0,0 +1,29 @@ +#![allow(unused)] +#![warn(clippy::permissions_set_readonly_false)] + +use std::fs::File; + +struct A; + +impl A { + pub fn set_readonly(&mut self, b: bool) {} +} + +fn set_readonly(b: bool) {} + +fn main() { + let f = File::create("foo.txt").unwrap(); + let metadata = f.metadata().unwrap(); + let mut permissions = metadata.permissions(); + // lint here + permissions.set_readonly(false); + // no lint + permissions.set_readonly(true); + + let mut a = A; + // no lint here - a is not of type std::fs::Permissions + a.set_readonly(false); + + // no lint here - plain function + set_readonly(false); +} diff --git a/tests/ui/permissions_set_readonly_false.stderr b/tests/ui/permissions_set_readonly_false.stderr new file mode 100644 index 0000000000000..e7a8ee6cb19be --- /dev/null +++ b/tests/ui/permissions_set_readonly_false.stderr @@ -0,0 +1,13 @@ +error: call to `set_readonly` with argument `false` + --> $DIR/permissions_set_readonly_false.rs:19:5 + | +LL | permissions.set_readonly(false); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: on Unix platforms this results in the file being world writable + = help: you can set the desired permissions using `PermissionsExt`. For more information, see + https://doc.rust-lang.org/std/os/unix/fs/trait.PermissionsExt.html + = note: `-D clippy::permissions-set-readonly-false` implied by `-D warnings` + +error: aborting due to previous error + diff --git a/tests/ui/redundant_clone.fixed b/tests/ui/redundant_clone.fixed index 00b427450935d..a157b6a6f9adb 100644 --- a/tests/ui/redundant_clone.fixed +++ b/tests/ui/redundant_clone.fixed @@ -239,3 +239,9 @@ fn false_negative_5707() { let _z = x.clone(); // pr 7346 can't lint on `x` drop(y); } + +#[allow(unused, clippy::manual_retain)] +fn possible_borrower_improvements() { + let mut s = String::from("foobar"); + s = s.chars().filter(|&c| c != 'o').collect(); +} diff --git a/tests/ui/redundant_clone.rs b/tests/ui/redundant_clone.rs index f899127db8d04..430672e8b8df2 100644 --- a/tests/ui/redundant_clone.rs +++ b/tests/ui/redundant_clone.rs @@ -239,3 +239,9 @@ fn false_negative_5707() { let _z = x.clone(); // pr 7346 can't lint on `x` drop(y); } + +#[allow(unused, clippy::manual_retain)] +fn possible_borrower_improvements() { + let mut s = String::from("foobar"); + s = s.chars().filter(|&c| c != 'o').to_owned().collect(); +} diff --git a/tests/ui/redundant_clone.stderr b/tests/ui/redundant_clone.stderr index 782590034d051..1bacc2c76af15 100644 --- a/tests/ui/redundant_clone.stderr +++ b/tests/ui/redundant_clone.stderr @@ -179,5 +179,17 @@ note: this value is dropped without further use LL | foo(&x.clone(), move || { | ^ -error: aborting due to 15 previous errors +error: redundant clone + --> $DIR/redundant_clone.rs:246:40 + | +LL | s = s.chars().filter(|&c| c != 'o').to_owned().collect(); + | ^^^^^^^^^^^ help: remove this + | +note: this value is dropped without further use + --> $DIR/redundant_clone.rs:246:9 + | +LL | s = s.chars().filter(|&c| c != 'o').to_owned().collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 16 previous errors diff --git a/tests/ui/size_of_ref.rs b/tests/ui/size_of_ref.rs new file mode 100644 index 0000000000000..1e83ab82907d3 --- /dev/null +++ b/tests/ui/size_of_ref.rs @@ -0,0 +1,27 @@ +#![allow(unused)] +#![warn(clippy::size_of_ref)] + +use std::mem::size_of_val; + +fn main() { + let x = 5; + let y = &x; + + size_of_val(&x); // no lint + size_of_val(y); // no lint + + size_of_val(&&x); + size_of_val(&y); +} + +struct S { + field: u32, + data: Vec, +} + +impl S { + /// Get size of object including `self`, in bytes. + pub fn size(&self) -> usize { + std::mem::size_of_val(&self) + (std::mem::size_of::() * self.data.capacity()) + } +} diff --git a/tests/ui/size_of_ref.stderr b/tests/ui/size_of_ref.stderr new file mode 100644 index 0000000000000..d4c13ac3290b6 --- /dev/null +++ b/tests/ui/size_of_ref.stderr @@ -0,0 +1,27 @@ +error: argument to `std::mem::size_of_val()` is a reference to a reference + --> $DIR/size_of_ref.rs:13:5 + | +LL | size_of_val(&&x); + | ^^^^^^^^^^^^^^^^ + | + = help: dereference the argument to `std::mem::size_of_val()` to get the size of the value instead of the size of the reference-type + = note: `-D clippy::size-of-ref` implied by `-D warnings` + +error: argument to `std::mem::size_of_val()` is a reference to a reference + --> $DIR/size_of_ref.rs:14:5 + | +LL | size_of_val(&y); + | ^^^^^^^^^^^^^^^ + | + = help: dereference the argument to `std::mem::size_of_val()` to get the size of the value instead of the size of the reference-type + +error: argument to `std::mem::size_of_val()` is a reference to a reference + --> $DIR/size_of_ref.rs:25:9 + | +LL | std::mem::size_of_val(&self) + (std::mem::size_of::() * self.data.capacity()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: dereference the argument to `std::mem::size_of_val()` to get the size of the value instead of the size of the reference-type + +error: aborting due to 3 previous errors + diff --git a/tests/ui/transmute_null_to_fn.rs b/tests/ui/transmute_null_to_fn.rs new file mode 100644 index 0000000000000..b3ea3d9039e08 --- /dev/null +++ b/tests/ui/transmute_null_to_fn.rs @@ -0,0 +1,28 @@ +#![allow(dead_code)] +#![warn(clippy::transmute_null_to_fn)] +#![allow(clippy::zero_ptr)] + +// Easy to lint because these only span one line. +fn one_liners() { + unsafe { + let _: fn() = std::mem::transmute(0 as *const ()); + let _: fn() = std::mem::transmute(std::ptr::null::<()>()); + } +} + +pub const ZPTR: *const usize = 0 as *const _; +pub const NOT_ZPTR: *const usize = 1 as *const _; + +fn transmute_const() { + unsafe { + // Should raise a lint. + let _: fn() = std::mem::transmute(ZPTR); + // Should NOT raise a lint. + let _: fn() = std::mem::transmute(NOT_ZPTR); + } +} + +fn main() { + one_liners(); + transmute_const(); +} diff --git a/tests/ui/transmute_null_to_fn.stderr b/tests/ui/transmute_null_to_fn.stderr new file mode 100644 index 0000000000000..f0c65497d750e --- /dev/null +++ b/tests/ui/transmute_null_to_fn.stderr @@ -0,0 +1,27 @@ +error: transmuting a known null pointer into a function pointer + --> $DIR/transmute_null_to_fn.rs:8:23 + | +LL | let _: fn() = std::mem::transmute(0 as *const ()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this transmute results in undefined behavior + | + = help: try wrapping your function pointer type in `Option` instead, and using `None` as a null pointer value + = note: `-D clippy::transmute-null-to-fn` implied by `-D warnings` + +error: transmuting a known null pointer into a function pointer + --> $DIR/transmute_null_to_fn.rs:9:23 + | +LL | let _: fn() = std::mem::transmute(std::ptr::null::<()>()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this transmute results in undefined behavior + | + = help: try wrapping your function pointer type in `Option` instead, and using `None` as a null pointer value + +error: transmuting a known null pointer into a function pointer + --> $DIR/transmute_null_to_fn.rs:19:23 + | +LL | let _: fn() = std::mem::transmute(ZPTR); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ this transmute results in undefined behavior + | + = help: try wrapping your function pointer type in `Option` instead, and using `None` as a null pointer value + +error: aborting due to 3 previous errors + diff --git a/tests/ui/useless_conversion.fixed b/tests/ui/useless_conversion.fixed index 70ff08f365518..94b206d8e58f6 100644 --- a/tests/ui/useless_conversion.fixed +++ b/tests/ui/useless_conversion.fixed @@ -33,12 +33,71 @@ fn test_issue_3913() -> Result<(), std::io::Error> { Ok(()) } -fn test_issue_5833() -> Result<(), ()> { +fn dont_lint_into_iter_on_immutable_local_implementing_iterator_in_expr() { let text = "foo\r\nbar\n\nbaz\n"; let lines = text.lines(); if Some("ok") == lines.into_iter().next() {} +} - Ok(()) +fn lint_into_iter_on_mutable_local_implementing_iterator_in_expr() { + let text = "foo\r\nbar\n\nbaz\n"; + let mut lines = text.lines(); + if Some("ok") == lines.next() {} +} + +fn lint_into_iter_on_expr_implementing_iterator() { + let text = "foo\r\nbar\n\nbaz\n"; + let mut lines = text.lines(); + if Some("ok") == lines.next() {} +} + +fn lint_into_iter_on_expr_implementing_iterator_2() { + let text = "foo\r\nbar\n\nbaz\n"; + if Some("ok") == text.lines().next() {} +} + +#[allow(const_item_mutation)] +fn lint_into_iter_on_const_implementing_iterator() { + const NUMBERS: std::ops::Range = 0..10; + let _ = NUMBERS.next(); +} + +fn lint_into_iter_on_const_implementing_iterator_2() { + const NUMBERS: std::ops::Range = 0..10; + let mut n = NUMBERS; + n.next(); +} + +#[derive(Clone, Copy)] +struct CopiableCounter { + counter: u32, +} + +impl Iterator for CopiableCounter { + type Item = u32; + + fn next(&mut self) -> Option { + self.counter = self.counter.wrapping_add(1); + Some(self.counter) + } +} + +fn dont_lint_into_iter_on_copy_iter() { + let mut c = CopiableCounter { counter: 0 }; + assert_eq!(c.into_iter().next(), Some(1)); + assert_eq!(c.into_iter().next(), Some(1)); + assert_eq!(c.next(), Some(1)); + assert_eq!(c.next(), Some(2)); +} + +fn dont_lint_into_iter_on_static_copy_iter() { + static mut C: CopiableCounter = CopiableCounter { counter: 0 }; + unsafe { + assert_eq!(C.into_iter().next(), Some(1)); + assert_eq!(C.into_iter().next(), Some(1)); + assert_eq!(C.next(), Some(1)); + assert_eq!(C.next(), Some(2)); + } } fn main() { @@ -46,7 +105,15 @@ fn main() { test_generic2::(10i32); test_questionmark().unwrap(); test_issue_3913().unwrap(); - test_issue_5833().unwrap(); + + dont_lint_into_iter_on_immutable_local_implementing_iterator_in_expr(); + lint_into_iter_on_mutable_local_implementing_iterator_in_expr(); + lint_into_iter_on_expr_implementing_iterator(); + lint_into_iter_on_expr_implementing_iterator_2(); + lint_into_iter_on_const_implementing_iterator(); + lint_into_iter_on_const_implementing_iterator_2(); + dont_lint_into_iter_on_copy_iter(); + dont_lint_into_iter_on_static_copy_iter(); let _: String = "foo".into(); let _: String = From::from("foo"); diff --git a/tests/ui/useless_conversion.rs b/tests/ui/useless_conversion.rs index f2444a8f436bf..c7ae927941bf1 100644 --- a/tests/ui/useless_conversion.rs +++ b/tests/ui/useless_conversion.rs @@ -33,12 +33,71 @@ fn test_issue_3913() -> Result<(), std::io::Error> { Ok(()) } -fn test_issue_5833() -> Result<(), ()> { +fn dont_lint_into_iter_on_immutable_local_implementing_iterator_in_expr() { let text = "foo\r\nbar\n\nbaz\n"; let lines = text.lines(); if Some("ok") == lines.into_iter().next() {} +} - Ok(()) +fn lint_into_iter_on_mutable_local_implementing_iterator_in_expr() { + let text = "foo\r\nbar\n\nbaz\n"; + let mut lines = text.lines(); + if Some("ok") == lines.into_iter().next() {} +} + +fn lint_into_iter_on_expr_implementing_iterator() { + let text = "foo\r\nbar\n\nbaz\n"; + let mut lines = text.lines().into_iter(); + if Some("ok") == lines.next() {} +} + +fn lint_into_iter_on_expr_implementing_iterator_2() { + let text = "foo\r\nbar\n\nbaz\n"; + if Some("ok") == text.lines().into_iter().next() {} +} + +#[allow(const_item_mutation)] +fn lint_into_iter_on_const_implementing_iterator() { + const NUMBERS: std::ops::Range = 0..10; + let _ = NUMBERS.into_iter().next(); +} + +fn lint_into_iter_on_const_implementing_iterator_2() { + const NUMBERS: std::ops::Range = 0..10; + let mut n = NUMBERS.into_iter(); + n.next(); +} + +#[derive(Clone, Copy)] +struct CopiableCounter { + counter: u32, +} + +impl Iterator for CopiableCounter { + type Item = u32; + + fn next(&mut self) -> Option { + self.counter = self.counter.wrapping_add(1); + Some(self.counter) + } +} + +fn dont_lint_into_iter_on_copy_iter() { + let mut c = CopiableCounter { counter: 0 }; + assert_eq!(c.into_iter().next(), Some(1)); + assert_eq!(c.into_iter().next(), Some(1)); + assert_eq!(c.next(), Some(1)); + assert_eq!(c.next(), Some(2)); +} + +fn dont_lint_into_iter_on_static_copy_iter() { + static mut C: CopiableCounter = CopiableCounter { counter: 0 }; + unsafe { + assert_eq!(C.into_iter().next(), Some(1)); + assert_eq!(C.into_iter().next(), Some(1)); + assert_eq!(C.next(), Some(1)); + assert_eq!(C.next(), Some(2)); + } } fn main() { @@ -46,7 +105,15 @@ fn main() { test_generic2::(10i32); test_questionmark().unwrap(); test_issue_3913().unwrap(); - test_issue_5833().unwrap(); + + dont_lint_into_iter_on_immutable_local_implementing_iterator_in_expr(); + lint_into_iter_on_mutable_local_implementing_iterator_in_expr(); + lint_into_iter_on_expr_implementing_iterator(); + lint_into_iter_on_expr_implementing_iterator_2(); + lint_into_iter_on_const_implementing_iterator(); + lint_into_iter_on_const_implementing_iterator_2(); + dont_lint_into_iter_on_copy_iter(); + dont_lint_into_iter_on_static_copy_iter(); let _: String = "foo".into(); let _: String = From::from("foo"); diff --git a/tests/ui/useless_conversion.stderr b/tests/ui/useless_conversion.stderr index 65ee3807fa9d9..be067c6843ace 100644 --- a/tests/ui/useless_conversion.stderr +++ b/tests/ui/useless_conversion.stderr @@ -22,71 +22,101 @@ error: useless conversion to the same type: `i32` LL | let _: i32 = 0i32.into(); | ^^^^^^^^^^^ help: consider removing `.into()`: `0i32` +error: useless conversion to the same type: `std::str::Lines<'_>` + --> $DIR/useless_conversion.rs:45:22 + | +LL | if Some("ok") == lines.into_iter().next() {} + | ^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `lines` + +error: useless conversion to the same type: `std::str::Lines<'_>` + --> $DIR/useless_conversion.rs:50:21 + | +LL | let mut lines = text.lines().into_iter(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `text.lines()` + +error: useless conversion to the same type: `std::str::Lines<'_>` + --> $DIR/useless_conversion.rs:56:22 + | +LL | if Some("ok") == text.lines().into_iter().next() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `text.lines()` + +error: useless conversion to the same type: `std::ops::Range` + --> $DIR/useless_conversion.rs:62:13 + | +LL | let _ = NUMBERS.into_iter().next(); + | ^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `NUMBERS` + +error: useless conversion to the same type: `std::ops::Range` + --> $DIR/useless_conversion.rs:67:17 + | +LL | let mut n = NUMBERS.into_iter(); + | ^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `NUMBERS` + error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion.rs:61:21 + --> $DIR/useless_conversion.rs:128:21 | LL | let _: String = "foo".to_string().into(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `"foo".to_string()` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion.rs:62:21 + --> $DIR/useless_conversion.rs:129:21 | LL | let _: String = From::from("foo".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `From::from()`: `"foo".to_string()` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion.rs:63:13 + --> $DIR/useless_conversion.rs:130:13 | LL | let _ = String::from("foo".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `"foo".to_string()` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion.rs:64:13 + --> $DIR/useless_conversion.rs:131:13 | LL | let _ = String::from(format!("A: {:04}", 123)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `format!("A: {:04}", 123)` error: useless conversion to the same type: `std::str::Lines<'_>` - --> $DIR/useless_conversion.rs:65:13 + --> $DIR/useless_conversion.rs:132:13 | LL | let _ = "".lines().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `"".lines()` error: useless conversion to the same type: `std::vec::IntoIter` - --> $DIR/useless_conversion.rs:66:13 + --> $DIR/useless_conversion.rs:133:13 | LL | let _ = vec![1, 2, 3].into_iter().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![1, 2, 3].into_iter()` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion.rs:67:21 + --> $DIR/useless_conversion.rs:134:21 | LL | let _: String = format!("Hello {}", "world").into(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `format!("Hello {}", "world")` error: useless conversion to the same type: `i32` - --> $DIR/useless_conversion.rs:72:13 + --> $DIR/useless_conversion.rs:139:13 | LL | let _ = i32::from(a + b) * 3; | ^^^^^^^^^^^^^^^^ help: consider removing `i32::from()`: `(a + b)` error: useless conversion to the same type: `Foo<'a'>` - --> $DIR/useless_conversion.rs:78:23 + --> $DIR/useless_conversion.rs:145:23 | LL | let _: Foo<'a'> = s2.into(); | ^^^^^^^^^ help: consider removing `.into()`: `s2` error: useless conversion to the same type: `Foo<'a'>` - --> $DIR/useless_conversion.rs:80:13 + --> $DIR/useless_conversion.rs:147:13 | LL | let _ = Foo::<'a'>::from(s3); | ^^^^^^^^^^^^^^^^^^^^ help: consider removing `Foo::<'a'>::from()`: `s3` error: useless conversion to the same type: `std::vec::IntoIter>` - --> $DIR/useless_conversion.rs:82:13 + --> $DIR/useless_conversion.rs:149:13 | LL | let _ = vec![s4, s4, s4].into_iter().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![s4, s4, s4].into_iter()` -error: aborting due to 14 previous errors +error: aborting due to 19 previous errors diff --git a/tests/ui/wildcard_imports.fixed b/tests/ui/wildcard_imports.fixed index ef55f1c31a88b..0baec6f0b641e 100644 --- a/tests/ui/wildcard_imports.fixed +++ b/tests/ui/wildcard_imports.fixed @@ -5,7 +5,6 @@ // the 2015 edition here is needed because edition 2018 changed the module system // (see https://doc.rust-lang.org/edition-guide/rust-2018/path-changes.html) which means the lint // no longer detects some of the cases starting with Rust 2018. -// FIXME: We should likely add another edition 2021 test case for this lint #![warn(clippy::wildcard_imports)] #![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)] diff --git a/tests/ui/wildcard_imports.rs b/tests/ui/wildcard_imports.rs index b81285142069b..db591d56ab4d1 100644 --- a/tests/ui/wildcard_imports.rs +++ b/tests/ui/wildcard_imports.rs @@ -5,7 +5,6 @@ // the 2015 edition here is needed because edition 2018 changed the module system // (see https://doc.rust-lang.org/edition-guide/rust-2018/path-changes.html) which means the lint // no longer detects some of the cases starting with Rust 2018. -// FIXME: We should likely add another edition 2021 test case for this lint #![warn(clippy::wildcard_imports)] #![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)] diff --git a/tests/ui/wildcard_imports.stderr b/tests/ui/wildcard_imports.stderr index 626c1754fc82c..6b469cdfc4449 100644 --- a/tests/ui/wildcard_imports.stderr +++ b/tests/ui/wildcard_imports.stderr @@ -1,5 +1,5 @@ error: usage of wildcard import - --> $DIR/wildcard_imports.rs:16:5 + --> $DIR/wildcard_imports.rs:15:5 | LL | use crate::fn_mod::*; | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` @@ -7,85 +7,85 @@ LL | use crate::fn_mod::*; = note: `-D clippy::wildcard-imports` implied by `-D warnings` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:17:5 + --> $DIR/wildcard_imports.rs:16:5 | LL | use crate::mod_mod::*; | ^^^^^^^^^^^^^^^^^ help: try: `crate::mod_mod::inner_mod` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:18:5 + --> $DIR/wildcard_imports.rs:17:5 | LL | use crate::multi_fn_mod::*; | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:20:5 + --> $DIR/wildcard_imports.rs:19:5 | LL | use crate::struct_mod::*; | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::struct_mod::{A, inner_struct_mod}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:24:5 + --> $DIR/wildcard_imports.rs:23:5 | LL | use wildcard_imports_helper::inner::inner_for_self_import::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:25:5 + --> $DIR/wildcard_imports.rs:24:5 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:96:13 + --> $DIR/wildcard_imports.rs:95:13 | LL | use crate::fn_mod::*; | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:102:75 + --> $DIR/wildcard_imports.rs:101:75 | LL | use wildcard_imports_helper::inner::inner_for_self_import::{self, *}; | ^ help: try: `inner_extern_foo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:103:13 + --> $DIR/wildcard_imports.rs:102:13 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:114:20 + --> $DIR/wildcard_imports.rs:113:20 | LL | use self::{inner::*, inner2::*}; | ^^^^^^^^ help: try: `inner::inner_foo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:114:30 + --> $DIR/wildcard_imports.rs:113:30 | LL | use self::{inner::*, inner2::*}; | ^^^^^^^^^ help: try: `inner2::inner_bar` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:121:13 + --> $DIR/wildcard_imports.rs:120:13 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:150:9 + --> $DIR/wildcard_imports.rs:149:9 | LL | use crate::in_fn_test::*; | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:159:9 + --> $DIR/wildcard_imports.rs:158:9 | LL | use crate:: in_fn_test:: * ; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:160:9 + --> $DIR/wildcard_imports.rs:159:9 | LL | use crate:: fn_mod:: | _________^ @@ -93,37 +93,37 @@ LL | | *; | |_________^ help: try: `crate:: fn_mod::foo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:171:13 + --> $DIR/wildcard_imports.rs:170:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:206:17 + --> $DIR/wildcard_imports.rs:205:17 | LL | use super::*; | ^^^^^^^^ help: try: `super::insidefoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:214:13 + --> $DIR/wildcard_imports.rs:213:13 | LL | use super_imports::*; | ^^^^^^^^^^^^^^^^ help: try: `super_imports::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:223:17 + --> $DIR/wildcard_imports.rs:222:17 | LL | use super::super::*; | ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:232:13 + --> $DIR/wildcard_imports.rs:231:13 | LL | use super::super::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:240:13 + --> $DIR/wildcard_imports.rs:239:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` diff --git a/tests/ui/wildcard_imports_2021.edition2018.fixed b/tests/ui/wildcard_imports_2021.edition2018.fixed new file mode 100644 index 0000000000000..6d534a10edcd1 --- /dev/null +++ b/tests/ui/wildcard_imports_2021.edition2018.fixed @@ -0,0 +1,240 @@ +// revisions: edition2018 edition2021 +//[edition2018] edition:2018 +//[edition2021] edition:2021 +// run-rustfix +// aux-build:wildcard_imports_helper.rs + +#![warn(clippy::wildcard_imports)] +#![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)] +#![warn(unused_imports)] + +extern crate wildcard_imports_helper; + +use crate::fn_mod::foo; +use crate::mod_mod::inner_mod; +use crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}; +use crate::struct_mod::{A, inner_struct_mod}; + +#[allow(unused_imports)] +use wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar; +use wildcard_imports_helper::prelude::v1::*; +use wildcard_imports_helper::{ExternA, extern_foo}; + +use std::io::prelude::*; + +struct ReadFoo; + +impl Read for ReadFoo { + fn read(&mut self, _buf: &mut [u8]) -> std::io::Result { + Ok(0) + } +} + +mod fn_mod { + pub fn foo() {} +} + +mod mod_mod { + pub mod inner_mod { + pub fn foo() {} + } +} + +mod multi_fn_mod { + pub fn multi_foo() {} + pub fn multi_bar() {} + pub fn multi_baz() {} + pub mod multi_inner_mod { + pub fn foo() {} + } +} + +mod struct_mod { + pub struct A; + pub struct B; + pub mod inner_struct_mod { + pub struct C; + } + + #[macro_export] + macro_rules! double_struct_import_test { + () => { + let _ = A; + }; + } +} + +fn main() { + foo(); + multi_foo(); + multi_bar(); + multi_inner_mod::foo(); + inner_mod::foo(); + extern_foo(); + inner_extern_bar(); + + let _ = A; + let _ = inner_struct_mod::C; + let _ = ExternA; + let _ = PreludeModAnywhere; + + double_struct_import_test!(); + double_struct_import_test!(); +} + +mod in_fn_test { + pub use self::inner_exported::*; + #[allow(unused_imports)] + pub(crate) use self::inner_exported2::*; + + fn test_intern() { + use crate::fn_mod::foo; + + foo(); + } + + fn test_extern() { + use wildcard_imports_helper::inner::inner_for_self_import::{self, inner_extern_foo}; + use wildcard_imports_helper::{ExternA, extern_foo}; + + inner_for_self_import::inner_extern_foo(); + inner_extern_foo(); + + extern_foo(); + + let _ = ExternA; + } + + fn test_inner_nested() { + use self::{inner::inner_foo, inner2::inner_bar}; + + inner_foo(); + inner_bar(); + } + + fn test_extern_reexported() { + use wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}; + + extern_exported(); + let _ = ExternExportedStruct; + let _ = ExternExportedEnum::A; + } + + mod inner_exported { + pub fn exported() {} + pub struct ExportedStruct; + pub enum ExportedEnum { + A, + } + } + + mod inner_exported2 { + pub(crate) fn exported2() {} + } + + mod inner { + pub fn inner_foo() {} + } + + mod inner2 { + pub fn inner_bar() {} + } +} + +fn test_reexported() { + use crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}; + + exported(); + let _ = ExportedStruct; + let _ = ExportedEnum::A; +} + +#[rustfmt::skip] +fn test_weird_formatting() { + use crate:: in_fn_test::exported; + use crate:: fn_mod::foo; + + exported(); + foo(); +} + +mod super_imports { + fn foofoo() {} + + mod should_be_replaced { + use super::foofoo; + + fn with_super() { + let _ = foofoo(); + } + } + + mod test_should_pass { + use super::*; + + fn with_super() { + let _ = foofoo(); + } + } + + mod test_should_pass_inside_function { + fn with_super_inside_function() { + use super::*; + let _ = foofoo(); + } + } + + mod test_should_pass_further_inside { + fn insidefoo() {} + mod inner { + use super::*; + fn with_super() { + let _ = insidefoo(); + } + } + } + + mod should_be_replaced_further_inside { + fn insidefoo() {} + mod inner { + use super::insidefoo; + fn with_super() { + let _ = insidefoo(); + } + } + } + + mod use_explicit_should_be_replaced { + use crate::super_imports::foofoo; + + fn with_explicit() { + let _ = foofoo(); + } + } + + mod use_double_super_should_be_replaced { + mod inner { + use super::super::foofoo; + + fn with_double_super() { + let _ = foofoo(); + } + } + } + + mod use_super_explicit_should_be_replaced { + use super::super::super_imports::foofoo; + + fn with_super_explicit() { + let _ = foofoo(); + } + } + + mod attestation_should_be_replaced { + use super::foofoo; + + fn with_explicit() { + let _ = foofoo(); + } + } +} diff --git a/tests/ui/wildcard_imports_2021.edition2018.stderr b/tests/ui/wildcard_imports_2021.edition2018.stderr new file mode 100644 index 0000000000000..acca9f651b474 --- /dev/null +++ b/tests/ui/wildcard_imports_2021.edition2018.stderr @@ -0,0 +1,132 @@ +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:13:5 + | +LL | use crate::fn_mod::*; + | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` + | + = note: `-D clippy::wildcard-imports` implied by `-D warnings` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:14:5 + | +LL | use crate::mod_mod::*; + | ^^^^^^^^^^^^^^^^^ help: try: `crate::mod_mod::inner_mod` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:15:5 + | +LL | use crate::multi_fn_mod::*; + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:16:5 + | +LL | use crate::struct_mod::*; + | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::struct_mod::{A, inner_struct_mod}` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:19:5 + | +LL | use wildcard_imports_helper::inner::inner_for_self_import::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:21:5 + | +LL | use wildcard_imports_helper::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:91:13 + | +LL | use crate::fn_mod::*; + | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:97:75 + | +LL | use wildcard_imports_helper::inner::inner_for_self_import::{self, *}; + | ^ help: try: `inner_extern_foo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:98:13 + | +LL | use wildcard_imports_helper::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:109:20 + | +LL | use self::{inner::*, inner2::*}; + | ^^^^^^^^ help: try: `inner::inner_foo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:109:30 + | +LL | use self::{inner::*, inner2::*}; + | ^^^^^^^^^ help: try: `inner2::inner_bar` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:116:13 + | +LL | use wildcard_imports_helper::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:145:9 + | +LL | use crate::in_fn_test::*; + | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:154:9 + | +LL | use crate:: in_fn_test:: * ; + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:155:9 + | +LL | use crate:: fn_mod:: + | _________^ +LL | | *; + | |_________^ help: try: `crate:: fn_mod::foo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:166:13 + | +LL | use super::*; + | ^^^^^^^^ help: try: `super::foofoo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:201:17 + | +LL | use super::*; + | ^^^^^^^^ help: try: `super::insidefoo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:209:13 + | +LL | use crate::super_imports::*; + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:218:17 + | +LL | use super::super::*; + | ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:227:13 + | +LL | use super::super::super_imports::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:235:13 + | +LL | use super::*; + | ^^^^^^^^ help: try: `super::foofoo` + +error: aborting due to 21 previous errors + diff --git a/tests/ui/wildcard_imports_2021.edition2021.fixed b/tests/ui/wildcard_imports_2021.edition2021.fixed new file mode 100644 index 0000000000000..6d534a10edcd1 --- /dev/null +++ b/tests/ui/wildcard_imports_2021.edition2021.fixed @@ -0,0 +1,240 @@ +// revisions: edition2018 edition2021 +//[edition2018] edition:2018 +//[edition2021] edition:2021 +// run-rustfix +// aux-build:wildcard_imports_helper.rs + +#![warn(clippy::wildcard_imports)] +#![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)] +#![warn(unused_imports)] + +extern crate wildcard_imports_helper; + +use crate::fn_mod::foo; +use crate::mod_mod::inner_mod; +use crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}; +use crate::struct_mod::{A, inner_struct_mod}; + +#[allow(unused_imports)] +use wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar; +use wildcard_imports_helper::prelude::v1::*; +use wildcard_imports_helper::{ExternA, extern_foo}; + +use std::io::prelude::*; + +struct ReadFoo; + +impl Read for ReadFoo { + fn read(&mut self, _buf: &mut [u8]) -> std::io::Result { + Ok(0) + } +} + +mod fn_mod { + pub fn foo() {} +} + +mod mod_mod { + pub mod inner_mod { + pub fn foo() {} + } +} + +mod multi_fn_mod { + pub fn multi_foo() {} + pub fn multi_bar() {} + pub fn multi_baz() {} + pub mod multi_inner_mod { + pub fn foo() {} + } +} + +mod struct_mod { + pub struct A; + pub struct B; + pub mod inner_struct_mod { + pub struct C; + } + + #[macro_export] + macro_rules! double_struct_import_test { + () => { + let _ = A; + }; + } +} + +fn main() { + foo(); + multi_foo(); + multi_bar(); + multi_inner_mod::foo(); + inner_mod::foo(); + extern_foo(); + inner_extern_bar(); + + let _ = A; + let _ = inner_struct_mod::C; + let _ = ExternA; + let _ = PreludeModAnywhere; + + double_struct_import_test!(); + double_struct_import_test!(); +} + +mod in_fn_test { + pub use self::inner_exported::*; + #[allow(unused_imports)] + pub(crate) use self::inner_exported2::*; + + fn test_intern() { + use crate::fn_mod::foo; + + foo(); + } + + fn test_extern() { + use wildcard_imports_helper::inner::inner_for_self_import::{self, inner_extern_foo}; + use wildcard_imports_helper::{ExternA, extern_foo}; + + inner_for_self_import::inner_extern_foo(); + inner_extern_foo(); + + extern_foo(); + + let _ = ExternA; + } + + fn test_inner_nested() { + use self::{inner::inner_foo, inner2::inner_bar}; + + inner_foo(); + inner_bar(); + } + + fn test_extern_reexported() { + use wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}; + + extern_exported(); + let _ = ExternExportedStruct; + let _ = ExternExportedEnum::A; + } + + mod inner_exported { + pub fn exported() {} + pub struct ExportedStruct; + pub enum ExportedEnum { + A, + } + } + + mod inner_exported2 { + pub(crate) fn exported2() {} + } + + mod inner { + pub fn inner_foo() {} + } + + mod inner2 { + pub fn inner_bar() {} + } +} + +fn test_reexported() { + use crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}; + + exported(); + let _ = ExportedStruct; + let _ = ExportedEnum::A; +} + +#[rustfmt::skip] +fn test_weird_formatting() { + use crate:: in_fn_test::exported; + use crate:: fn_mod::foo; + + exported(); + foo(); +} + +mod super_imports { + fn foofoo() {} + + mod should_be_replaced { + use super::foofoo; + + fn with_super() { + let _ = foofoo(); + } + } + + mod test_should_pass { + use super::*; + + fn with_super() { + let _ = foofoo(); + } + } + + mod test_should_pass_inside_function { + fn with_super_inside_function() { + use super::*; + let _ = foofoo(); + } + } + + mod test_should_pass_further_inside { + fn insidefoo() {} + mod inner { + use super::*; + fn with_super() { + let _ = insidefoo(); + } + } + } + + mod should_be_replaced_further_inside { + fn insidefoo() {} + mod inner { + use super::insidefoo; + fn with_super() { + let _ = insidefoo(); + } + } + } + + mod use_explicit_should_be_replaced { + use crate::super_imports::foofoo; + + fn with_explicit() { + let _ = foofoo(); + } + } + + mod use_double_super_should_be_replaced { + mod inner { + use super::super::foofoo; + + fn with_double_super() { + let _ = foofoo(); + } + } + } + + mod use_super_explicit_should_be_replaced { + use super::super::super_imports::foofoo; + + fn with_super_explicit() { + let _ = foofoo(); + } + } + + mod attestation_should_be_replaced { + use super::foofoo; + + fn with_explicit() { + let _ = foofoo(); + } + } +} diff --git a/tests/ui/wildcard_imports_2021.edition2021.stderr b/tests/ui/wildcard_imports_2021.edition2021.stderr new file mode 100644 index 0000000000000..acca9f651b474 --- /dev/null +++ b/tests/ui/wildcard_imports_2021.edition2021.stderr @@ -0,0 +1,132 @@ +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:13:5 + | +LL | use crate::fn_mod::*; + | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` + | + = note: `-D clippy::wildcard-imports` implied by `-D warnings` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:14:5 + | +LL | use crate::mod_mod::*; + | ^^^^^^^^^^^^^^^^^ help: try: `crate::mod_mod::inner_mod` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:15:5 + | +LL | use crate::multi_fn_mod::*; + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:16:5 + | +LL | use crate::struct_mod::*; + | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::struct_mod::{A, inner_struct_mod}` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:19:5 + | +LL | use wildcard_imports_helper::inner::inner_for_self_import::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:21:5 + | +LL | use wildcard_imports_helper::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:91:13 + | +LL | use crate::fn_mod::*; + | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:97:75 + | +LL | use wildcard_imports_helper::inner::inner_for_self_import::{self, *}; + | ^ help: try: `inner_extern_foo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:98:13 + | +LL | use wildcard_imports_helper::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:109:20 + | +LL | use self::{inner::*, inner2::*}; + | ^^^^^^^^ help: try: `inner::inner_foo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:109:30 + | +LL | use self::{inner::*, inner2::*}; + | ^^^^^^^^^ help: try: `inner2::inner_bar` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:116:13 + | +LL | use wildcard_imports_helper::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:145:9 + | +LL | use crate::in_fn_test::*; + | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:154:9 + | +LL | use crate:: in_fn_test:: * ; + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:155:9 + | +LL | use crate:: fn_mod:: + | _________^ +LL | | *; + | |_________^ help: try: `crate:: fn_mod::foo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:166:13 + | +LL | use super::*; + | ^^^^^^^^ help: try: `super::foofoo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:201:17 + | +LL | use super::*; + | ^^^^^^^^ help: try: `super::insidefoo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:209:13 + | +LL | use crate::super_imports::*; + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:218:17 + | +LL | use super::super::*; + | ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:227:13 + | +LL | use super::super::super_imports::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:235:13 + | +LL | use super::*; + | ^^^^^^^^ help: try: `super::foofoo` + +error: aborting due to 21 previous errors + diff --git a/tests/ui/wildcard_imports_2021.rs b/tests/ui/wildcard_imports_2021.rs new file mode 100644 index 0000000000000..b5ed58e68136f --- /dev/null +++ b/tests/ui/wildcard_imports_2021.rs @@ -0,0 +1,241 @@ +// revisions: edition2018 edition2021 +//[edition2018] edition:2018 +//[edition2021] edition:2021 +// run-rustfix +// aux-build:wildcard_imports_helper.rs + +#![warn(clippy::wildcard_imports)] +#![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)] +#![warn(unused_imports)] + +extern crate wildcard_imports_helper; + +use crate::fn_mod::*; +use crate::mod_mod::*; +use crate::multi_fn_mod::*; +use crate::struct_mod::*; + +#[allow(unused_imports)] +use wildcard_imports_helper::inner::inner_for_self_import::*; +use wildcard_imports_helper::prelude::v1::*; +use wildcard_imports_helper::*; + +use std::io::prelude::*; + +struct ReadFoo; + +impl Read for ReadFoo { + fn read(&mut self, _buf: &mut [u8]) -> std::io::Result { + Ok(0) + } +} + +mod fn_mod { + pub fn foo() {} +} + +mod mod_mod { + pub mod inner_mod { + pub fn foo() {} + } +} + +mod multi_fn_mod { + pub fn multi_foo() {} + pub fn multi_bar() {} + pub fn multi_baz() {} + pub mod multi_inner_mod { + pub fn foo() {} + } +} + +mod struct_mod { + pub struct A; + pub struct B; + pub mod inner_struct_mod { + pub struct C; + } + + #[macro_export] + macro_rules! double_struct_import_test { + () => { + let _ = A; + }; + } +} + +fn main() { + foo(); + multi_foo(); + multi_bar(); + multi_inner_mod::foo(); + inner_mod::foo(); + extern_foo(); + inner_extern_bar(); + + let _ = A; + let _ = inner_struct_mod::C; + let _ = ExternA; + let _ = PreludeModAnywhere; + + double_struct_import_test!(); + double_struct_import_test!(); +} + +mod in_fn_test { + pub use self::inner_exported::*; + #[allow(unused_imports)] + pub(crate) use self::inner_exported2::*; + + fn test_intern() { + use crate::fn_mod::*; + + foo(); + } + + fn test_extern() { + use wildcard_imports_helper::inner::inner_for_self_import::{self, *}; + use wildcard_imports_helper::*; + + inner_for_self_import::inner_extern_foo(); + inner_extern_foo(); + + extern_foo(); + + let _ = ExternA; + } + + fn test_inner_nested() { + use self::{inner::*, inner2::*}; + + inner_foo(); + inner_bar(); + } + + fn test_extern_reexported() { + use wildcard_imports_helper::*; + + extern_exported(); + let _ = ExternExportedStruct; + let _ = ExternExportedEnum::A; + } + + mod inner_exported { + pub fn exported() {} + pub struct ExportedStruct; + pub enum ExportedEnum { + A, + } + } + + mod inner_exported2 { + pub(crate) fn exported2() {} + } + + mod inner { + pub fn inner_foo() {} + } + + mod inner2 { + pub fn inner_bar() {} + } +} + +fn test_reexported() { + use crate::in_fn_test::*; + + exported(); + let _ = ExportedStruct; + let _ = ExportedEnum::A; +} + +#[rustfmt::skip] +fn test_weird_formatting() { + use crate:: in_fn_test:: * ; + use crate:: fn_mod:: + *; + + exported(); + foo(); +} + +mod super_imports { + fn foofoo() {} + + mod should_be_replaced { + use super::*; + + fn with_super() { + let _ = foofoo(); + } + } + + mod test_should_pass { + use super::*; + + fn with_super() { + let _ = foofoo(); + } + } + + mod test_should_pass_inside_function { + fn with_super_inside_function() { + use super::*; + let _ = foofoo(); + } + } + + mod test_should_pass_further_inside { + fn insidefoo() {} + mod inner { + use super::*; + fn with_super() { + let _ = insidefoo(); + } + } + } + + mod should_be_replaced_further_inside { + fn insidefoo() {} + mod inner { + use super::*; + fn with_super() { + let _ = insidefoo(); + } + } + } + + mod use_explicit_should_be_replaced { + use crate::super_imports::*; + + fn with_explicit() { + let _ = foofoo(); + } + } + + mod use_double_super_should_be_replaced { + mod inner { + use super::super::*; + + fn with_double_super() { + let _ = foofoo(); + } + } + } + + mod use_super_explicit_should_be_replaced { + use super::super::super_imports::*; + + fn with_super_explicit() { + let _ = foofoo(); + } + } + + mod attestation_should_be_replaced { + use super::*; + + fn with_explicit() { + let _ = foofoo(); + } + } +} diff --git a/tests/ui/wildcard_imports_2021.stderr b/tests/ui/wildcard_imports_2021.stderr new file mode 100644 index 0000000000000..92f6d31530fa8 --- /dev/null +++ b/tests/ui/wildcard_imports_2021.stderr @@ -0,0 +1,132 @@ +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:9:5 + | +LL | use crate::fn_mod::*; + | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` + | + = note: `-D clippy::wildcard-imports` implied by `-D warnings` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:10:5 + | +LL | use crate::mod_mod::*; + | ^^^^^^^^^^^^^^^^^ help: try: `crate::mod_mod::inner_mod` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:11:5 + | +LL | use crate::multi_fn_mod::*; + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:12:5 + | +LL | use crate::struct_mod::*; + | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::struct_mod::{A, inner_struct_mod}` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:15:5 + | +LL | use wildcard_imports_helper::inner::inner_for_self_import::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:17:5 + | +LL | use wildcard_imports_helper::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:87:13 + | +LL | use crate::fn_mod::*; + | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:93:75 + | +LL | use wildcard_imports_helper::inner::inner_for_self_import::{self, *}; + | ^ help: try: `inner_extern_foo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:94:13 + | +LL | use wildcard_imports_helper::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:105:20 + | +LL | use self::{inner::*, inner2::*}; + | ^^^^^^^^ help: try: `inner::inner_foo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:105:30 + | +LL | use self::{inner::*, inner2::*}; + | ^^^^^^^^^ help: try: `inner2::inner_bar` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:112:13 + | +LL | use wildcard_imports_helper::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:141:9 + | +LL | use crate::in_fn_test::*; + | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:150:9 + | +LL | use crate:: in_fn_test:: * ; + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:151:9 + | +LL | use crate:: fn_mod:: + | _________^ +LL | | *; + | |_________^ help: try: `crate:: fn_mod::foo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:162:13 + | +LL | use super::*; + | ^^^^^^^^ help: try: `super::foofoo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:197:17 + | +LL | use super::*; + | ^^^^^^^^ help: try: `super::insidefoo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:205:13 + | +LL | use crate::super_imports::*; + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:214:17 + | +LL | use super::super::*; + | ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:223:13 + | +LL | use super::super::super_imports::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:231:13 + | +LL | use super::*; + | ^^^^^^^^ help: try: `super::foofoo` + +error: aborting due to 21 previous errors + From 315bb10405ec6082f46c73791bed24a134a307c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 27 Dec 2022 11:03:59 -0800 Subject: [PATCH 07/51] Account for multiple multiline spans with empty padding Instead of ``` LL | fn oom( | __^ | | _| | || LL | || ) { | ||_- LL | | } | |__^ ``` emit ``` LL | // fn oom( LL | || ) { | ||_- LL | | } | |__^ ``` --- tests/ui/async_yields_async.stderr | 6 ++---- tests/ui/result_map_unit_fn_unfixable.stderr | 5 +---- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/tests/ui/async_yields_async.stderr b/tests/ui/async_yields_async.stderr index 92ba359296780..22ce1c6f6471b 100644 --- a/tests/ui/async_yields_async.stderr +++ b/tests/ui/async_yields_async.stderr @@ -3,8 +3,7 @@ error: an async construct yields a type which is itself awaitable | LL | let _h = async { | _____________________- -LL | | async { - | | _________^ +LL | |/ async { LL | || 3 LL | || } | ||_________^ awaitable value not awaited @@ -37,8 +36,7 @@ error: an async construct yields a type which is itself awaitable | LL | let _j = async || { | ________________________- -LL | | async { - | | _________^ +LL | |/ async { LL | || 3 LL | || } | ||_________^ awaitable value not awaited diff --git a/tests/ui/result_map_unit_fn_unfixable.stderr b/tests/ui/result_map_unit_fn_unfixable.stderr index 2e1eb8eb18066..d0e534f635682 100644 --- a/tests/ui/result_map_unit_fn_unfixable.stderr +++ b/tests/ui/result_map_unit_fn_unfixable.stderr @@ -19,10 +19,7 @@ LL | x.field.map(|value| if value > 0 { do_nothing(value); do_nothing(value) error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_unfixable.rs:29:5 | -LL | x.field.map(|value| { - | ______^ - | | _____| - | || +LL | // x.field.map(|value| { LL | || do_nothing(value); LL | || do_nothing(value) LL | || }); From 0298095ac21e8fd5eb5ead8edc1b49a365972cc4 Mon Sep 17 00:00:00 2001 From: Ray Redondo Date: Thu, 29 Dec 2022 14:48:36 -0600 Subject: [PATCH 08/51] add comment about mutex_atomic issue to description --- clippy_lints/src/mutex_atomic.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/mutex_atomic.rs b/clippy_lints/src/mutex_atomic.rs index 45bb217979aae..dc866ab6373bb 100644 --- a/clippy_lints/src/mutex_atomic.rs +++ b/clippy_lints/src/mutex_atomic.rs @@ -1,6 +1,6 @@ //! Checks for uses of mutex where an atomic value could be used //! -//! This lint is **warn** by default +//! This lint is **allow** by default use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::is_type_diagnostic_item; @@ -20,6 +20,10 @@ declare_clippy_lint! { /// `std::sync::atomic::AtomicBool` and `std::sync::atomic::AtomicPtr` are leaner and /// faster. /// + /// On the other hand, `Mutex`es are, in general, easier to + /// verify correctness. An atomic does not behave the same as + /// an equivalent mutex. See [this issue](https://github.com/rust-lang/rust-clippy/issues/4295)'s commentary for more details. + /// /// ### Known problems /// This lint cannot detect if the mutex is actually used /// for waiting before a critical section. @@ -40,7 +44,7 @@ declare_clippy_lint! { #[clippy::version = "pre 1.29.0"] pub MUTEX_ATOMIC, restriction, - "using a mutex where an atomic value could be used instead" + "using a mutex where an atomic value could be used instead." } declare_clippy_lint! { From 7a64a51818d73b36ca4fd2ff2bbcdabe3dcd9a5c Mon Sep 17 00:00:00 2001 From: Ardis Lu Date: Sat, 31 Dec 2022 02:14:20 -0800 Subject: [PATCH 09/51] Fix typo --- book/src/installation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/src/installation.md b/book/src/installation.md index b2a28d0be622f..cce888b17d4d3 100644 --- a/book/src/installation.md +++ b/book/src/installation.md @@ -1,6 +1,6 @@ # Installation -If you're using `rustup` to install and manage you're Rust toolchains, Clippy is +If you're using `rustup` to install and manage your Rust toolchains, Clippy is usually **already installed**. In that case you can skip this chapter and go to the [Usage] chapter. From da7c99b81e7f863539a88f0d6ad2b79076d425f0 Mon Sep 17 00:00:00 2001 From: Samuel Moelius Date: Sun, 1 Jan 2023 06:21:28 -0500 Subject: [PATCH 10/51] Fix typo in `unused_self` diagnostic message --- clippy_lints/src/unused_self.rs | 2 +- tests/ui/unused_self.stderr | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/clippy_lints/src/unused_self.rs b/clippy_lints/src/unused_self.rs index 42bccc7212b30..18231b6a7e869 100644 --- a/clippy_lints/src/unused_self.rs +++ b/clippy_lints/src/unused_self.rs @@ -72,7 +72,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedSelf { self_param.span, "unused `self` argument", None, - "consider refactoring to a associated function", + "consider refactoring to an associated function", ); } } diff --git a/tests/ui/unused_self.stderr b/tests/ui/unused_self.stderr index 23186122a9af7..919f9b6efdab8 100644 --- a/tests/ui/unused_self.stderr +++ b/tests/ui/unused_self.stderr @@ -4,7 +4,7 @@ error: unused `self` argument LL | fn unused_self_move(self) {} | ^^^^ | - = help: consider refactoring to a associated function + = help: consider refactoring to an associated function = note: `-D clippy::unused-self` implied by `-D warnings` error: unused `self` argument @@ -13,7 +13,7 @@ error: unused `self` argument LL | fn unused_self_ref(&self) {} | ^^^^^ | - = help: consider refactoring to a associated function + = help: consider refactoring to an associated function error: unused `self` argument --> $DIR/unused_self.rs:13:32 @@ -21,7 +21,7 @@ error: unused `self` argument LL | fn unused_self_mut_ref(&mut self) {} | ^^^^^^^^^ | - = help: consider refactoring to a associated function + = help: consider refactoring to an associated function error: unused `self` argument --> $DIR/unused_self.rs:14:32 @@ -29,7 +29,7 @@ error: unused `self` argument LL | fn unused_self_pin_ref(self: Pin<&Self>) {} | ^^^^ | - = help: consider refactoring to a associated function + = help: consider refactoring to an associated function error: unused `self` argument --> $DIR/unused_self.rs:15:36 @@ -37,7 +37,7 @@ error: unused `self` argument LL | fn unused_self_pin_mut_ref(self: Pin<&mut Self>) {} | ^^^^ | - = help: consider refactoring to a associated function + = help: consider refactoring to an associated function error: unused `self` argument --> $DIR/unused_self.rs:16:35 @@ -45,7 +45,7 @@ error: unused `self` argument LL | fn unused_self_pin_nested(self: Pin>) {} | ^^^^ | - = help: consider refactoring to a associated function + = help: consider refactoring to an associated function error: unused `self` argument --> $DIR/unused_self.rs:17:28 @@ -53,7 +53,7 @@ error: unused `self` argument LL | fn unused_self_box(self: Box) {} | ^^^^ | - = help: consider refactoring to a associated function + = help: consider refactoring to an associated function error: unused `self` argument --> $DIR/unused_self.rs:18:40 @@ -61,7 +61,7 @@ error: unused `self` argument LL | fn unused_with_other_used_args(&self, x: u8, y: u8) -> u8 { | ^^^^^ | - = help: consider refactoring to a associated function + = help: consider refactoring to an associated function error: unused `self` argument --> $DIR/unused_self.rs:21:37 @@ -69,7 +69,7 @@ error: unused `self` argument LL | fn unused_self_class_method(&self) { | ^^^^^ | - = help: consider refactoring to a associated function + = help: consider refactoring to an associated function error: aborting due to 9 previous errors From 5b46f2db594fc3f2e8c6d8c7f9274ba77736b67c Mon Sep 17 00:00:00 2001 From: chansuke Date: Thu, 22 Dec 2022 22:59:06 +0900 Subject: [PATCH 11/51] chore: fix identation of `if_chain` in `filter_map` --- clippy_lints/src/methods/filter_map.rs | 174 ++++++++++++------------- 1 file changed, 87 insertions(+), 87 deletions(-) diff --git a/clippy_lints/src/methods/filter_map.rs b/clippy_lints/src/methods/filter_map.rs index f888c58a72de9..fc80f2eeae015 100644 --- a/clippy_lints/src/methods/filter_map.rs +++ b/clippy_lints/src/methods/filter_map.rs @@ -30,12 +30,12 @@ fn is_method(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol) -> match closure_expr.kind { hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, receiver, ..) => { if_chain! { - if ident.name == method_name; - if let hir::ExprKind::Path(path) = &receiver.kind; - if let Res::Local(ref local) = cx.qpath_res(path, receiver.hir_id); - then { - return arg_id == *local - } + if ident.name == method_name; + if let hir::ExprKind::Path(path) = &receiver.kind; + if let Res::Local(ref local) = cx.qpath_res(path, receiver.hir_id); + then { + return arg_id == *local + } } false }, @@ -92,92 +92,92 @@ pub(super) fn check( } if_chain! { - if is_trait_method(cx, map_recv, sym::Iterator); - - // filter(|x| ...is_some())... - if let ExprKind::Closure(&Closure { body: filter_body_id, .. }) = filter_arg.kind; - let filter_body = cx.tcx.hir().body(filter_body_id); - if let [filter_param] = filter_body.params; - // optional ref pattern: `filter(|&x| ..)` - let (filter_pat, is_filter_param_ref) = if let PatKind::Ref(ref_pat, _) = filter_param.pat.kind { - (ref_pat, true) - } else { - (filter_param.pat, false) + if is_trait_method(cx, map_recv, sym::Iterator); + + // filter(|x| ...is_some())... + if let ExprKind::Closure(&Closure { body: filter_body_id, .. }) = filter_arg.kind; + let filter_body = cx.tcx.hir().body(filter_body_id); + if let [filter_param] = filter_body.params; + // optional ref pattern: `filter(|&x| ..)` + let (filter_pat, is_filter_param_ref) = if let PatKind::Ref(ref_pat, _) = filter_param.pat.kind { + (ref_pat, true) + } else { + (filter_param.pat, false) + }; + // closure ends with is_some() or is_ok() + if let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind; + if let ExprKind::MethodCall(path, filter_arg, [], _) = filter_body.value.kind; + if let Some(opt_ty) = cx.typeck_results().expr_ty(filter_arg).peel_refs().ty_adt_def(); + if let Some(is_result) = if cx.tcx.is_diagnostic_item(sym::Option, opt_ty.did()) { + Some(false) + } else if cx.tcx.is_diagnostic_item(sym::Result, opt_ty.did()) { + Some(true) + } else { + None + }; + if path.ident.name.as_str() == if is_result { "is_ok" } else { "is_some" }; + + // ...map(|x| ...unwrap()) + if let ExprKind::Closure(&Closure { body: map_body_id, .. }) = map_arg.kind; + let map_body = cx.tcx.hir().body(map_body_id); + if let [map_param] = map_body.params; + if let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind; + // closure ends with expect() or unwrap() + if let ExprKind::MethodCall(seg, map_arg, ..) = map_body.value.kind; + if matches!(seg.ident.name, sym::expect | sym::unwrap | sym::unwrap_or); + + // .filter(..).map(|y| f(y).copied().unwrap()) + // ~~~~ + let map_arg_peeled = match map_arg.kind { + ExprKind::MethodCall(method, original_arg, [], _) if acceptable_methods(method) => { + original_arg + }, + _ => map_arg, + }; + + // .filter(|x| x.is_some()).map(|y| y[.acceptable_method()].unwrap()) + let simple_equal = path_to_local_id(filter_arg, filter_param_id) + && path_to_local_id(map_arg_peeled, map_param_id); + + let eq_fallback = |a: &Expr<'_>, b: &Expr<'_>| { + // in `filter(|x| ..)`, replace `*x` with `x` + let a_path = if_chain! { + if !is_filter_param_ref; + if let ExprKind::Unary(UnOp::Deref, expr_path) = a.kind; + then { expr_path } else { a } }; - // closure ends with is_some() or is_ok() - if let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind; - if let ExprKind::MethodCall(path, filter_arg, [], _) = filter_body.value.kind; - if let Some(opt_ty) = cx.typeck_results().expr_ty(filter_arg).peel_refs().ty_adt_def(); - if let Some(is_result) = if cx.tcx.is_diagnostic_item(sym::Option, opt_ty.did()) { - Some(false) - } else if cx.tcx.is_diagnostic_item(sym::Result, opt_ty.did()) { - Some(true) + // let the filter closure arg and the map closure arg be equal + path_to_local_id(a_path, filter_param_id) + && path_to_local_id(b, map_param_id) + && cx.typeck_results().expr_ty_adjusted(a) == cx.typeck_results().expr_ty_adjusted(b) + }; + + if simple_equal || SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(filter_arg, map_arg_peeled); + then { + let span = filter_span.with_hi(expr.span.hi()); + let (filter_name, lint) = if is_find { + ("find", MANUAL_FIND_MAP) } else { - None - }; - if path.ident.name.as_str() == if is_result { "is_ok" } else { "is_some" }; - - // ...map(|x| ...unwrap()) - if let ExprKind::Closure(&Closure { body: map_body_id, .. }) = map_arg.kind; - let map_body = cx.tcx.hir().body(map_body_id); - if let [map_param] = map_body.params; - if let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind; - // closure ends with expect() or unwrap() - if let ExprKind::MethodCall(seg, map_arg, ..) = map_body.value.kind; - if matches!(seg.ident.name, sym::expect | sym::unwrap | sym::unwrap_or); - - // .filter(..).map(|y| f(y).copied().unwrap()) - // ~~~~ - let map_arg_peeled = match map_arg.kind { - ExprKind::MethodCall(method, original_arg, [], _) if acceptable_methods(method) => { - original_arg - }, - _ => map_arg, + ("filter", MANUAL_FILTER_MAP) }; + let msg = format!("`{filter_name}(..).map(..)` can be simplified as `{filter_name}_map(..)`"); + let (to_opt, deref) = if is_result { + (".ok()", String::new()) + } else { + let derefs = cx.typeck_results() + .expr_adjustments(map_arg) + .iter() + .filter(|adj| matches!(adj.kind, Adjust::Deref(_))) + .count(); - // .filter(|x| x.is_some()).map(|y| y[.acceptable_method()].unwrap()) - let simple_equal = path_to_local_id(filter_arg, filter_param_id) - && path_to_local_id(map_arg_peeled, map_param_id); - - let eq_fallback = |a: &Expr<'_>, b: &Expr<'_>| { - // in `filter(|x| ..)`, replace `*x` with `x` - let a_path = if_chain! { - if !is_filter_param_ref; - if let ExprKind::Unary(UnOp::Deref, expr_path) = a.kind; - then { expr_path } else { a } - }; - // let the filter closure arg and the map closure arg be equal - path_to_local_id(a_path, filter_param_id) - && path_to_local_id(b, map_param_id) - && cx.typeck_results().expr_ty_adjusted(a) == cx.typeck_results().expr_ty_adjusted(b) + ("", "*".repeat(derefs)) }; - - if simple_equal || SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(filter_arg, map_arg_peeled); - then { - let span = filter_span.with_hi(expr.span.hi()); - let (filter_name, lint) = if is_find { - ("find", MANUAL_FIND_MAP) - } else { - ("filter", MANUAL_FILTER_MAP) - }; - let msg = format!("`{filter_name}(..).map(..)` can be simplified as `{filter_name}_map(..)`"); - let (to_opt, deref) = if is_result { - (".ok()", String::new()) - } else { - let derefs = cx.typeck_results() - .expr_adjustments(map_arg) - .iter() - .filter(|adj| matches!(adj.kind, Adjust::Deref(_))) - .count(); - - ("", "*".repeat(derefs)) - }; - let sugg = format!( - "{filter_name}_map(|{map_param_ident}| {deref}{}{to_opt})", - snippet(cx, map_arg.span, ".."), - ); - span_lint_and_sugg(cx, lint, span, &msg, "try", sugg, Applicability::MachineApplicable); - } + let sugg = format!( + "{filter_name}_map(|{map_param_ident}| {deref}{}{to_opt})", + snippet(cx, map_arg.span, ".."), + ); + span_lint_and_sugg(cx, lint, span, &msg, "try", sugg, Applicability::MachineApplicable); + } } } From 6145194b687b67e65049ac8d9ec730ebadfc34d7 Mon Sep 17 00:00:00 2001 From: chansuke Date: Thu, 22 Dec 2022 23:30:51 +0900 Subject: [PATCH 12/51] chore: add simple comment for `get_enclosing_block` --- clippy_utils/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 43e2d1ec826c2..c3eb4e229ca04 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1304,6 +1304,7 @@ pub fn get_parent_expr_for_hir<'tcx>(cx: &LateContext<'tcx>, hir_id: hir::HirId) } } +/// Gets the enclosing block, if any. pub fn get_enclosing_block<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Block<'tcx>> { let map = &cx.tcx.hir(); let enclosing_node = map From 8de011fdf72849e6dc25555bc1800632a66615f6 Mon Sep 17 00:00:00 2001 From: Eric Wu Date: Sun, 1 Jan 2023 21:23:32 -0500 Subject: [PATCH 13/51] don't lint field_reassign when field in closure This commit makes the ContainsName struct visit all interior expressions, which means that ContainsName will return true even if `name` is used in a closure within `expr`. --- clippy_lints/src/copies.rs | 6 +++++- clippy_lints/src/default.rs | 2 +- clippy_lints/src/loops/needless_range_loop.rs | 4 ++-- clippy_utils/src/lib.rs | 21 +++++++++++++++---- tests/ui/field_reassign_with_default.rs | 21 +++++++++++++++++++ 5 files changed, 46 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index 0e3d9317590f3..f10c35cde52a1 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -525,7 +525,11 @@ fn check_for_warn_of_moved_symbol(cx: &LateContext<'_>, symbols: &[(HirId, Symbo .iter() .filter(|&&(_, name)| !name.as_str().starts_with('_')) .any(|&(_, name)| { - let mut walker = ContainsName { name, result: false }; + let mut walker = ContainsName { + name, + result: false, + cx, + }; // Scan block block diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs index 7f937de1dd312..55f6121a09d2e 100644 --- a/clippy_lints/src/default.rs +++ b/clippy_lints/src/default.rs @@ -170,7 +170,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { // find out if and which field was set by this `consecutive_statement` if let Some((field_ident, assign_rhs)) = field_reassigned_by_stmt(consecutive_statement, binding_name) { // interrupt and cancel lint if assign_rhs references the original binding - if contains_name(binding_name, assign_rhs) { + if contains_name(binding_name, assign_rhs, cx) { cancel_lint = true; break; } diff --git a/clippy_lints/src/loops/needless_range_loop.rs b/clippy_lints/src/loops/needless_range_loop.rs index 27ba27202bf7e..3bca93d80aa7f 100644 --- a/clippy_lints/src/loops/needless_range_loop.rs +++ b/clippy_lints/src/loops/needless_range_loop.rs @@ -81,7 +81,7 @@ pub(super) fn check<'tcx>( let skip = if starts_at_zero { String::new() - } else if visitor.indexed_mut.contains(&indexed) && contains_name(indexed, start) { + } else if visitor.indexed_mut.contains(&indexed) && contains_name(indexed, start, cx) { return; } else { format!(".skip({})", snippet(cx, start.span, "..")) @@ -109,7 +109,7 @@ pub(super) fn check<'tcx>( if is_len_call(end, indexed) || is_end_eq_array_len(cx, end, limits, indexed_ty) { String::new() - } else if visitor.indexed_mut.contains(&indexed) && contains_name(indexed, take_expr) { + } else if visitor.indexed_mut.contains(&indexed) && contains_name(indexed, take_expr, cx) { return; } else { match limits { diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 43e2d1ec826c2..b2175c5cb169a 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -116,6 +116,8 @@ use crate::consts::{constant, Constant}; use crate::ty::{can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type, ty_is_fn_once_param}; use crate::visitors::for_each_expr; +use rustc_middle::hir::nested_filter; + #[macro_export] macro_rules! extract_msrv_attr { ($context:ident) => { @@ -1253,22 +1255,33 @@ pub fn get_item_name(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { } } -pub struct ContainsName { +pub struct ContainsName<'a, 'tcx> { + pub cx: &'a LateContext<'tcx>, pub name: Symbol, pub result: bool, } -impl<'tcx> Visitor<'tcx> for ContainsName { +impl<'a, 'tcx> Visitor<'tcx> for ContainsName<'a, 'tcx> { + type NestedFilter = nested_filter::All; + fn visit_name(&mut self, name: Symbol) { if self.name == name { self.result = true; } } + + fn nested_visit_map(&mut self) -> Self::Map { + self.cx.tcx.hir() + } } /// Checks if an `Expr` contains a certain name. -pub fn contains_name(name: Symbol, expr: &Expr<'_>) -> bool { - let mut cn = ContainsName { name, result: false }; +pub fn contains_name<'tcx>(name: Symbol, expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) -> bool { + let mut cn = ContainsName { + name, + result: false, + cx, + }; cn.visit_expr(expr); cn.result } diff --git a/tests/ui/field_reassign_with_default.rs b/tests/ui/field_reassign_with_default.rs index 7367910eaa126..1f989bb122052 100644 --- a/tests/ui/field_reassign_with_default.rs +++ b/tests/ui/field_reassign_with_default.rs @@ -247,3 +247,24 @@ mod issue6312 { } } } + +struct Collection { + items: Vec, + len: usize, +} + +impl Default for Collection { + fn default() -> Self { + Self { + items: vec![1, 2, 3], + len: 0, + } + } +} + +#[allow(clippy::redundant_closure_call)] +fn issue10136() { + let mut c = Collection::default(); + // don't lint, since c.items was used to calculate this value + c.len = (|| c.items.len())(); +} From 01a2a9df4300749f5c96209e707d02aae44f39e3 Mon Sep 17 00:00:00 2001 From: Eric Wu Date: Sun, 1 Jan 2023 19:10:21 -0500 Subject: [PATCH 14/51] [`drop_ref`]: don't lint idiomatic in match arm --- clippy_lints/src/drop_forget_ref.rs | 2 +- tests/ui/drop_ref.rs | 23 +++++++++++++++++ tests/ui/drop_ref.stderr | 38 ++++++++++++++++++++++++++++- 3 files changed, 61 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/drop_forget_ref.rs b/clippy_lints/src/drop_forget_ref.rs index 4721a7b370567..11e1bcdf12d1e 100644 --- a/clippy_lints/src/drop_forget_ref.rs +++ b/clippy_lints/src/drop_forget_ref.rs @@ -206,7 +206,7 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef { let is_copy = is_copy(cx, arg_ty); let drop_is_single_call_in_arm = is_single_call_in_arm(cx, arg, expr); let (lint, msg) = match fn_name { - sym::mem_drop if arg_ty.is_ref() => (DROP_REF, DROP_REF_SUMMARY), + sym::mem_drop if arg_ty.is_ref() && !drop_is_single_call_in_arm => (DROP_REF, DROP_REF_SUMMARY), sym::mem_forget if arg_ty.is_ref() => (FORGET_REF, FORGET_REF_SUMMARY), sym::mem_drop if is_copy && !drop_is_single_call_in_arm => (DROP_COPY, DROP_COPY_SUMMARY), sym::mem_forget if is_copy => (FORGET_COPY, FORGET_COPY_SUMMARY), diff --git a/tests/ui/drop_ref.rs b/tests/ui/drop_ref.rs index 7de0b0bbdf9ae..10044e65f1156 100644 --- a/tests/ui/drop_ref.rs +++ b/tests/ui/drop_ref.rs @@ -72,3 +72,26 @@ fn test_owl_result_2() -> Result { produce_half_owl_ok().map(drop)?; Ok(1) } + +#[allow(unused)] +#[allow(clippy::unit_cmp)] +fn issue10122(x: u8) { + // This is a function which returns a reference and has a side-effect, which means + // that calling drop() on the function is considered an idiomatic way of achieving the side-effect + // in a match arm. + fn println_and(t: &T) -> &T { + println!("foo"); + t + } + + match x { + 0 => drop(println_and(&12)), // Don't lint (copy type), we only care about side-effects + 1 => drop(println_and(&String::new())), // Don't lint (no copy type), we only care about side-effects + 2 => { + drop(println_and(&13)); // Lint, even if we only care about the side-effect, it's already in a block + }, + 3 if drop(println_and(&14)) == () => (), // Lint, idiomatic use is only in body of `Arm` + 4 => drop(&2), // Lint, not a fn/method call + _ => (), + } +} diff --git a/tests/ui/drop_ref.stderr b/tests/ui/drop_ref.stderr index 4743cf79b5d3c..293b9f6de832d 100644 --- a/tests/ui/drop_ref.stderr +++ b/tests/ui/drop_ref.stderr @@ -107,5 +107,41 @@ note: argument has type `&SomeStruct` LL | std::mem::drop(&SomeStruct); | ^^^^^^^^^^^ -error: aborting due to 9 previous errors +error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing + --> $DIR/drop_ref.rs:91:13 + | +LL | drop(println_and(&13)); // Lint, even if we only care about the side-effect, it's already in a block + | ^^^^^^^^^^^^^^^^^^^^^^ + | +note: argument has type `&i32` + --> $DIR/drop_ref.rs:91:18 + | +LL | drop(println_and(&13)); // Lint, even if we only care about the side-effect, it's already in a block + | ^^^^^^^^^^^^^^^^ + +error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing + --> $DIR/drop_ref.rs:93:14 + | +LL | 3 if drop(println_and(&14)) == () => (), // Lint, idiomatic use is only in body of `Arm` + | ^^^^^^^^^^^^^^^^^^^^^^ + | +note: argument has type `&i32` + --> $DIR/drop_ref.rs:93:19 + | +LL | 3 if drop(println_and(&14)) == () => (), // Lint, idiomatic use is only in body of `Arm` + | ^^^^^^^^^^^^^^^^ + +error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing + --> $DIR/drop_ref.rs:94:14 + | +LL | 4 => drop(&2), // Lint, not a fn/method call + | ^^^^^^^^ + | +note: argument has type `&i32` + --> $DIR/drop_ref.rs:94:19 + | +LL | 4 => drop(&2), // Lint, not a fn/method call + | ^^ + +error: aborting due to 12 previous errors From 7a1a9c8188eed7212eab35c820dcdff88cf0f3df Mon Sep 17 00:00:00 2001 From: Max Baumann Date: Mon, 2 Jan 2023 14:58:10 +0100 Subject: [PATCH 15/51] empty_structs_with_brackets: not MachineApplicable anymore --- clippy_lints/src/empty_structs_with_brackets.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/empty_structs_with_brackets.rs b/clippy_lints/src/empty_structs_with_brackets.rs index 08bf80a422900..c3a020433de85 100644 --- a/clippy_lints/src/empty_structs_with_brackets.rs +++ b/clippy_lints/src/empty_structs_with_brackets.rs @@ -45,7 +45,7 @@ impl EarlyLintPass for EmptyStructsWithBrackets { span_after_ident, "remove the brackets", ";", - Applicability::MachineApplicable); + Applicability::Unspecified); }, ); } From 9aef1a264a52d59e959e4b0a2f9a71d06c3def13 Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Sun, 1 Jan 2023 02:41:45 -0500 Subject: [PATCH 16/51] reword dbg_macro labels --- clippy_lints/src/dbg_macro.rs | 10 ++--- tests/ui-toml/dbg_macro/dbg_macro.stderr | 36 ++++++++-------- tests/ui/dbg_macro.stderr | 52 ++++++++++++------------ 3 files changed, 49 insertions(+), 49 deletions(-) diff --git a/clippy_lints/src/dbg_macro.rs b/clippy_lints/src/dbg_macro.rs index fe9f4f9ae3cb9..799e71e847a9f 100644 --- a/clippy_lints/src/dbg_macro.rs +++ b/clippy_lints/src/dbg_macro.rs @@ -10,11 +10,11 @@ use rustc_span::sym; declare_clippy_lint! { /// ### What it does - /// Checks for usage of dbg!() macro. + /// Checks for usage of the [`dbg!`](https://doc.rust-lang.org/std/macro.dbg.html) macro. /// /// ### Why is this bad? - /// `dbg!` macro is intended as a debugging tool. It - /// should not be in version control. + /// The `dbg!` macro is intended as a debugging tool. It should not be present in released + /// software or committed to a version control system. /// /// ### Example /// ```rust,ignore @@ -91,8 +91,8 @@ impl LateLintPass<'_> for DbgMacro { cx, DBG_MACRO, macro_call.span, - "`dbg!` macro is intended as a debugging tool", - "ensure to avoid having uses of it in version control", + "the `dbg!` macro is intended as a debugging tool", + "remove the invocation before committing it to a version control system", suggestion, applicability, ); diff --git a/tests/ui-toml/dbg_macro/dbg_macro.stderr b/tests/ui-toml/dbg_macro/dbg_macro.stderr index 46efb86dcfc5f..859383a71194f 100644 --- a/tests/ui-toml/dbg_macro/dbg_macro.stderr +++ b/tests/ui-toml/dbg_macro/dbg_macro.stderr @@ -1,99 +1,99 @@ -error: `dbg!` macro is intended as a debugging tool +error: the `dbg!` macro is intended as a debugging tool --> $DIR/dbg_macro.rs:5:22 | LL | if let Some(n) = dbg!(n.checked_sub(4)) { n } else { n } | ^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::dbg-macro` implied by `-D warnings` -help: ensure to avoid having uses of it in version control +help: remove the invocation before committing it to a version control system | LL | if let Some(n) = n.checked_sub(4) { n } else { n } | ~~~~~~~~~~~~~~~~ -error: `dbg!` macro is intended as a debugging tool +error: the `dbg!` macro is intended as a debugging tool --> $DIR/dbg_macro.rs:9:8 | LL | if dbg!(n <= 1) { | ^^^^^^^^^^^^ | -help: ensure to avoid having uses of it in version control +help: remove the invocation before committing it to a version control system | LL | if n <= 1 { | ~~~~~~ -error: `dbg!` macro is intended as a debugging tool +error: the `dbg!` macro is intended as a debugging tool --> $DIR/dbg_macro.rs:10:9 | LL | dbg!(1) | ^^^^^^^ | -help: ensure to avoid having uses of it in version control +help: remove the invocation before committing it to a version control system | LL | 1 | -error: `dbg!` macro is intended as a debugging tool +error: the `dbg!` macro is intended as a debugging tool --> $DIR/dbg_macro.rs:12:9 | LL | dbg!(n * factorial(n - 1)) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: ensure to avoid having uses of it in version control +help: remove the invocation before committing it to a version control system | LL | n * factorial(n - 1) | -error: `dbg!` macro is intended as a debugging tool +error: the `dbg!` macro is intended as a debugging tool --> $DIR/dbg_macro.rs:17:5 | LL | dbg!(42); | ^^^^^^^^ | -help: ensure to avoid having uses of it in version control +help: remove the invocation before committing it to a version control system | LL | 42; | ~~ -error: `dbg!` macro is intended as a debugging tool +error: the `dbg!` macro is intended as a debugging tool --> $DIR/dbg_macro.rs:18:5 | LL | dbg!(dbg!(dbg!(42))); | ^^^^^^^^^^^^^^^^^^^^ | -help: ensure to avoid having uses of it in version control +help: remove the invocation before committing it to a version control system | LL | dbg!(dbg!(42)); | ~~~~~~~~~~~~~~ -error: `dbg!` macro is intended as a debugging tool +error: the `dbg!` macro is intended as a debugging tool --> $DIR/dbg_macro.rs:19:14 | LL | foo(3) + dbg!(factorial(4)); | ^^^^^^^^^^^^^^^^^^ | -help: ensure to avoid having uses of it in version control +help: remove the invocation before committing it to a version control system | LL | foo(3) + factorial(4); | ~~~~~~~~~~~~ -error: `dbg!` macro is intended as a debugging tool +error: the `dbg!` macro is intended as a debugging tool --> $DIR/dbg_macro.rs:20:5 | LL | dbg!(1, 2, dbg!(3, 4)); | ^^^^^^^^^^^^^^^^^^^^^^ | -help: ensure to avoid having uses of it in version control +help: remove the invocation before committing it to a version control system | LL | (1, 2, dbg!(3, 4)); | ~~~~~~~~~~~~~~~~~~ -error: `dbg!` macro is intended as a debugging tool +error: the `dbg!` macro is intended as a debugging tool --> $DIR/dbg_macro.rs:21:5 | LL | dbg!(1, 2, 3, 4, 5); | ^^^^^^^^^^^^^^^^^^^ | -help: ensure to avoid having uses of it in version control +help: remove the invocation before committing it to a version control system | LL | (1, 2, 3, 4, 5); | ~~~~~~~~~~~~~~~ diff --git a/tests/ui/dbg_macro.stderr b/tests/ui/dbg_macro.stderr index e6a65b46d975c..ddb5f1342e994 100644 --- a/tests/ui/dbg_macro.stderr +++ b/tests/ui/dbg_macro.stderr @@ -1,143 +1,143 @@ -error: `dbg!` macro is intended as a debugging tool +error: the `dbg!` macro is intended as a debugging tool --> $DIR/dbg_macro.rs:5:22 | LL | if let Some(n) = dbg!(n.checked_sub(4)) { n } else { n } | ^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::dbg-macro` implied by `-D warnings` -help: ensure to avoid having uses of it in version control +help: remove the invocation before committing it to a version control system | LL | if let Some(n) = n.checked_sub(4) { n } else { n } | ~~~~~~~~~~~~~~~~ -error: `dbg!` macro is intended as a debugging tool +error: the `dbg!` macro is intended as a debugging tool --> $DIR/dbg_macro.rs:9:8 | LL | if dbg!(n <= 1) { | ^^^^^^^^^^^^ | -help: ensure to avoid having uses of it in version control +help: remove the invocation before committing it to a version control system | LL | if n <= 1 { | ~~~~~~ -error: `dbg!` macro is intended as a debugging tool +error: the `dbg!` macro is intended as a debugging tool --> $DIR/dbg_macro.rs:10:9 | LL | dbg!(1) | ^^^^^^^ | -help: ensure to avoid having uses of it in version control +help: remove the invocation before committing it to a version control system | LL | 1 | -error: `dbg!` macro is intended as a debugging tool +error: the `dbg!` macro is intended as a debugging tool --> $DIR/dbg_macro.rs:12:9 | LL | dbg!(n * factorial(n - 1)) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: ensure to avoid having uses of it in version control +help: remove the invocation before committing it to a version control system | LL | n * factorial(n - 1) | -error: `dbg!` macro is intended as a debugging tool +error: the `dbg!` macro is intended as a debugging tool --> $DIR/dbg_macro.rs:17:5 | LL | dbg!(42); | ^^^^^^^^ | -help: ensure to avoid having uses of it in version control +help: remove the invocation before committing it to a version control system | LL | 42; | ~~ -error: `dbg!` macro is intended as a debugging tool +error: the `dbg!` macro is intended as a debugging tool --> $DIR/dbg_macro.rs:18:5 | LL | dbg!(dbg!(dbg!(42))); | ^^^^^^^^^^^^^^^^^^^^ | -help: ensure to avoid having uses of it in version control +help: remove the invocation before committing it to a version control system | LL | dbg!(dbg!(42)); | ~~~~~~~~~~~~~~ -error: `dbg!` macro is intended as a debugging tool +error: the `dbg!` macro is intended as a debugging tool --> $DIR/dbg_macro.rs:19:14 | LL | foo(3) + dbg!(factorial(4)); | ^^^^^^^^^^^^^^^^^^ | -help: ensure to avoid having uses of it in version control +help: remove the invocation before committing it to a version control system | LL | foo(3) + factorial(4); | ~~~~~~~~~~~~ -error: `dbg!` macro is intended as a debugging tool +error: the `dbg!` macro is intended as a debugging tool --> $DIR/dbg_macro.rs:20:5 | LL | dbg!(1, 2, dbg!(3, 4)); | ^^^^^^^^^^^^^^^^^^^^^^ | -help: ensure to avoid having uses of it in version control +help: remove the invocation before committing it to a version control system | LL | (1, 2, dbg!(3, 4)); | ~~~~~~~~~~~~~~~~~~ -error: `dbg!` macro is intended as a debugging tool +error: the `dbg!` macro is intended as a debugging tool --> $DIR/dbg_macro.rs:21:5 | LL | dbg!(1, 2, 3, 4, 5); | ^^^^^^^^^^^^^^^^^^^ | -help: ensure to avoid having uses of it in version control +help: remove the invocation before committing it to a version control system | LL | (1, 2, 3, 4, 5); | ~~~~~~~~~~~~~~~ -error: `dbg!` macro is intended as a debugging tool +error: the `dbg!` macro is intended as a debugging tool --> $DIR/dbg_macro.rs:41:9 | LL | dbg!(2); | ^^^^^^^ | -help: ensure to avoid having uses of it in version control +help: remove the invocation before committing it to a version control system | LL | 2; | ~ -error: `dbg!` macro is intended as a debugging tool +error: the `dbg!` macro is intended as a debugging tool --> $DIR/dbg_macro.rs:47:5 | LL | dbg!(1); | ^^^^^^^ | -help: ensure to avoid having uses of it in version control +help: remove the invocation before committing it to a version control system | LL | 1; | ~ -error: `dbg!` macro is intended as a debugging tool +error: the `dbg!` macro is intended as a debugging tool --> $DIR/dbg_macro.rs:52:5 | LL | dbg!(1); | ^^^^^^^ | -help: ensure to avoid having uses of it in version control +help: remove the invocation before committing it to a version control system | LL | 1; | ~ -error: `dbg!` macro is intended as a debugging tool +error: the `dbg!` macro is intended as a debugging tool --> $DIR/dbg_macro.rs:58:9 | LL | dbg!(1); | ^^^^^^^ | -help: ensure to avoid having uses of it in version control +help: remove the invocation before committing it to a version control system | LL | 1; | ~ From f53c6e2f15a54dee84cbf20228a54861fa66bf09 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Mon, 2 Jan 2023 19:58:00 +0100 Subject: [PATCH 17/51] Correct Gankra's name in the linkedlist lint --- clippy_lints/src/types/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/types/mod.rs b/clippy_lints/src/types/mod.rs index 20978e81dc584..b0d49d268569f 100644 --- a/clippy_lints/src/types/mod.rs +++ b/clippy_lints/src/types/mod.rs @@ -127,7 +127,7 @@ declare_clippy_lint! { /// `Vec` or a `VecDeque` (formerly called `RingBuf`). /// /// ### Why is this bad? - /// Gankro says: + /// Gankra says: /// /// > The TL;DR of `LinkedList` is that it's built on a massive amount of /// pointers and indirection. From bd83650e91a751ad352444b458f9f50549fac208 Mon Sep 17 00:00:00 2001 From: Tyler Weaver Date: Wed, 21 Dec 2022 12:47:39 -0700 Subject: [PATCH 18/51] Suggest using Path for comparing extensions Signed-off-by: Tyler Weaver --- ...se_sensitive_file_extension_comparisons.rs | 38 +++++++-- ...sensitive_file_extension_comparisons.fixed | 64 +++++++++++++++ ...se_sensitive_file_extension_comparisons.rs | 8 +- ...ensitive_file_extension_comparisons.stderr | 82 ++++++++++++++++--- 4 files changed, 175 insertions(+), 17 deletions(-) create mode 100644 tests/ui/case_sensitive_file_extension_comparisons.fixed diff --git a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs index d226c0bba6593..bc9b7a73b5b18 100644 --- a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs +++ b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs @@ -1,7 +1,9 @@ -use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_type_lang_item; use if_chain::if_chain; use rustc_ast::ast::LitKind; +use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem}; use rustc_lint::LateContext; use rustc_span::{source_map::Spanned, Span}; @@ -28,13 +30,39 @@ pub(super) fn check<'tcx>( let recv_ty = cx.typeck_results().expr_ty(recv).peel_refs(); if recv_ty.is_str() || is_type_lang_item(cx, recv_ty, LangItem::String); then { - span_lint_and_help( + span_lint_and_then( cx, CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, - call_span, + recv.span.to(call_span), "case-sensitive file extension comparison", - None, - "consider using a case-insensitive comparison instead", + |diag| { + diag.help("consider using a case-insensitive comparison instead"); + let mut recv_str = Sugg::hir(cx, recv, "").to_string(); + + if is_type_lang_item(cx, recv_ty, LangItem::String) { + recv_str = format!("&{recv_str}"); + } + + if recv_str.contains(".to_lowercase()") { + diag.note("to_lowercase allocates memory, this can be avoided by using Path"); + recv_str = recv_str.replace(".to_lowercase()", ""); + } + + if recv_str.contains(".to_uppercase()") { + diag.note("to_uppercase allocates memory, this can be avoided by using Path"); + recv_str = recv_str.replace(".to_uppercase()", ""); + } + + diag.span_suggestion( + recv.span.to(call_span), + "use std::path::Path", + format!("std::path::Path::new({}) + .extension() + .map_or(false, |ext| ext.eq_ignore_ascii_case(\"{}\"))", + recv_str, ext_str.strip_prefix('.').unwrap()), + Applicability::MaybeIncorrect, + ); + } ); } } diff --git a/tests/ui/case_sensitive_file_extension_comparisons.fixed b/tests/ui/case_sensitive_file_extension_comparisons.fixed new file mode 100644 index 0000000000000..a8b5950f2087d --- /dev/null +++ b/tests/ui/case_sensitive_file_extension_comparisons.fixed @@ -0,0 +1,64 @@ +// run-rustfix +#![warn(clippy::case_sensitive_file_extension_comparisons)] + +use std::string::String; + +struct TestStruct; + +impl TestStruct { + fn ends_with(self, _arg: &str) {} +} + +#[allow(dead_code)] +fn is_rust_file(filename: &str) -> bool { + std::path::Path::new(filename) + .extension() + .map_or(false, |ext| ext.eq_ignore_ascii_case("rs")) +} + +fn main() { + // std::string::String and &str should trigger the lint failure with .ext12 + let _ = std::path::Path::new(&String::new()) + .extension() + .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12")); + let _ = std::path::Path::new("str") + .extension() + .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12")); + + // The test struct should not trigger the lint failure with .ext12 + TestStruct {}.ends_with(".ext12"); + + // std::string::String and &str should trigger the lint failure with .EXT12 + let _ = std::path::Path::new(&String::new()) + .extension() + .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12")); + let _ = std::path::Path::new("str") + .extension() + .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12")); + + // This should print a note about how to_lowercase and to_uppercase allocates + let _ = std::path::Path::new(&String::new()) + .extension() + .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12")); + let _ = std::path::Path::new(&String::new()) + .extension() + .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12")); + + // The test struct should not trigger the lint failure with .EXT12 + TestStruct {}.ends_with(".EXT12"); + + // Should not trigger the lint failure with .eXT12 + let _ = String::new().ends_with(".eXT12"); + let _ = "str".ends_with(".eXT12"); + TestStruct {}.ends_with(".eXT12"); + + // Should not trigger the lint failure with .EXT123 (too long) + let _ = String::new().ends_with(".EXT123"); + let _ = "str".ends_with(".EXT123"); + TestStruct {}.ends_with(".EXT123"); + + // Shouldn't fail if it doesn't start with a dot + let _ = String::new().ends_with("a.ext"); + let _ = "str".ends_with("a.extA"); + TestStruct {}.ends_with("a.ext"); +} diff --git a/tests/ui/case_sensitive_file_extension_comparisons.rs b/tests/ui/case_sensitive_file_extension_comparisons.rs index 6f0485b5279b1..ee9bcd73d52e7 100644 --- a/tests/ui/case_sensitive_file_extension_comparisons.rs +++ b/tests/ui/case_sensitive_file_extension_comparisons.rs @@ -1,3 +1,4 @@ +// run-rustfix #![warn(clippy::case_sensitive_file_extension_comparisons)] use std::string::String; @@ -5,9 +6,10 @@ use std::string::String; struct TestStruct; impl TestStruct { - fn ends_with(self, arg: &str) {} + fn ends_with(self, _arg: &str) {} } +#[allow(dead_code)] fn is_rust_file(filename: &str) -> bool { filename.ends_with(".rs") } @@ -24,6 +26,10 @@ fn main() { let _ = String::new().ends_with(".EXT12"); let _ = "str".ends_with(".EXT12"); + // This should print a note about how to_lowercase and to_uppercase allocates + let _ = String::new().to_lowercase().ends_with(".EXT12"); + let _ = String::new().to_uppercase().ends_with(".EXT12"); + // The test struct should not trigger the lint failure with .EXT12 TestStruct {}.ends_with(".EXT12"); diff --git a/tests/ui/case_sensitive_file_extension_comparisons.stderr b/tests/ui/case_sensitive_file_extension_comparisons.stderr index a28dd8bd5ad3f..33435f086d43c 100644 --- a/tests/ui/case_sensitive_file_extension_comparisons.stderr +++ b/tests/ui/case_sensitive_file_extension_comparisons.stderr @@ -1,43 +1,103 @@ error: case-sensitive file extension comparison - --> $DIR/case_sensitive_file_extension_comparisons.rs:12:14 + --> $DIR/case_sensitive_file_extension_comparisons.rs:14:5 | LL | filename.ends_with(".rs") - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider using a case-insensitive comparison instead = note: `-D clippy::case-sensitive-file-extension-comparisons` implied by `-D warnings` +help: use std::path::Path + | +LL ~ std::path::Path::new(filename) +LL + .extension() +LL + .map_or(false, |ext| ext.eq_ignore_ascii_case("rs")) + | error: case-sensitive file extension comparison - --> $DIR/case_sensitive_file_extension_comparisons.rs:17:27 + --> $DIR/case_sensitive_file_extension_comparisons.rs:19:13 | LL | let _ = String::new().ends_with(".ext12"); - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider using a case-insensitive comparison instead +help: use std::path::Path + | +LL ~ let _ = std::path::Path::new(&String::new()) +LL + .extension() +LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12")); + | error: case-sensitive file extension comparison - --> $DIR/case_sensitive_file_extension_comparisons.rs:18:19 + --> $DIR/case_sensitive_file_extension_comparisons.rs:20:13 | LL | let _ = "str".ends_with(".ext12"); - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider using a case-insensitive comparison instead +help: use std::path::Path + | +LL ~ let _ = std::path::Path::new("str") +LL + .extension() +LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12")); + | error: case-sensitive file extension comparison - --> $DIR/case_sensitive_file_extension_comparisons.rs:24:27 + --> $DIR/case_sensitive_file_extension_comparisons.rs:26:13 | LL | let _ = String::new().ends_with(".EXT12"); - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider using a case-insensitive comparison instead +help: use std::path::Path + | +LL ~ let _ = std::path::Path::new(&String::new()) +LL + .extension() +LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12")); + | error: case-sensitive file extension comparison - --> $DIR/case_sensitive_file_extension_comparisons.rs:25:19 + --> $DIR/case_sensitive_file_extension_comparisons.rs:27:13 | LL | let _ = "str".ends_with(".EXT12"); - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using a case-insensitive comparison instead +help: use std::path::Path + | +LL ~ let _ = std::path::Path::new("str") +LL + .extension() +LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12")); + | + +error: case-sensitive file extension comparison + --> $DIR/case_sensitive_file_extension_comparisons.rs:30:13 + | +LL | let _ = String::new().to_lowercase().ends_with(".EXT12"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using a case-insensitive comparison instead + = note: to_lowercase allocates memory, this can be avoided by using Path +help: use std::path::Path + | +LL ~ let _ = std::path::Path::new(&String::new()) +LL + .extension() +LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12")); + | + +error: case-sensitive file extension comparison + --> $DIR/case_sensitive_file_extension_comparisons.rs:31:13 + | +LL | let _ = String::new().to_uppercase().ends_with(".EXT12"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider using a case-insensitive comparison instead + = note: to_uppercase allocates memory, this can be avoided by using Path +help: use std::path::Path + | +LL ~ let _ = std::path::Path::new(&String::new()) +LL + .extension() +LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12")); + | -error: aborting due to 5 previous errors +error: aborting due to 7 previous errors From 0aa7d73df37470b9f868873587faf64c3339f964 Mon Sep 17 00:00:00 2001 From: Tyler Weaver Date: Mon, 2 Jan 2023 07:12:43 -0700 Subject: [PATCH 19/51] Only remove method from end of recv, indent suggestion source Signed-off-by: Tyler Weaver --- ...se_sensitive_file_extension_comparisons.rs | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs index bc9b7a73b5b18..e34c377f5fc3e 100644 --- a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs +++ b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::{indent_of, reindent_multiline}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_type_lang_item; use if_chain::if_chain; @@ -37,29 +38,36 @@ pub(super) fn check<'tcx>( "case-sensitive file extension comparison", |diag| { diag.help("consider using a case-insensitive comparison instead"); - let mut recv_str = Sugg::hir(cx, recv, "").to_string(); + let mut recv_source = Sugg::hir(cx, recv, "").to_string(); if is_type_lang_item(cx, recv_ty, LangItem::String) { - recv_str = format!("&{recv_str}"); + recv_source = format!("&{recv_source}"); } - if recv_str.contains(".to_lowercase()") { + if recv_source.ends_with(".to_lowercase()") { diag.note("to_lowercase allocates memory, this can be avoided by using Path"); - recv_str = recv_str.replace(".to_lowercase()", ""); + recv_source = recv_source.strip_suffix(".to_lowercase()").unwrap().to_string(); } - if recv_str.contains(".to_uppercase()") { + if recv_source.ends_with(".to_uppercase()") { diag.note("to_uppercase allocates memory, this can be avoided by using Path"); - recv_str = recv_str.replace(".to_uppercase()", ""); + recv_source = recv_source.strip_suffix(".to_uppercase()").unwrap().to_string(); } + let suggestion_source = reindent_multiline( + format!( + "std::path::Path::new({}) + .extension() + .map_or(false, |ext| ext.eq_ignore_ascii_case(\"{}\"))", + recv_source, ext_str.strip_prefix('.').unwrap()).into(), + true, + Some(indent_of(cx, call_span).unwrap_or(0) + 4) + ); + diag.span_suggestion( recv.span.to(call_span), "use std::path::Path", - format!("std::path::Path::new({}) - .extension() - .map_or(false, |ext| ext.eq_ignore_ascii_case(\"{}\"))", - recv_str, ext_str.strip_prefix('.').unwrap()), + suggestion_source, Applicability::MaybeIncorrect, ); } From cf4e9813b0fee5a8a0d7e93eadd4d51d0492a9d6 Mon Sep 17 00:00:00 2001 From: Eric Wu Date: Mon, 2 Jan 2023 18:35:21 -0500 Subject: [PATCH 20/51] use OnlyBodies instead of All we only need to check closures, so nestedfilter::All was overkill here. --- 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 b2175c5cb169a..46769cf2392b4 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1262,7 +1262,7 @@ pub struct ContainsName<'a, 'tcx> { } impl<'a, 'tcx> Visitor<'tcx> for ContainsName<'a, 'tcx> { - type NestedFilter = nested_filter::All; + type NestedFilter = nested_filter::OnlyBodies; fn visit_name(&mut self, name: Symbol) { if self.name == name { From 0cee2c50952a11099692652af367b4fea3cb09a6 Mon Sep 17 00:00:00 2001 From: Tyler Weaver Date: Mon, 2 Jan 2023 16:42:56 -0700 Subject: [PATCH 21/51] Don't trigger lint if last method is to_lower/upper --- ...se_sensitive_file_extension_comparisons.rs | 17 ++++------ ...sensitive_file_extension_comparisons.fixed | 10 ++---- ...se_sensitive_file_extension_comparisons.rs | 2 +- ...ensitive_file_extension_comparisons.stderr | 32 +------------------ 4 files changed, 12 insertions(+), 49 deletions(-) diff --git a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs index e34c377f5fc3e..b6ec0fba6cfbb 100644 --- a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs +++ b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs @@ -18,6 +18,13 @@ pub(super) fn check<'tcx>( recv: &'tcx Expr<'_>, arg: &'tcx Expr<'_>, ) { + if let ExprKind::MethodCall(path_segment, ..) = recv.kind { + let method_name = path_segment.ident.name.as_str(); + if method_name == "to_lowercase" || method_name == "to_uppercase" { + return; + } + } + if_chain! { if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if let Some(impl_id) = cx.tcx.impl_of_method(method_id); @@ -44,16 +51,6 @@ pub(super) fn check<'tcx>( recv_source = format!("&{recv_source}"); } - if recv_source.ends_with(".to_lowercase()") { - diag.note("to_lowercase allocates memory, this can be avoided by using Path"); - recv_source = recv_source.strip_suffix(".to_lowercase()").unwrap().to_string(); - } - - if recv_source.ends_with(".to_uppercase()") { - diag.note("to_uppercase allocates memory, this can be avoided by using Path"); - recv_source = recv_source.strip_suffix(".to_uppercase()").unwrap().to_string(); - } - let suggestion_source = reindent_multiline( format!( "std::path::Path::new({}) diff --git a/tests/ui/case_sensitive_file_extension_comparisons.fixed b/tests/ui/case_sensitive_file_extension_comparisons.fixed index a8b5950f2087d..a19ed1ddcd54a 100644 --- a/tests/ui/case_sensitive_file_extension_comparisons.fixed +++ b/tests/ui/case_sensitive_file_extension_comparisons.fixed @@ -36,13 +36,9 @@ fn main() { .extension() .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12")); - // This should print a note about how to_lowercase and to_uppercase allocates - let _ = std::path::Path::new(&String::new()) - .extension() - .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12")); - let _ = std::path::Path::new(&String::new()) - .extension() - .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12")); + // Should not trigger the lint failure because of the calls to to_lowercase and to_uppercase + let _ = String::new().to_lowercase().ends_with(".EXT12"); + let _ = String::new().to_uppercase().ends_with(".EXT12"); // The test struct should not trigger the lint failure with .EXT12 TestStruct {}.ends_with(".EXT12"); diff --git a/tests/ui/case_sensitive_file_extension_comparisons.rs b/tests/ui/case_sensitive_file_extension_comparisons.rs index ee9bcd73d52e7..ad56b7296f75f 100644 --- a/tests/ui/case_sensitive_file_extension_comparisons.rs +++ b/tests/ui/case_sensitive_file_extension_comparisons.rs @@ -26,7 +26,7 @@ fn main() { let _ = String::new().ends_with(".EXT12"); let _ = "str".ends_with(".EXT12"); - // This should print a note about how to_lowercase and to_uppercase allocates + // Should not trigger the lint failure because of the calls to to_lowercase and to_uppercase let _ = String::new().to_lowercase().ends_with(".EXT12"); let _ = String::new().to_uppercase().ends_with(".EXT12"); diff --git a/tests/ui/case_sensitive_file_extension_comparisons.stderr b/tests/ui/case_sensitive_file_extension_comparisons.stderr index 33435f086d43c..b5c8e4b4fe683 100644 --- a/tests/ui/case_sensitive_file_extension_comparisons.stderr +++ b/tests/ui/case_sensitive_file_extension_comparisons.stderr @@ -69,35 +69,5 @@ LL + .extension() LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12")); | -error: case-sensitive file extension comparison - --> $DIR/case_sensitive_file_extension_comparisons.rs:30:13 - | -LL | let _ = String::new().to_lowercase().ends_with(".EXT12"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using a case-insensitive comparison instead - = note: to_lowercase allocates memory, this can be avoided by using Path -help: use std::path::Path - | -LL ~ let _ = std::path::Path::new(&String::new()) -LL + .extension() -LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12")); - | - -error: case-sensitive file extension comparison - --> $DIR/case_sensitive_file_extension_comparisons.rs:31:13 - | -LL | let _ = String::new().to_uppercase().ends_with(".EXT12"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using a case-insensitive comparison instead - = note: to_uppercase allocates memory, this can be avoided by using Path -help: use std::path::Path - | -LL ~ let _ = std::path::Path::new(&String::new()) -LL + .extension() -LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12")); - | - -error: aborting due to 7 previous errors +error: aborting due to 5 previous errors From d3a50d2fda4fd1a024dfe7b01ab69fb5a0a6b7a7 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Wed, 4 Jan 2023 00:44:20 +0100 Subject: [PATCH 22/51] trim paths in `box_default` --- clippy_lints/src/box_default.rs | 4 ++-- tests/ui/box_default.fixed | 8 ++++---- tests/ui/box_default.stderr | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/clippy_lints/src/box_default.rs b/clippy_lints/src/box_default.rs index 91900542af833..9d98a6bab7107 100644 --- a/clippy_lints/src/box_default.rs +++ b/clippy_lints/src/box_default.rs @@ -8,7 +8,7 @@ use rustc_hir::{ Block, Expr, ExprKind, Local, Node, QPath, TyKind, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; +use rustc_middle::{lint::in_external_macro, ty::print::with_forced_trimmed_paths}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; @@ -59,7 +59,7 @@ impl LateLintPass<'_> for BoxDefault { if is_plain_default(arg_path) || given_type(cx, expr) { "Box::default()".into() } else { - format!("Box::<{arg_ty}>::default()") + with_forced_trimmed_paths!(format!("Box::<{arg_ty}>::default()")) }, Applicability::MachineApplicable ); diff --git a/tests/ui/box_default.fixed b/tests/ui/box_default.fixed index 911fa856aa0a3..68ab996a70492 100644 --- a/tests/ui/box_default.fixed +++ b/tests/ui/box_default.fixed @@ -21,16 +21,16 @@ macro_rules! outer { fn main() { let _string: Box = Box::default(); let _byte = Box::::default(); - let _vec = Box::>::default(); + let _vec = Box::>::default(); let _impl = Box::::default(); let _impl2 = Box::::default(); let _impl3: Box = Box::default(); let _own = Box::new(OwnDefault::default()); // should not lint - let _in_macro = outer!(Box::::default()); - let _string_default = outer!(Box::::default()); + let _in_macro = outer!(Box::::default()); + let _string_default = outer!(Box::::default()); let _vec2: Box> = Box::default(); let _vec3: Box> = Box::default(); - let _vec4: Box<_> = Box::>::default(); + let _vec4: Box<_> = Box::>::default(); let _more = ret_ty_fn(); call_ty_fn(Box::default()); } diff --git a/tests/ui/box_default.stderr b/tests/ui/box_default.stderr index 5ea410331afb3..f77c97cdfa269 100644 --- a/tests/ui/box_default.stderr +++ b/tests/ui/box_default.stderr @@ -16,7 +16,7 @@ error: `Box::new(_)` of default value --> $DIR/box_default.rs:24:16 | LL | let _vec = Box::new(Vec::::new()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::>::default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::>::default()` error: `Box::new(_)` of default value --> $DIR/box_default.rs:25:17 @@ -40,13 +40,13 @@ error: `Box::new(_)` of default value --> $DIR/box_default.rs:29:28 | LL | let _in_macro = outer!(Box::new(String::new())); - | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::::default()` + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::::default()` error: `Box::new(_)` of default value --> $DIR/box_default.rs:30:34 | LL | let _string_default = outer!(Box::new(String::from(""))); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::::default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::::default()` error: `Box::new(_)` of default value --> $DIR/box_default.rs:31:46 @@ -64,7 +64,7 @@ error: `Box::new(_)` of default value --> $DIR/box_default.rs:33:25 | LL | let _vec4: Box<_> = Box::new(Vec::from([false; 0])); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::>::default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::>::default()` error: `Box::new(_)` of default value --> $DIR/box_default.rs:35:16 From 73d293fb6df79060f483f3eb1b3f59af7b6493a9 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 3 Jan 2023 07:31:04 +0000 Subject: [PATCH 23/51] rename get_parent_node to parent_id --- clippy_lints/src/escape.rs | 6 +++--- clippy_lints/src/index_refutable_slice.rs | 4 ++-- clippy_lints/src/loops/same_item_push.rs | 2 +- clippy_lints/src/manual_rem_euclid.rs | 2 +- clippy_lints/src/matches/match_single_binding.rs | 6 +++--- clippy_lints/src/mixed_read_write_in_expression.rs | 2 +- clippy_lints/src/needless_pass_by_value.rs | 2 +- clippy_lints/src/non_copy_const.rs | 2 +- clippy_lints/src/pass_by_ref_or_value.rs | 2 +- clippy_lints/src/unit_types/unit_arg.rs | 4 ++-- clippy_lints/src/unnecessary_wraps.rs | 2 +- clippy_lints/src/utils/internal_lints/metadata_collector.rs | 2 +- .../src/utils/internal_lints/unnecessary_def_path.rs | 2 +- clippy_utils/src/lib.rs | 4 ++-- 14 files changed, 21 insertions(+), 21 deletions(-) diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs index 1d09adec12f3f..58b7b9829a100 100644 --- a/clippy_lints/src/escape.rs +++ b/clippy_lints/src/escape.rs @@ -131,7 +131,7 @@ fn is_argument(map: rustc_middle::hir::map::Map<'_>, id: HirId) -> bool { _ => return false, } - matches!(map.find(map.get_parent_node(id)), Some(Node::Param(_))) + matches!(map.find(map.parent_id(id)), Some(Node::Param(_))) } impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { @@ -156,8 +156,8 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { let map = &self.cx.tcx.hir(); if is_argument(*map, cmt.hir_id) { // Skip closure arguments - let parent_id = map.get_parent_node(cmt.hir_id); - if let Some(Node::Expr(..)) = map.find(map.get_parent_node(parent_id)) { + let parent_id = map.parent_id(cmt.hir_id); + if let Some(Node::Expr(..)) = map.find(map.parent_id(parent_id)) { return; } diff --git a/clippy_lints/src/index_refutable_slice.rs b/clippy_lints/src/index_refutable_slice.rs index cf35b1f175c60..bdeddf44df7bd 100644 --- a/clippy_lints/src/index_refutable_slice.rs +++ b/clippy_lints/src/index_refutable_slice.rs @@ -251,7 +251,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SliceIndexLintingVisitor<'a, 'tcx> { let map = cx.tcx.hir(); // Checking for slice indexing - let parent_id = map.get_parent_node(expr.hir_id); + let parent_id = map.parent_id(expr.hir_id); if let Some(hir::Node::Expr(parent_expr)) = map.find(parent_id); if let hir::ExprKind::Index(_, index_expr) = parent_expr.kind; if let Some((Constant::Int(index_value), _)) = constant(cx, cx.typeck_results(), index_expr); @@ -259,7 +259,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SliceIndexLintingVisitor<'a, 'tcx> { if index_value < max_suggested_slice; // Make sure that this slice index is read only - let maybe_addrof_id = map.get_parent_node(parent_id); + let maybe_addrof_id = map.parent_id(parent_id); if let Some(hir::Node::Expr(maybe_addrof_expr)) = map.find(maybe_addrof_id); if let hir::ExprKind::AddrOf(_kind, hir::Mutability::Not, _inner_expr) = maybe_addrof_expr.kind; then { diff --git a/clippy_lints/src/loops/same_item_push.rs b/clippy_lints/src/loops/same_item_push.rs index 07edee46fa657..540656a2cd991 100644 --- a/clippy_lints/src/loops/same_item_push.rs +++ b/clippy_lints/src/loops/same_item_push.rs @@ -63,7 +63,7 @@ pub(super) fn check<'tcx>( if let Node::Pat(pat) = node; if let PatKind::Binding(bind_ann, ..) = pat.kind; if !matches!(bind_ann, BindingAnnotation(_, Mutability::Mut)); - let parent_node = cx.tcx.hir().get_parent_node(hir_id); + let parent_node = cx.tcx.hir().parent_id(hir_id); if let Some(Node::Local(parent_let_expr)) = cx.tcx.hir().find(parent_node); if let Some(init) = parent_let_expr.init; then { diff --git a/clippy_lints/src/manual_rem_euclid.rs b/clippy_lints/src/manual_rem_euclid.rs index 8d447c37150b8..494fde395e933 100644 --- a/clippy_lints/src/manual_rem_euclid.rs +++ b/clippy_lints/src/manual_rem_euclid.rs @@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid { && let Some(hir_id) = path_to_local(expr3) && let Some(Node::Pat(_)) = cx.tcx.hir().find(hir_id) { // Apply only to params or locals with annotated types - match cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_id)) { + match cx.tcx.hir().find(cx.tcx.hir().parent_id(hir_id)) { Some(Node::Param(..)) => (), Some(Node::Local(local)) => { let Some(ty) = local.ty else { return }; diff --git a/clippy_lints/src/matches/match_single_binding.rs b/clippy_lints/src/matches/match_single_binding.rs index c94a1f763306e..abe9d231f4aa1 100644 --- a/clippy_lints/src/matches/match_single_binding.rs +++ b/clippy_lints/src/matches/match_single_binding.rs @@ -140,8 +140,8 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e fn opt_parent_assign_span<'a>(cx: &LateContext<'a>, ex: &Expr<'a>) -> Option { let map = &cx.tcx.hir(); - if let Some(Node::Expr(parent_arm_expr)) = map.find(map.get_parent_node(ex.hir_id)) { - return match map.find(map.get_parent_node(parent_arm_expr.hir_id)) { + if let Some(Node::Expr(parent_arm_expr)) = map.find(map.parent_id(ex.hir_id)) { + return match map.find(map.parent_id(parent_arm_expr.hir_id)) { Some(Node::Local(parent_let_expr)) => Some(AssignmentExpr::Local { span: parent_let_expr.span, pat_span: parent_let_expr.pat.span(), @@ -183,7 +183,7 @@ fn sugg_with_curlies<'a>( // If the parent is already an arm, and the body is another match statement, // we need curly braces around suggestion - let parent_node_id = cx.tcx.hir().get_parent_node(match_expr.hir_id); + let parent_node_id = cx.tcx.hir().parent_id(match_expr.hir_id); if let Node::Arm(arm) = &cx.tcx.hir().get(parent_node_id) { if let ExprKind::Match(..) = arm.body.kind { cbrace_end = format!("\n{indent}}}"); diff --git a/clippy_lints/src/mixed_read_write_in_expression.rs b/clippy_lints/src/mixed_read_write_in_expression.rs index 321fa4b7f9996..f0be7771bb1a6 100644 --- a/clippy_lints/src/mixed_read_write_in_expression.rs +++ b/clippy_lints/src/mixed_read_write_in_expression.rs @@ -186,7 +186,7 @@ fn check_for_unsequenced_reads(vis: &mut ReadVisitor<'_, '_>) { let map = &vis.cx.tcx.hir(); let mut cur_id = vis.write_expr.hir_id; loop { - let parent_id = map.get_parent_node(cur_id); + let parent_id = map.parent_id(cur_id); if parent_id == cur_id { break; } diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 2f0b7ce16e51b..58c54280a2346 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -100,7 +100,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { } // Exclude non-inherent impls - if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_id)) { + if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().parent_id(hir_id)) { if matches!( item.kind, ItemKind::Impl(Impl { of_trait: Some(_), .. }) | ItemKind::Trait(..) diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 2a3bd4ee6ce65..07fd321d69fce 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -366,7 +366,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { let mut dereferenced_expr = expr; let mut needs_check_adjustment = true; loop { - let parent_id = cx.tcx.hir().get_parent_node(cur_expr.hir_id); + let parent_id = cx.tcx.hir().parent_id(cur_expr.hir_id); if parent_id == cur_expr.hir_id { break; } diff --git a/clippy_lints/src/pass_by_ref_or_value.rs b/clippy_lints/src/pass_by_ref_or_value.rs index 75add4ee4aade..f96a19b272359 100644 --- a/clippy_lints/src/pass_by_ref_or_value.rs +++ b/clippy_lints/src/pass_by_ref_or_value.rs @@ -299,7 +299,7 @@ impl<'tcx> LateLintPass<'tcx> for PassByRefOrValue { } // Exclude non-inherent impls - if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_id)) { + if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().parent_id(hir_id)) { if matches!( item.kind, ItemKind::Impl(Impl { of_trait: Some(_), .. }) | ItemKind::Trait(..) diff --git a/clippy_lints/src/unit_types/unit_arg.rs b/clippy_lints/src/unit_types/unit_arg.rs index ef9f740f7047c..ac4f8789a4342 100644 --- a/clippy_lints/src/unit_types/unit_arg.rs +++ b/clippy_lints/src/unit_types/unit_arg.rs @@ -21,7 +21,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { return; } let map = &cx.tcx.hir(); - let opt_parent_node = map.find(map.get_parent_node(expr.hir_id)); + let opt_parent_node = map.find(map.parent_id(expr.hir_id)); if_chain! { if let Some(hir::Node::Expr(parent_expr)) = opt_parent_node; if is_questionmark_desugar_marked_call(parent_expr); @@ -192,7 +192,7 @@ fn fmt_stmts_and_call( let mut stmts_and_call_snippet = stmts_and_call.join(&format!("{}{}", ";\n", " ".repeat(call_expr_indent))); // expr is not in a block statement or result expression position, wrap in a block - let parent_node = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(call_expr.hir_id)); + let parent_node = cx.tcx.hir().find(cx.tcx.hir().parent_id(call_expr.hir_id)); if !matches!(parent_node, Some(Node::Block(_))) && !matches!(parent_node, Some(Node::Stmt(_))) { let block_indent = call_expr_indent + 4; stmts_and_call_snippet = diff --git a/clippy_lints/src/unnecessary_wraps.rs b/clippy_lints/src/unnecessary_wraps.rs index 60b46854b4ffe..63f4f01b08778 100644 --- a/clippy_lints/src/unnecessary_wraps.rs +++ b/clippy_lints/src/unnecessary_wraps.rs @@ -91,7 +91,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { } // Abort if the method is implementing a trait or of it a trait method. - if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_id)) { + if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().parent_id(hir_id)) { if matches!( item.kind, ItemKind::Impl(Impl { of_trait: Some(_), .. }) | ItemKind::Trait(..) diff --git a/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/clippy_lints/src/utils/internal_lints/metadata_collector.rs index 929544cd69d5b..a177ae507bbed 100644 --- a/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ b/clippy_lints/src/utils/internal_lints/metadata_collector.rs @@ -1058,7 +1058,7 @@ fn get_parent_local<'hir>(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) - fn get_parent_local_hir_id<'hir>(cx: &LateContext<'hir>, hir_id: hir::HirId) -> Option<&'hir hir::Local<'hir>> { let map = cx.tcx.hir(); - match map.find(map.get_parent_node(hir_id)) { + match map.find(map.parent_id(hir_id)) { Some(hir::Node::Local(local)) => Some(local), Some(hir::Node::Pat(pattern)) => get_parent_local_hir_id(cx, pattern.hir_id), _ => None, diff --git a/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs b/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs index 393988dbad384..7144363637a04 100644 --- a/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs +++ b/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs @@ -219,7 +219,7 @@ fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option match cx.qpath_res(qpath, expr.hir_id) { Res::Local(hir_id) => { - let parent_id = cx.tcx.hir().get_parent_node(hir_id); + let parent_id = cx.tcx.hir().parent_id(hir_id); if let Some(Node::Local(Local { init: Some(init), .. })) = cx.tcx.hir().find(parent_id) { path_to_matched_type(cx, init) } else { diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index d863609b6a726..63d0938169a82 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -174,7 +174,7 @@ pub fn find_binding_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option< if_chain! { if let Some(Node::Pat(pat)) = hir.find(hir_id); if matches!(pat.kind, PatKind::Binding(BindingAnnotation::NONE, ..)); - let parent = hir.get_parent_node(hir_id); + let parent = hir.parent_id(hir_id); if let Some(Node::Local(local)) = hir.find(parent); then { return local.init; @@ -2075,7 +2075,7 @@ pub fn is_no_core_crate(cx: &LateContext<'_>) -> bool { /// } /// ``` pub fn is_trait_impl_item(cx: &LateContext<'_>, hir_id: HirId) -> bool { - if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_id)) { + if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().parent_id(hir_id)) { matches!(item.kind, ItemKind::Impl(hir::Impl { of_trait: Some(_), .. })) } else { false From bd1d8971cf3fe6f3cefcf7cc03dbdc7d1c684617 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 3 Jan 2023 07:31:33 +0000 Subject: [PATCH 24/51] rename find_parent_node to opt_parent_id --- clippy_lints/src/casts/cast_slice_different_sizes.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/casts/cast_slice_different_sizes.rs b/clippy_lints/src/casts/cast_slice_different_sizes.rs index c8e54d7b8e0c3..27cc5a1c3f04c 100644 --- a/clippy_lints/src/casts/cast_slice_different_sizes.rs +++ b/clippy_lints/src/casts/cast_slice_different_sizes.rs @@ -68,7 +68,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: &Msrv fn is_child_of_cast(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { let map = cx.tcx.hir(); if_chain! { - if let Some(parent_id) = map.find_parent_node(expr.hir_id); + if let Some(parent_id) = map.opt_parent_id(expr.hir_id); if let Some(parent) = map.find(parent_id); then { let expr = match parent { From 70f6c478f65993f4150f5f41b33f57d7b2715f3b Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 3 Jan 2023 17:30:35 +0000 Subject: [PATCH 25/51] get_parent and find_parent --- clippy_lints/src/escape.rs | 4 ++-- clippy_lints/src/manual_rem_euclid.rs | 2 +- clippy_lints/src/matches/match_single_binding.rs | 7 +++---- clippy_lints/src/needless_pass_by_value.rs | 2 +- clippy_lints/src/pass_by_ref_or_value.rs | 2 +- clippy_lints/src/unit_types/unit_arg.rs | 4 ++-- clippy_lints/src/unnecessary_wraps.rs | 2 +- .../src/utils/internal_lints/metadata_collector.rs | 2 +- clippy_utils/src/lib.rs | 4 ++-- 9 files changed, 14 insertions(+), 15 deletions(-) diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs index 58b7b9829a100..dfb43893326eb 100644 --- a/clippy_lints/src/escape.rs +++ b/clippy_lints/src/escape.rs @@ -131,7 +131,7 @@ fn is_argument(map: rustc_middle::hir::map::Map<'_>, id: HirId) -> bool { _ => return false, } - matches!(map.find(map.parent_id(id)), Some(Node::Param(_))) + matches!(map.find_parent(id), Some(Node::Param(_))) } impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { @@ -157,7 +157,7 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { if is_argument(*map, cmt.hir_id) { // Skip closure arguments let parent_id = map.parent_id(cmt.hir_id); - if let Some(Node::Expr(..)) = map.find(map.parent_id(parent_id)) { + if let Some(Node::Expr(..)) = map.find_parent(parent_id) { return; } diff --git a/clippy_lints/src/manual_rem_euclid.rs b/clippy_lints/src/manual_rem_euclid.rs index 494fde395e933..38f41d077c161 100644 --- a/clippy_lints/src/manual_rem_euclid.rs +++ b/clippy_lints/src/manual_rem_euclid.rs @@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid { && let Some(hir_id) = path_to_local(expr3) && let Some(Node::Pat(_)) = cx.tcx.hir().find(hir_id) { // Apply only to params or locals with annotated types - match cx.tcx.hir().find(cx.tcx.hir().parent_id(hir_id)) { + match cx.tcx.hir().find_parent(hir_id) { Some(Node::Param(..)) => (), Some(Node::Local(local)) => { let Some(ty) = local.ty else { return }; diff --git a/clippy_lints/src/matches/match_single_binding.rs b/clippy_lints/src/matches/match_single_binding.rs index abe9d231f4aa1..065a5c72621cd 100644 --- a/clippy_lints/src/matches/match_single_binding.rs +++ b/clippy_lints/src/matches/match_single_binding.rs @@ -140,8 +140,8 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e fn opt_parent_assign_span<'a>(cx: &LateContext<'a>, ex: &Expr<'a>) -> Option { let map = &cx.tcx.hir(); - if let Some(Node::Expr(parent_arm_expr)) = map.find(map.parent_id(ex.hir_id)) { - return match map.find(map.parent_id(parent_arm_expr.hir_id)) { + if let Some(Node::Expr(parent_arm_expr)) = map.find_parent(ex.hir_id) { + return match map.find_parent(parent_arm_expr.hir_id) { Some(Node::Local(parent_let_expr)) => Some(AssignmentExpr::Local { span: parent_let_expr.span, pat_span: parent_let_expr.pat.span(), @@ -183,8 +183,7 @@ fn sugg_with_curlies<'a>( // If the parent is already an arm, and the body is another match statement, // we need curly braces around suggestion - let parent_node_id = cx.tcx.hir().parent_id(match_expr.hir_id); - if let Node::Arm(arm) = &cx.tcx.hir().get(parent_node_id) { + if let Node::Arm(arm) = &cx.tcx.hir().get_parent(match_expr.hir_id) { if let ExprKind::Match(..) = arm.body.kind { cbrace_end = format!("\n{indent}}}"); // Fix body indent due to the match diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 58c54280a2346..1249db5dc4792 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -100,7 +100,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { } // Exclude non-inherent impls - if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().parent_id(hir_id)) { + if let Some(Node::Item(item)) = cx.tcx.hir().find_parent(hir_id) { if matches!( item.kind, ItemKind::Impl(Impl { of_trait: Some(_), .. }) | ItemKind::Trait(..) diff --git a/clippy_lints/src/pass_by_ref_or_value.rs b/clippy_lints/src/pass_by_ref_or_value.rs index f96a19b272359..870a1c7d88d53 100644 --- a/clippy_lints/src/pass_by_ref_or_value.rs +++ b/clippy_lints/src/pass_by_ref_or_value.rs @@ -299,7 +299,7 @@ impl<'tcx> LateLintPass<'tcx> for PassByRefOrValue { } // Exclude non-inherent impls - if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().parent_id(hir_id)) { + if let Some(Node::Item(item)) = cx.tcx.hir().find_parent(hir_id) { if matches!( item.kind, ItemKind::Impl(Impl { of_trait: Some(_), .. }) | ItemKind::Trait(..) diff --git a/clippy_lints/src/unit_types/unit_arg.rs b/clippy_lints/src/unit_types/unit_arg.rs index ac4f8789a4342..dd120599c04e1 100644 --- a/clippy_lints/src/unit_types/unit_arg.rs +++ b/clippy_lints/src/unit_types/unit_arg.rs @@ -21,7 +21,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { return; } let map = &cx.tcx.hir(); - let opt_parent_node = map.find(map.parent_id(expr.hir_id)); + let opt_parent_node = map.find_parent(expr.hir_id); if_chain! { if let Some(hir::Node::Expr(parent_expr)) = opt_parent_node; if is_questionmark_desugar_marked_call(parent_expr); @@ -192,7 +192,7 @@ fn fmt_stmts_and_call( let mut stmts_and_call_snippet = stmts_and_call.join(&format!("{}{}", ";\n", " ".repeat(call_expr_indent))); // expr is not in a block statement or result expression position, wrap in a block - let parent_node = cx.tcx.hir().find(cx.tcx.hir().parent_id(call_expr.hir_id)); + let parent_node = cx.tcx.hir().find_parent(call_expr.hir_id); if !matches!(parent_node, Some(Node::Block(_))) && !matches!(parent_node, Some(Node::Stmt(_))) { let block_indent = call_expr_indent + 4; stmts_and_call_snippet = diff --git a/clippy_lints/src/unnecessary_wraps.rs b/clippy_lints/src/unnecessary_wraps.rs index 63f4f01b08778..84ec0d0fb1cf4 100644 --- a/clippy_lints/src/unnecessary_wraps.rs +++ b/clippy_lints/src/unnecessary_wraps.rs @@ -91,7 +91,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { } // Abort if the method is implementing a trait or of it a trait method. - if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().parent_id(hir_id)) { + if let Some(Node::Item(item)) = cx.tcx.hir().find_parent(hir_id) { if matches!( item.kind, ItemKind::Impl(Impl { of_trait: Some(_), .. }) | ItemKind::Trait(..) diff --git a/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/clippy_lints/src/utils/internal_lints/metadata_collector.rs index a177ae507bbed..c86f24cbd3780 100644 --- a/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ b/clippy_lints/src/utils/internal_lints/metadata_collector.rs @@ -1058,7 +1058,7 @@ fn get_parent_local<'hir>(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) - fn get_parent_local_hir_id<'hir>(cx: &LateContext<'hir>, hir_id: hir::HirId) -> Option<&'hir hir::Local<'hir>> { let map = cx.tcx.hir(); - match map.find(map.parent_id(hir_id)) { + match map.find_parent((hir_id)) { Some(hir::Node::Local(local)) => Some(local), Some(hir::Node::Pat(pattern)) => get_parent_local_hir_id(cx, pattern.hir_id), _ => None, diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 63d0938169a82..8290fe9ecb4c6 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1287,7 +1287,7 @@ pub fn contains_return(expr: &hir::Expr<'_>) -> bool { /// Gets the parent node, if any. pub fn get_parent_node(tcx: TyCtxt<'_>, id: HirId) -> Option> { - tcx.hir().parent_iter(id).next().map(|(_, node)| node) + tcx.hir().find_parent(id) } /// Gets the parent expression, if any –- this is useful to constrain a lint. @@ -2075,7 +2075,7 @@ pub fn is_no_core_crate(cx: &LateContext<'_>) -> bool { /// } /// ``` pub fn is_trait_impl_item(cx: &LateContext<'_>, hir_id: HirId) -> bool { - if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().parent_id(hir_id)) { + if let Some(Node::Item(item)) = cx.tcx.hir().find_parent(hir_id) { matches!(item.kind, ItemKind::Impl(hir::Impl { of_trait: Some(_), .. })) } else { false From ea6ff7ed04b5785d20af03b1e4ac73b4960fa5d5 Mon Sep 17 00:00:00 2001 From: Tyler Weaver Date: Wed, 4 Jan 2023 07:06:07 -0700 Subject: [PATCH 26/51] Apply changes suggested in review --- ...se_sensitive_file_extension_comparisons.rs | 47 ++++++++++--------- ...sensitive_file_extension_comparisons.fixed | 7 +++ ...se_sensitive_file_extension_comparisons.rs | 5 ++ ...ensitive_file_extension_comparisons.stderr | 20 ++++++-- 4 files changed, 54 insertions(+), 25 deletions(-) diff --git a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs index b6ec0fba6cfbb..0b3bf22743fae 100644 --- a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs +++ b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::snippet_opt; use clippy_utils::source::{indent_of, reindent_multiline}; -use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_type_lang_item; use if_chain::if_chain; use rustc_ast::ast::LitKind; @@ -19,8 +19,10 @@ pub(super) fn check<'tcx>( arg: &'tcx Expr<'_>, ) { if let ExprKind::MethodCall(path_segment, ..) = recv.kind { - let method_name = path_segment.ident.name.as_str(); - if method_name == "to_lowercase" || method_name == "to_uppercase" { + if matches!( + path_segment.ident.name.as_str(), + "to_lowercase" | "to_uppercase" | "to_ascii_lowercase" | "to_ascii_uppercase" + ) { return; } } @@ -45,28 +47,29 @@ pub(super) fn check<'tcx>( "case-sensitive file extension comparison", |diag| { diag.help("consider using a case-insensitive comparison instead"); - let mut recv_source = Sugg::hir(cx, recv, "").to_string(); + if let Some(mut recv_source) = snippet_opt(cx, recv.span) { - if is_type_lang_item(cx, recv_ty, LangItem::String) { - recv_source = format!("&{recv_source}"); - } + if !cx.typeck_results().expr_ty(recv).is_ref() { + recv_source = format!("&{recv_source}"); + } - let suggestion_source = reindent_multiline( - format!( - "std::path::Path::new({}) - .extension() - .map_or(false, |ext| ext.eq_ignore_ascii_case(\"{}\"))", - recv_source, ext_str.strip_prefix('.').unwrap()).into(), - true, - Some(indent_of(cx, call_span).unwrap_or(0) + 4) - ); + let suggestion_source = reindent_multiline( + format!( + "std::path::Path::new({}) + .extension() + .map_or(false, |ext| ext.eq_ignore_ascii_case(\"{}\"))", + recv_source, ext_str.strip_prefix('.').unwrap()).into(), + true, + Some(indent_of(cx, call_span).unwrap_or(0) + 4) + ); - diag.span_suggestion( - recv.span.to(call_span), - "use std::path::Path", - suggestion_source, - Applicability::MaybeIncorrect, - ); + diag.span_suggestion( + recv.span.to(call_span), + "use std::path::Path", + suggestion_source, + Applicability::MaybeIncorrect, + ); + } } ); } diff --git a/tests/ui/case_sensitive_file_extension_comparisons.fixed b/tests/ui/case_sensitive_file_extension_comparisons.fixed index a19ed1ddcd54a..5fbaa64db39ed 100644 --- a/tests/ui/case_sensitive_file_extension_comparisons.fixed +++ b/tests/ui/case_sensitive_file_extension_comparisons.fixed @@ -25,6 +25,13 @@ fn main() { .extension() .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12")); + // The fixup should preserve the indentation level + { + let _ = std::path::Path::new("str") + .extension() + .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12")); + } + // The test struct should not trigger the lint failure with .ext12 TestStruct {}.ends_with(".ext12"); diff --git a/tests/ui/case_sensitive_file_extension_comparisons.rs b/tests/ui/case_sensitive_file_extension_comparisons.rs index ad56b7296f75f..3c0d4821f9f3a 100644 --- a/tests/ui/case_sensitive_file_extension_comparisons.rs +++ b/tests/ui/case_sensitive_file_extension_comparisons.rs @@ -19,6 +19,11 @@ fn main() { let _ = String::new().ends_with(".ext12"); let _ = "str".ends_with(".ext12"); + // The fixup should preserve the indentation level + { + let _ = "str".ends_with(".ext12"); + } + // The test struct should not trigger the lint failure with .ext12 TestStruct {}.ends_with(".ext12"); diff --git a/tests/ui/case_sensitive_file_extension_comparisons.stderr b/tests/ui/case_sensitive_file_extension_comparisons.stderr index b5c8e4b4fe683..44c8e3fdf7403 100644 --- a/tests/ui/case_sensitive_file_extension_comparisons.stderr +++ b/tests/ui/case_sensitive_file_extension_comparisons.stderr @@ -42,7 +42,21 @@ LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12")); | error: case-sensitive file extension comparison - --> $DIR/case_sensitive_file_extension_comparisons.rs:26:13 + --> $DIR/case_sensitive_file_extension_comparisons.rs:24:17 + | +LL | let _ = "str".ends_with(".ext12"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using a case-insensitive comparison instead +help: use std::path::Path + | +LL ~ let _ = std::path::Path::new("str") +LL + .extension() +LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12")); + | + +error: case-sensitive file extension comparison + --> $DIR/case_sensitive_file_extension_comparisons.rs:31:13 | LL | let _ = String::new().ends_with(".EXT12"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -56,7 +70,7 @@ LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12")); | error: case-sensitive file extension comparison - --> $DIR/case_sensitive_file_extension_comparisons.rs:27:13 + --> $DIR/case_sensitive_file_extension_comparisons.rs:32:13 | LL | let _ = "str".ends_with(".EXT12"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -69,5 +83,5 @@ LL + .extension() LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12")); | -error: aborting due to 5 previous errors +error: aborting due to 6 previous errors From d0c1605d5151c86215ad609feadead811e5602c0 Mon Sep 17 00:00:00 2001 From: Kyle Huey Date: Wed, 4 Jan 2023 13:32:34 -0800 Subject: [PATCH 27/51] Make the iter_kv_map lint handle ref/mut annotations. For the degenerate (`map(|(k, _)| k)`/`map(|(_, v)| v)`) cases a mut annotation is superfluous and a ref annotation won't compile, so no additional handling is required. For cases where the `map` call must be preserved ref/mut annotations should also be presereved so that the map body continues to work as expected. --- clippy_lints/src/methods/iter_kv_map.rs | 20 +++-- tests/ui/iter_kv_map.fixed | 35 +++++++- tests/ui/iter_kv_map.rs | 39 +++++++- tests/ui/iter_kv_map.stderr | 114 +++++++++++++++++++----- 4 files changed, 174 insertions(+), 34 deletions(-) diff --git a/clippy_lints/src/methods/iter_kv_map.rs b/clippy_lints/src/methods/iter_kv_map.rs index 2244ebfb12927..1e5805c534772 100644 --- a/clippy_lints/src/methods/iter_kv_map.rs +++ b/clippy_lints/src/methods/iter_kv_map.rs @@ -6,7 +6,7 @@ use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::sugg; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::is_local_used; -use rustc_hir::{BindingAnnotation, Body, BorrowKind, Expr, ExprKind, Mutability, Pat, PatKind}; +use rustc_hir::{BindingAnnotation, Body, BorrowKind, ByRef, Expr, ExprKind, Mutability, Pat, PatKind}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty; use rustc_span::sym; @@ -30,9 +30,9 @@ pub(super) fn check<'tcx>( if let Body {params: [p], value: body_expr, generator_kind: _ } = cx.tcx.hir().body(c.body); if let PatKind::Tuple([key_pat, val_pat], _) = p.pat.kind; - let (replacement_kind, binded_ident) = match (&key_pat.kind, &val_pat.kind) { - (key, PatKind::Binding(_, _, value, _)) if pat_is_wild(cx, key, m_arg) => ("value", value), - (PatKind::Binding(_, _, key, _), value) if pat_is_wild(cx, value, m_arg) => ("key", key), + let (replacement_kind, annotation, binded_ident) = match (&key_pat.kind, &val_pat.kind) { + (key, PatKind::Binding(ann, _, value, _)) if pat_is_wild(cx, key, m_arg) => ("value", ann, value), + (PatKind::Binding(ann, _, key, _), value) if pat_is_wild(cx, value, m_arg) => ("key", ann, key), _ => return, }; @@ -60,13 +60,23 @@ pub(super) fn check<'tcx>( applicability, ); } else { + let ref_annotation = if annotation.0 == ByRef::Yes { + "ref " + } else { + "" + }; + let mut_annotation = if annotation.1 == Mutability::Mut { + "mut " + } else { + "" + }; span_lint_and_sugg( cx, ITER_KV_MAP, expr.span, &format!("iterating on a map's {replacement_kind}s"), "try", - format!("{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{binded_ident}| {})", + format!("{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{ref_annotation}{mut_annotation}{binded_ident}| {})", snippet_with_applicability(cx, body_expr.span, "/* body */", &mut applicability)), applicability, ); diff --git a/tests/ui/iter_kv_map.fixed b/tests/ui/iter_kv_map.fixed index 83fee04080fa7..f2a4c284cb16d 100644 --- a/tests/ui/iter_kv_map.fixed +++ b/tests/ui/iter_kv_map.fixed @@ -1,14 +1,15 @@ // run-rustfix #![warn(clippy::iter_kv_map)] -#![allow(clippy::redundant_clone)] -#![allow(clippy::suspicious_map)] -#![allow(clippy::map_identity)] +#![allow(unused_mut, clippy::redundant_clone, clippy::suspicious_map, clippy::map_identity)] use std::collections::{BTreeMap, HashMap}; fn main() { let get_key = |(key, _val)| key; + fn ref_acceptor(v: &u32) -> u32 { + *v + } let map: HashMap = HashMap::new(); @@ -36,6 +37,20 @@ fn main() { let _ = map.keys().map(|key| key * 9).count(); let _ = map.values().map(|value| value * 17).count(); + // Preserve the ref in the fix. + let _ = map.clone().into_values().map(|ref val| ref_acceptor(val)).count(); + + // Preserve the mut in the fix. + let _ = map + .clone().into_values().map(|mut val| { + val += 2; + val + }) + .count(); + + // Don't let a mut interfere. + let _ = map.clone().into_values().count(); + let map: BTreeMap = BTreeMap::new(); let _ = map.keys().collect::>(); @@ -61,4 +76,18 @@ fn main() { // Lint let _ = map.keys().map(|key| key * 9).count(); let _ = map.values().map(|value| value * 17).count(); + + // Preserve the ref in the fix. + let _ = map.clone().into_values().map(|ref val| ref_acceptor(val)).count(); + + // Preserve the mut in the fix. + let _ = map + .clone().into_values().map(|mut val| { + val += 2; + val + }) + .count(); + + // Don't let a mut interfere. + let _ = map.clone().into_values().count(); } diff --git a/tests/ui/iter_kv_map.rs b/tests/ui/iter_kv_map.rs index 7a1f1fb0198c7..ad6564df40846 100644 --- a/tests/ui/iter_kv_map.rs +++ b/tests/ui/iter_kv_map.rs @@ -1,14 +1,15 @@ // run-rustfix #![warn(clippy::iter_kv_map)] -#![allow(clippy::redundant_clone)] -#![allow(clippy::suspicious_map)] -#![allow(clippy::map_identity)] +#![allow(unused_mut, clippy::redundant_clone, clippy::suspicious_map, clippy::map_identity)] use std::collections::{BTreeMap, HashMap}; fn main() { let get_key = |(key, _val)| key; + fn ref_acceptor(v: &u32) -> u32 { + *v + } let map: HashMap = HashMap::new(); @@ -36,6 +37,22 @@ fn main() { let _ = map.iter().map(|(key, _value)| key * 9).count(); let _ = map.iter().map(|(_key, value)| value * 17).count(); + // Preserve the ref in the fix. + let _ = map.clone().into_iter().map(|(_, ref val)| ref_acceptor(val)).count(); + + // Preserve the mut in the fix. + let _ = map + .clone() + .into_iter() + .map(|(_, mut val)| { + val += 2; + val + }) + .count(); + + // Don't let a mut interfere. + let _ = map.clone().into_iter().map(|(_, mut val)| val).count(); + let map: BTreeMap = BTreeMap::new(); let _ = map.iter().map(|(key, _)| key).collect::>(); @@ -61,4 +78,20 @@ fn main() { // Lint let _ = map.iter().map(|(key, _value)| key * 9).count(); let _ = map.iter().map(|(_key, value)| value * 17).count(); + + // Preserve the ref in the fix. + let _ = map.clone().into_iter().map(|(_, ref val)| ref_acceptor(val)).count(); + + // Preserve the mut in the fix. + let _ = map + .clone() + .into_iter() + .map(|(_, mut val)| { + val += 2; + val + }) + .count(); + + // Don't let a mut interfere. + let _ = map.clone().into_iter().map(|(_, mut val)| val).count(); } diff --git a/tests/ui/iter_kv_map.stderr b/tests/ui/iter_kv_map.stderr index 9b9b04c97d81e..e00da223b4dd2 100644 --- a/tests/ui/iter_kv_map.stderr +++ b/tests/ui/iter_kv_map.stderr @@ -1,5 +1,5 @@ error: iterating on a map's keys - --> $DIR/iter_kv_map.rs:15:13 + --> $DIR/iter_kv_map.rs:16:13 | LL | let _ = map.iter().map(|(key, _)| key).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()` @@ -7,130 +7,198 @@ LL | let _ = map.iter().map(|(key, _)| key).collect::>(); = note: `-D clippy::iter-kv-map` implied by `-D warnings` error: iterating on a map's values - --> $DIR/iter_kv_map.rs:16:13 + --> $DIR/iter_kv_map.rs:17:13 | LL | let _ = map.iter().map(|(_, value)| value).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values()` error: iterating on a map's values - --> $DIR/iter_kv_map.rs:17:13 + --> $DIR/iter_kv_map.rs:18:13 | LL | let _ = map.iter().map(|(_, v)| v + 2).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)` error: iterating on a map's keys - --> $DIR/iter_kv_map.rs:19:13 + --> $DIR/iter_kv_map.rs:20:13 | LL | let _ = map.clone().into_iter().map(|(key, _)| key).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys()` error: iterating on a map's keys - --> $DIR/iter_kv_map.rs:20:13 + --> $DIR/iter_kv_map.rs:21:13 | LL | let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys().map(|key| key + 2)` error: iterating on a map's values - --> $DIR/iter_kv_map.rs:22:13 + --> $DIR/iter_kv_map.rs:23:13 | LL | let _ = map.clone().into_iter().map(|(_, val)| val).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()` error: iterating on a map's values - --> $DIR/iter_kv_map.rs:23:13 + --> $DIR/iter_kv_map.rs:24:13 | LL | let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|val| val + 2)` error: iterating on a map's values - --> $DIR/iter_kv_map.rs:25:13 + --> $DIR/iter_kv_map.rs:26:13 | LL | let _ = map.clone().iter().map(|(_, val)| val).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().values()` error: iterating on a map's keys - --> $DIR/iter_kv_map.rs:26:13 + --> $DIR/iter_kv_map.rs:27:13 | LL | let _ = map.iter().map(|(key, _)| key).filter(|x| *x % 2 == 0).count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()` error: iterating on a map's keys - --> $DIR/iter_kv_map.rs:36:13 + --> $DIR/iter_kv_map.rs:37:13 | LL | let _ = map.iter().map(|(key, _value)| key * 9).count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys().map(|key| key * 9)` error: iterating on a map's values - --> $DIR/iter_kv_map.rs:37:13 + --> $DIR/iter_kv_map.rs:38:13 | LL | let _ = map.iter().map(|(_key, value)| value * 17).count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|value| value * 17)` -error: iterating on a map's keys +error: iterating on a map's values --> $DIR/iter_kv_map.rs:41:13 | +LL | let _ = map.clone().into_iter().map(|(_, ref val)| ref_acceptor(val)).count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|ref val| ref_acceptor(val))` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:44:13 + | +LL | let _ = map + | _____________^ +LL | | .clone() +LL | | .into_iter() +LL | | .map(|(_, mut val)| { +LL | | val += 2; +LL | | val +LL | | }) + | |__________^ + | +help: try + | +LL ~ let _ = map +LL + .clone().into_values().map(|mut val| { +LL + val += 2; +LL + val +LL + }) + | + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:54:13 + | +LL | let _ = map.clone().into_iter().map(|(_, mut val)| val).count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()` + +error: iterating on a map's keys + --> $DIR/iter_kv_map.rs:58:13 + | LL | let _ = map.iter().map(|(key, _)| key).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()` error: iterating on a map's values - --> $DIR/iter_kv_map.rs:42:13 + --> $DIR/iter_kv_map.rs:59:13 | LL | let _ = map.iter().map(|(_, value)| value).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values()` error: iterating on a map's values - --> $DIR/iter_kv_map.rs:43:13 + --> $DIR/iter_kv_map.rs:60:13 | LL | let _ = map.iter().map(|(_, v)| v + 2).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)` error: iterating on a map's keys - --> $DIR/iter_kv_map.rs:45:13 + --> $DIR/iter_kv_map.rs:62:13 | LL | let _ = map.clone().into_iter().map(|(key, _)| key).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys()` error: iterating on a map's keys - --> $DIR/iter_kv_map.rs:46:13 + --> $DIR/iter_kv_map.rs:63:13 | LL | let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys().map(|key| key + 2)` error: iterating on a map's values - --> $DIR/iter_kv_map.rs:48:13 + --> $DIR/iter_kv_map.rs:65:13 | LL | let _ = map.clone().into_iter().map(|(_, val)| val).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()` error: iterating on a map's values - --> $DIR/iter_kv_map.rs:49:13 + --> $DIR/iter_kv_map.rs:66:13 | LL | let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|val| val + 2)` error: iterating on a map's values - --> $DIR/iter_kv_map.rs:51:13 + --> $DIR/iter_kv_map.rs:68:13 | LL | let _ = map.clone().iter().map(|(_, val)| val).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().values()` error: iterating on a map's keys - --> $DIR/iter_kv_map.rs:52:13 + --> $DIR/iter_kv_map.rs:69:13 | LL | let _ = map.iter().map(|(key, _)| key).filter(|x| *x % 2 == 0).count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()` error: iterating on a map's keys - --> $DIR/iter_kv_map.rs:62:13 + --> $DIR/iter_kv_map.rs:79:13 | LL | let _ = map.iter().map(|(key, _value)| key * 9).count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys().map(|key| key * 9)` error: iterating on a map's values - --> $DIR/iter_kv_map.rs:63:13 + --> $DIR/iter_kv_map.rs:80:13 | LL | let _ = map.iter().map(|(_key, value)| value * 17).count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|value| value * 17)` -error: aborting due to 22 previous errors +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:83:13 + | +LL | let _ = map.clone().into_iter().map(|(_, ref val)| ref_acceptor(val)).count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|ref val| ref_acceptor(val))` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:86:13 + | +LL | let _ = map + | _____________^ +LL | | .clone() +LL | | .into_iter() +LL | | .map(|(_, mut val)| { +LL | | val += 2; +LL | | val +LL | | }) + | |__________^ + | +help: try + | +LL ~ let _ = map +LL + .clone().into_values().map(|mut val| { +LL + val += 2; +LL + val +LL + }) + | + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:96:13 + | +LL | let _ = map.clone().into_iter().map(|(_, mut val)| val).count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()` + +error: aborting due to 28 previous errors From 05ba519a3ab8c06ba449d41a14e8584d785c1cb9 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Wed, 4 Jan 2023 11:23:35 +0100 Subject: [PATCH 28/51] trim paths in `default_trait_access`/`clone_on_copy` suggestions --- clippy_lints/src/default.rs | 5 ++--- clippy_lints/src/methods/clone_on_copy.rs | 14 ++++++++------ tests/ui/clone_on_copy.stderr | 2 +- tests/ui/default_trait_access.fixed | 8 ++++---- tests/ui/default_trait_access.stderr | 16 ++++++++-------- tests/ui/unnecessary_clone.stderr | 10 +++++----- 6 files changed, 28 insertions(+), 27 deletions(-) diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs index 55f6121a09d2e..a04693f4637ab 100644 --- a/clippy_lints/src/default.rs +++ b/clippy_lints/src/default.rs @@ -11,6 +11,7 @@ use rustc_hir::def::Res; use rustc_hir::{Block, Expr, ExprKind, PatKind, QPath, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; +use rustc_middle::ty::print::with_forced_trimmed_paths; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::Span; @@ -98,9 +99,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { 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. - let replacement = format!("{}::default()", cx.tcx.def_path_str(def.did())); + let replacement = with_forced_trimmed_paths!(format!("{}::default()", cx.tcx.def_path_str(def.did()))); span_lint_and_sugg( cx, DEFAULT_TRAIT_ACCESS, diff --git a/clippy_lints/src/methods/clone_on_copy.rs b/clippy_lints/src/methods/clone_on_copy.rs index 7c7938dd2e8b0..3795c0ec25098 100644 --- a/clippy_lints/src/methods/clone_on_copy.rs +++ b/clippy_lints/src/methods/clone_on_copy.rs @@ -6,7 +6,7 @@ use clippy_utils::ty::is_copy; use rustc_errors::Applicability; use rustc_hir::{BindingAnnotation, ByRef, Expr, ExprKind, MatchSource, Node, PatKind, QPath}; use rustc_lint::LateContext; -use rustc_middle::ty::{self, adjustment::Adjust}; +use rustc_middle::ty::{self, adjustment::Adjust, print::with_forced_trimmed_paths}; use rustc_span::symbol::{sym, Symbol}; use super::CLONE_DOUBLE_REF; @@ -47,10 +47,10 @@ pub(super) fn check( cx, CLONE_DOUBLE_REF, expr.span, - &format!( + &with_forced_trimmed_paths!(format!( "using `clone` on a double-reference; \ this will copy the reference of type `{ty}` instead of cloning the inner type" - ), + )), |diag| { if let Some(snip) = sugg::Sugg::hir_opt(cx, arg) { let mut ty = innermost; @@ -61,11 +61,11 @@ pub(super) fn check( } let refs = "&".repeat(n + 1); let derefs = "*".repeat(n); - let explicit = format!("<{refs}{ty}>::clone({snip})"); + let explicit = with_forced_trimmed_paths!(format!("<{refs}{ty}>::clone({snip})")); diag.span_suggestion( expr.span, "try dereferencing it", - format!("{refs}({derefs}{}).clone()", snip.deref()), + with_forced_trimmed_paths!(format!("{refs}({derefs}{}).clone()", snip.deref())), Applicability::MaybeIncorrect, ); diag.span_suggestion( @@ -129,7 +129,9 @@ pub(super) fn check( cx, CLONE_ON_COPY, expr.span, - &format!("using `clone` on type `{ty}` which implements the `Copy` trait"), + &with_forced_trimmed_paths!(format!( + "using `clone` on type `{ty}` which implements the `Copy` trait" + )), help, sugg, app, diff --git a/tests/ui/clone_on_copy.stderr b/tests/ui/clone_on_copy.stderr index 42ae227777c70..862234d204be3 100644 --- a/tests/ui/clone_on_copy.stderr +++ b/tests/ui/clone_on_copy.stderr @@ -48,7 +48,7 @@ error: using `clone` on type `i32` which implements the `Copy` trait 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 +error: using `clone` on type `Option` which implements the `Copy` trait --> $DIR/clone_on_copy.rs:77:17 | LL | let value = opt.clone()?; // operator precedence needed (*opt)? diff --git a/tests/ui/default_trait_access.fixed b/tests/ui/default_trait_access.fixed index eedd43619392d..5640599d48ae8 100644 --- a/tests/ui/default_trait_access.fixed +++ b/tests/ui/default_trait_access.fixed @@ -12,17 +12,17 @@ use std::default::Default as D2; use std::string; fn main() { - let s1: String = std::string::String::default(); + let s1: String = String::default(); let s2 = String::default(); - let s3: String = std::string::String::default(); + let s3: String = String::default(); - let s4: String = std::string::String::default(); + let s4: String = String::default(); let s5 = string::String::default(); - let s6: String = std::string::String::default(); + let s6: String = String::default(); let s7 = std::string::String::default(); diff --git a/tests/ui/default_trait_access.stderr b/tests/ui/default_trait_access.stderr index 49b2dde3f1e8c..e4f73c08d190a 100644 --- a/tests/ui/default_trait_access.stderr +++ b/tests/ui/default_trait_access.stderr @@ -1,8 +1,8 @@ -error: calling `std::string::String::default()` is more clear than this expression +error: calling `String::default()` is more clear than this expression --> $DIR/default_trait_access.rs:15:22 | LL | let s1: String = Default::default(); - | ^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()` + | ^^^^^^^^^^^^^^^^^^ help: try: `String::default()` | note: the lint level is defined here --> $DIR/default_trait_access.rs:3:9 @@ -10,23 +10,23 @@ note: the lint level is defined here LL | #![deny(clippy::default_trait_access)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: calling `std::string::String::default()` is more clear than this expression +error: calling `String::default()` is more clear than this expression --> $DIR/default_trait_access.rs:19:22 | LL | let s3: String = D2::default(); - | ^^^^^^^^^^^^^ help: try: `std::string::String::default()` + | ^^^^^^^^^^^^^ help: try: `String::default()` -error: calling `std::string::String::default()` is more clear than this expression +error: calling `String::default()` is more clear than this expression --> $DIR/default_trait_access.rs:21:22 | LL | let s4: String = std::default::Default::default(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `String::default()` -error: calling `std::string::String::default()` is more clear than this expression +error: calling `String::default()` is more clear than this expression --> $DIR/default_trait_access.rs:25:22 | LL | let s6: String = default::Default::default(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `String::default()` error: calling `GenericDerivedDefault::default()` is more clear than this expression --> $DIR/default_trait_access.rs:35:46 diff --git a/tests/ui/unnecessary_clone.stderr b/tests/ui/unnecessary_clone.stderr index 94cc7777acacd..6022d9fa4c5c3 100644 --- a/tests/ui/unnecessary_clone.stderr +++ b/tests/ui/unnecessary_clone.stderr @@ -38,13 +38,13 @@ LL | t.clone(); | = note: `-D clippy::clone-on-copy` implied by `-D warnings` -error: using `clone` on type `std::option::Option` which implements the `Copy` trait +error: using `clone` on type `Option` which implements the `Copy` trait --> $DIR/unnecessary_clone.rs:42:5 | LL | Some(t).clone(); | ^^^^^^^^^^^^^^^ help: try removing the `clone` call: `Some(t)` -error: using `clone` on a double-reference; this will copy the reference of type `&std::vec::Vec` instead of cloning the inner type +error: using `clone` on a double-reference; this will copy the reference of type `&Vec` instead of cloning the inner type --> $DIR/unnecessary_clone.rs:48:22 | LL | let z: &Vec<_> = y.clone(); @@ -57,10 +57,10 @@ LL | let z: &Vec<_> = &(*y).clone(); | ~~~~~~~~~~~~~ help: or try being explicit if you are sure, that you want to clone a reference | -LL | let z: &Vec<_> = <&std::vec::Vec>::clone(y); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | let z: &Vec<_> = <&Vec>::clone(y); + | ~~~~~~~~~~~~~~~~~~~~~ -error: using `clone` on type `many_derefs::E` which implements the `Copy` trait +error: using `clone` on type `E` which implements the `Copy` trait --> $DIR/unnecessary_clone.rs:84:20 | LL | let _: E = a.clone(); From 755ae3fa29b0b2c6b11eaecf81b201b0a9a026bf Mon Sep 17 00:00:00 2001 From: Kyle Huey Date: Wed, 4 Jan 2023 14:58:07 -0800 Subject: [PATCH 29/51] Fix spelling while we're in the neighborhood. --- clippy_lints/src/methods/iter_kv_map.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/methods/iter_kv_map.rs b/clippy_lints/src/methods/iter_kv_map.rs index 1e5805c534772..c87f5daab6f24 100644 --- a/clippy_lints/src/methods/iter_kv_map.rs +++ b/clippy_lints/src/methods/iter_kv_map.rs @@ -30,7 +30,7 @@ pub(super) fn check<'tcx>( if let Body {params: [p], value: body_expr, generator_kind: _ } = cx.tcx.hir().body(c.body); if let PatKind::Tuple([key_pat, val_pat], _) = p.pat.kind; - let (replacement_kind, annotation, binded_ident) = match (&key_pat.kind, &val_pat.kind) { + let (replacement_kind, annotation, bound_ident) = match (&key_pat.kind, &val_pat.kind) { (key, PatKind::Binding(ann, _, value, _)) if pat_is_wild(cx, key, m_arg) => ("value", ann, value), (PatKind::Binding(ann, _, key, _), value) if pat_is_wild(cx, value, m_arg) => ("key", ann, key), _ => return, @@ -47,7 +47,7 @@ pub(super) fn check<'tcx>( if_chain! { if let ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) = body_expr.kind; if let [local_ident] = path.segments; - if local_ident.ident.as_str() == binded_ident.as_str(); + if local_ident.ident.as_str() == bound_ident.as_str(); then { span_lint_and_sugg( @@ -76,7 +76,7 @@ pub(super) fn check<'tcx>( expr.span, &format!("iterating on a map's {replacement_kind}s"), "try", - format!("{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{ref_annotation}{mut_annotation}{binded_ident}| {})", + format!("{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{ref_annotation}{mut_annotation}{bound_ident}| {})", snippet_with_applicability(cx, body_expr.span, "/* body */", &mut applicability)), applicability, ); From 1c42dbba60ece87f3031bc2dad5497f3cc9ad7d0 Mon Sep 17 00:00:00 2001 From: Kyle Huey Date: Wed, 4 Jan 2023 19:08:37 -0800 Subject: [PATCH 30/51] Expand derivable-impls to cover enums with a default unit variant. --- clippy_lints/src/derivable_impls.rs | 143 ++++++++++++++++++++-------- tests/ui/derivable_impls.fixed | 21 ++++ tests/ui/derivable_impls.rs | 23 +++++ tests/ui/derivable_impls.stderr | 23 ++++- 4 files changed, 167 insertions(+), 43 deletions(-) diff --git a/clippy_lints/src/derivable_impls.rs b/clippy_lints/src/derivable_impls.rs index ae8f6b794499f..c987fdb1a6795 100644 --- a/clippy_lints/src/derivable_impls.rs +++ b/clippy_lints/src/derivable_impls.rs @@ -1,11 +1,13 @@ use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::indent_of; use clippy_utils::{is_default_equivalent, peel_blocks}; use rustc_errors::Applicability; use rustc_hir::{ - def::{DefKind, Res}, - Body, Expr, ExprKind, GenericArg, Impl, ImplItemKind, Item, ItemKind, Node, PathSegment, QPath, TyKind, + def::{CtorKind, CtorOf, DefKind, Res}, + Body, Expr, ExprKind, GenericArg, Impl, ImplItemKind, Item, ItemKind, Node, PathSegment, QPath, Ty, TyKind, }; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::{AdtDef, DefIdTree}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; @@ -61,6 +63,98 @@ fn is_path_self(e: &Expr<'_>) -> bool { } } +fn check_struct<'tcx>( + cx: &LateContext<'tcx>, + item: &'tcx Item<'_>, + self_ty: &Ty<'_>, + func_expr: &Expr<'_>, + adt_def: AdtDef<'_>, +) { + if let TyKind::Path(QPath::Resolved(_, p)) = self_ty.kind { + if let Some(PathSegment { args: Some(a), .. }) = p.segments.last() { + for arg in a.args { + if !matches!(arg, GenericArg::Lifetime(_)) { + return; + } + } + } + } + let should_emit = match peel_blocks(func_expr).kind { + ExprKind::Tup(fields) => fields.iter().all(|e| is_default_equivalent(cx, e)), + ExprKind::Call(callee, args) if is_path_self(callee) => args.iter().all(|e| is_default_equivalent(cx, e)), + ExprKind::Struct(_, fields, _) => fields.iter().all(|ef| is_default_equivalent(cx, ef.expr)), + _ => false, + }; + + if should_emit { + let struct_span = cx.tcx.def_span(adt_def.did()); + span_lint_and_then(cx, DERIVABLE_IMPLS, item.span, "this `impl` can be derived", |diag| { + diag.span_suggestion_hidden( + item.span, + "remove the manual implementation...", + String::new(), + Applicability::MachineApplicable, + ); + diag.span_suggestion( + struct_span.shrink_to_lo(), + "...and instead derive it", + "#[derive(Default)]\n".to_string(), + Applicability::MachineApplicable, + ); + }); + } +} + +fn check_enum<'tcx>(cx: &LateContext<'tcx>, item: &'tcx Item<'_>, func_expr: &Expr<'_>, adt_def: AdtDef<'_>) { + if_chain! { + if let ExprKind::Path(QPath::Resolved(None, p)) = &peel_blocks(func_expr).kind; + if let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Const), id) = p.res; + if let variant_id = cx.tcx.parent(id); + if let Some(variant_def) = adt_def.variants().iter().find(|v| v.def_id == variant_id); + if variant_def.fields.is_empty(); + if !variant_def.is_field_list_non_exhaustive(); + + then { + let enum_span = cx.tcx.def_span(adt_def.did()); + let indent_enum = indent_of(cx, enum_span).unwrap_or(0); + let variant_span = cx.tcx.def_span(variant_def.def_id); + let indent_variant = indent_of(cx, variant_span).unwrap_or(0); + span_lint_and_then( + cx, + DERIVABLE_IMPLS, + item.span, + "this `impl` can be derived", + |diag| { + diag.span_suggestion_hidden( + item.span, + "remove the manual implementation...", + String::new(), + Applicability::MachineApplicable + ); + diag.span_suggestion( + enum_span.shrink_to_lo(), + "...and instead derive it...", + format!( + "#[derive(Default)]\n{indent}", + indent = " ".repeat(indent_enum), + ), + Applicability::MachineApplicable + ); + diag.span_suggestion( + variant_span.shrink_to_lo(), + "...and mark the default variant", + format!( + "#[default]\n{indent}", + indent = " ".repeat(indent_variant), + ), + Applicability::MachineApplicable + ); + } + ); + } + } +} + impl<'tcx> LateLintPass<'tcx> for DerivableImpls { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { if_chain! { @@ -83,47 +177,12 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls { if !attrs.iter().any(|attr| attr.doc_str().is_some()); if let child_attrs = cx.tcx.hir().attrs(impl_item_hir); if !child_attrs.iter().any(|attr| attr.doc_str().is_some()); - if adt_def.is_struct(); - then { - if let TyKind::Path(QPath::Resolved(_, p)) = self_ty.kind { - if let Some(PathSegment { args: Some(a), .. }) = p.segments.last() { - for arg in a.args { - if !matches!(arg, GenericArg::Lifetime(_)) { - return; - } - } - } - } - let should_emit = match peel_blocks(func_expr).kind { - ExprKind::Tup(fields) => fields.iter().all(|e| is_default_equivalent(cx, e)), - ExprKind::Call(callee, args) - if is_path_self(callee) => args.iter().all(|e| is_default_equivalent(cx, e)), - ExprKind::Struct(_, fields, _) => fields.iter().all(|ef| is_default_equivalent(cx, ef.expr)), - _ => false, - }; - if should_emit { - let struct_span = cx.tcx.def_span(adt_def.did()); - span_lint_and_then( - cx, - DERIVABLE_IMPLS, - item.span, - "this `impl` can be derived", - |diag| { - diag.span_suggestion_hidden( - item.span, - "remove the manual implementation...", - String::new(), - Applicability::MachineApplicable - ); - diag.span_suggestion( - struct_span.shrink_to_lo(), - "...and instead derive it", - "#[derive(Default)]\n".to_string(), - Applicability::MachineApplicable - ); - } - ); + then { + if adt_def.is_struct() { + check_struct(cx, item, self_ty, func_expr, adt_def); + } else if adt_def.is_enum() { + check_enum(cx, item, func_expr, adt_def); } } } diff --git a/tests/ui/derivable_impls.fixed b/tests/ui/derivable_impls.fixed index 7dcdfb0937e89..ee8456f5deb8a 100644 --- a/tests/ui/derivable_impls.fixed +++ b/tests/ui/derivable_impls.fixed @@ -210,4 +210,25 @@ impl Default for IntOrString { } } +#[derive(Default)] +pub enum SimpleEnum { + Foo, + #[default] + Bar, +} + + + +pub enum NonExhaustiveEnum { + Foo, + #[non_exhaustive] + Bar, +} + +impl Default for NonExhaustiveEnum { + fn default() -> Self { + NonExhaustiveEnum::Bar + } +} + fn main() {} diff --git a/tests/ui/derivable_impls.rs b/tests/ui/derivable_impls.rs index 625cbcdde230a..14af419bcad14 100644 --- a/tests/ui/derivable_impls.rs +++ b/tests/ui/derivable_impls.rs @@ -244,4 +244,27 @@ impl Default for IntOrString { } } +pub enum SimpleEnum { + Foo, + Bar, +} + +impl Default for SimpleEnum { + fn default() -> Self { + SimpleEnum::Bar + } +} + +pub enum NonExhaustiveEnum { + Foo, + #[non_exhaustive] + Bar, +} + +impl Default for NonExhaustiveEnum { + fn default() -> Self { + NonExhaustiveEnum::Bar + } +} + fn main() {} diff --git a/tests/ui/derivable_impls.stderr b/tests/ui/derivable_impls.stderr index c1db5a58b1f51..81963c3be5b5d 100644 --- a/tests/ui/derivable_impls.stderr +++ b/tests/ui/derivable_impls.stderr @@ -113,5 +113,26 @@ help: ...and instead derive it LL | #[derive(Default)] | -error: aborting due to 7 previous errors +error: this `impl` can be derived + --> $DIR/derivable_impls.rs:252:1 + | +LL | / impl Default for SimpleEnum { +LL | | fn default() -> Self { +LL | | SimpleEnum::Bar +LL | | } +LL | | } + | |_^ + | + = help: remove the manual implementation... +help: ...and instead derive it... + | +LL | #[derive(Default)] + | +help: ...and mark the default variant + | +LL ~ #[default] +LL ~ Bar, + | + +error: aborting due to 8 previous errors From 79ed23ff815bc39d0062ade40b2c38dd37e77373 Mon Sep 17 00:00:00 2001 From: Raiki Tamura Date: Thu, 5 Jan 2023 18:30:13 +0900 Subject: [PATCH 31/51] fix --- clippy_lints/src/loops/single_element_loop.rs | 14 +++++++++ tests/ui/single_element_loop.fixed | 27 +++++++++++++++++ tests/ui/single_element_loop.rs | 26 +++++++++++++++++ tests/ui/single_element_loop.stderr | 29 ++++++++++++++++++- 4 files changed, 95 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/loops/single_element_loop.rs b/clippy_lints/src/loops/single_element_loop.rs index f4b47808dfaa3..7cbc456244e40 100644 --- a/clippy_lints/src/loops/single_element_loop.rs +++ b/clippy_lints/src/loops/single_element_loop.rs @@ -1,6 +1,7 @@ use super::SINGLE_ELEMENT_LOOP; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{indent_of, snippet_with_applicability}; +use clippy_utils::visitors::for_each_expr; use if_chain::if_chain; use rustc_ast::util::parser::PREC_PREFIX; use rustc_ast::Mutability; @@ -8,6 +9,18 @@ use rustc_errors::Applicability; use rustc_hir::{is_range_literal, BorrowKind, Expr, ExprKind, Pat}; use rustc_lint::LateContext; use rustc_span::edition::Edition; +use std::ops::ControlFlow; + +fn contains_break_or_continue(expr: &Expr<'_>) -> bool { + for_each_expr(expr, |e| { + if matches!(e.kind, ExprKind::Break(..) | ExprKind::Continue(..)) { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(()) + } + }) + .is_some() +} pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, @@ -67,6 +80,7 @@ pub(super) fn check<'tcx>( if_chain! { if let ExprKind::Block(block, _) = body.kind; if !block.stmts.is_empty(); + if !contains_break_or_continue(body); then { let mut applicability = Applicability::MachineApplicable; let pat_snip = snippet_with_applicability(cx, pat.span, "..", &mut applicability); diff --git a/tests/ui/single_element_loop.fixed b/tests/ui/single_element_loop.fixed index 63d31ff83f9b5..a0dcc0172e8b0 100644 --- a/tests/ui/single_element_loop.fixed +++ b/tests/ui/single_element_loop.fixed @@ -33,4 +33,31 @@ fn main() { let item = 0..5; dbg!(item); } + + // should not lint (issue #10018) + for e in [42] { + if e > 0 { + continue; + } + } + + // should not lint (issue #10018) + for e in [42] { + if e > 0 { + break; + } + } + + // should lint (issue #10018) + { + let _ = 42; + let _f = |n: u32| { + for i in 0..n { + if i > 10 { + dbg!(i); + break; + } + } + }; + } } diff --git a/tests/ui/single_element_loop.rs b/tests/ui/single_element_loop.rs index 2cda5a329d254..bc014035c98a5 100644 --- a/tests/ui/single_element_loop.rs +++ b/tests/ui/single_element_loop.rs @@ -27,4 +27,30 @@ fn main() { for item in [0..5].into_iter() { dbg!(item); } + + // should not lint (issue #10018) + for e in [42] { + if e > 0 { + continue; + } + } + + // should not lint (issue #10018) + for e in [42] { + if e > 0 { + break; + } + } + + // should lint (issue #10018) + for _ in [42] { + let _f = |n: u32| { + for i in 0..n { + if i > 10 { + dbg!(i); + break; + } + } + }; + } } diff --git a/tests/ui/single_element_loop.stderr b/tests/ui/single_element_loop.stderr index 0aeb8da1a2e23..14437a59745e0 100644 --- a/tests/ui/single_element_loop.stderr +++ b/tests/ui/single_element_loop.stderr @@ -95,5 +95,32 @@ LL + dbg!(item); LL + } | -error: aborting due to 6 previous errors +error: for loop over a single element + --> $DIR/single_element_loop.rs:46:5 + | +LL | / for _ in [42] { +LL | | let _f = |n: u32| { +LL | | for i in 0..n { +LL | | if i > 10 { +... | +LL | | }; +LL | | } + | |_____^ + | +help: try + | +LL ~ { +LL + let _ = 42; +LL + let _f = |n: u32| { +LL + for i in 0..n { +LL + if i > 10 { +LL + dbg!(i); +LL + break; +LL + } +LL + } +LL + }; +LL + } + | + +error: aborting due to 7 previous errors From 6433d796a1e22ea37f9b51bda5248b9ac82df578 Mon Sep 17 00:00:00 2001 From: Kyle Huey Date: Thu, 5 Jan 2023 13:06:43 -0800 Subject: [PATCH 32/51] Restrict suggestion of deriving Default for enums to MSRV 1.62. See https://blog.rust-lang.org/2022/06/30/Rust-1.62.0.html#default-enum-variants --- clippy_lints/src/derivable_impls.rs | 20 +++++++++++++++++--- clippy_lints/src/lib.rs | 2 +- clippy_utils/src/msrvs.rs | 4 ++-- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/clippy_lints/src/derivable_impls.rs b/clippy_lints/src/derivable_impls.rs index c987fdb1a6795..bc18e2e5ed5fd 100644 --- a/clippy_lints/src/derivable_impls.rs +++ b/clippy_lints/src/derivable_impls.rs @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::indent_of; use clippy_utils::{is_default_equivalent, peel_blocks}; use rustc_errors::Applicability; @@ -8,7 +9,7 @@ use rustc_hir::{ }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{AdtDef, DefIdTree}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::sym; declare_clippy_lint! { @@ -53,7 +54,18 @@ declare_clippy_lint! { "manual implementation of the `Default` trait which is equal to a derive" } -declare_lint_pass!(DerivableImpls => [DERIVABLE_IMPLS]); +pub struct DerivableImpls { + msrv: Msrv, +} + +impl DerivableImpls { + #[must_use] + pub fn new(msrv: Msrv) -> Self { + DerivableImpls { msrv } + } +} + +impl_lint_pass!(DerivableImpls => [DERIVABLE_IMPLS]); fn is_path_self(e: &Expr<'_>) -> bool { if let ExprKind::Path(QPath::Resolved(_, p)) = e.kind { @@ -181,10 +193,12 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls { then { if adt_def.is_struct() { check_struct(cx, item, self_ty, func_expr, adt_def); - } else if adt_def.is_enum() { + } else if adt_def.is_enum() && self.msrv.meets(msrvs::DEFAULT_ENUM_ATTRIBUTE) { check_enum(cx, item, func_expr, adt_def); } } } } + + extract_msrv_attr!(LateContext); } diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index dcd8ca81ae872..d8e2ae02c5a65 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -639,7 +639,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(panic_unimplemented::PanicUnimplemented)); store.register_late_pass(|_| Box::new(strings::StringLitAsBytes)); store.register_late_pass(|_| Box::new(derive::Derive)); - store.register_late_pass(|_| Box::new(derivable_impls::DerivableImpls)); + store.register_late_pass(move |_| Box::new(derivable_impls::DerivableImpls::new(msrv()))); store.register_late_pass(|_| Box::new(drop_forget_ref::DropForgetRef)); store.register_late_pass(|_| Box::new(empty_enum::EmptyEnum)); store.register_late_pass(|_| Box::new(invalid_upcast_comparisons::InvalidUpcastComparisons)); diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index ba5bc9c3135da..dbf9f3b621d7a 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -20,8 +20,9 @@ macro_rules! msrv_aliases { // names may refer to stabilized feature flags or library items msrv_aliases! { 1,65,0 { LET_ELSE } - 1,62,0 { BOOL_THEN_SOME } + 1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE } 1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY } + 1,55,0 { SEEK_REWIND } 1,53,0 { OR_PATTERNS, MANUAL_BITS, BTREE_MAP_RETAIN, BTREE_SET_RETAIN, ARRAY_INTO_ITERATOR } 1,52,0 { STR_SPLIT_ONCE, REM_EUCLID_CONST } 1,51,0 { BORROW_AS_PTR, SEEK_FROM_CURRENT, UNSIGNED_ABS } @@ -45,7 +46,6 @@ msrv_aliases! { 1,18,0 { HASH_MAP_RETAIN, HASH_SET_RETAIN } 1,17,0 { FIELD_INIT_SHORTHAND, STATIC_IN_CONST, EXPECT_ERR } 1,16,0 { STR_REPEAT } - 1,55,0 { SEEK_REWIND } } fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option) -> Option { From e443604a24029e0ffd77f917e82980539fdacbbe Mon Sep 17 00:00:00 2001 From: Robin Schroer Date: Fri, 6 Jan 2023 12:52:51 +0900 Subject: [PATCH 33/51] unused_self: Don't trigger if the method body contains todo!() If the author is using todo!(), presumably they intend to use self at some point later, so we don't have a good basis to recommend factoring out to an associated function. Fixes #10117. changelog: Don't trigger [`unused_self`] if the method body contains a `todo!()` call --- clippy_lints/src/unused_self.rs | 19 ++++++++++++++++++- tests/ui/unused_self.rs | 10 ++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/unused_self.rs b/clippy_lints/src/unused_self.rs index 18231b6a7e869..f864c520302e4 100644 --- a/clippy_lints/src/unused_self.rs +++ b/clippy_lints/src/unused_self.rs @@ -1,9 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::macros::root_macro_call_first_node; use clippy_utils::visitors::is_local_used; use if_chain::if_chain; -use rustc_hir::{Impl, ImplItem, ImplItemKind, ItemKind}; +use rustc_hir::{Body, Impl, ImplItem, ImplItemKind, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; +use std::ops::ControlFlow; declare_clippy_lint! { /// ### What it does @@ -57,6 +59,20 @@ impl<'tcx> LateLintPass<'tcx> for UnusedSelf { let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id()).def_id; let parent_item = cx.tcx.hir().expect_item(parent); let assoc_item = cx.tcx.associated_item(impl_item.owner_id); + let contains_todo = |cx, body: &'_ Body<'_>| -> bool { + clippy_utils::visitors::for_each_expr(body.value, |e| { + if let Some(macro_call) = root_macro_call_first_node(cx, e) { + if cx.tcx.item_name(macro_call.def_id).as_str() == "todo" { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(()) + } + } else { + ControlFlow::Continue(()) + } + }) + .is_some() + }; if_chain! { if let ItemKind::Impl(Impl { of_trait: None, .. }) = parent_item.kind; if assoc_item.fn_has_self_parameter; @@ -65,6 +81,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedSelf { 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); + if !contains_todo(cx, body); then { span_lint_and_help( cx, diff --git a/tests/ui/unused_self.rs b/tests/ui/unused_self.rs index 92e8e1dba69dd..55bd5607185c6 100644 --- a/tests/ui/unused_self.rs +++ b/tests/ui/unused_self.rs @@ -60,6 +60,16 @@ mod unused_self_allow { // shouldn't trigger for public methods pub fn unused_self_move(self) {} } + + pub struct E; + + impl E { + // shouldn't trigger if body contains todo!() + pub fn unused_self_todo(self) { + let x = 42; + todo!() + } + } } pub use unused_self_allow::D; From 1b9a25e28d76221ee9906b2c3ec833a9837d0349 Mon Sep 17 00:00:00 2001 From: blyxyas Date: Fri, 6 Jan 2023 14:41:50 +0100 Subject: [PATCH 34/51] [#10167] Clarify that the lint only works if x eq. y in a `for` loop. Reading the documentation for the lint, one could expect that the lint works in all cases that `X == Y`. This is false. While the lint was updated, the documentation wasn't. More information about the `N..N` problem in #5689 and #5628 --- clippy_lints/src/ranges.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 0a1b9d173cf94..fc655fe2d0bb3 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -103,7 +103,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does /// Checks for range expressions `x..y` where both `x` and `y` - /// are constant and `x` is greater or equal to `y`. + /// are constant and `x` is greater to `y`. Also triggers if `x` is equal to `y` when they are conditions to a `for` loop. /// /// ### Why is this bad? /// Empty ranges yield no values so iterating them is a no-op. From 4262aebeaaa5789279110b1f039e991ad8996fa2 Mon Sep 17 00:00:00 2001 From: Caio Date: Fri, 6 Jan 2023 12:25:51 -0300 Subject: [PATCH 35/51] [arithmetic-side-effects] Consider negative numbers and add more tests --- .../src/operators/arithmetic_side_effects.rs | 11 +- clippy_utils/src/lib.rs | 12 + .../arithmetic_side_effects_allowed.rs | 2 +- tests/ui/arithmetic_side_effects.rs | 67 ++++- tests/ui/arithmetic_side_effects.stderr | 274 ++++++++++++++---- 5 files changed, 304 insertions(+), 62 deletions(-) diff --git a/clippy_lints/src/operators/arithmetic_side_effects.rs b/clippy_lints/src/operators/arithmetic_side_effects.rs index 4fbc8398e3734..cff82b875f11a 100644 --- a/clippy_lints/src/operators/arithmetic_side_effects.rs +++ b/clippy_lints/src/operators/arithmetic_side_effects.rs @@ -2,7 +2,7 @@ use super::ARITHMETIC_SIDE_EFFECTS; use clippy_utils::{ consts::{constant, constant_simple}, diagnostics::span_lint, - peel_hir_expr_refs, + peel_hir_expr_refs, peel_hir_expr_unary, }; use rustc_ast as ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -98,8 +98,11 @@ impl ArithmeticSideEffects { } /// If `expr` is not a literal integer like `1`, returns `None`. + /// + /// Returns the absolute value of the expression, if this is an integer literal. fn literal_integer(expr: &hir::Expr<'_>) -> Option { - if let hir::ExprKind::Lit(ref lit) = expr.kind && let ast::LitKind::Int(n, _) = lit.node { + let actual = peel_hir_expr_unary(expr).0; + if let hir::ExprKind::Lit(ref lit) = actual.kind && let ast::LitKind::Int(n, _) = lit.node { Some(n) } else { @@ -123,12 +126,12 @@ impl ArithmeticSideEffects { if !matches!( op.node, hir::BinOpKind::Add - | hir::BinOpKind::Sub - | hir::BinOpKind::Mul | hir::BinOpKind::Div + | hir::BinOpKind::Mul | hir::BinOpKind::Rem | hir::BinOpKind::Shl | hir::BinOpKind::Shr + | hir::BinOpKind::Sub ) { return; }; diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index e7000fb505869..1dc68be31d923 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -2258,6 +2258,18 @@ pub fn peel_n_hir_expr_refs<'a>(expr: &'a Expr<'a>, count: usize) -> (&'a Expr<' (e, count - remaining) } +/// Peels off all unary operators of an expression. Returns the underlying expression and the number +/// of operators removed. +pub fn peel_hir_expr_unary<'a>(expr: &'a Expr<'a>) -> (&'a Expr<'a>, usize) { + let mut count: usize = 0; + let mut curr_expr = expr; + while let ExprKind::Unary(_, local_expr) = curr_expr.kind { + count = count.wrapping_add(1); + curr_expr = local_expr; + } + (curr_expr, count) +} + /// Peels off all references on the expression. Returns the underlying expression and the number of /// references removed. pub fn peel_hir_expr_refs<'a>(expr: &'a Expr<'a>) -> (&'a Expr<'a>, usize) { diff --git a/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs b/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs index 36db9e54a2288..fb5b1b193f841 100644 --- a/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs +++ b/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs @@ -107,7 +107,7 @@ fn rhs_is_different() { fn unary() { // is explicitly on the list let _ = -OutOfNames; - // is specifically on the list + // is explicitly on the list let _ = -Foo; // not on the list let _ = -Bar; diff --git a/tests/ui/arithmetic_side_effects.rs b/tests/ui/arithmetic_side_effects.rs index b5ed8988a518f..66c468c940635 100644 --- a/tests/ui/arithmetic_side_effects.rs +++ b/tests/ui/arithmetic_side_effects.rs @@ -2,6 +2,7 @@ clippy::assign_op_pattern, clippy::erasing_op, clippy::identity_op, + clippy::no_effect, clippy::op_ref, clippy::unnecessary_owned_empty_strings, arithmetic_overflow, @@ -125,6 +126,18 @@ pub fn non_overflowing_ops_or_ops_already_handled_by_the_compiler_should_not_tri _n *= &0; _n *= 1; _n *= &1; + _n += -0; + _n += &-0; + _n -= -0; + _n -= &-0; + _n /= -99; + _n /= &-99; + _n %= -99; + _n %= &-99; + _n *= -0; + _n *= &-0; + _n *= -1; + _n *= &-1; // Binary _n = _n + 0; @@ -158,7 +171,7 @@ pub fn non_overflowing_ops_or_ops_already_handled_by_the_compiler_should_not_tri _n = -&i32::MIN; } -pub fn runtime_ops() { +pub fn unknown_ops_or_runtime_ops_that_can_overflow() { let mut _n = i32::MAX; // Assign @@ -172,6 +185,16 @@ pub fn runtime_ops() { _n %= &0; _n *= 2; _n *= &2; + _n += -1; + _n += &-1; + _n -= -1; + _n -= &-1; + _n /= -0; + _n /= &-0; + _n %= -0; + _n %= &-0; + _n *= -2; + _n *= &-2; // Binary _n = _n + 1; @@ -225,4 +248,46 @@ pub fn runtime_ops() { _n = -&_n; } +// Copied and pasted from the `integer_arithmetic` lint for comparison. +pub fn integer_arithmetic() { + let mut i = 1i32; + let mut var1 = 0i32; + let mut var2 = -1i32; + + 1 + i; + i * 2; + 1 % i / 2; + i - 2 + 2 - i; + -i; + i >> 1; + i << 1; + + -1; + -(-1); + + i & 1; + i | 1; + i ^ 1; + + i += 1; + i -= 1; + i *= 2; + i /= 2; + i /= 0; + i /= -1; + i /= var1; + i /= var2; + i %= 2; + i %= 0; + i %= -1; + i %= var1; + i %= var2; + i <<= 3; + i >>= 2; + + i |= 1; + i &= 1; + i ^= i; +} + fn main() {} diff --git a/tests/ui/arithmetic_side_effects.stderr b/tests/ui/arithmetic_side_effects.stderr index 9fe4b7cf28d8d..a9bb0ae9280e6 100644 --- a/tests/ui/arithmetic_side_effects.stderr +++ b/tests/ui/arithmetic_side_effects.stderr @@ -1,5 +1,5 @@ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:165:5 + --> $DIR/arithmetic_side_effects.rs:178:5 | LL | _n += 1; | ^^^^^^^ @@ -7,328 +7,490 @@ LL | _n += 1; = note: `-D clippy::arithmetic-side-effects` implied by `-D warnings` error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:166:5 + --> $DIR/arithmetic_side_effects.rs:179:5 | LL | _n += &1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:167:5 + --> $DIR/arithmetic_side_effects.rs:180:5 | LL | _n -= 1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:168:5 + --> $DIR/arithmetic_side_effects.rs:181:5 | LL | _n -= &1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:169:5 + --> $DIR/arithmetic_side_effects.rs:182:5 | LL | _n /= 0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:170:5 + --> $DIR/arithmetic_side_effects.rs:183:5 | LL | _n /= &0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:171:5 + --> $DIR/arithmetic_side_effects.rs:184:5 | LL | _n %= 0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:172:5 + --> $DIR/arithmetic_side_effects.rs:185:5 | LL | _n %= &0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:173:5 + --> $DIR/arithmetic_side_effects.rs:186:5 | LL | _n *= 2; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:174:5 + --> $DIR/arithmetic_side_effects.rs:187:5 | LL | _n *= &2; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:177:10 + --> $DIR/arithmetic_side_effects.rs:188:5 + | +LL | _n += -1; + | ^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:189:5 + | +LL | _n += &-1; + | ^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:190:5 + | +LL | _n -= -1; + | ^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:191:5 + | +LL | _n -= &-1; + | ^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:192:5 + | +LL | _n /= -0; + | ^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:193:5 + | +LL | _n /= &-0; + | ^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:194:5 + | +LL | _n %= -0; + | ^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:195:5 + | +LL | _n %= &-0; + | ^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:196:5 + | +LL | _n *= -2; + | ^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:197:5 + | +LL | _n *= &-2; + | ^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:200:10 | LL | _n = _n + 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:178:10 + --> $DIR/arithmetic_side_effects.rs:201:10 | LL | _n = _n + &1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:179:10 + --> $DIR/arithmetic_side_effects.rs:202:10 | LL | _n = 1 + _n; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:180:10 + --> $DIR/arithmetic_side_effects.rs:203:10 | LL | _n = &1 + _n; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:181:10 + --> $DIR/arithmetic_side_effects.rs:204:10 | LL | _n = _n - 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:182:10 + --> $DIR/arithmetic_side_effects.rs:205:10 | LL | _n = _n - &1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:183:10 + --> $DIR/arithmetic_side_effects.rs:206:10 | LL | _n = 1 - _n; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:184:10 + --> $DIR/arithmetic_side_effects.rs:207:10 | LL | _n = &1 - _n; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:185:10 + --> $DIR/arithmetic_side_effects.rs:208:10 | LL | _n = _n / 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:186:10 + --> $DIR/arithmetic_side_effects.rs:209:10 | LL | _n = _n / &0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:187:10 + --> $DIR/arithmetic_side_effects.rs:210:10 | LL | _n = _n % 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:188:10 + --> $DIR/arithmetic_side_effects.rs:211:10 | LL | _n = _n % &0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:189:10 + --> $DIR/arithmetic_side_effects.rs:212:10 | LL | _n = _n * 2; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:190:10 + --> $DIR/arithmetic_side_effects.rs:213:10 | LL | _n = _n * &2; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:191:10 + --> $DIR/arithmetic_side_effects.rs:214:10 | LL | _n = 2 * _n; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:192:10 + --> $DIR/arithmetic_side_effects.rs:215:10 | LL | _n = &2 * _n; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:193:10 + --> $DIR/arithmetic_side_effects.rs:216:10 | LL | _n = 23 + &85; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:194:10 + --> $DIR/arithmetic_side_effects.rs:217:10 | LL | _n = &23 + 85; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:195:10 + --> $DIR/arithmetic_side_effects.rs:218:10 | LL | _n = &23 + &85; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:198:13 + --> $DIR/arithmetic_side_effects.rs:221:13 | LL | let _ = Custom + 0; | ^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:199:13 + --> $DIR/arithmetic_side_effects.rs:222:13 | LL | let _ = Custom + 1; | ^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:200:13 + --> $DIR/arithmetic_side_effects.rs:223:13 | LL | let _ = Custom + 2; | ^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:201:13 + --> $DIR/arithmetic_side_effects.rs:224:13 | LL | let _ = Custom + 0.0; | ^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:202:13 + --> $DIR/arithmetic_side_effects.rs:225:13 | LL | let _ = Custom + 1.0; | ^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:203:13 + --> $DIR/arithmetic_side_effects.rs:226:13 | LL | let _ = Custom + 2.0; | ^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:204:13 + --> $DIR/arithmetic_side_effects.rs:227:13 | LL | let _ = Custom - 0; | ^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:205:13 + --> $DIR/arithmetic_side_effects.rs:228:13 | LL | let _ = Custom - 1; | ^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:206:13 + --> $DIR/arithmetic_side_effects.rs:229:13 | LL | let _ = Custom - 2; | ^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:207:13 + --> $DIR/arithmetic_side_effects.rs:230:13 | LL | let _ = Custom - 0.0; | ^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:208:13 + --> $DIR/arithmetic_side_effects.rs:231:13 | LL | let _ = Custom - 1.0; | ^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:209:13 + --> $DIR/arithmetic_side_effects.rs:232:13 | LL | let _ = Custom - 2.0; | ^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:210:13 + --> $DIR/arithmetic_side_effects.rs:233:13 | LL | let _ = Custom / 0; | ^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:211:13 + --> $DIR/arithmetic_side_effects.rs:234:13 | LL | let _ = Custom / 1; | ^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:212:13 + --> $DIR/arithmetic_side_effects.rs:235:13 | LL | let _ = Custom / 2; | ^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:213:13 + --> $DIR/arithmetic_side_effects.rs:236:13 | LL | let _ = Custom / 0.0; | ^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:214:13 + --> $DIR/arithmetic_side_effects.rs:237:13 | LL | let _ = Custom / 1.0; | ^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:215:13 + --> $DIR/arithmetic_side_effects.rs:238:13 | LL | let _ = Custom / 2.0; | ^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:216:13 + --> $DIR/arithmetic_side_effects.rs:239:13 | LL | let _ = Custom * 0; | ^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:217:13 + --> $DIR/arithmetic_side_effects.rs:240:13 | LL | let _ = Custom * 1; | ^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:218:13 + --> $DIR/arithmetic_side_effects.rs:241:13 | LL | let _ = Custom * 2; | ^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:219:13 + --> $DIR/arithmetic_side_effects.rs:242:13 | LL | let _ = Custom * 0.0; | ^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:220:13 + --> $DIR/arithmetic_side_effects.rs:243:13 | LL | let _ = Custom * 1.0; | ^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:221:13 + --> $DIR/arithmetic_side_effects.rs:244:13 | LL | let _ = Custom * 2.0; | ^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:224:10 + --> $DIR/arithmetic_side_effects.rs:247:10 | LL | _n = -_n; | ^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:225:10 + --> $DIR/arithmetic_side_effects.rs:248:10 | LL | _n = -&_n; | ^^^^ -error: aborting due to 55 previous errors +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:257:5 + | +LL | 1 + i; + | ^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:258:5 + | +LL | i * 2; + | ^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:260:5 + | +LL | i - 2 + 2 - i; + | ^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:261:5 + | +LL | -i; + | ^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:262:5 + | +LL | i >> 1; + | ^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:263:5 + | +LL | i << 1; + | ^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:272:5 + | +LL | i += 1; + | ^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:273:5 + | +LL | i -= 1; + | ^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:274:5 + | +LL | i *= 2; + | ^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:276:5 + | +LL | i /= 0; + | ^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:278:5 + | +LL | i /= var1; + | ^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:279:5 + | +LL | i /= var2; + | ^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:281:5 + | +LL | i %= 0; + | ^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:283:5 + | +LL | i %= var1; + | ^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:284:5 + | +LL | i %= var2; + | ^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:285:5 + | +LL | i <<= 3; + | ^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:286:5 + | +LL | i >>= 2; + | ^^^^^^^ + +error: aborting due to 82 previous errors From fb34fbf7e01d2cd9b44d762d4cd17d456796a63a Mon Sep 17 00:00:00 2001 From: Caio Date: Fri, 6 Jan 2023 14:50:25 -0300 Subject: [PATCH 36/51] [arithmetic_side_effects] Add more tests related to custom types --- tests/ui/arithmetic_side_effects.rs | 158 +++++++--- tests/ui/arithmetic_side_effects.stderr | 390 +++++++++++++++--------- 2 files changed, 365 insertions(+), 183 deletions(-) diff --git a/tests/ui/arithmetic_side_effects.rs b/tests/ui/arithmetic_side_effects.rs index 66c468c940635..918cf81c600af 100644 --- a/tests/ui/arithmetic_side_effects.rs +++ b/tests/ui/arithmetic_side_effects.rs @@ -13,31 +13,95 @@ use core::num::{Saturating, Wrapping}; +#[derive(Clone, Copy)] pub struct Custom; macro_rules! impl_arith { - ( $( $_trait:ident, $ty:ty, $method:ident; )* ) => { + ( $( $_trait:ident, $lhs:ty, $rhs:ty, $method:ident; )* ) => { $( - impl core::ops::$_trait<$ty> for Custom { - type Output = Self; - fn $method(self, _: $ty) -> Self::Output { Self } + impl core::ops::$_trait<$lhs> for $rhs { + type Output = Custom; + fn $method(self, _: $lhs) -> Self::Output { todo!() } + } + )* + } +} + +macro_rules! impl_assign_arith { + ( $( $_trait:ident, $lhs:ty, $rhs:ty, $method:ident; )* ) => { + $( + impl core::ops::$_trait<$lhs> for $rhs { + fn $method(&mut self, _: $lhs) {} } )* } } impl_arith!( - Add, i32, add; - Div, i32, div; - Mul, i32, mul; - Sub, i32, sub; - - Add, f64, add; - Div, f64, div; - Mul, f64, mul; - Sub, f64, sub; + Add, Custom, Custom, add; + Div, Custom, Custom, div; + Mul, Custom, Custom, mul; + Rem, Custom, Custom, rem; + Sub, Custom, Custom, sub; + + Add, Custom, &Custom, add; + Div, Custom, &Custom, div; + Mul, Custom, &Custom, mul; + Rem, Custom, &Custom, rem; + Sub, Custom, &Custom, sub; + + Add, &Custom, Custom, add; + Div, &Custom, Custom, div; + Mul, &Custom, Custom, mul; + Rem, &Custom, Custom, rem; + Sub, &Custom, Custom, sub; + + Add, &Custom, &Custom, add; + Div, &Custom, &Custom, div; + Mul, &Custom, &Custom, mul; + Rem, &Custom, &Custom, rem; + Sub, &Custom, &Custom, sub; +); + +impl_assign_arith!( + AddAssign, Custom, Custom, add_assign; + DivAssign, Custom, Custom, div_assign; + MulAssign, Custom, Custom, mul_assign; + RemAssign, Custom, Custom, rem_assign; + SubAssign, Custom, Custom, sub_assign; + + AddAssign, Custom, &Custom, add_assign; + DivAssign, Custom, &Custom, div_assign; + MulAssign, Custom, &Custom, mul_assign; + RemAssign, Custom, &Custom, rem_assign; + SubAssign, Custom, &Custom, sub_assign; + + AddAssign, &Custom, Custom, add_assign; + DivAssign, &Custom, Custom, div_assign; + MulAssign, &Custom, Custom, mul_assign; + RemAssign, &Custom, Custom, rem_assign; + SubAssign, &Custom, Custom, sub_assign; + + AddAssign, &Custom, &Custom, add_assign; + DivAssign, &Custom, &Custom, div_assign; + MulAssign, &Custom, &Custom, mul_assign; + RemAssign, &Custom, &Custom, rem_assign; + SubAssign, &Custom, &Custom, sub_assign; ); +impl core::ops::Neg for Custom { + type Output = Custom; + fn neg(self) -> Self::Output { + todo!() + } +} +impl core::ops::Neg for &Custom { + type Output = Custom; + fn neg(self) -> Self::Output { + todo!() + } +} + pub fn association_with_structures_should_not_trigger_the_lint() { enum Foo { Bar = -2, @@ -173,6 +237,7 @@ pub fn non_overflowing_ops_or_ops_already_handled_by_the_compiler_should_not_tri pub fn unknown_ops_or_runtime_ops_that_can_overflow() { let mut _n = i32::MAX; + let mut _custom = Custom; // Assign _n += 1; @@ -195,6 +260,26 @@ pub fn unknown_ops_or_runtime_ops_that_can_overflow() { _n %= &-0; _n *= -2; _n *= &-2; + _custom += Custom; + _custom += &Custom; + _custom -= Custom; + _custom -= &Custom; + _custom /= Custom; + _custom /= &Custom; + _custom %= Custom; + _custom %= &Custom; + _custom *= Custom; + _custom *= &Custom; + _custom += -Custom; + _custom += &-Custom; + _custom -= -Custom; + _custom -= &-Custom; + _custom /= -Custom; + _custom /= &-Custom; + _custom %= -Custom; + _custom %= &-Custom; + _custom *= -Custom; + _custom *= &-Custom; // Binary _n = _n + 1; @@ -216,36 +301,31 @@ pub fn unknown_ops_or_runtime_ops_that_can_overflow() { _n = 23 + &85; _n = &23 + 85; _n = &23 + &85; - - // Custom - let _ = Custom + 0; - let _ = Custom + 1; - let _ = Custom + 2; - let _ = Custom + 0.0; - let _ = Custom + 1.0; - let _ = Custom + 2.0; - let _ = Custom - 0; - let _ = Custom - 1; - let _ = Custom - 2; - let _ = Custom - 0.0; - let _ = Custom - 1.0; - let _ = Custom - 2.0; - let _ = Custom / 0; - let _ = Custom / 1; - let _ = Custom / 2; - let _ = Custom / 0.0; - let _ = Custom / 1.0; - let _ = Custom / 2.0; - let _ = Custom * 0; - let _ = Custom * 1; - let _ = Custom * 2; - let _ = Custom * 0.0; - let _ = Custom * 1.0; - let _ = Custom * 2.0; + _custom = _custom + _custom; + _custom = _custom + &_custom; + _custom = Custom + _custom; + _custom = &Custom + _custom; + _custom = _custom - Custom; + _custom = _custom - &Custom; + _custom = Custom - _custom; + _custom = &Custom - _custom; + _custom = _custom / Custom; + _custom = _custom / &Custom; + _custom = _custom % Custom; + _custom = _custom % &Custom; + _custom = _custom * Custom; + _custom = _custom * &Custom; + _custom = Custom * _custom; + _custom = &Custom * _custom; + _custom = Custom + &Custom; + _custom = &Custom + Custom; + _custom = &Custom + &Custom; // Unary _n = -_n; _n = -&_n; + _custom = -_custom; + _custom = -&_custom; } // Copied and pasted from the `integer_arithmetic` lint for comparison. diff --git a/tests/ui/arithmetic_side_effects.stderr b/tests/ui/arithmetic_side_effects.stderr index a9bb0ae9280e6..5e349f6b497cd 100644 --- a/tests/ui/arithmetic_side_effects.stderr +++ b/tests/ui/arithmetic_side_effects.stderr @@ -1,5 +1,5 @@ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:178:5 + --> $DIR/arithmetic_side_effects.rs:243:5 | LL | _n += 1; | ^^^^^^^ @@ -7,490 +7,592 @@ LL | _n += 1; = note: `-D clippy::arithmetic-side-effects` implied by `-D warnings` error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:179:5 + --> $DIR/arithmetic_side_effects.rs:244:5 | LL | _n += &1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:180:5 + --> $DIR/arithmetic_side_effects.rs:245:5 | LL | _n -= 1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:181:5 + --> $DIR/arithmetic_side_effects.rs:246:5 | LL | _n -= &1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:182:5 + --> $DIR/arithmetic_side_effects.rs:247:5 | LL | _n /= 0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:183:5 + --> $DIR/arithmetic_side_effects.rs:248:5 | LL | _n /= &0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:184:5 + --> $DIR/arithmetic_side_effects.rs:249:5 | LL | _n %= 0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:185:5 + --> $DIR/arithmetic_side_effects.rs:250:5 | LL | _n %= &0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:186:5 + --> $DIR/arithmetic_side_effects.rs:251:5 | LL | _n *= 2; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:187:5 + --> $DIR/arithmetic_side_effects.rs:252:5 | LL | _n *= &2; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:188:5 + --> $DIR/arithmetic_side_effects.rs:253:5 | LL | _n += -1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:189:5 + --> $DIR/arithmetic_side_effects.rs:254:5 | LL | _n += &-1; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:190:5 + --> $DIR/arithmetic_side_effects.rs:255:5 | LL | _n -= -1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:191:5 + --> $DIR/arithmetic_side_effects.rs:256:5 | LL | _n -= &-1; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:192:5 + --> $DIR/arithmetic_side_effects.rs:257:5 | LL | _n /= -0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:193:5 + --> $DIR/arithmetic_side_effects.rs:258:5 | LL | _n /= &-0; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:194:5 + --> $DIR/arithmetic_side_effects.rs:259:5 | LL | _n %= -0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:195:5 + --> $DIR/arithmetic_side_effects.rs:260:5 | LL | _n %= &-0; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:196:5 + --> $DIR/arithmetic_side_effects.rs:261:5 | LL | _n *= -2; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:197:5 + --> $DIR/arithmetic_side_effects.rs:262:5 | LL | _n *= &-2; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:200:10 + --> $DIR/arithmetic_side_effects.rs:263:5 + | +LL | _custom += Custom; + | ^^^^^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:264:5 + | +LL | _custom += &Custom; + | ^^^^^^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:265:5 + | +LL | _custom -= Custom; + | ^^^^^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:266:5 + | +LL | _custom -= &Custom; + | ^^^^^^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:267:5 + | +LL | _custom /= Custom; + | ^^^^^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:268:5 + | +LL | _custom /= &Custom; + | ^^^^^^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:269:5 + | +LL | _custom %= Custom; + | ^^^^^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:270:5 + | +LL | _custom %= &Custom; + | ^^^^^^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:271:5 + | +LL | _custom *= Custom; + | ^^^^^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:272:5 + | +LL | _custom *= &Custom; + | ^^^^^^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:273:5 + | +LL | _custom += -Custom; + | ^^^^^^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:274:5 + | +LL | _custom += &-Custom; + | ^^^^^^^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:275:5 + | +LL | _custom -= -Custom; + | ^^^^^^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:276:5 + | +LL | _custom -= &-Custom; + | ^^^^^^^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:277:5 + | +LL | _custom /= -Custom; + | ^^^^^^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:278:5 + | +LL | _custom /= &-Custom; + | ^^^^^^^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:279:5 + | +LL | _custom %= -Custom; + | ^^^^^^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:280:5 + | +LL | _custom %= &-Custom; + | ^^^^^^^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:281:5 + | +LL | _custom *= -Custom; + | ^^^^^^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:282:5 + | +LL | _custom *= &-Custom; + | ^^^^^^^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:285:10 | LL | _n = _n + 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:201:10 + --> $DIR/arithmetic_side_effects.rs:286:10 | LL | _n = _n + &1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:202:10 + --> $DIR/arithmetic_side_effects.rs:287:10 | LL | _n = 1 + _n; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:203:10 + --> $DIR/arithmetic_side_effects.rs:288:10 | LL | _n = &1 + _n; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:204:10 + --> $DIR/arithmetic_side_effects.rs:289:10 | LL | _n = _n - 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:205:10 + --> $DIR/arithmetic_side_effects.rs:290:10 | LL | _n = _n - &1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:206:10 + --> $DIR/arithmetic_side_effects.rs:291:10 | LL | _n = 1 - _n; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:207:10 + --> $DIR/arithmetic_side_effects.rs:292:10 | LL | _n = &1 - _n; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:208:10 + --> $DIR/arithmetic_side_effects.rs:293:10 | LL | _n = _n / 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:209:10 + --> $DIR/arithmetic_side_effects.rs:294:10 | LL | _n = _n / &0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:210:10 + --> $DIR/arithmetic_side_effects.rs:295:10 | LL | _n = _n % 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:211:10 + --> $DIR/arithmetic_side_effects.rs:296:10 | LL | _n = _n % &0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:212:10 + --> $DIR/arithmetic_side_effects.rs:297:10 | LL | _n = _n * 2; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:213:10 + --> $DIR/arithmetic_side_effects.rs:298:10 | LL | _n = _n * &2; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:214:10 + --> $DIR/arithmetic_side_effects.rs:299:10 | LL | _n = 2 * _n; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:215:10 + --> $DIR/arithmetic_side_effects.rs:300:10 | LL | _n = &2 * _n; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:216:10 + --> $DIR/arithmetic_side_effects.rs:301:10 | LL | _n = 23 + &85; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:217:10 + --> $DIR/arithmetic_side_effects.rs:302:10 | LL | _n = &23 + 85; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:218:10 + --> $DIR/arithmetic_side_effects.rs:303:10 | LL | _n = &23 + &85; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:221:13 - | -LL | let _ = Custom + 0; - | ^^^^^^^^^^ - -error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:222:13 + --> $DIR/arithmetic_side_effects.rs:304:15 | -LL | let _ = Custom + 1; - | ^^^^^^^^^^ +LL | _custom = _custom + _custom; + | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:223:13 + --> $DIR/arithmetic_side_effects.rs:305:15 | -LL | let _ = Custom + 2; - | ^^^^^^^^^^ +LL | _custom = _custom + &_custom; + | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:224:13 + --> $DIR/arithmetic_side_effects.rs:306:15 | -LL | let _ = Custom + 0.0; - | ^^^^^^^^^^^^ +LL | _custom = Custom + _custom; + | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:225:13 + --> $DIR/arithmetic_side_effects.rs:307:15 | -LL | let _ = Custom + 1.0; - | ^^^^^^^^^^^^ +LL | _custom = &Custom + _custom; + | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:226:13 + --> $DIR/arithmetic_side_effects.rs:308:15 | -LL | let _ = Custom + 2.0; - | ^^^^^^^^^^^^ +LL | _custom = _custom - Custom; + | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:227:13 + --> $DIR/arithmetic_side_effects.rs:309:15 | -LL | let _ = Custom - 0; - | ^^^^^^^^^^ +LL | _custom = _custom - &Custom; + | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:228:13 + --> $DIR/arithmetic_side_effects.rs:310:15 | -LL | let _ = Custom - 1; - | ^^^^^^^^^^ +LL | _custom = Custom - _custom; + | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:229:13 + --> $DIR/arithmetic_side_effects.rs:311:15 | -LL | let _ = Custom - 2; - | ^^^^^^^^^^ +LL | _custom = &Custom - _custom; + | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:230:13 + --> $DIR/arithmetic_side_effects.rs:312:15 | -LL | let _ = Custom - 0.0; - | ^^^^^^^^^^^^ +LL | _custom = _custom / Custom; + | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:231:13 + --> $DIR/arithmetic_side_effects.rs:313:15 | -LL | let _ = Custom - 1.0; - | ^^^^^^^^^^^^ +LL | _custom = _custom / &Custom; + | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:232:13 + --> $DIR/arithmetic_side_effects.rs:314:15 | -LL | let _ = Custom - 2.0; - | ^^^^^^^^^^^^ +LL | _custom = _custom % Custom; + | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:233:13 + --> $DIR/arithmetic_side_effects.rs:315:15 | -LL | let _ = Custom / 0; - | ^^^^^^^^^^ +LL | _custom = _custom % &Custom; + | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:234:13 + --> $DIR/arithmetic_side_effects.rs:316:15 | -LL | let _ = Custom / 1; - | ^^^^^^^^^^ +LL | _custom = _custom * Custom; + | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:235:13 + --> $DIR/arithmetic_side_effects.rs:317:15 | -LL | let _ = Custom / 2; - | ^^^^^^^^^^ +LL | _custom = _custom * &Custom; + | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:236:13 + --> $DIR/arithmetic_side_effects.rs:318:15 | -LL | let _ = Custom / 0.0; - | ^^^^^^^^^^^^ +LL | _custom = Custom * _custom; + | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:237:13 + --> $DIR/arithmetic_side_effects.rs:319:15 | -LL | let _ = Custom / 1.0; - | ^^^^^^^^^^^^ +LL | _custom = &Custom * _custom; + | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:238:13 + --> $DIR/arithmetic_side_effects.rs:320:15 | -LL | let _ = Custom / 2.0; - | ^^^^^^^^^^^^ +LL | _custom = Custom + &Custom; + | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:239:13 + --> $DIR/arithmetic_side_effects.rs:321:15 | -LL | let _ = Custom * 0; - | ^^^^^^^^^^ +LL | _custom = &Custom + Custom; + | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:240:13 + --> $DIR/arithmetic_side_effects.rs:322:15 | -LL | let _ = Custom * 1; - | ^^^^^^^^^^ +LL | _custom = &Custom + &Custom; + | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:241:13 + --> $DIR/arithmetic_side_effects.rs:325:10 | -LL | let _ = Custom * 2; - | ^^^^^^^^^^ - -error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:242:13 - | -LL | let _ = Custom * 0.0; - | ^^^^^^^^^^^^ - -error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:243:13 - | -LL | let _ = Custom * 1.0; - | ^^^^^^^^^^^^ +LL | _n = -_n; + | ^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:244:13 + --> $DIR/arithmetic_side_effects.rs:326:10 | -LL | let _ = Custom * 2.0; - | ^^^^^^^^^^^^ +LL | _n = -&_n; + | ^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:247:10 + --> $DIR/arithmetic_side_effects.rs:327:15 | -LL | _n = -_n; - | ^^^ +LL | _custom = -_custom; + | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:248:10 + --> $DIR/arithmetic_side_effects.rs:328:15 | -LL | _n = -&_n; - | ^^^^ +LL | _custom = -&_custom; + | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:257:5 + --> $DIR/arithmetic_side_effects.rs:337:5 | LL | 1 + i; | ^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:258:5 + --> $DIR/arithmetic_side_effects.rs:338:5 | LL | i * 2; | ^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:260:5 + --> $DIR/arithmetic_side_effects.rs:340:5 | LL | i - 2 + 2 - i; | ^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:261:5 + --> $DIR/arithmetic_side_effects.rs:341:5 | LL | -i; | ^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:262:5 + --> $DIR/arithmetic_side_effects.rs:342:5 | LL | i >> 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:263:5 + --> $DIR/arithmetic_side_effects.rs:343:5 | LL | i << 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:272:5 + --> $DIR/arithmetic_side_effects.rs:352:5 | LL | i += 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:273:5 + --> $DIR/arithmetic_side_effects.rs:353:5 | LL | i -= 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:274:5 + --> $DIR/arithmetic_side_effects.rs:354:5 | LL | i *= 2; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:276:5 + --> $DIR/arithmetic_side_effects.rs:356:5 | LL | i /= 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:278:5 + --> $DIR/arithmetic_side_effects.rs:358:5 | LL | i /= var1; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:279:5 + --> $DIR/arithmetic_side_effects.rs:359:5 | LL | i /= var2; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:281:5 + --> $DIR/arithmetic_side_effects.rs:361:5 | LL | i %= 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:283:5 + --> $DIR/arithmetic_side_effects.rs:363:5 | LL | i %= var1; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:284:5 + --> $DIR/arithmetic_side_effects.rs:364:5 | LL | i %= var2; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:285:5 + --> $DIR/arithmetic_side_effects.rs:365:5 | LL | i <<= 3; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:286:5 + --> $DIR/arithmetic_side_effects.rs:366:5 | LL | i >>= 2; | ^^^^^^^ -error: aborting due to 82 previous errors +error: aborting due to 99 previous errors From ce56cf71d956ea78c319ff510651473ca8dce47c Mon Sep 17 00:00:00 2001 From: Raiki Tamura Date: Sat, 7 Jan 2023 20:44:02 +0900 Subject: [PATCH 37/51] chore --- clippy_lints/src/loops/single_element_loop.rs | 14 +------------- clippy_utils/src/visitors.rs | 11 +++++++++++ 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/clippy_lints/src/loops/single_element_loop.rs b/clippy_lints/src/loops/single_element_loop.rs index 7cbc456244e40..744fd61bd135c 100644 --- a/clippy_lints/src/loops/single_element_loop.rs +++ b/clippy_lints/src/loops/single_element_loop.rs @@ -1,7 +1,7 @@ use super::SINGLE_ELEMENT_LOOP; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{indent_of, snippet_with_applicability}; -use clippy_utils::visitors::for_each_expr; +use clippy_utils::visitors::contains_break_or_continue; use if_chain::if_chain; use rustc_ast::util::parser::PREC_PREFIX; use rustc_ast::Mutability; @@ -9,18 +9,6 @@ use rustc_errors::Applicability; use rustc_hir::{is_range_literal, BorrowKind, Expr, ExprKind, Pat}; use rustc_lint::LateContext; use rustc_span::edition::Edition; -use std::ops::ControlFlow; - -fn contains_break_or_continue(expr: &Expr<'_>) -> bool { - for_each_expr(expr, |e| { - if matches!(e.kind, ExprKind::Break(..) | ExprKind::Continue(..)) { - ControlFlow::Break(()) - } else { - ControlFlow::Continue(()) - } - }) - .is_some() -} pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, diff --git a/clippy_utils/src/visitors.rs b/clippy_utils/src/visitors.rs index 863fb60fcfca1..14c01a60b4c32 100644 --- a/clippy_utils/src/visitors.rs +++ b/clippy_utils/src/visitors.rs @@ -724,3 +724,14 @@ pub fn for_each_local_assignment<'tcx, B>( ControlFlow::Continue(()) } } + +pub fn contains_break_or_continue(expr: &Expr<'_>) -> bool { + for_each_expr(expr, |e| { + if matches!(e.kind, ExprKind::Break(..) | ExprKind::Continue(..)) { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(()) + } + }) + .is_some() +} From d8877bbd8a04e2fb5edd22f092f1ef360ee8075c Mon Sep 17 00:00:00 2001 From: chansuke Date: Sat, 7 Jan 2023 22:57:30 +0900 Subject: [PATCH 38/51] hotfix: remove `ITER_COUNT` since it is not called --- clippy_utils/src/paths.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 9ca50105ae57d..95eebab756776 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -47,7 +47,6 @@ pub const IDENT: [&str; 3] = ["rustc_span", "symbol", "Ident"]; #[cfg(feature = "internal")] pub const IDENT_AS_STR: [&str; 4] = ["rustc_span", "symbol", "Ident", "as_str"]; pub const INSERT_STR: [&str; 4] = ["alloc", "string", "String", "insert_str"]; -pub const ITER_COUNT: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "count"]; pub const ITER_EMPTY: [&str; 5] = ["core", "iter", "sources", "empty", "Empty"]; pub const ITERTOOLS_NEXT_TUPLE: [&str; 3] = ["itertools", "Itertools", "next_tuple"]; #[cfg(feature = "internal")] From d23dce54ecbc5b94837ddb77db4b3a5edcdf0cd9 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Sun, 8 Jan 2023 20:25:42 +0100 Subject: [PATCH 39/51] add a test against #100898 --- tests/ui/box_default.fixed | 10 ++++++++++ tests/ui/box_default.rs | 10 ++++++++++ tests/ui/box_default.stderr | 8 +++++++- 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/tests/ui/box_default.fixed b/tests/ui/box_default.fixed index 68ab996a70492..7e9f074fdcabd 100644 --- a/tests/ui/box_default.fixed +++ b/tests/ui/box_default.fixed @@ -54,4 +54,14 @@ impl Read for ImplementsDefault { fn issue_9621_dyn_trait() { let _: Box = Box::::default(); + issue_10089(); +} + +fn issue_10089() { + let _closure = || { + #[derive(Default)] + struct WeirdPathed; + + let _ = Box::::default(); + }; } diff --git a/tests/ui/box_default.rs b/tests/ui/box_default.rs index 20019c2ee5a07..5c8d0b8354ccc 100644 --- a/tests/ui/box_default.rs +++ b/tests/ui/box_default.rs @@ -54,4 +54,14 @@ impl Read for ImplementsDefault { fn issue_9621_dyn_trait() { let _: Box = Box::new(ImplementsDefault::default()); + issue_10089(); +} + +fn issue_10089() { + let _closure = || { + #[derive(Default)] + struct WeirdPathed; + + let _ = Box::new(WeirdPathed::default()); + }; } diff --git a/tests/ui/box_default.stderr b/tests/ui/box_default.stderr index f77c97cdfa269..249eb340f96cb 100644 --- a/tests/ui/box_default.stderr +++ b/tests/ui/box_default.stderr @@ -84,5 +84,11 @@ error: `Box::new(_)` of default value LL | let _: Box = Box::new(ImplementsDefault::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::::default()` -error: aborting due to 14 previous errors +error: `Box::new(_)` of default value + --> $DIR/box_default.rs:65:17 + | +LL | let _ = Box::new(WeirdPathed::default()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::::default()` + +error: aborting due to 15 previous errors From 53c12e085ab9595dff369f26046038afa20e8e5c Mon Sep 17 00:00:00 2001 From: Robert Bastian Date: Mon, 9 Jan 2023 21:29:42 +0100 Subject: [PATCH 40/51] hash xor peq --- clippy_lints/src/derive.rs | 10 ++-------- tests/ui/derive_hash_xor_eq.rs | 19 ------------------ tests/ui/derive_hash_xor_eq.stderr | 32 +----------------------------- 3 files changed, 3 insertions(+), 58 deletions(-) diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index cf3483d4c00b1..e39a31a8c725e 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -243,7 +243,7 @@ fn check_hash_peq<'tcx>( cx.tcx.for_each_relevant_impl(peq_trait_def_id, ty, |impl_id| { let peq_is_automatically_derived = cx.tcx.has_attr(impl_id, sym::automatically_derived); - if peq_is_automatically_derived == hash_is_automatically_derived { + if !hash_is_automatically_derived || peq_is_automatically_derived { return; } @@ -252,17 +252,11 @@ fn check_hash_peq<'tcx>( // Only care about `impl PartialEq for Foo` // For `impl PartialEq for A, input_types is [A, B] if trait_ref.substs.type_at(1) == ty { - let mess = if peq_is_automatically_derived { - "you are implementing `Hash` explicitly but have derived `PartialEq`" - } else { - "you are deriving `Hash` but have implemented `PartialEq` explicitly" - }; - span_lint_and_then( cx, DERIVE_HASH_XOR_EQ, span, - mess, + "you are deriving `Hash` but have implemented `PartialEq` explicitly", |diag| { if let Some(local_def_id) = impl_id.as_local() { let hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_def_id); diff --git a/tests/ui/derive_hash_xor_eq.rs b/tests/ui/derive_hash_xor_eq.rs index 813ddc5664642..0804e3cffa1a2 100644 --- a/tests/ui/derive_hash_xor_eq.rs +++ b/tests/ui/derive_hash_xor_eq.rs @@ -34,23 +34,4 @@ impl std::hash::Hash for Bah { fn hash(&self, _: &mut H) {} } -#[derive(PartialEq)] -struct Foo2; - -trait Hash {} - -// We don't want to lint on user-defined traits called `Hash` -impl Hash for Foo2 {} - -mod use_hash { - use std::hash::{Hash, Hasher}; - - #[derive(PartialEq)] - struct Foo3; - - impl Hash for Foo3 { - fn hash(&self, _: &mut H) {} - } -} - fn main() {} diff --git a/tests/ui/derive_hash_xor_eq.stderr b/tests/ui/derive_hash_xor_eq.stderr index 16c92397804e5..16965aa42d8c4 100644 --- a/tests/ui/derive_hash_xor_eq.stderr +++ b/tests/ui/derive_hash_xor_eq.stderr @@ -25,35 +25,5 @@ LL | impl PartialEq for Baz { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info) -error: you are implementing `Hash` explicitly but have derived `PartialEq` - --> $DIR/derive_hash_xor_eq.rs:33:1 - | -LL | / impl std::hash::Hash for Bah { -LL | | fn hash(&self, _: &mut H) {} -LL | | } - | |_^ - | -note: `PartialEq` implemented here - --> $DIR/derive_hash_xor_eq.rs:30:10 - | -LL | #[derive(PartialEq)] - | ^^^^^^^^^ - = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: you are implementing `Hash` explicitly but have derived `PartialEq` - --> $DIR/derive_hash_xor_eq.rs:51:5 - | -LL | / impl Hash for Foo3 { -LL | | fn hash(&self, _: &mut H) {} -LL | | } - | |_____^ - | -note: `PartialEq` implemented here - --> $DIR/derive_hash_xor_eq.rs:48:14 - | -LL | #[derive(PartialEq)] - | ^^^^^^^^^ - = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors From 8ca900b01ce5ff90511fd9d02c29e50a89fcccf0 Mon Sep 17 00:00:00 2001 From: Robert Bastian Date: Tue, 10 Jan 2023 11:12:54 +0100 Subject: [PATCH 41/51] rename --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 2 +- clippy_lints/src/derive.rs | 8 ++++---- clippy_lints/src/renamed_lints.rs | 1 + ...rive_hash_xor_eq.rs => derived_hash_with_manual_eq.rs} | 0 ...h_xor_eq.stderr => derived_hash_with_manual_eq.stderr} | 0 tests/ui/rename.rs | 2 ++ 7 files changed, 9 insertions(+), 5 deletions(-) rename tests/ui/{derive_hash_xor_eq.rs => derived_hash_with_manual_eq.rs} (100%) rename tests/ui/{derive_hash_xor_eq.stderr => derived_hash_with_manual_eq.stderr} (100%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 02f3188f8be08..8e31e8f0d9815 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4137,6 +4137,7 @@ Released 2018-09-13 [`derive_hash_xor_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_hash_xor_eq [`derive_ord_xor_partial_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_ord_xor_partial_ord [`derive_partial_eq_without_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_partial_eq_without_eq +[`derived_hash_with_manual_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derived_hash_with_manual_eq [`disallowed_macros`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_macros [`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 diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 2982460c9cfa4..91ca73633f062 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -111,7 +111,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::dereference::NEEDLESS_BORROW_INFO, crate::dereference::REF_BINDING_TO_REFERENCE_INFO, crate::derivable_impls::DERIVABLE_IMPLS_INFO, - crate::derive::DERIVE_HASH_XOR_EQ_INFO, + crate::derive::DERIVED_HASH_WITH_MANUAL_EQ_INFO, crate::derive::DERIVE_ORD_XOR_PARTIAL_ORD_INFO, crate::derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ_INFO, crate::derive::EXPL_IMPL_CLONE_ON_COPY_INFO, diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index e39a31a8c725e..983a517bc1238 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -46,7 +46,7 @@ declare_clippy_lint! { /// } /// ``` #[clippy::version = "pre 1.29.0"] - pub DERIVE_HASH_XOR_EQ, + pub DERIVED_HASH_WITH_MANUAL_EQ, correctness, "deriving `Hash` but implementing `PartialEq` explicitly" } @@ -197,7 +197,7 @@ declare_clippy_lint! { declare_lint_pass!(Derive => [ EXPL_IMPL_CLONE_ON_COPY, - DERIVE_HASH_XOR_EQ, + DERIVED_HASH_WITH_MANUAL_EQ, DERIVE_ORD_XOR_PARTIAL_ORD, UNSAFE_DERIVE_DESERIALIZE, DERIVE_PARTIAL_EQ_WITHOUT_EQ @@ -226,7 +226,7 @@ impl<'tcx> LateLintPass<'tcx> for Derive { } } -/// Implementation of the `DERIVE_HASH_XOR_EQ` lint. +/// Implementation of the `DERIVED_HASH_WITH_MANUAL_EQ` lint. fn check_hash_peq<'tcx>( cx: &LateContext<'tcx>, span: Span, @@ -254,7 +254,7 @@ fn check_hash_peq<'tcx>( if trait_ref.substs.type_at(1) == ty { span_lint_and_then( cx, - DERIVE_HASH_XOR_EQ, + DERIVED_HASH_WITH_MANUAL_EQ, span, "you are deriving `Hash` but have implemented `PartialEq` explicitly", |diag| { diff --git a/clippy_lints/src/renamed_lints.rs b/clippy_lints/src/renamed_lints.rs index 72c25592609ba..9f487dedb8cb6 100644 --- a/clippy_lints/src/renamed_lints.rs +++ b/clippy_lints/src/renamed_lints.rs @@ -9,6 +9,7 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[ ("clippy::box_vec", "clippy::box_collection"), ("clippy::const_static_lifetime", "clippy::redundant_static_lifetimes"), ("clippy::cyclomatic_complexity", "clippy::cognitive_complexity"), + ("clippy::derive_hash_xor_eq", "clippy::derived_hash_with_manual_eq"), ("clippy::disallowed_method", "clippy::disallowed_methods"), ("clippy::disallowed_type", "clippy::disallowed_types"), ("clippy::eval_order_dependence", "clippy::mixed_read_write_in_expression"), diff --git a/tests/ui/derive_hash_xor_eq.rs b/tests/ui/derived_hash_with_manual_eq.rs similarity index 100% rename from tests/ui/derive_hash_xor_eq.rs rename to tests/ui/derived_hash_with_manual_eq.rs diff --git a/tests/ui/derive_hash_xor_eq.stderr b/tests/ui/derived_hash_with_manual_eq.stderr similarity index 100% rename from tests/ui/derive_hash_xor_eq.stderr rename to tests/ui/derived_hash_with_manual_eq.stderr diff --git a/tests/ui/rename.rs b/tests/ui/rename.rs index 699c0ff464e9f..64bc1ca7116c5 100644 --- a/tests/ui/rename.rs +++ b/tests/ui/rename.rs @@ -10,6 +10,7 @@ #![allow(clippy::box_collection)] #![allow(clippy::redundant_static_lifetimes)] #![allow(clippy::cognitive_complexity)] +#![allow(clippy::derived_hash_with_manual_eq)] #![allow(clippy::disallowed_methods)] #![allow(clippy::disallowed_types)] #![allow(clippy::mixed_read_write_in_expression)] @@ -45,6 +46,7 @@ #![warn(clippy::box_vec)] #![warn(clippy::const_static_lifetime)] #![warn(clippy::cyclomatic_complexity)] +#![warn(clippy::derive_hash_xor_eq)] #![warn(clippy::disallowed_method)] #![warn(clippy::disallowed_type)] #![warn(clippy::eval_order_dependence)] From 5f8686ec3b598ca33b64c6e1cd31f72214b49e96 Mon Sep 17 00:00:00 2001 From: Albert Larsan <74931857+albertlarsan68@users.noreply.github.com> Date: Thu, 5 Jan 2023 09:45:44 +0100 Subject: [PATCH 42/51] Change `src/test` to `tests` in source files, fix tidy and tests --- tests/ui/crashes/ice-6254.rs | 2 +- tests/ui/crashes/ice-6255.rs | 2 +- tests/ui/crashes/ice-6256.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/ui/crashes/ice-6254.rs b/tests/ui/crashes/ice-6254.rs index a2a60a1691534..8af60890390e7 100644 --- a/tests/ui/crashes/ice-6254.rs +++ b/tests/ui/crashes/ice-6254.rs @@ -1,4 +1,4 @@ -// originally from ./src/test/ui/pattern/usefulness/consts-opaque.rs +// originally from ./tests/ui/pattern/usefulness/consts-opaque.rs // panicked at 'assertion failed: rows.iter().all(|r| r.len() == v.len())', // compiler/rustc_mir_build/src/thir/pattern/_match.rs:2030:5 diff --git a/tests/ui/crashes/ice-6255.rs b/tests/ui/crashes/ice-6255.rs index bd4a81d98e2e7..ccde6aa2b0f77 100644 --- a/tests/ui/crashes/ice-6255.rs +++ b/tests/ui/crashes/ice-6255.rs @@ -1,4 +1,4 @@ -// originally from rustc ./src/test/ui/macros/issue-78325-inconsistent-resolution.rs +// originally from rustc ./tests/ui/macros/issue-78325-inconsistent-resolution.rs // inconsistent resolution for a macro macro_rules! define_other_core { diff --git a/tests/ui/crashes/ice-6256.rs b/tests/ui/crashes/ice-6256.rs index 67308263dadda..f9ee3e058c111 100644 --- a/tests/ui/crashes/ice-6256.rs +++ b/tests/ui/crashes/ice-6256.rs @@ -1,4 +1,4 @@ -// originally from rustc ./src/test/ui/regions/issue-78262.rs +// originally from rustc ./tests/ui/regions/issue-78262.rs // ICE: to get the signature of a closure, use substs.as_closure().sig() not fn_sig() #![allow(clippy::upper_case_acronyms)] From bd76d9133b62447035741e0f693de9c98893902a Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Sun, 8 Jan 2023 16:19:11 +0100 Subject: [PATCH 43/51] trim paths in `suspicious_to_owned` --- clippy_lints/src/methods/suspicious_to_owned.rs | 6 ++++-- tests/ui/suspicious_to_owned.stderr | 8 ++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/clippy_lints/src/methods/suspicious_to_owned.rs b/clippy_lints/src/methods/suspicious_to_owned.rs index 15c1c618c5137..fe88fa41fd91e 100644 --- a/clippy_lints/src/methods/suspicious_to_owned.rs +++ b/clippy_lints/src/methods/suspicious_to_owned.rs @@ -5,7 +5,7 @@ use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_middle::ty; +use rustc_middle::ty::{self, print::with_forced_trimmed_paths}; use rustc_span::sym; use super::SUSPICIOUS_TO_OWNED; @@ -24,7 +24,9 @@ pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) - cx, SUSPICIOUS_TO_OWNED, expr.span, - &format!("this `to_owned` call clones the {input_type} itself and does not cause the {input_type} contents to become owned"), + &with_forced_trimmed_paths!(format!( + "this `to_owned` call clones the {input_type} itself and does not cause the {input_type} contents to become owned" + )), "consider using, depending on intent", format!("{recv_snip}.clone()` or `{recv_snip}.into_owned()"), app, diff --git a/tests/ui/suspicious_to_owned.stderr b/tests/ui/suspicious_to_owned.stderr index ae1aec34d82e0..dec3f50d6f1b6 100644 --- a/tests/ui/suspicious_to_owned.stderr +++ b/tests/ui/suspicious_to_owned.stderr @@ -1,4 +1,4 @@ -error: this `to_owned` call clones the std::borrow::Cow<'_, str> itself and does not cause the std::borrow::Cow<'_, str> contents to become owned +error: this `to_owned` call clones the Cow<'_, str> itself and does not cause the Cow<'_, str> contents to become owned --> $DIR/suspicious_to_owned.rs:16:13 | LL | let _ = cow.to_owned(); @@ -6,19 +6,19 @@ LL | let _ = cow.to_owned(); | = note: `-D clippy::suspicious-to-owned` implied by `-D warnings` -error: this `to_owned` call clones the std::borrow::Cow<'_, [char; 3]> itself and does not cause the std::borrow::Cow<'_, [char; 3]> contents to become owned +error: this `to_owned` call clones the Cow<'_, [char; 3]> itself and does not cause the Cow<'_, [char; 3]> contents to become owned --> $DIR/suspicious_to_owned.rs:26:13 | LL | let _ = cow.to_owned(); | ^^^^^^^^^^^^^^ help: consider using, depending on intent: `cow.clone()` or `cow.into_owned()` -error: this `to_owned` call clones the std::borrow::Cow<'_, std::vec::Vec> itself and does not cause the std::borrow::Cow<'_, std::vec::Vec> contents to become owned +error: this `to_owned` call clones the Cow<'_, Vec> itself and does not cause the Cow<'_, Vec> contents to become owned --> $DIR/suspicious_to_owned.rs:36:13 | LL | let _ = cow.to_owned(); | ^^^^^^^^^^^^^^ help: consider using, depending on intent: `cow.clone()` or `cow.into_owned()` -error: this `to_owned` call clones the std::borrow::Cow<'_, str> itself and does not cause the std::borrow::Cow<'_, str> contents to become owned +error: this `to_owned` call clones the Cow<'_, str> itself and does not cause the Cow<'_, str> contents to become owned --> $DIR/suspicious_to_owned.rs:46:13 | LL | let _ = cow.to_owned(); From 34024adc88df9d95e2b002250d41a00c5a937234 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Wed, 11 Jan 2023 17:25:47 +0000 Subject: [PATCH 44/51] expl_impl_clone_on_copy: ignore packed structs with type/const params --- clippy_lints/src/derive.rs | 13 +++++++++++-- tests/ui/derive.rs | 11 +++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index cf3483d4c00b1..df32fbd4b33e9 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -14,8 +14,8 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::traits::Reveal; use rustc_middle::ty::{ - self, Binder, BoundConstness, Clause, GenericParamDefKind, ImplPolarity, ParamEnv, PredicateKind, TraitPredicate, - Ty, TyCtxt, + self, Binder, BoundConstness, Clause, GenericArgKind, GenericParamDefKind, ImplPolarity, ParamEnv, PredicateKind, + TraitPredicate, Ty, TyCtxt, }; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; @@ -366,6 +366,15 @@ fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &h if ty_subs.types().any(|ty| !implements_trait(cx, ty, clone_id, &[])) { return; } + // `#[repr(packed)]` structs with type/const parameters can't derive `Clone`. + // https://github.com/rust-lang/rust-clippy/issues/10188 + if ty_adt.repr().packed() + && ty_subs + .iter() + .any(|arg| matches!(arg.unpack(), GenericArgKind::Type(_) | GenericArgKind::Const(_))) + { + return; + } span_lint_and_note( cx, diff --git a/tests/ui/derive.rs b/tests/ui/derive.rs index c629c0e535377..843e1df8bc6bb 100644 --- a/tests/ui/derive.rs +++ b/tests/ui/derive.rs @@ -85,4 +85,15 @@ impl Clone for GenericRef<'_, T, U> { } } +// https://github.com/rust-lang/rust-clippy/issues/10188 +#[repr(packed)] +#[derive(Copy)] +struct Packed(T); + +impl Clone for Packed { + fn clone(&self) -> Self { + *self + } +} + fn main() {} From 920633258f237e3aed59adb1e9e900431962ab7a Mon Sep 17 00:00:00 2001 From: Robert Bastian Date: Thu, 12 Jan 2023 14:22:18 +0100 Subject: [PATCH 45/51] fix --- tests/ui/derived_hash_with_manual_eq.rs | 2 + tests/ui/derived_hash_with_manual_eq.stderr | 10 +-- tests/ui/rename.fixed | 2 + tests/ui/rename.stderr | 90 +++++++++++---------- 4 files changed, 57 insertions(+), 47 deletions(-) diff --git a/tests/ui/derived_hash_with_manual_eq.rs b/tests/ui/derived_hash_with_manual_eq.rs index 0804e3cffa1a2..8ad09a8de43d5 100644 --- a/tests/ui/derived_hash_with_manual_eq.rs +++ b/tests/ui/derived_hash_with_manual_eq.rs @@ -27,6 +27,8 @@ impl PartialEq for Baz { } } +// Implementing `Hash` with a derived `PartialEq` is fine. See #2627 + #[derive(PartialEq)] struct Bah; diff --git a/tests/ui/derived_hash_with_manual_eq.stderr b/tests/ui/derived_hash_with_manual_eq.stderr index 16965aa42d8c4..230940f25fb60 100644 --- a/tests/ui/derived_hash_with_manual_eq.stderr +++ b/tests/ui/derived_hash_with_manual_eq.stderr @@ -1,25 +1,25 @@ error: you are deriving `Hash` but have implemented `PartialEq` explicitly - --> $DIR/derive_hash_xor_eq.rs:12:10 + --> $DIR/derived_hash_with_manual_eq.rs:12:10 | LL | #[derive(Hash)] | ^^^^ | note: `PartialEq` implemented here - --> $DIR/derive_hash_xor_eq.rs:15:1 + --> $DIR/derived_hash_with_manual_eq.rs:15:1 | LL | impl PartialEq for Bar { | ^^^^^^^^^^^^^^^^^^^^^^ - = note: `#[deny(clippy::derive_hash_xor_eq)]` on by default + = note: `#[deny(clippy::derived_hash_with_manual_eq)]` on by default = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info) error: you are deriving `Hash` but have implemented `PartialEq` explicitly - --> $DIR/derive_hash_xor_eq.rs:21:10 + --> $DIR/derived_hash_with_manual_eq.rs:21:10 | LL | #[derive(Hash)] | ^^^^ | note: `PartialEq` implemented here - --> $DIR/derive_hash_xor_eq.rs:24:1 + --> $DIR/derived_hash_with_manual_eq.rs:24:1 | LL | impl PartialEq for Baz { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/rename.fixed b/tests/ui/rename.fixed index 2f76b57529607..5076f61334d67 100644 --- a/tests/ui/rename.fixed +++ b/tests/ui/rename.fixed @@ -10,6 +10,7 @@ #![allow(clippy::box_collection)] #![allow(clippy::redundant_static_lifetimes)] #![allow(clippy::cognitive_complexity)] +#![allow(clippy::derived_hash_with_manual_eq)] #![allow(clippy::disallowed_methods)] #![allow(clippy::disallowed_types)] #![allow(clippy::mixed_read_write_in_expression)] @@ -45,6 +46,7 @@ #![warn(clippy::box_collection)] #![warn(clippy::redundant_static_lifetimes)] #![warn(clippy::cognitive_complexity)] +#![warn(clippy::derived_hash_with_manual_eq)] #![warn(clippy::disallowed_methods)] #![warn(clippy::disallowed_types)] #![warn(clippy::mixed_read_write_in_expression)] diff --git a/tests/ui/rename.stderr b/tests/ui/rename.stderr index 9af58dc75a68f..27a0263292ef1 100644 --- a/tests/ui/rename.stderr +++ b/tests/ui/rename.stderr @@ -1,5 +1,5 @@ error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range` - --> $DIR/rename.rs:41:9 + --> $DIR/rename.rs:42:9 | LL | #![warn(clippy::almost_complete_letter_range)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range` @@ -7,244 +7,250 @@ LL | #![warn(clippy::almost_complete_letter_range)] = note: `-D renamed-and-removed-lints` implied by `-D warnings` error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names` - --> $DIR/rename.rs:42:9 + --> $DIR/rename.rs:43:9 | LL | #![warn(clippy::blacklisted_name)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names` error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions` - --> $DIR/rename.rs:43:9 + --> $DIR/rename.rs:44:9 | LL | #![warn(clippy::block_in_if_condition_expr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions` - --> $DIR/rename.rs:44:9 + --> $DIR/rename.rs:45: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:45:9 + --> $DIR/rename.rs:46:9 | LL | #![warn(clippy::box_vec)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection` error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes` - --> $DIR/rename.rs:46:9 + --> $DIR/rename.rs:47: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:47:9 + --> $DIR/rename.rs:48:9 | LL | #![warn(clippy::cyclomatic_complexity)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity` +error: lint `clippy::derive_hash_xor_eq` has been renamed to `clippy::derived_hash_with_manual_eq` + --> $DIR/rename.rs:49:9 + | +LL | #![warn(clippy::derive_hash_xor_eq)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq` + error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods` - --> $DIR/rename.rs:48:9 + --> $DIR/rename.rs:50: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:49:9 + --> $DIR/rename.rs:51: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:50:9 + --> $DIR/rename.rs:52:9 | LL | #![warn(clippy::eval_order_dependence)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression` error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion` - --> $DIR/rename.rs:51:9 + --> $DIR/rename.rs:53: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:52:9 + --> $DIR/rename.rs:54: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:53:9 + --> $DIR/rename.rs:55: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:54:9 + --> $DIR/rename.rs:56: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:55:9 + --> $DIR/rename.rs:57: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:56:9 + --> $DIR/rename.rs:58: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:57:9 + --> $DIR/rename.rs:59: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:58:9 + --> $DIR/rename.rs:60: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:59:9 + --> $DIR/rename.rs:61: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:60:9 + --> $DIR/rename.rs:62: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:61:9 + --> $DIR/rename.rs:63: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:62:9 + --> $DIR/rename.rs:64: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:63:9 + --> $DIR/rename.rs:65: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:64:9 + --> $DIR/rename.rs:66: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:65:9 + --> $DIR/rename.rs:67: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:66:9 + --> $DIR/rename.rs:68: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:67:9 + --> $DIR/rename.rs:69: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:68:9 + --> $DIR/rename.rs:70:9 | LL | #![warn(clippy::drop_bounds)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds` error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles` - --> $DIR/rename.rs:69:9 + --> $DIR/rename.rs:71:9 | LL | #![warn(clippy::for_loop_over_option)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles` - --> $DIR/rename.rs:70:9 + --> $DIR/rename.rs:72:9 | LL | #![warn(clippy::for_loop_over_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles` - --> $DIR/rename.rs:71:9 + --> $DIR/rename.rs:73:9 | LL | #![warn(clippy::for_loops_over_fallibles)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter` - --> $DIR/rename.rs:72:9 + --> $DIR/rename.rs:74: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:73:9 + --> $DIR/rename.rs:75: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:74:9 + --> $DIR/rename.rs:76:9 | LL | #![warn(clippy::invalid_ref)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value` error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop` - --> $DIR/rename.rs:75:9 + --> $DIR/rename.rs:77:9 | LL | #![warn(clippy::let_underscore_drop)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop` error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums` - --> $DIR/rename.rs:76:9 + --> $DIR/rename.rs:78: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:77:9 + --> $DIR/rename.rs:79:9 | LL | #![warn(clippy::panic_params)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics` error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally` - --> $DIR/rename.rs:78:9 + --> $DIR/rename.rs:80:9 | LL | #![warn(clippy::positional_named_format_parameters)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally` error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr` - --> $DIR/rename.rs:79:9 + --> $DIR/rename.rs:81: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:80:9 + --> $DIR/rename.rs:82: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:81:9 + --> $DIR/rename.rs:83:9 | LL | #![warn(clippy::unused_label)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels` -error: aborting due to 41 previous errors +error: aborting due to 42 previous errors From 321c530fadb766c594698be7c83ab7cbc443bf1c Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Tue, 3 Jan 2023 18:04:28 +0000 Subject: [PATCH 46/51] Don't pass `--sysroot` twice if SYSROOT is set This is useful for rust-lang/rust to allow setting a sysroot that's *only* for build scripts, different from the regular sysroot passed in RUSTFLAGS (since cargo doesn't apply RUSTFLAGS to build scripts or proc-macros). That said, the exact motivation is not particularly important: this fixes a regression from https://github.com/rust-lang/rust-clippy/pull/9881/commits/5907e9155ed7f1312d108aa2110853472da3b029#r1060215684. Note that only RUSTFLAGS is tested in the new integration test; passing --sysroot through `clippy-driver` never worked as far as I can tell, and no one is using it, so I didn't fix it here. --- src/driver.rs | 5 ++- tests/integration.rs | 97 +++++++++++++++++++++++++++++++++----------- 2 files changed, 77 insertions(+), 25 deletions(-) diff --git a/src/driver.rs b/src/driver.rs index bcc096c570e1b..d521e8d883983 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -256,11 +256,14 @@ pub fn main() { LazyLock::force(&ICE_HOOK); exit(rustc_driver::catch_with_exit_code(move || { let mut orig_args: Vec = env::args().collect(); + let has_sysroot_arg = arg_value(&orig_args, "--sysroot", |_| true).is_some(); let sys_root_env = std::env::var("SYSROOT").ok(); let pass_sysroot_env_if_given = |args: &mut Vec, sys_root_env| { if let Some(sys_root) = sys_root_env { - args.extend(vec!["--sysroot".into(), sys_root]); + if !has_sysroot_arg { + args.extend(vec!["--sysroot".into(), sys_root]); + } }; }; diff --git a/tests/integration.rs b/tests/integration.rs index 818ff70b33f4d..319e8eb2da602 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -1,19 +1,42 @@ +//! To run this test, use +//! `env INTEGRATION=rust-lang/log cargo test --test integration --features=integration` +//! +//! You can use a different `INTEGRATION` value to test different repositories. + #![cfg(feature = "integration")] #![cfg_attr(feature = "deny-warnings", deny(warnings))] #![warn(rust_2018_idioms, unused_lifetimes)] -use std::env; use std::ffi::OsStr; +use std::path::{Path, PathBuf}; use std::process::Command; +use std::{env, eprintln}; #[cfg(not(windows))] const CARGO_CLIPPY: &str = "cargo-clippy"; #[cfg(windows)] const CARGO_CLIPPY: &str = "cargo-clippy.exe"; -#[cfg_attr(feature = "integration", test)] -fn integration_test() { - let repo_name = env::var("INTEGRATION").expect("`INTEGRATION` var not set"); +// NOTE: arguments passed to the returned command will be `clippy-driver` args, not `cargo-clippy` +// args. Use `cargo_args` to pass arguments to cargo-clippy. +fn clippy_command(repo_dir: &Path, cargo_args: &[&str]) -> Command { + let root_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let target_dir = option_env!("CARGO_TARGET_DIR").map_or_else(|| root_dir.join("target"), PathBuf::from); + let clippy_binary = target_dir.join(env!("PROFILE")).join(CARGO_CLIPPY); + + let mut cargo_clippy = Command::new(clippy_binary); + cargo_clippy + .current_dir(repo_dir) + .env("RUST_BACKTRACE", "full") + .env("CARGO_TARGET_DIR", root_dir.join("target")) + .args(["clippy", "--all-targets", "--all-features"]) + .args(cargo_args) + .args(["--", "--cap-lints", "warn", "-Wclippy::pedantic", "-Wclippy::nursery"]); + cargo_clippy +} + +/// Return a directory with a checkout of the repository in `INTEGRATION`. +fn repo_dir(repo_name: &str) -> PathBuf { let repo_url = format!("https://github.com/{repo_name}"); let crate_name = repo_name .split('/') @@ -34,28 +57,19 @@ fn integration_test() { .expect("unable to run git"); assert!(st.success()); - let root_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")); - let target_dir = std::path::Path::new(&root_dir).join("target"); - let clippy_binary = target_dir.join(env!("PROFILE")).join(CARGO_CLIPPY); - - let output = Command::new(clippy_binary) - .current_dir(repo_dir) - .env("RUST_BACKTRACE", "full") - .env("CARGO_TARGET_DIR", target_dir) - .args([ - "clippy", - "--all-targets", - "--all-features", - "--", - "--cap-lints", - "warn", - "-Wclippy::pedantic", - "-Wclippy::nursery", - ]) - .output() - .expect("unable to run clippy"); + repo_dir +} +#[cfg_attr(feature = "integration", test)] +fn integration_test() { + let repo_name = env::var("INTEGRATION").expect("`INTEGRATION` var not set"); + let repo_dir = repo_dir(&repo_name); + let output = clippy_command(&repo_dir, &[]).output().expect("failed to run clippy"); let stderr = String::from_utf8_lossy(&output.stderr); + if !stderr.is_empty() { + eprintln!("{stderr}"); + } + if let Some(backtrace_start) = stderr.find("error: internal compiler error") { static BACKTRACE_END_MSG: &str = "end of query stack"; let backtrace_end = stderr[backtrace_start..] @@ -90,3 +104,38 @@ fn integration_test() { None => panic!("Process terminated by signal"), } } + +#[cfg_attr(feature = "integration", test)] +fn test_sysroot() { + #[track_caller] + fn verify_cmd(cmd: &mut Command) { + // Test that SYSROOT is ignored if `--sysroot` is passed explicitly. + cmd.env("SYSROOT", "/dummy/value/does/not/exist"); + // We don't actually care about emitting lints, we only want to verify clippy doesn't give a hard + // error. + cmd.arg("-Awarnings"); + let output = cmd.output().expect("failed to run clippy"); + let stderr = String::from_utf8_lossy(&output.stderr); + assert!(stderr.is_empty(), "clippy printed an error: {stderr}"); + assert!(output.status.success(), "clippy exited with an error"); + } + + let rustc = std::env::var("RUSTC").unwrap_or("rustc".to_string()); + let rustc_output = Command::new(rustc) + .args(["--print", "sysroot"]) + .output() + .expect("unable to run rustc"); + assert!(rustc_output.status.success()); + let sysroot = String::from_utf8(rustc_output.stdout).unwrap(); + let sysroot = sysroot.trim_end(); + + // This is a fairly small repo; we want to avoid checking out anything heavy twice, so just + // hard-code it. + let repo_name = "rust-lang/log"; + let repo_dir = repo_dir(repo_name); + // Pass the sysroot through RUSTFLAGS. + verify_cmd(clippy_command(&repo_dir, &["--quiet"]).env("RUSTFLAGS", format!("--sysroot={sysroot}"))); + // NOTE: we don't test passing the arguments directly to clippy-driver (with `-- --sysroot`) + // because it breaks for some reason. I (@jyn514) haven't taken time to track down the bug + // because rust-lang/rust uses RUSTFLAGS and nearly no one else uses --sysroot. +} From fe007179ec3560f86bd15686d60372f8307ca225 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 12 Jan 2023 18:30:51 +0100 Subject: [PATCH 47/51] Add cargo-clippy sysroot test Whne SYSROOT is defined, clippy-driver will insert a --sysroot argument when calling rustc. However, when a sysroot argument is already defined, e.g. through RUSTFLAGS=--sysroot=... the `cargo clippy` call would error. This tests that the sysroot argument is only passed once and that SYSROOT is ignored in this case. --- .github/driver.sh | 7 ++++ tests/integration.rs | 98 +++++++++++++------------------------------- 2 files changed, 36 insertions(+), 69 deletions(-) diff --git a/.github/driver.sh b/.github/driver.sh index 6ff189fc85926..798782340ee7d 100644 --- a/.github/driver.sh +++ b/.github/driver.sh @@ -17,6 +17,13 @@ test "$sysroot" = $desired_sysroot sysroot=$(SYSROOT=$desired_sysroot ./target/debug/clippy-driver --print sysroot) test "$sysroot" = $desired_sysroot +# Check that the --sysroot argument is only passed once (SYSROOT is ignored) +( + cd rustc_tools_util + touch src/lib.rs + SYSROOT=/tmp RUSTFLAGS="--sysroot=$(rustc --print sysroot)" ../target/debug/cargo-clippy clippy --verbose +) + # Make sure this isn't set - clippy-driver should cope without it unset CARGO_MANIFEST_DIR diff --git a/tests/integration.rs b/tests/integration.rs index 319e8eb2da602..a771d8b87c81a 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -1,42 +1,28 @@ -//! To run this test, use +//! This test is meant to only be run in CI. To run it locally use: +//! //! `env INTEGRATION=rust-lang/log cargo test --test integration --features=integration` //! //! You can use a different `INTEGRATION` value to test different repositories. +//! +//! This test will clone the specified repository and run Clippy on it. The test succeeds, if +//! Clippy doesn't produce an ICE. Lint warnings are ignored by this test. #![cfg(feature = "integration")] #![cfg_attr(feature = "deny-warnings", deny(warnings))] #![warn(rust_2018_idioms, unused_lifetimes)] +use std::env; use std::ffi::OsStr; -use std::path::{Path, PathBuf}; use std::process::Command; -use std::{env, eprintln}; #[cfg(not(windows))] const CARGO_CLIPPY: &str = "cargo-clippy"; #[cfg(windows)] const CARGO_CLIPPY: &str = "cargo-clippy.exe"; -// NOTE: arguments passed to the returned command will be `clippy-driver` args, not `cargo-clippy` -// args. Use `cargo_args` to pass arguments to cargo-clippy. -fn clippy_command(repo_dir: &Path, cargo_args: &[&str]) -> Command { - let root_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")); - let target_dir = option_env!("CARGO_TARGET_DIR").map_or_else(|| root_dir.join("target"), PathBuf::from); - let clippy_binary = target_dir.join(env!("PROFILE")).join(CARGO_CLIPPY); - - let mut cargo_clippy = Command::new(clippy_binary); - cargo_clippy - .current_dir(repo_dir) - .env("RUST_BACKTRACE", "full") - .env("CARGO_TARGET_DIR", root_dir.join("target")) - .args(["clippy", "--all-targets", "--all-features"]) - .args(cargo_args) - .args(["--", "--cap-lints", "warn", "-Wclippy::pedantic", "-Wclippy::nursery"]); - cargo_clippy -} - -/// Return a directory with a checkout of the repository in `INTEGRATION`. -fn repo_dir(repo_name: &str) -> PathBuf { +#[cfg_attr(feature = "integration", test)] +fn integration_test() { + let repo_name = env::var("INTEGRATION").expect("`INTEGRATION` var not set"); let repo_url = format!("https://github.com/{repo_name}"); let crate_name = repo_name .split('/') @@ -57,19 +43,28 @@ fn repo_dir(repo_name: &str) -> PathBuf { .expect("unable to run git"); assert!(st.success()); - repo_dir -} + let root_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let target_dir = std::path::Path::new(&root_dir).join("target"); + let clippy_binary = target_dir.join(env!("PROFILE")).join(CARGO_CLIPPY); -#[cfg_attr(feature = "integration", test)] -fn integration_test() { - let repo_name = env::var("INTEGRATION").expect("`INTEGRATION` var not set"); - let repo_dir = repo_dir(&repo_name); - let output = clippy_command(&repo_dir, &[]).output().expect("failed to run clippy"); - let stderr = String::from_utf8_lossy(&output.stderr); - if !stderr.is_empty() { - eprintln!("{stderr}"); - } + let output = Command::new(clippy_binary) + .current_dir(repo_dir) + .env("RUST_BACKTRACE", "full") + .env("CARGO_TARGET_DIR", target_dir) + .args([ + "clippy", + "--all-targets", + "--all-features", + "--", + "--cap-lints", + "warn", + "-Wclippy::pedantic", + "-Wclippy::nursery", + ]) + .output() + .expect("unable to run clippy"); + let stderr = String::from_utf8_lossy(&output.stderr); if let Some(backtrace_start) = stderr.find("error: internal compiler error") { static BACKTRACE_END_MSG: &str = "end of query stack"; let backtrace_end = stderr[backtrace_start..] @@ -104,38 +99,3 @@ fn integration_test() { None => panic!("Process terminated by signal"), } } - -#[cfg_attr(feature = "integration", test)] -fn test_sysroot() { - #[track_caller] - fn verify_cmd(cmd: &mut Command) { - // Test that SYSROOT is ignored if `--sysroot` is passed explicitly. - cmd.env("SYSROOT", "/dummy/value/does/not/exist"); - // We don't actually care about emitting lints, we only want to verify clippy doesn't give a hard - // error. - cmd.arg("-Awarnings"); - let output = cmd.output().expect("failed to run clippy"); - let stderr = String::from_utf8_lossy(&output.stderr); - assert!(stderr.is_empty(), "clippy printed an error: {stderr}"); - assert!(output.status.success(), "clippy exited with an error"); - } - - let rustc = std::env::var("RUSTC").unwrap_or("rustc".to_string()); - let rustc_output = Command::new(rustc) - .args(["--print", "sysroot"]) - .output() - .expect("unable to run rustc"); - assert!(rustc_output.status.success()); - let sysroot = String::from_utf8(rustc_output.stdout).unwrap(); - let sysroot = sysroot.trim_end(); - - // This is a fairly small repo; we want to avoid checking out anything heavy twice, so just - // hard-code it. - let repo_name = "rust-lang/log"; - let repo_dir = repo_dir(repo_name); - // Pass the sysroot through RUSTFLAGS. - verify_cmd(clippy_command(&repo_dir, &["--quiet"]).env("RUSTFLAGS", format!("--sysroot={sysroot}"))); - // NOTE: we don't test passing the arguments directly to clippy-driver (with `-- --sysroot`) - // because it breaks for some reason. I (@jyn514) haven't taken time to track down the bug - // because rust-lang/rust uses RUSTFLAGS and nearly no one else uses --sysroot. -} From 616b6d2be13092b53b83cd4e53e5e88f310a86fc Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 12 Jan 2023 19:00:16 +0100 Subject: [PATCH 48/51] Bump nightly version -> 2023-01-12 --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 9399d422036d4..40a6f47095ec2 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2022-12-29" +channel = "nightly-2023-01-12" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] From cd76d574e444197d692d8652c27f869038430af1 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 12 Jan 2023 19:12:06 +0100 Subject: [PATCH 49/51] Also add rustc_driver to clippy_utils I'm not sure why this is necessary. It worked without this for me locally, but this fails in CI. The same was done in clippy_dev --- clippy_utils/src/lib.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 991be9727c217..7a4a9036dd363 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -22,6 +22,9 @@ extern crate rustc_ast; extern crate rustc_ast_pretty; extern crate rustc_attr; extern crate rustc_data_structures; +// The `rustc_driver` crate seems to be required in order to use the `rust_ast` crate. +#[allow(unused_extern_crates)] +extern crate rustc_driver; extern crate rustc_errors; extern crate rustc_hir; extern crate rustc_hir_typeck; From 5eed9c69ca9fa04a1417f1f14df0bb5bab2fc8c8 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Thu, 12 Jan 2023 13:28:22 -0500 Subject: [PATCH 50/51] Revert 4dbd8ad34e7f6820f6e9e99531353e7ffe37b76a, c7dc96155853a3919b973347277d0e9bcaaa22f0, ed519ad746e31f64c4e9255be561785612532d37 and c6477eb71188311f01f409da628fab7062697bd7 --- clippy_lints/src/dereference.rs | 8 +- clippy_lints/src/redundant_clone.rs | 4 +- clippy_utils/src/mir/possible_borrower.rs | 271 ++++++++-------------- tests/ui/needless_borrow.fixed | 13 +- tests/ui/needless_borrow.rs | 13 +- tests/ui/needless_borrow.stderr | 8 +- tests/ui/redundant_clone.fixed | 6 - tests/ui/redundant_clone.rs | 6 - tests/ui/redundant_clone.stderr | 14 +- 9 files changed, 109 insertions(+), 234 deletions(-) diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 728941b8b3d9a..7b43d8ccc67d1 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -1282,10 +1282,10 @@ fn referent_used_exactly_once<'tcx>( possible_borrowers.push((body_owner_local_def_id, PossibleBorrowerMap::new(cx, mir))); } let possible_borrower = &mut possible_borrowers.last_mut().unwrap().1; - // If `place.local` were not included here, the `copyable_iterator::warn` test would fail. The - // reason is that `PossibleBorrowerVisitor::visit_terminator` considers `place.local` a possible - // borrower of itself. See the comment in that method for an explanation as to why. - possible_borrower.at_most_borrowers(cx, &[local, place.local], place.local, location) + // If `only_borrowers` were used here, the `copyable_iterator::warn` test would fail. The reason is + // that `PossibleBorrowerVisitor::visit_terminator` considers `place.local` a possible borrower of + // itself. See the comment in that method for an explanation as to why. + possible_borrower.bounded_borrowers(&[local], &[local, place.local], place.local, location) && used_exactly_once(mir, place.local).unwrap_or(false) } else { false diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index 0e7c5cca7240b..c1677fb3da1c4 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -131,7 +131,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone { // `res = clone(arg)` can be turned into `res = move arg;` // if `arg` is the only borrow of `cloned` at this point. - if cannot_move_out || !possible_borrower.at_most_borrowers(cx, &[arg], cloned, loc) { + if cannot_move_out || !possible_borrower.only_borrowers(&[arg], cloned, loc) { continue; } @@ -178,7 +178,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone { // StorageDead(pred_arg); // res = to_path_buf(cloned); // ``` - if cannot_move_out || !possible_borrower.at_most_borrowers(cx, &[arg, cloned], local, loc) { + if cannot_move_out || !possible_borrower.only_borrowers(&[arg, cloned], local, loc) { continue; } diff --git a/clippy_utils/src/mir/possible_borrower.rs b/clippy_utils/src/mir/possible_borrower.rs index 395d46e7a2f8a..8c695801c73fc 100644 --- a/clippy_utils/src/mir/possible_borrower.rs +++ b/clippy_utils/src/mir/possible_borrower.rs @@ -1,137 +1,89 @@ -use super::possible_origin::PossibleOriginVisitor; +use super::{possible_origin::PossibleOriginVisitor, transitive_relation::TransitiveRelation}; use crate::ty::is_copy; -use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; +use rustc_data_structures::fx::FxHashMap; use rustc_index::bit_set::{BitSet, HybridBitSet}; use rustc_lint::LateContext; -use rustc_middle::mir::{ - self, visit::Visitor as _, BasicBlock, Local, Location, Mutability, Statement, StatementKind, Terminator, -}; -use rustc_middle::ty::{self, visit::TypeVisitor, TyCtxt}; -use rustc_mir_dataflow::{ - fmt::DebugWithContext, impls::MaybeStorageLive, lattice::JoinSemiLattice, Analysis, AnalysisDomain, - CallReturnPlaces, ResultsCursor, -}; -use std::borrow::Cow; +use rustc_middle::mir::{self, visit::Visitor as _, Mutability}; +use rustc_middle::ty::{self, visit::TypeVisitor}; +use rustc_mir_dataflow::{impls::MaybeStorageLive, Analysis, ResultsCursor}; use std::ops::ControlFlow; /// Collects the possible borrowers of each local. /// For example, `b = &a; c = &a;` will make `b` and (transitively) `c` /// possible borrowers of `a`. #[allow(clippy::module_name_repetitions)] -struct PossibleBorrowerAnalysis<'b, 'tcx> { - tcx: TyCtxt<'tcx>, +struct PossibleBorrowerVisitor<'a, 'b, 'tcx> { + possible_borrower: TransitiveRelation, body: &'b mir::Body<'tcx>, + cx: &'a LateContext<'tcx>, possible_origin: FxHashMap>, } -#[derive(Clone, Debug, Eq, PartialEq)] -struct PossibleBorrowerState { - map: FxIndexMap>, - domain_size: usize, -} - -impl PossibleBorrowerState { - fn new(domain_size: usize) -> Self { +impl<'a, 'b, 'tcx> PossibleBorrowerVisitor<'a, 'b, 'tcx> { + fn new( + cx: &'a LateContext<'tcx>, + body: &'b mir::Body<'tcx>, + possible_origin: FxHashMap>, + ) -> Self { Self { - map: FxIndexMap::default(), - domain_size, + possible_borrower: TransitiveRelation::default(), + cx, + body, + possible_origin, } } - #[allow(clippy::similar_names)] - fn add(&mut self, borrowed: Local, borrower: Local) { - self.map - .entry(borrowed) - .or_insert(BitSet::new_empty(self.domain_size)) - .insert(borrower); - } -} - -impl DebugWithContext for PossibleBorrowerState { - fn fmt_with(&self, _ctxt: &C, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - <_ as std::fmt::Debug>::fmt(self, f) - } - fn fmt_diff_with(&self, _old: &Self, _ctxt: &C, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - unimplemented!() - } -} + fn into_map( + self, + cx: &'a LateContext<'tcx>, + maybe_live: ResultsCursor<'b, 'tcx, MaybeStorageLive>, + ) -> PossibleBorrowerMap<'b, 'tcx> { + let mut map = FxHashMap::default(); + for row in (1..self.body.local_decls.len()).map(mir::Local::from_usize) { + if is_copy(cx, self.body.local_decls[row].ty) { + continue; + } -impl JoinSemiLattice for PossibleBorrowerState { - fn join(&mut self, other: &Self) -> bool { - let mut changed = false; - for (&borrowed, borrowers) in other.map.iter() { + let mut borrowers = self.possible_borrower.reachable_from(row, self.body.local_decls.len()); + borrowers.remove(mir::Local::from_usize(0)); if !borrowers.is_empty() { - changed |= self - .map - .entry(borrowed) - .or_insert(BitSet::new_empty(self.domain_size)) - .union(borrowers); + map.insert(row, borrowers); } } - changed - } -} - -impl<'b, 'tcx> AnalysisDomain<'tcx> for PossibleBorrowerAnalysis<'b, 'tcx> { - type Domain = PossibleBorrowerState; - - const NAME: &'static str = "possible_borrower"; - - fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain { - PossibleBorrowerState::new(body.local_decls.len()) - } - - fn initialize_start_block(&self, _body: &mir::Body<'tcx>, _entry_set: &mut Self::Domain) {} -} -impl<'b, 'tcx> PossibleBorrowerAnalysis<'b, 'tcx> { - fn new( - tcx: TyCtxt<'tcx>, - body: &'b mir::Body<'tcx>, - possible_origin: FxHashMap>, - ) -> Self { - Self { - tcx, - body, - possible_origin, + let bs = BitSet::new_empty(self.body.local_decls.len()); + PossibleBorrowerMap { + map, + maybe_live, + bitset: (bs.clone(), bs), } } } -impl<'b, 'tcx> Analysis<'tcx> for PossibleBorrowerAnalysis<'b, 'tcx> { - fn apply_call_return_effect( - &self, - _state: &mut Self::Domain, - _block: BasicBlock, - _return_places: CallReturnPlaces<'_, 'tcx>, - ) { - } - - fn apply_statement_effect(&self, state: &mut Self::Domain, statement: &Statement<'tcx>, _location: Location) { - if let StatementKind::Assign(box (place, rvalue)) = &statement.kind { - let lhs = place.local; - match rvalue { - mir::Rvalue::Ref(_, _, borrowed) => { - state.add(borrowed.local, lhs); - }, - other => { - if ContainsRegion - .visit_ty(place.ty(&self.body.local_decls, self.tcx).ty) - .is_continue() - { - return; +impl<'a, 'b, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'b, 'tcx> { + fn visit_assign(&mut self, place: &mir::Place<'tcx>, rvalue: &mir::Rvalue<'_>, _location: mir::Location) { + let lhs = place.local; + match rvalue { + mir::Rvalue::Ref(_, _, borrowed) => { + self.possible_borrower.add(borrowed.local, lhs); + }, + other => { + if ContainsRegion + .visit_ty(place.ty(&self.body.local_decls, self.cx.tcx).ty) + .is_continue() + { + return; + } + rvalue_locals(other, |rhs| { + if lhs != rhs { + self.possible_borrower.add(rhs, lhs); } - rvalue_locals(other, |rhs| { - if lhs != rhs { - state.add(rhs, lhs); - } - }); - }, - } + }); + }, } } - fn apply_terminator_effect(&self, state: &mut Self::Domain, terminator: &Terminator<'tcx>, _location: Location) { + fn visit_terminator(&mut self, terminator: &mir::Terminator<'_>, _loc: mir::Location) { if let mir::TerminatorKind::Call { args, destination: mir::Place { local: dest, .. }, @@ -171,10 +123,10 @@ impl<'b, 'tcx> Analysis<'tcx> for PossibleBorrowerAnalysis<'b, 'tcx> { for y in mutable_variables { for x in &immutable_borrowers { - state.add(*x, y); + self.possible_borrower.add(*x, y); } for x in &mutable_borrowers { - state.add(*x, y); + self.possible_borrower.add(*x, y); } } } @@ -210,98 +162,73 @@ fn rvalue_locals(rvalue: &mir::Rvalue<'_>, mut visit: impl FnMut(mir::Local)) { } } -/// Result of `PossibleBorrowerAnalysis`. +/// Result of `PossibleBorrowerVisitor`. #[allow(clippy::module_name_repetitions)] pub struct PossibleBorrowerMap<'b, 'tcx> { - body: &'b mir::Body<'tcx>, - possible_borrower: ResultsCursor<'b, 'tcx, PossibleBorrowerAnalysis<'b, 'tcx>>, - maybe_live: ResultsCursor<'b, 'tcx, MaybeStorageLive<'b>>, - pushed: BitSet, - stack: Vec, + /// Mapping `Local -> its possible borrowers` + pub map: FxHashMap>, + maybe_live: ResultsCursor<'b, 'tcx, MaybeStorageLive>, + // Caches to avoid allocation of `BitSet` on every query + pub bitset: (BitSet, BitSet), } -impl<'b, 'tcx> PossibleBorrowerMap<'b, 'tcx> { - pub fn new(cx: &LateContext<'tcx>, mir: &'b mir::Body<'tcx>) -> Self { +impl<'a, 'b, 'tcx> PossibleBorrowerMap<'b, 'tcx> { + pub fn new(cx: &'a LateContext<'tcx>, mir: &'b mir::Body<'tcx>) -> Self { let possible_origin = { let mut vis = PossibleOriginVisitor::new(mir); vis.visit_body(mir); vis.into_map(cx) }; - let possible_borrower = PossibleBorrowerAnalysis::new(cx.tcx, mir, possible_origin) + let maybe_storage_live_result = MaybeStorageLive::new(BitSet::new_empty(mir.local_decls.len())) .into_engine(cx.tcx, mir) - .pass_name("possible_borrower") + .pass_name("redundant_clone") .iterate_to_fixpoint() .into_results_cursor(mir); - let maybe_live = MaybeStorageLive::new(Cow::Owned(BitSet::new_empty(mir.local_decls.len()))) - .into_engine(cx.tcx, mir) - .pass_name("possible_borrower") - .iterate_to_fixpoint() - .into_results_cursor(mir); - PossibleBorrowerMap { - body: mir, - possible_borrower, - maybe_live, - pushed: BitSet::new_empty(mir.local_decls.len()), - stack: Vec::with_capacity(mir.local_decls.len()), - } + let mut vis = PossibleBorrowerVisitor::new(cx, mir, possible_origin); + vis.visit_body(mir); + vis.into_map(cx, maybe_storage_live_result) } - /// Returns true if the set of borrowers of `borrowed` living at `at` includes no more than - /// `borrowers`. - /// Notes: - /// 1. It would be nice if `PossibleBorrowerMap` could store `cx` so that `at_most_borrowers` - /// would not require it to be passed in. But a `PossibleBorrowerMap` is stored in `LintPass` - /// `Dereferencing`, which outlives any `LateContext`. - /// 2. In all current uses of `at_most_borrowers`, `borrowers` is a slice of at most two - /// elements. Thus, `borrowers.contains(...)` is effectively a constant-time operation. If - /// `at_most_borrowers`'s uses were to expand beyond this, its implementation might have to be - /// adjusted. - pub fn at_most_borrowers( + /// Returns true if the set of borrowers of `borrowed` living at `at` matches with `borrowers`. + pub fn only_borrowers(&mut self, borrowers: &[mir::Local], borrowed: mir::Local, at: mir::Location) -> bool { + self.bounded_borrowers(borrowers, borrowers, borrowed, at) + } + + /// Returns true if the set of borrowers of `borrowed` living at `at` includes at least `below` + /// but no more than `above`. + pub fn bounded_borrowers( &mut self, - cx: &LateContext<'tcx>, - borrowers: &[mir::Local], + below: &[mir::Local], + above: &[mir::Local], borrowed: mir::Local, at: mir::Location, ) -> bool { - if is_copy(cx, self.body.local_decls[borrowed].ty) { - return true; - } - - self.possible_borrower.seek_before_primary_effect(at); - self.maybe_live.seek_before_primary_effect(at); - - let possible_borrower = &self.possible_borrower.get().map; - let maybe_live = &self.maybe_live; - - self.pushed.clear(); - self.stack.clear(); + self.maybe_live.seek_after_primary_effect(at); - if let Some(borrowers) = possible_borrower.get(&borrowed) { - for b in borrowers.iter() { - if self.pushed.insert(b) { - self.stack.push(b); - } + self.bitset.0.clear(); + let maybe_live = &mut self.maybe_live; + if let Some(bitset) = self.map.get(&borrowed) { + for b in bitset.iter().filter(move |b| maybe_live.contains(*b)) { + self.bitset.0.insert(b); } } else { - // Nothing borrows `borrowed` at `at`. - return true; + return false; } - while let Some(borrower) = self.stack.pop() { - if maybe_live.contains(borrower) && !borrowers.contains(&borrower) { - return false; - } + self.bitset.1.clear(); + for b in below { + self.bitset.1.insert(*b); + } - if let Some(borrowers) = possible_borrower.get(&borrower) { - for b in borrowers.iter() { - if self.pushed.insert(b) { - self.stack.push(b); - } - } - } + if !self.bitset.0.superset(&self.bitset.1) { + return false; + } + + for b in above { + self.bitset.0.remove(*b); } - true + self.bitset.0.is_empty() } pub fn local_is_alive_at(&mut self, local: mir::Local, at: mir::Location) -> bool { diff --git a/tests/ui/needless_borrow.fixed b/tests/ui/needless_borrow.fixed index 31e1cb6c3d7f7..4cb7f6b687f11 100644 --- a/tests/ui/needless_borrow.fixed +++ b/tests/ui/needless_borrow.fixed @@ -1,5 +1,5 @@ // run-rustfix -#![feature(custom_inner_attributes, lint_reasons, rustc_private)] +#![feature(lint_reasons)] #![allow( unused, clippy::uninlined_format_args, @@ -491,14 +491,3 @@ mod issue_9782_method_variant { S.foo::<&[u8; 100]>(&a); } } - -extern crate rustc_lint; -extern crate rustc_span; - -#[allow(dead_code)] -mod span_lint { - use rustc_lint::{LateContext, Lint, LintContext}; - fn foo(cx: &LateContext<'_>, lint: &'static Lint) { - cx.struct_span_lint(lint, rustc_span::Span::default(), "", |diag| diag.note(String::new())); - } -} diff --git a/tests/ui/needless_borrow.rs b/tests/ui/needless_borrow.rs index 55c2738fcf273..9a01190ed8dbd 100644 --- a/tests/ui/needless_borrow.rs +++ b/tests/ui/needless_borrow.rs @@ -1,5 +1,5 @@ // run-rustfix -#![feature(custom_inner_attributes, lint_reasons, rustc_private)] +#![feature(lint_reasons)] #![allow( unused, clippy::uninlined_format_args, @@ -491,14 +491,3 @@ mod issue_9782_method_variant { S.foo::<&[u8; 100]>(&a); } } - -extern crate rustc_lint; -extern crate rustc_span; - -#[allow(dead_code)] -mod span_lint { - use rustc_lint::{LateContext, Lint, LintContext}; - fn foo(cx: &LateContext<'_>, lint: &'static Lint) { - cx.struct_span_lint(lint, rustc_span::Span::default(), "", |diag| diag.note(&String::new())); - } -} diff --git a/tests/ui/needless_borrow.stderr b/tests/ui/needless_borrow.stderr index 98a48d68317b4..d26c317124b8d 100644 --- a/tests/ui/needless_borrow.stderr +++ b/tests/ui/needless_borrow.stderr @@ -216,11 +216,5 @@ error: the borrowed expression implements the required traits LL | foo(&a); | ^^ help: change this to: `a` -error: the borrowed expression implements the required traits - --> $DIR/needless_borrow.rs:502:85 - | -LL | cx.struct_span_lint(lint, rustc_span::Span::default(), "", |diag| diag.note(&String::new())); - | ^^^^^^^^^^^^^^ help: change this to: `String::new()` - -error: aborting due to 37 previous errors +error: aborting due to 36 previous errors diff --git a/tests/ui/redundant_clone.fixed b/tests/ui/redundant_clone.fixed index a157b6a6f9adb..00b427450935d 100644 --- a/tests/ui/redundant_clone.fixed +++ b/tests/ui/redundant_clone.fixed @@ -239,9 +239,3 @@ fn false_negative_5707() { let _z = x.clone(); // pr 7346 can't lint on `x` drop(y); } - -#[allow(unused, clippy::manual_retain)] -fn possible_borrower_improvements() { - let mut s = String::from("foobar"); - s = s.chars().filter(|&c| c != 'o').collect(); -} diff --git a/tests/ui/redundant_clone.rs b/tests/ui/redundant_clone.rs index 430672e8b8df2..f899127db8d04 100644 --- a/tests/ui/redundant_clone.rs +++ b/tests/ui/redundant_clone.rs @@ -239,9 +239,3 @@ fn false_negative_5707() { let _z = x.clone(); // pr 7346 can't lint on `x` drop(y); } - -#[allow(unused, clippy::manual_retain)] -fn possible_borrower_improvements() { - let mut s = String::from("foobar"); - s = s.chars().filter(|&c| c != 'o').to_owned().collect(); -} diff --git a/tests/ui/redundant_clone.stderr b/tests/ui/redundant_clone.stderr index 1bacc2c76af15..782590034d051 100644 --- a/tests/ui/redundant_clone.stderr +++ b/tests/ui/redundant_clone.stderr @@ -179,17 +179,5 @@ note: this value is dropped without further use LL | foo(&x.clone(), move || { | ^ -error: redundant clone - --> $DIR/redundant_clone.rs:246:40 - | -LL | s = s.chars().filter(|&c| c != 'o').to_owned().collect(); - | ^^^^^^^^^^^ help: remove this - | -note: this value is dropped without further use - --> $DIR/redundant_clone.rs:246:9 - | -LL | s = s.chars().filter(|&c| c != 'o').to_owned().collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 16 previous errors +error: aborting due to 15 previous errors From 757e944ba6ace471727cb320c75a52b321c05322 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Thu, 12 Jan 2023 13:29:23 -0500 Subject: [PATCH 51/51] Adjust old code for newer rustc version. --- clippy_utils/src/mir/possible_borrower.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/clippy_utils/src/mir/possible_borrower.rs b/clippy_utils/src/mir/possible_borrower.rs index 8c695801c73fc..9adae77338945 100644 --- a/clippy_utils/src/mir/possible_borrower.rs +++ b/clippy_utils/src/mir/possible_borrower.rs @@ -6,6 +6,7 @@ use rustc_lint::LateContext; use rustc_middle::mir::{self, visit::Visitor as _, Mutability}; use rustc_middle::ty::{self, visit::TypeVisitor}; use rustc_mir_dataflow::{impls::MaybeStorageLive, Analysis, ResultsCursor}; +use std::borrow::Cow; use std::ops::ControlFlow; /// Collects the possible borrowers of each local. @@ -36,7 +37,7 @@ impl<'a, 'b, 'tcx> PossibleBorrowerVisitor<'a, 'b, 'tcx> { fn into_map( self, cx: &'a LateContext<'tcx>, - maybe_live: ResultsCursor<'b, 'tcx, MaybeStorageLive>, + maybe_live: ResultsCursor<'b, 'tcx, MaybeStorageLive<'tcx>>, ) -> PossibleBorrowerMap<'b, 'tcx> { let mut map = FxHashMap::default(); for row in (1..self.body.local_decls.len()).map(mir::Local::from_usize) { @@ -167,7 +168,7 @@ fn rvalue_locals(rvalue: &mir::Rvalue<'_>, mut visit: impl FnMut(mir::Local)) { pub struct PossibleBorrowerMap<'b, 'tcx> { /// Mapping `Local -> its possible borrowers` pub map: FxHashMap>, - maybe_live: ResultsCursor<'b, 'tcx, MaybeStorageLive>, + maybe_live: ResultsCursor<'b, 'tcx, MaybeStorageLive<'tcx>>, // Caches to avoid allocation of `BitSet` on every query pub bitset: (BitSet, BitSet), } @@ -179,7 +180,7 @@ impl<'a, 'b, 'tcx> PossibleBorrowerMap<'b, 'tcx> { vis.visit_body(mir); vis.into_map(cx) }; - let maybe_storage_live_result = MaybeStorageLive::new(BitSet::new_empty(mir.local_decls.len())) + let maybe_storage_live_result = MaybeStorageLive::new(Cow::Owned(BitSet::new_empty(mir.local_decls.len()))) .into_engine(cx.tcx, mir) .pass_name("redundant_clone") .iterate_to_fixpoint()