From c36d5e3280fbb8001a4c506f2c21227156cb3771 Mon Sep 17 00:00:00 2001 From: Ross Smyth Date: Sat, 17 Feb 2024 12:43:54 -0500 Subject: [PATCH 01/24] Add MatchKind member to the Match expr for pretty printing & fmt --- clippy_lints/src/redundant_else.rs | 2 +- clippy_lints/src/suspicious_operation_groupings.rs | 2 +- clippy_utils/src/ast_utils.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/redundant_else.rs b/clippy_lints/src/redundant_else.rs index fb434fb7450a7..3bdf13dbbea65 100644 --- a/clippy_lints/src/redundant_else.rs +++ b/clippy_lints/src/redundant_else.rs @@ -105,7 +105,7 @@ impl<'ast> Visitor<'ast> for BreakVisitor { fn visit_expr(&mut self, expr: &'ast Expr) { self.is_break = match expr.kind { ExprKind::Break(..) | ExprKind::Continue(..) | ExprKind::Ret(..) => true, - ExprKind::Match(_, ref arms) => arms.iter().all(|arm| + ExprKind::Match(_, ref arms, _) => arms.iter().all(|arm| arm.body.is_none() || arm.body.as_deref().is_some_and(|body| self.check_expr(body)) ), ExprKind::If(_, ref then, Some(ref els)) => self.check_block(then) && self.check_expr(els), diff --git a/clippy_lints/src/suspicious_operation_groupings.rs b/clippy_lints/src/suspicious_operation_groupings.rs index 60e9d262e7e09..ab1b3043f0c38 100644 --- a/clippy_lints/src/suspicious_operation_groupings.rs +++ b/clippy_lints/src/suspicious_operation_groupings.rs @@ -552,7 +552,7 @@ fn ident_difference_expr_with_base_location( | (Gen(_, _, _), Gen(_, _, _)) | (Block(_, _), Block(_, _)) | (Closure(_), Closure(_)) - | (Match(_, _), Match(_, _)) + | (Match(_, _, _), Match(_, _, _)) | (Loop(_, _, _), Loop(_, _, _)) | (ForLoop { .. }, ForLoop { .. }) | (While(_, _, _), While(_, _, _)) diff --git a/clippy_utils/src/ast_utils.rs b/clippy_utils/src/ast_utils.rs index 3b3939da7b6bc..eb916a37f6ea5 100644 --- a/clippy_utils/src/ast_utils.rs +++ b/clippy_utils/src/ast_utils.rs @@ -198,7 +198,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool { }, (AssignOp(lo, lp, lv), AssignOp(ro, rp, rv)) => lo.node == ro.node && eq_expr(lp, rp) && eq_expr(lv, rv), (Field(lp, lf), Field(rp, rf)) => eq_id(*lf, *rf) && eq_expr(lp, rp), - (Match(ls, la), Match(rs, ra)) => eq_expr(ls, rs) && over(la, ra, eq_arm), + (Match(ls, la, lkind), Match(rs, ra, rkind)) => (lkind == rkind) && eq_expr(ls, rs) && over(la, ra, eq_arm), ( Closure(box ast::Closure { binder: lb, From cbbb0ae7d2c430327e77aec5ac1235014a09b793 Mon Sep 17 00:00:00 2001 From: Arthur Carcano Date: Fri, 5 Jan 2024 16:13:24 +0100 Subject: [PATCH 02/24] fix: allow-one-hash-in-raw-strings option of needless_raw_string_hashes was ignored Fixes: https://github.com/rust-lang/rust-clippy/issues/11481 changelog: Fix `allow-one-hash-in-raw-strings` option of [`needless_raw_string_hashes`] was ignored --- clippy_lints/src/raw_strings.rs | 6 ++- .../clippy.toml | 1 + .../needless_raw_string_hashes.fixed | 9 +++++ .../needless_raw_string_hashes.rs | 9 +++++ .../needless_raw_string_hashes.stderr | 40 +++++++++++++++++++ 5 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 tests/ui-toml/needless_raw_string_hashes_one_allowed/clippy.toml create mode 100644 tests/ui-toml/needless_raw_string_hashes_one_allowed/needless_raw_string_hashes.fixed create mode 100644 tests/ui-toml/needless_raw_string_hashes_one_allowed/needless_raw_string_hashes.rs create mode 100644 tests/ui-toml/needless_raw_string_hashes_one_allowed/needless_raw_string_hashes.stderr diff --git a/clippy_lints/src/raw_strings.rs b/clippy_lints/src/raw_strings.rs index ac29d27303c8b..7e71f48c6d9a6 100644 --- a/clippy_lints/src/raw_strings.rs +++ b/clippy_lints/src/raw_strings.rs @@ -108,7 +108,7 @@ impl EarlyLintPass for RawStrings { } } - let req = { + let mut req = { let mut following_quote = false; let mut req = 0; // `once` so a raw string ending in hashes is still checked @@ -136,7 +136,9 @@ impl EarlyLintPass for RawStrings { ControlFlow::Continue(num) | ControlFlow::Break(num) => num, } }; - + if self.allow_one_hash_in_raw_strings { + req = req.max(1); + } if req < max { span_lint_and_then( cx, diff --git a/tests/ui-toml/needless_raw_string_hashes_one_allowed/clippy.toml b/tests/ui-toml/needless_raw_string_hashes_one_allowed/clippy.toml new file mode 100644 index 0000000000000..2f3d60be3a73a --- /dev/null +++ b/tests/ui-toml/needless_raw_string_hashes_one_allowed/clippy.toml @@ -0,0 +1 @@ +allow-one-hash-in-raw-strings = true diff --git a/tests/ui-toml/needless_raw_string_hashes_one_allowed/needless_raw_string_hashes.fixed b/tests/ui-toml/needless_raw_string_hashes_one_allowed/needless_raw_string_hashes.fixed new file mode 100644 index 0000000000000..fd20bdff6e258 --- /dev/null +++ b/tests/ui-toml/needless_raw_string_hashes_one_allowed/needless_raw_string_hashes.fixed @@ -0,0 +1,9 @@ +#![allow(clippy::no_effect, unused)] +#![warn(clippy::needless_raw_string_hashes)] + +fn main() { + r#"\aaa"#; + r#"\aaa"#; + r#"Hello "world"!"#; + r####" "### "## "# "####; +} diff --git a/tests/ui-toml/needless_raw_string_hashes_one_allowed/needless_raw_string_hashes.rs b/tests/ui-toml/needless_raw_string_hashes_one_allowed/needless_raw_string_hashes.rs new file mode 100644 index 0000000000000..3c6c246370068 --- /dev/null +++ b/tests/ui-toml/needless_raw_string_hashes_one_allowed/needless_raw_string_hashes.rs @@ -0,0 +1,9 @@ +#![allow(clippy::no_effect, unused)] +#![warn(clippy::needless_raw_string_hashes)] + +fn main() { + r#"\aaa"#; + r##"\aaa"##; + r##"Hello "world"!"##; + r######" "### "## "# "######; +} diff --git a/tests/ui-toml/needless_raw_string_hashes_one_allowed/needless_raw_string_hashes.stderr b/tests/ui-toml/needless_raw_string_hashes_one_allowed/needless_raw_string_hashes.stderr new file mode 100644 index 0000000000000..421ad66e4c968 --- /dev/null +++ b/tests/ui-toml/needless_raw_string_hashes_one_allowed/needless_raw_string_hashes.stderr @@ -0,0 +1,40 @@ +error: unnecessary hashes around raw string literal + --> tests/ui-toml/needless_raw_string_hashes_one_allowed/needless_raw_string_hashes.rs:6:5 + | +LL | r##"\aaa"##; + | ^^^^^^^^^^^ + | + = note: `-D clippy::needless-raw-string-hashes` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_raw_string_hashes)]` +help: remove one hash from both sides of the string literal + | +LL - r##"\aaa"##; +LL + r#"\aaa"#; + | + +error: unnecessary hashes around raw string literal + --> tests/ui-toml/needless_raw_string_hashes_one_allowed/needless_raw_string_hashes.rs:7:5 + | +LL | r##"Hello "world"!"##; + | ^^^^^^^^^^^^^^^^^^^^^ + | +help: remove one hash from both sides of the string literal + | +LL - r##"Hello "world"!"##; +LL + r#"Hello "world"!"#; + | + +error: unnecessary hashes around raw string literal + --> tests/ui-toml/needless_raw_string_hashes_one_allowed/needless_raw_string_hashes.rs:8:5 + | +LL | r######" "### "## "# "######; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove 2 hashes from both sides of the string literal + | +LL - r######" "### "## "# "######; +LL + r####" "### "## "# "####; + | + +error: aborting due to 3 previous errors + From f9a9c4bf3bc8c8675ef12c6f3580aea6a9df667c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Sat, 9 Mar 2024 20:32:36 +0000 Subject: [PATCH 03/24] Note that type param is chosen by caller when suggesting return impl Trait --- tests/ui/builtin_type_shadow.stderr | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/ui/builtin_type_shadow.stderr b/tests/ui/builtin_type_shadow.stderr index 1e15cdee772a2..033204af9255f 100644 --- a/tests/ui/builtin_type_shadow.stderr +++ b/tests/ui/builtin_type_shadow.stderr @@ -19,6 +19,7 @@ LL | 42 | = note: expected type parameter `u32` found type `{integer}` + = note: the caller chooses a type for `u32` which can be different from `i32` error: aborting due to 2 previous errors From 54d1260174c4c587fe56323459332f667978e8b4 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 20 Mar 2024 16:47:11 +0100 Subject: [PATCH 04/24] Rename `hir::Let` into `hir::LetExpr` --- clippy_lints/src/pattern_type_mismatch.rs | 4 ++-- clippy_lints/src/shadow.rs | 4 ++-- clippy_lints/src/unused_io_amount.rs | 2 +- clippy_utils/src/higher.rs | 4 ++-- clippy_utils/src/hir_utils.rs | 4 ++-- clippy_utils/src/visitors.rs | 4 ++-- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/clippy_lints/src/pattern_type_mismatch.rs b/clippy_lints/src/pattern_type_mismatch.rs index fbca4329342a9..127801de7defa 100644 --- a/clippy_lints/src/pattern_type_mismatch.rs +++ b/clippy_lints/src/pattern_type_mismatch.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_help; -use rustc_hir::{intravisit, Body, Expr, ExprKind, FnDecl, Let, LocalSource, Mutability, Pat, PatKind, Stmt, StmtKind}; +use rustc_hir::{intravisit, Body, Expr, ExprKind, FnDecl, LetExpr, LocalSource, Mutability, Pat, PatKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; @@ -103,7 +103,7 @@ impl<'tcx> LateLintPass<'tcx> for PatternTypeMismatch { } } } - if let ExprKind::Let(Let { pat, .. }) = expr.kind { + if let ExprKind::Let(LetExpr { pat, .. }) = expr.kind { apply_lint(cx, pat, DerefPossible::Possible); } } diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index c74364d89d61b..df7bd4c8d1d39 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -5,7 +5,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::Res; use rustc_hir::def_id::LocalDefId; use rustc_hir::hir_id::ItemLocalId; -use rustc_hir::{Block, Body, BodyOwnerKind, Expr, ExprKind, HirId, Let, Node, Pat, PatKind, QPath, UnOp}; +use rustc_hir::{Block, Body, BodyOwnerKind, Expr, ExprKind, HirId, LetExpr, Node, Pat, PatKind, QPath, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; use rustc_span::{Span, Symbol}; @@ -238,7 +238,7 @@ fn find_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Expr<' let init = match node { Node::Arm(_) | Node::Pat(_) => continue, Node::Expr(expr) => match expr.kind { - ExprKind::Match(e, _, _) | ExprKind::Let(&Let { init: e, .. }) => Some(e), + ExprKind::Match(e, _, _) | ExprKind::Let(&LetExpr { init: e, .. }) => Some(e), _ => None, }, Node::Local(local) => local.init, diff --git a/clippy_lints/src/unused_io_amount.rs b/clippy_lints/src/unused_io_amount.rs index eb64dd633f606..1497d883dfc48 100644 --- a/clippy_lints/src/unused_io_amount.rs +++ b/clippy_lints/src/unused_io_amount.rs @@ -131,7 +131,7 @@ fn non_consuming_ok_arm<'a>(cx: &LateContext<'a>, arm: &hir::Arm<'a>) -> bool { fn check_expr<'a>(cx: &LateContext<'a>, expr: &'a hir::Expr<'a>) { match expr.kind { hir::ExprKind::If(cond, _, _) - if let ExprKind::Let(hir::Let { pat, init, .. }) = cond.kind + if let ExprKind::Let(hir::LetExpr { pat, init, .. }) = cond.kind && is_ok_wild_or_dotdot_pattern(cx, pat) && let Some(op) = should_lint(cx, init) => { diff --git a/clippy_utils/src/higher.rs b/clippy_utils/src/higher.rs index ba682813dadf8..8ce19998a0828 100644 --- a/clippy_utils/src/higher.rs +++ b/clippy_utils/src/higher.rs @@ -102,7 +102,7 @@ impl<'hir> IfLet<'hir> { if let ExprKind::If( Expr { kind: - ExprKind::Let(&hir::Let { + ExprKind::Let(&hir::LetExpr { pat: let_pat, init: let_expr, span: let_span, @@ -379,7 +379,7 @@ impl<'hir> WhileLet<'hir> { ExprKind::If( Expr { kind: - ExprKind::Let(&hir::Let { + ExprKind::Let(&hir::LetExpr { pat: let_pat, init: let_expr, span: let_span, diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index 106d1d0d77f01..162bf24d85d29 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -8,7 +8,7 @@ use rustc_hir::def::Res; use rustc_hir::MatchSource::TryDesugar; use rustc_hir::{ ArrayLen, BinOpKind, BindingAnnotation, Block, BodyId, Closure, Expr, ExprField, ExprKind, FnRetTy, GenericArg, - GenericArgs, HirId, HirIdMap, InlineAsmOperand, Let, Lifetime, LifetimeName, Pat, PatField, PatKind, Path, + GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime, LifetimeName, Pat, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, Ty, TyKind, TypeBinding, }; use rustc_lexer::{tokenize, TokenKind}; @@ -837,7 +837,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { } } }, - ExprKind::Let(Let { pat, init, ty, .. }) => { + ExprKind::Let(LetExpr { pat, init, ty, .. }) => { self.hash_expr(init); if let Some(ty) = ty { self.hash_ty(ty); diff --git a/clippy_utils/src/visitors.rs b/clippy_utils/src/visitors.rs index ebc38e531fe6e..0a05ac029eae5 100644 --- a/clippy_utils/src/visitors.rs +++ b/clippy_utils/src/visitors.rs @@ -5,7 +5,7 @@ use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::intravisit::{self, walk_block, walk_expr, Visitor}; use rustc_hir::{ - AnonConst, Arm, Block, BlockCheckMode, Body, BodyId, Expr, ExprKind, HirId, ItemId, ItemKind, Let, Pat, QPath, + AnonConst, Arm, Block, BlockCheckMode, Body, BodyId, Expr, ExprKind, HirId, ItemId, ItemKind, LetExpr, Pat, QPath, Stmt, UnOp, UnsafeSource, Unsafety, }; use rustc_lint::LateContext; @@ -624,7 +624,7 @@ pub fn for_each_unconsumed_temporary<'tcx, B>( | ExprKind::Field(e, _) | ExprKind::Unary(UnOp::Deref, e) | ExprKind::Match(e, ..) - | ExprKind::Let(&Let { init: e, .. }) => { + | ExprKind::Let(&LetExpr { init: e, .. }) => { helper(typeck, false, e, f)?; }, ExprKind::Block(&Block { expr: Some(e), .. }, _) | ExprKind::Cast(e, _) | ExprKind::Unary(_, e) => { From 1dbabc1767d080066ddf6f16f3aad01e46257d9c Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 20 Mar 2024 12:52:54 -0400 Subject: [PATCH 05/24] Bless test fallout (duplicate diagnostics) --- clippy_lints/src/future_not_send.rs | 2 +- clippy_utils/src/ty.rs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/future_not_send.rs b/clippy_lints/src/future_not_send.rs index 9fb59a320d488..18f4e51ebd663 100644 --- a/clippy_lints/src/future_not_send.rs +++ b/clippy_lints/src/future_not_send.rs @@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { } let ret_ty = return_ty(cx, cx.tcx.local_def_id_to_hir_id(fn_def_id).expect_owner()); if let ty::Alias(ty::Opaque, AliasTy { def_id, args, .. }) = *ret_ty.kind() { - let preds = cx.tcx.explicit_item_bounds(def_id); + let preds = cx.tcx.explicit_item_super_predicates(def_id); let mut is_future = false; for (p, _span) in preds.iter_instantiated_copied(cx.tcx, args) { if let Some(trait_pred) = p.as_trait_clause() { diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 6e011a28bb7bc..801452e444c6a 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -96,7 +96,7 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<' return false; } - for (predicate, _span) in cx.tcx.explicit_item_bounds(def_id).instantiate_identity_iter_copied() { + for (predicate, _span) in cx.tcx.explicit_item_super_predicates(def_id).instantiate_identity_iter_copied() { match predicate.kind().skip_binder() { // For `impl Trait`, it will register a predicate of `T: Trait`, so we go through // and check substitutions to find `U`. @@ -328,7 +328,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { }, ty::Tuple(args) => args.iter().any(|ty| is_must_use_ty(cx, ty)), ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => { - for (predicate, _) in cx.tcx.explicit_item_bounds(def_id).skip_binder() { + for (predicate, _) in cx.tcx.explicit_item_super_predicates(def_id).skip_binder() { if let ty::ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() { if cx.tcx.has_attr(trait_predicate.trait_ref.def_id, sym::must_use) { return true; @@ -729,7 +729,7 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option sig_from_bounds( cx, ty, - cx.tcx.item_bounds(def_id).iter_instantiated(cx.tcx, args), + cx.tcx.item_super_predicates(def_id).iter_instantiated(cx.tcx, args), cx.tcx.opt_parent(def_id), ), ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig, None)), @@ -807,7 +807,7 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: AliasTy<'tcx>) -> Option for (pred, _) in cx .tcx - .explicit_item_bounds(ty.def_id) + .explicit_item_super_predicates(ty.def_id) .iter_instantiated_copied(cx.tcx, ty.args) { match pred.kind().skip_binder() { From 9022122b8b33e5a1fb9c07fcb3984005ef1a63e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 20 Mar 2024 22:50:32 +0000 Subject: [PATCH 06/24] Replace closures with `_` when suggesting fully qualified path for method call ``` error[E0283]: type annotations needed --> $DIR/into-inference-needs-type.rs:12:10 | LL | .into()?; | ^^^^ | = note: cannot satisfy `_: From<...>` = note: required for `FilterMap<...>` to implement `Into<_>` help: try using a fully qualified path to specify the expected types | LL ~ let list = , _>, _> as Into>::into(vec LL | .iter() LL | .map(|s| s.strip_prefix("t")) LL ~ .filter_map(Option::Some))?; | ``` Fix #122569. --- clippy_lints/src/box_default.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/box_default.rs b/clippy_lints/src/box_default.rs index 779ae03c4640b..66206d1a059b9 100644 --- a/clippy_lints/src/box_default.rs +++ b/clippy_lints/src/box_default.rs @@ -70,7 +70,9 @@ impl LateLintPass<'_> for BoxDefault { "try", if is_plain_default(cx, arg_path) || given_type(cx, expr) { "Box::default()".into() - } else if let Some(arg_ty) = cx.typeck_results().expr_ty(arg).make_suggestable(cx.tcx, true) { + } else if let Some(arg_ty) = + cx.typeck_results().expr_ty(arg).make_suggestable(cx.tcx, true, None) + { // Check if we can copy from the source expression in the replacement. // We need the call to have no argument (see `explicit_default_type`). if inner_call_args.is_empty() From bc0965e2ff3a44850983fddd5ade495711adbd8d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 20 Mar 2024 16:53:50 -0400 Subject: [PATCH 07/24] Implement macro-based deref!() syntax for deref patterns Stop using `box PAT` syntax for deref patterns, as it's misleading and also causes their semantics being tangled up. --- clippy_lints/src/equatable_if_let.rs | 2 +- clippy_lints/src/matches/match_same_arms.rs | 2 +- clippy_lints/src/unnested_or_patterns.rs | 2 ++ clippy_lints/src/utils/author.rs | 5 +++++ clippy_utils/src/hir_utils.rs | 1 + clippy_utils/src/lib.rs | 2 +- 6 files changed, 11 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/equatable_if_let.rs b/clippy_lints/src/equatable_if_let.rs index 4e728d61b853a..37442bf3e2867 100644 --- a/clippy_lints/src/equatable_if_let.rs +++ b/clippy_lints/src/equatable_if_let.rs @@ -55,7 +55,7 @@ fn unary_pattern(pat: &Pat<'_>) -> bool { | PatKind::Err(_) => false, PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)), PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => etc.as_opt_usize().is_none() && array_rec(a), - PatKind::Ref(x, _) | PatKind::Box(x) => unary_pattern(x), + PatKind::Ref(x, _) | PatKind::Box(x) | PatKind::Deref(x) => unary_pattern(x), PatKind::Path(_) | PatKind::Lit(_) => true, } } diff --git a/clippy_lints/src/matches/match_same_arms.rs b/clippy_lints/src/matches/match_same_arms.rs index c7c453b7f6ec8..cd61e733694bb 100644 --- a/clippy_lints/src/matches/match_same_arms.rs +++ b/clippy_lints/src/matches/match_same_arms.rs @@ -243,7 +243,7 @@ impl<'a> NormalizedPat<'a> { fn from_pat(cx: &LateContext<'_>, arena: &'a DroplessArena, pat: &'a Pat<'_>) -> Self { match pat.kind { PatKind::Wild | PatKind::Binding(.., None) => Self::Wild, - PatKind::Binding(.., Some(pat)) | PatKind::Box(pat) | PatKind::Ref(pat, _) => { + PatKind::Binding(.., Some(pat)) | PatKind::Box(pat) | PatKind::Deref(pat) | PatKind::Ref(pat, _) => { Self::from_pat(cx, arena, pat) }, PatKind::Never => Self::Never, diff --git a/clippy_lints/src/unnested_or_patterns.rs b/clippy_lints/src/unnested_or_patterns.rs index 7246214f9bf87..d4dd31e11781a 100644 --- a/clippy_lints/src/unnested_or_patterns.rs +++ b/clippy_lints/src/unnested_or_patterns.rs @@ -242,6 +242,8 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec>, focus_idx: us |k| matches!(k, Box(_)), |k| always_pat!(k, Box(p) => p), ), + // FIXME(deref_patterns): Should we merge patterns here? + Deref(_) => false, // Transform `&mut x | ... | &mut y` into `&mut (x | y)`. Ref(target, Mutability::Mut) => extend_with_matching( target, start, alternatives, diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index 187bfda129cd7..5319915b2eac1 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -689,6 +689,11 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { kind!("Box({pat})"); self.pat(pat); }, + PatKind::Deref(pat) => { + bind!(self, pat); + kind!("Deref({pat})"); + self.pat(pat); + }, PatKind::Ref(pat, muta) => { bind!(self, pat); kind!("Ref({pat}, Mutability::{muta:?})"); diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index 162bf24d85d29..7a4eba9790ed4 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -955,6 +955,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { } }, PatKind::Box(pat) => self.hash_pat(pat), + PatKind::Deref(pat) => self.hash_pat(pat), PatKind::Lit(expr) => self.hash_expr(expr), PatKind::Or(pats) => { for pat in pats { diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index a38db0ebec0f5..b4cc747e0e62b 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1678,7 +1678,7 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool { match pat.kind { PatKind::Wild | PatKind::Never => false, // If `!` typechecked then the type is empty, so not refutable. PatKind::Binding(_, _, _, pat) => pat.map_or(false, |pat| is_refutable(cx, pat)), - PatKind::Box(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat), + PatKind::Box(pat) | PatKind::Deref(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat), PatKind::Path(ref qpath) => is_enum_variant(cx, qpath, pat.hir_id), PatKind::Or(pats) => { // TODO: should be the honest check, that pats is exhaustive set From 0e62b184353c0c76b5e908746c0dc99dea05f7a5 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 21 Mar 2024 22:20:40 +0100 Subject: [PATCH 08/24] Merge commit '9d6f41691ed9dbfaec2a2df2661c42451f2fe0d3' into clippy-subtree-update --- .github/workflows/clippy.yml | 10 +- .github/workflows/clippy_bors.yml | 25 +-- CHANGELOG.md | 63 +++++- Cargo.toml | 12 +- book/src/development/macro_expansions.md | 4 +- book/src/lint_configuration.md | 1 + clippy.toml | 13 +- clippy_config/Cargo.toml | 2 +- clippy_config/src/conf.rs | 2 +- clippy_config/src/msrvs.rs | 1 + clippy_dev/src/update_lints.rs | 2 + clippy_lints/Cargo.toml | 2 +- clippy_lints/src/assigning_clones.rs | 29 ++- .../src/attrs/duplicated_attributes.rs | 64 +++++++ clippy_lints/src/attrs/mod.rs | 35 +++- clippy_lints/src/casts/cast_lossless.rs | 41 +++- clippy_lints/src/casts/mod.rs | 2 +- clippy_lints/src/dbg_macro.rs | 51 +++-- clippy_lints/src/declared_lints.rs | 5 + clippy_lints/src/doc/markdown.rs | 17 +- clippy_lints/src/doc/mod.rs | 24 ++- clippy_lints/src/else_if_without_else.rs | 26 ++- clippy_lints/src/entry.rs | 5 +- clippy_lints/src/functions/mod.rs | 2 +- .../src/integer_division_remainder_used.rs | 50 +++++ clippy_lints/src/let_if_seq.rs | 5 +- clippy_lints/src/lib.rs | 8 +- clippy_lints/src/loops/needless_range_loop.rs | 2 +- clippy_lints/src/loops/never_loop.rs | 4 +- .../src/loops/unused_enumerate_index.rs | 81 +++----- .../src/loops/while_immutable_condition.rs | 2 +- clippy_lints/src/manual_retain.rs | 11 +- clippy_lints/src/manual_unwrap_or_default.rs | 181 ++++++++++++++++++ clippy_lints/src/matches/single_match.rs | 31 +-- clippy_lints/src/methods/expect_fun_call.rs | 2 +- clippy_lints/src/methods/is_empty.rs | 49 +++++ clippy_lints/src/methods/iter_nth.rs | 49 ++--- clippy_lints/src/methods/map_clone.rs | 11 +- clippy_lints/src/methods/mod.rs | 143 +++++++++----- clippy_lints/src/methods/no_effect_replace.rs | 1 + .../src/methods/unused_enumerate_index.rs | 135 +++++++++++++ clippy_lints/src/missing_doc.rs | 64 ++++++- .../src/multiple_unsafe_ops_per_block.rs | 17 +- clippy_lints/src/mut_mut.rs | 70 ++++--- clippy_lints/src/non_copy_const.rs | 11 +- clippy_lints/src/read_zero_byte_vec.rs | 56 ++++-- clippy_lints/src/redundant_closure_call.rs | 5 +- clippy_lints/src/returns.rs | 35 ++-- clippy_lints/src/std_instead_of_core.rs | 2 + ...ead_local_initializer_can_be_made_const.rs | 2 +- clippy_lints/src/transmute/mod.rs | 2 +- clippy_lints/src/types/mod.rs | 4 + clippy_lints/src/unconditional_recursion.rs | 56 ++++-- clippy_lints/src/unused_io_amount.rs | 16 +- clippy_lints/src/unused_peekable.rs | 10 +- clippy_lints/src/use_self.rs | 53 ++++- .../internal_lints/metadata_collector.rs | 2 +- .../internal_lints/unnecessary_def_path.rs | 2 +- clippy_lints/src/wildcard_imports.rs | 2 +- clippy_lints/src/zero_repeat_side_effects.rs | 154 +++++++++++++++ clippy_utils/Cargo.toml | 2 +- clippy_utils/src/consts.rs | 107 ++++++++++- clippy_utils/src/diagnostics.rs | 118 ++++++++++++ clippy_utils/src/lib.rs | 19 +- clippy_utils/src/paths.rs | 2 + declare_clippy_lint/Cargo.toml | 2 +- rust-toolchain | 2 +- tests/ui-internal/disallow_span_lint.stderr | 3 + tests/ui-toml/dbg_macro/dbg_macro.fixed | 38 ++++ tests/ui-toml/dbg_macro/dbg_macro.rs | 5 +- tests/ui-toml/dbg_macro/dbg_macro.stderr | 34 +--- tests/ui/allow_attributes_without_reason.rs | 2 +- .../ui/allow_attributes_without_reason.stderr | 4 +- tests/ui/assigning_clones.fixed | 13 ++ tests/ui/assigning_clones.rs | 13 ++ tests/ui/assigning_clones.stderr | 32 +++- tests/ui/auxiliary/proc_macro_attr.rs | 43 ++++- tests/ui/await_holding_lock.rs | 1 + tests/ui/await_holding_lock.stderr | 52 ++--- tests/ui/bool_assert_comparison.fixed | 2 +- tests/ui/bool_assert_comparison.rs | 2 +- tests/ui/cast_lossless_bool.fixed | 4 + tests/ui/cast_lossless_bool.rs | 4 + tests/ui/cast_lossless_bool.stderr | 36 ++-- tests/ui/cast_lossless_float.fixed | 5 + tests/ui/cast_lossless_float.rs | 5 + tests/ui/cast_lossless_float.stderr | 36 ++-- tests/ui/cast_lossless_integer.fixed | 10 + tests/ui/cast_lossless_integer.rs | 10 + tests/ui/cast_lossless_integer.stderr | 50 ++--- tests/ui/const_is_empty.rs | 174 +++++++++++++++++ tests/ui/const_is_empty.stderr | 161 ++++++++++++++++ tests/ui/crashes/ice-12491.fixed | 7 + tests/ui/crashes/ice-12491.rs | 8 + tests/ui/crashes/ice-12491.stderr | 19 ++ tests/ui/dbg_macro/dbg_macro.fixed | 111 +++++++++++ tests/ui/dbg_macro/dbg_macro.rs | 20 +- tests/ui/dbg_macro/dbg_macro.stderr | 108 ++++++----- tests/ui/dbg_macro/dbg_macro_unfixable.rs | 12 ++ tests/ui/dbg_macro/dbg_macro_unfixable.stderr | 71 +++++++ tests/ui/doc/issue_10262.fixed | 12 ++ tests/ui/doc/issue_10262.rs | 12 ++ tests/ui/doc/issue_10262.stderr | 15 ++ tests/ui/duplicated_attributes.rs | 17 ++ tests/ui/duplicated_attributes.stderr | 123 ++++++++++++ tests/ui/else_if_without_else.rs | 68 ++++++- tests/ui/else_if_without_else.stderr | 30 ++- tests/ui/empty_docs.rs | 17 ++ tests/ui/empty_docs.stderr | 18 +- tests/ui/empty_line_after_doc_comments.rs | 2 +- tests/ui/empty_line_after_outer_attribute.rs | 2 +- tests/ui/entry.fixed | 10 + tests/ui/entry.rs | 10 + tests/ui/entry.stderr | 23 ++- tests/ui/integer_division_remainder_used.rs | 41 ++++ .../ui/integer_division_remainder_used.stderr | 59 ++++++ tests/ui/iter_nth.fixed | 60 ++++++ tests/ui/iter_nth.rs | 3 + tests/ui/iter_nth.stderr | 48 ++++- tests/ui/len_zero.fixed | 8 +- tests/ui/len_zero.rs | 8 +- tests/ui/len_zero.stderr | 46 ++--- tests/ui/let_if_seq.rs | 11 ++ tests/ui/let_if_seq.stderr | 8 +- tests/ui/manual_let_else.rs | 3 +- tests/ui/manual_let_else.stderr | 62 +++--- tests/ui/manual_retain.fixed | 2 - tests/ui/manual_retain.rs | 2 - tests/ui/manual_retain.stderr | 76 ++++---- tests/ui/manual_unwrap_or.fixed | 7 +- tests/ui/manual_unwrap_or.rs | 7 +- tests/ui/manual_unwrap_or.stderr | 28 +-- tests/ui/manual_unwrap_or_default.fixed | 19 ++ tests/ui/manual_unwrap_or_default.rs | 40 ++++ tests/ui/manual_unwrap_or_default.stderr | 56 ++++++ tests/ui/map_clone.fixed | 16 +- tests/ui/map_clone.rs | 16 +- tests/ui/map_clone.stderr | 30 +-- tests/ui/match_result_ok.fixed | 2 +- tests/ui/match_result_ok.rs | 2 +- tests/ui/missing_doc.rs | 12 ++ tests/ui/missing_doc.stderr | 26 +-- tests/ui/mixed_attributes_style.rs | 1 + tests/ui/mixed_attributes_style.stderr | 6 +- tests/ui/mut_mut.rs | 6 +- tests/ui/mut_mut.stderr | 18 +- tests/ui/needless_bitwise_bool.fixed | 1 + tests/ui/needless_bitwise_bool.rs | 1 + tests/ui/needless_bitwise_bool.stderr | 2 +- tests/ui/needless_return.fixed | 7 + tests/ui/needless_return.rs | 7 + tests/ui/no_effect_replace.rs | 2 - tests/ui/no_effect_replace.stderr | 16 +- tests/ui/option_if_let_else.fixed | 3 +- tests/ui/option_if_let_else.rs | 3 +- tests/ui/option_if_let_else.stderr | 50 ++--- tests/ui/option_option.rs | 4 +- tests/ui/option_option.stderr | 26 +-- tests/ui/read_zero_byte_vec.rs | 6 + tests/ui/redundant_as_str.fixed | 1 + tests/ui/redundant_as_str.rs | 1 + tests/ui/redundant_as_str.stderr | 4 +- tests/ui/rename.fixed | 1 + tests/ui/rename.rs | 1 + tests/ui/rename.stderr | 116 +++++------ tests/ui/single_match.fixed | 5 +- tests/ui/single_match.rs | 5 +- tests/ui/single_match.stderr | 36 ++-- tests/ui/single_match_else.fixed | 1 - tests/ui/single_match_else.rs | 1 - tests/ui/single_match_else.stderr | 18 +- tests/ui/std_instead_of_core.fixed | 2 +- tests/ui/std_instead_of_core.stderr | 8 +- tests/ui/unconditional_recursion.rs | 50 ++++- tests/ui/unconditional_recursion.stderr | 136 ++++++------- tests/ui/unused_enumerate_index.fixed | 50 ++++- tests/ui/unused_enumerate_index.rs | 50 ++++- tests/ui/unused_enumerate_index.stderr | 78 +++++++- tests/ui/unused_io_amount.rs | 5 + tests/ui/unused_peekable.rs | 6 + tests/ui/use_self.fixed | 18 +- tests/ui/use_self.rs | 16 +- tests/ui/use_self.stderr | 92 ++++----- tests/ui/zero_repeat_side_effects.fixed | 60 ++++++ tests/ui/zero_repeat_side_effects.rs | 60 ++++++ tests/ui/zero_repeat_side_effects.stderr | 77 ++++++++ triagebot.toml | 2 +- 187 files changed, 4182 insertions(+), 1047 deletions(-) create mode 100644 clippy_lints/src/attrs/duplicated_attributes.rs create mode 100644 clippy_lints/src/integer_division_remainder_used.rs create mode 100644 clippy_lints/src/manual_unwrap_or_default.rs create mode 100644 clippy_lints/src/methods/is_empty.rs create mode 100644 clippy_lints/src/methods/unused_enumerate_index.rs create mode 100644 clippy_lints/src/zero_repeat_side_effects.rs create mode 100644 tests/ui-toml/dbg_macro/dbg_macro.fixed create mode 100644 tests/ui/const_is_empty.rs create mode 100644 tests/ui/const_is_empty.stderr create mode 100644 tests/ui/crashes/ice-12491.fixed create mode 100644 tests/ui/crashes/ice-12491.rs create mode 100644 tests/ui/crashes/ice-12491.stderr create mode 100644 tests/ui/dbg_macro/dbg_macro.fixed create mode 100644 tests/ui/dbg_macro/dbg_macro_unfixable.rs create mode 100644 tests/ui/dbg_macro/dbg_macro_unfixable.stderr create mode 100644 tests/ui/doc/issue_10262.fixed create mode 100644 tests/ui/doc/issue_10262.rs create mode 100644 tests/ui/doc/issue_10262.stderr create mode 100644 tests/ui/duplicated_attributes.rs create mode 100644 tests/ui/duplicated_attributes.stderr create mode 100644 tests/ui/integer_division_remainder_used.rs create mode 100644 tests/ui/integer_division_remainder_used.stderr create mode 100644 tests/ui/iter_nth.fixed create mode 100644 tests/ui/manual_unwrap_or_default.fixed create mode 100644 tests/ui/manual_unwrap_or_default.rs create mode 100644 tests/ui/manual_unwrap_or_default.stderr create mode 100644 tests/ui/zero_repeat_side_effects.fixed create mode 100644 tests/ui/zero_repeat_side_effects.rs create mode 100644 tests/ui/zero_repeat_side_effects.stderr diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml index 603f91a910b18..8179e3e65b541 100644 --- a/.github/workflows/clippy.yml +++ b/.github/workflows/clippy.yml @@ -26,6 +26,12 @@ env: NO_FMT_TEST: 1 CARGO_INCREMENTAL: 0 +concurrency: + # For a given workflow, if we push to the same PR, cancel all previous builds on that PR. + # If the push is not attached to a PR, we will cancel all builds on the same branch. + group: "${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}" + cancel-in-progress: true + jobs: base: # NOTE: If you modify this job, make sure you copy the changes to clippy_bors.yml @@ -33,10 +39,6 @@ jobs: steps: # Setup - - uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master - with: - github_token: "${{ secrets.github_token }}" - - name: Checkout uses: actions/checkout@v4 diff --git a/.github/workflows/clippy_bors.yml b/.github/workflows/clippy_bors.yml index 0bc28c1f9d996..94515987eba4a 100644 --- a/.github/workflows/clippy_bors.yml +++ b/.github/workflows/clippy_bors.yml @@ -12,6 +12,11 @@ env: NO_FMT_TEST: 1 CARGO_INCREMENTAL: 0 +concurrency: + # For a given workflow, if we push to the same branch, cancel all previous builds on that branch. + group: "${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}" + cancel-in-progress: true + defaults: run: shell: bash @@ -21,10 +26,6 @@ jobs: runs-on: ubuntu-latest steps: - - uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master - with: - github_token: "${{ secrets.github_token }}" - - name: Checkout uses: actions/checkout@v4 with: @@ -67,10 +68,6 @@ jobs: # NOTE: If you modify this job, make sure you copy the changes to clippy.yml steps: # Setup - - uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master - with: - github_token: "${{ secrets.github_token }}" - - name: Checkout uses: actions/checkout@v4 @@ -131,10 +128,6 @@ jobs: steps: # Setup - - uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master - with: - github_token: "${{ secrets.github_token }}" - - name: Checkout uses: actions/checkout@v4 @@ -155,10 +148,6 @@ jobs: steps: # Setup - - uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master - with: - github_token: "${{ secrets.github_token }}" - - name: Checkout uses: actions/checkout@v4 @@ -211,10 +200,6 @@ jobs: steps: # Setup - - uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master - with: - github_token: "${{ secrets.github_token }}" - - name: Checkout uses: actions/checkout@v4 diff --git a/CHANGELOG.md b/CHANGELOG.md index d3b2c0a7bf6ee..76ef84a48b817 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,11 +6,65 @@ document. ## Unreleased / Beta / In Rust Nightly -[a859e5cc...master](https://github.com/rust-lang/rust-clippy/compare/a859e5cc...master) +[66c29b97...master](https://github.com/rust-lang/rust-clippy/compare/66c29b97...master) + +## Rust 1.77 + +Current stable, released 2024-03-18 + +[View all 93 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2023-12-16T18%3A20%3A00Z..2024-01-25T18%3A15%3A56Z+base%3Amaster) + +### New Lints + +* [`suspicious_open_options`] + [#11608](https://github.com/rust-lang/rust-clippy/pull/11608) +* [`option_as_ref_cloned`] + [#12051](https://github.com/rust-lang/rust-clippy/pull/12051) +* [`thread_local_initializer_can_be_made_const`] + [#12026](https://github.com/rust-lang/rust-clippy/pull/12026) +* [`str_split_at_newline`] + [#11987](https://github.com/rust-lang/rust-clippy/pull/11987) +* [`empty_enum_variants_with_brackets`] + [#12047](https://github.com/rust-lang/rust-clippy/pull/12047) +* [`manual_is_variant_and`] + [#11865](https://github.com/rust-lang/rust-clippy/pull/11865) +* [`pub_underscore_fields`] + [#10283](https://github.com/rust-lang/rust-clippy/pull/10283) +* [`eager_transmute`] + [#11981](https://github.com/rust-lang/rust-clippy/pull/11981) +* [`iter_filter_is_some`] + [#12004](https://github.com/rust-lang/rust/pull/12004) +* [`iter_filter_is_ok`] + [#12004](https://github.com/rust-lang/rust/pull/12004) +* [`result_filter_map`] + [#11869](https://github.com/rust-lang/rust-clippy/pull/11869) +* [`unconditional_recursion`] + [#11938](https://github.com/rust-lang/rust-clippy/pull/11938) + +### Enhancements + +* [`multiple_crate_versions`]: Added the [`allowed-duplicate-crates`] configuration to allow specific crates + [#12179](https://github.com/rust-lang/rust-clippy/pull/12179) +* [`single_call_fn`]: No longer ignores `#[allow]` attributes + [#12183](https://github.com/rust-lang/rust-clippy/pull/12183) +* [`read_zero_byte_vec`]: Updated the heuristics used for linting + [#11766](https://github.com/rust-lang/rust-clippy/pull/11766) + +### ICE Fixes + +* [`unit_arg`]: No longer crashes when checking for const in nested bodies + [#11977](https://github.com/rust-lang/rust-clippy/pull/11977) +* [`indexing_slicing`]: No longer crashes when the array index exceeds `usize` + [#12266](https://github.com/rust-lang/rust-clippy/pull/12266) + +### Others + +* Warnings about invalid fields inside `clippy.toml` files now include suggestions for existing fields + [#12180](https://github.com/rust-lang/rust-clippy/pull/12180) ## Rust 1.76 -Current stable, released 2024-02-08 +Released 2024-02-08 [View all 85 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2023-11-02T20%3A23%3A40Z..2023-12-16T13%3A11%3A08Z+base%3Amaster) @@ -5110,6 +5164,7 @@ Released 2018-09-13 [`collection_is_never_read`]: https://rust-lang.github.io/rust-clippy/master/index.html#collection_is_never_read [`comparison_chain`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_chain [`comparison_to_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_to_empty +[`const_is_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#const_is_empty [`const_static_lifetime`]: https://rust-lang.github.io/rust-clippy/master/index.html#const_static_lifetime [`copy_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#copy_iterator [`crate_in_macro_def`]: https://rust-lang.github.io/rust-clippy/master/index.html#crate_in_macro_def @@ -5156,6 +5211,7 @@ Released 2018-09-13 [`drop_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_ref [`duplicate_mod`]: https://rust-lang.github.io/rust-clippy/master/index.html#duplicate_mod [`duplicate_underscore_argument`]: https://rust-lang.github.io/rust-clippy/master/index.html#duplicate_underscore_argument +[`duplicated_attributes`]: https://rust-lang.github.io/rust-clippy/master/index.html#duplicated_attributes [`duration_subsec`]: https://rust-lang.github.io/rust-clippy/master/index.html#duration_subsec [`eager_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#eager_transmute [`else_if_without_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#else_if_without_else @@ -5279,6 +5335,7 @@ Released 2018-09-13 [`int_plus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#int_plus_one [`integer_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_arithmetic [`integer_division`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_division +[`integer_division_remainder_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_division_remainder_used [`into_iter_on_array`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_array [`into_iter_on_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_ref [`into_iter_without_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_without_iter @@ -5376,6 +5433,7 @@ Released 2018-09-13 [`manual_swap`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_swap [`manual_try_fold`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_try_fold [`manual_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_unwrap_or +[`manual_unwrap_or_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_unwrap_or_default [`manual_while_let_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_while_let_some [`many_single_char_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#many_single_char_names [`map_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_clone @@ -5813,6 +5871,7 @@ Released 2018-09-13 [`zero_divided_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_divided_by_zero [`zero_prefixed_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_prefixed_literal [`zero_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_ptr +[`zero_repeat_side_effects`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_repeat_side_effects [`zero_sized_map_values`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_sized_map_values [`zero_width_space`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_width_space [`zst_offset`]: https://rust-lang.github.io/rust-clippy/master/index.html#zst_offset diff --git a/Cargo.toml b/Cargo.toml index 5d1d0ce2c42fb..2b37b54c0048b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.1.78" +version = "0.1.79" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" @@ -24,7 +24,7 @@ path = "src/driver.rs" clippy_config = { path = "clippy_config" } clippy_lints = { path = "clippy_lints" } rustc_tools_util = "0.3.0" -tempfile = { version = "3.2", optional = true } +tempfile = { version = "3.3", optional = true } termize = "0.1" color-print = "0.3.4" anstream = "0.6.0" @@ -32,18 +32,18 @@ anstream = "0.6.0" [dev-dependencies] ui_test = "0.22.2" tester = "0.9" -regex = "1.5" +regex = "1.5.5" toml = "0.7.3" walkdir = "2.3" # This is used by the `collect-metadata` alias. -filetime = "0.2" +filetime = "0.2.9" itertools = "0.12" # UI test dependencies clippy_utils = { path = "clippy_utils" } if_chain = "1.0" -quote = "1.0" -serde = { version = "1.0.125", features = ["derive"] } +quote = "1.0.25" +serde = { version = "1.0.145", features = ["derive"] } syn = { version = "2.0", features = ["full"] } futures = "0.3" parking_lot = "0.12" diff --git a/book/src/development/macro_expansions.md b/book/src/development/macro_expansions.md index aecca9ef72e98..125b6c4bc5be1 100644 --- a/book/src/development/macro_expansions.md +++ b/book/src/development/macro_expansions.md @@ -52,7 +52,7 @@ if expr.span.from_expansion() { ### `Span.ctxt` method -The `span`'s context, given by the method [`ctxt`] and returning [SpanContext], +The `span`'s context, given by the method [`ctxt`] and returning [SyntaxContext], represents if the span is from a macro expansion and, if it is, which macro call expanded this span. @@ -155,4 +155,4 @@ if in_external_macro(cx.sess(), foo_span) { [`from_expansion`]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_span/struct.Span.html#method.from_expansion [`in_external_macro`]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_middle/lint/fn.in_external_macro.html [Span]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_span/struct.Span.html -[SpanContext]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_span/hygiene/struct.SyntaxContext.html +[SyntaxContext]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_span/hygiene/struct.SyntaxContext.html diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index a985346b3c05f..a923489974646 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -602,6 +602,7 @@ The minimum rust version that the project supports. Defaults to the `rust-versio **Affected lints:** * [`almost_complete_range`](https://rust-lang.github.io/rust-clippy/master/index.html#almost_complete_range) * [`approx_constant`](https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant) +* [`assigning_clones`](https://rust-lang.github.io/rust-clippy/master/index.html#assigning_clones) * [`borrow_as_ptr`](https://rust-lang.github.io/rust-clippy/master/index.html#borrow_as_ptr) * [`cast_abs_to_unsigned`](https://rust-lang.github.io/rust-clippy/master/index.html#cast_abs_to_unsigned) * [`checked_conversions`](https://rust-lang.github.io/rust-clippy/master/index.html#checked_conversions) diff --git a/clippy.toml b/clippy.toml index 8c405ac6a4e82..62ed55beb1f34 100644 --- a/clippy.toml +++ b/clippy.toml @@ -1,7 +1,10 @@ avoid-breaking-exported-api = false -# use the various `span_lint_*` methods instead, which also add a link to the docs -disallowed-methods = [ - "rustc_lint::context::LintContext::span_lint", - "rustc_middle::ty::context::TyCtxt::node_span_lint" -] +[[disallowed-methods]] +path = "rustc_lint::context::LintContext::span_lint" +reason = "this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint*` functions instead" + + +[[disallowed-methods]] +path = "rustc_middle::ty::context::TyCtxt::node_span_lint" +reason = "this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint_hir*` functions instead" diff --git a/clippy_config/Cargo.toml b/clippy_config/Cargo.toml index 2edc5ed592cb0..8ba2ab5662569 100644 --- a/clippy_config/Cargo.toml +++ b/clippy_config/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_config" -version = "0.1.78" +version = "0.1.79" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index 673b6328b3901..3218fe7f45627 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -262,7 +262,7 @@ define_Conf! { /// /// Suppress lints whenever the suggested change would cause breakage for other crates. (avoid_breaking_exported_api: bool = true), - /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD, MANUAL_HASH_ONE, ITER_KV_MAP, MANUAL_C_STR_LITERALS. + /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD, MANUAL_HASH_ONE, ITER_KV_MAP, MANUAL_C_STR_LITERALS, ASSIGNING_CLONES. /// /// The minimum rust version that the project supports. Defaults to the `rust-version` field in `Cargo.toml` #[default_text = ""] diff --git a/clippy_config/src/msrvs.rs b/clippy_config/src/msrvs.rs index a8a32f7ed208b..bf4da5f14fe0a 100644 --- a/clippy_config/src/msrvs.rs +++ b/clippy_config/src/msrvs.rs @@ -23,6 +23,7 @@ msrv_aliases! { 1,70,0 { OPTION_RESULT_IS_VARIANT_AND, BINARY_HEAP_RETAIN } 1,68,0 { PATH_MAIN_SEPARATOR_STR } 1,65,0 { LET_ELSE, POINTER_CAST_CONSTNESS } + 1,63,0 { ASSIGNING_CLONES } 1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE } 1,59,0 { THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST } 1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY } diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs index 2222abff7adfb..76ae26dddf4de 100644 --- a/clippy_dev/src/update_lints.rs +++ b/clippy_dev/src/update_lints.rs @@ -689,6 +689,8 @@ fn gen_deprecated_lints_test(lints: &[DeprecatedLint]) -> String { fn gen_renamed_lints_test(lints: &[RenamedLint]) -> String { let mut seen_lints = HashSet::new(); let mut res: String = GENERATED_FILE_COMMENT.into(); + + res.push_str("#![allow(clippy::duplicated_attributes)]\n"); for lint in lints { if seen_lints.insert(&lint.new_name) { writeln!(res, "#![allow({})]", lint.new_name).unwrap(); diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index 6ae089b3e0321..1d954607eee8c 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_lints" -version = "0.1.78" +version = "0.1.79" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" diff --git a/clippy_lints/src/assigning_clones.rs b/clippy_lints/src/assigning_clones.rs index b1c552c7a8dd2..88d9f762a87b3 100644 --- a/clippy_lints/src/assigning_clones.rs +++ b/clippy_lints/src/assigning_clones.rs @@ -1,3 +1,4 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::HirNode; use clippy_utils::sugg::Sugg; @@ -6,7 +7,7 @@ use rustc_errors::Applicability; use rustc_hir::{self as hir, Expr, ExprKind, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Instance, Mutability}; -use rustc_session::declare_lint_pass; +use rustc_session::impl_lint_pass; use rustc_span::def_id::DefId; use rustc_span::symbol::sym; use rustc_span::ExpnKind; @@ -49,7 +50,19 @@ declare_clippy_lint! { perf, "assigning the result of cloning may be inefficient" } -declare_lint_pass!(AssigningClones => [ASSIGNING_CLONES]); + +pub struct AssigningClones { + msrv: Msrv, +} + +impl AssigningClones { + #[must_use] + pub fn new(msrv: Msrv) -> Self { + Self { msrv } + } +} + +impl_lint_pass!(AssigningClones => [ASSIGNING_CLONES]); impl<'tcx> LateLintPass<'tcx> for AssigningClones { fn check_expr(&mut self, cx: &LateContext<'tcx>, assign_expr: &'tcx hir::Expr<'_>) { @@ -68,10 +81,12 @@ impl<'tcx> LateLintPass<'tcx> for AssigningClones { return; }; - if is_ok_to_suggest(cx, lhs, &call) { + if is_ok_to_suggest(cx, lhs, &call, &self.msrv) { suggest(cx, assign_expr, lhs, &call); } } + + extract_msrv_attr!(LateContext); } // Try to resolve the call to `Clone::clone` or `ToOwned::to_owned`. @@ -135,7 +150,13 @@ fn extract_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option< // Return true if we find that the called method has a custom implementation and isn't derived or // provided by default by the corresponding trait. -fn is_ok_to_suggest<'tcx>(cx: &LateContext<'tcx>, lhs: &Expr<'tcx>, call: &CallCandidate<'tcx>) -> bool { +fn is_ok_to_suggest<'tcx>(cx: &LateContext<'tcx>, lhs: &Expr<'tcx>, call: &CallCandidate<'tcx>, msrv: &Msrv) -> bool { + // For calls to .to_owned we suggest using .clone_into(), which was only stablilized in 1.63. + // If the current MSRV is below that, don't suggest the lint. + if !msrv.meets(msrvs::ASSIGNING_CLONES) && matches!(call.target, TargetTrait::ToOwned) { + return false; + } + // If the left-hand side is a local variable, it might be uninitialized at this point. // In that case we do not want to suggest the lint. if let Some(local) = path_to_local(lhs) { diff --git a/clippy_lints/src/attrs/duplicated_attributes.rs b/clippy_lints/src/attrs/duplicated_attributes.rs new file mode 100644 index 0000000000000..3c5ac597fd5d4 --- /dev/null +++ b/clippy_lints/src/attrs/duplicated_attributes.rs @@ -0,0 +1,64 @@ +use super::DUPLICATED_ATTRIBUTES; +use clippy_utils::diagnostics::span_lint_and_then; +use rustc_ast::{Attribute, MetaItem}; +use rustc_data_structures::fx::FxHashMap; +use rustc_lint::EarlyContext; +use rustc_span::{sym, Span}; +use std::collections::hash_map::Entry; + +fn emit_if_duplicated( + cx: &EarlyContext<'_>, + attr: &MetaItem, + attr_paths: &mut FxHashMap, + complete_path: String, +) { + match attr_paths.entry(complete_path) { + Entry::Vacant(v) => { + v.insert(attr.span); + }, + Entry::Occupied(o) => { + span_lint_and_then(cx, DUPLICATED_ATTRIBUTES, attr.span, "duplicated attribute", |diag| { + diag.span_note(*o.get(), "first defined here"); + diag.span_help(attr.span, "remove this attribute"); + }); + }, + } +} + +fn check_duplicated_attr( + cx: &EarlyContext<'_>, + attr: &MetaItem, + attr_paths: &mut FxHashMap, + parent: &mut Vec, +) { + let Some(ident) = attr.ident() else { return }; + let name = ident.name; + if name == sym::doc || name == sym::cfg_attr { + // FIXME: Would be nice to handle `cfg_attr` as well. Only problem is to check that cfg + // conditions are the same. + return; + } + if let Some(value) = attr.value_str() { + emit_if_duplicated(cx, attr, attr_paths, format!("{}:{name}={value}", parent.join(":"))); + } else if let Some(sub_attrs) = attr.meta_item_list() { + parent.push(name.as_str().to_string()); + for sub_attr in sub_attrs { + if let Some(meta) = sub_attr.meta_item() { + check_duplicated_attr(cx, meta, attr_paths, parent); + } + } + parent.pop(); + } else { + emit_if_duplicated(cx, attr, attr_paths, format!("{}:{name}", parent.join(":"))); + } +} + +pub fn check(cx: &EarlyContext<'_>, attrs: &[Attribute]) { + let mut attr_paths = FxHashMap::default(); + + for attr in attrs { + if let Some(meta) = attr.meta() { + check_duplicated_attr(cx, &meta, &mut attr_paths, &mut Vec::new()); + } + } +} diff --git a/clippy_lints/src/attrs/mod.rs b/clippy_lints/src/attrs/mod.rs index c4c65d3248a7d..675c428948f68 100644 --- a/clippy_lints/src/attrs/mod.rs +++ b/clippy_lints/src/attrs/mod.rs @@ -4,6 +4,7 @@ mod allow_attributes_without_reason; mod blanket_clippy_restriction_lints; mod deprecated_cfg_attr; mod deprecated_semver; +mod duplicated_attributes; mod empty_line_after; mod inline_always; mod maybe_misused_cfg; @@ -16,7 +17,7 @@ mod useless_attribute; mod utils; use clippy_config::msrvs::Msrv; -use rustc_ast::{Attribute, MetaItemKind, NestedMetaItem}; +use rustc_ast::{Attribute, Crate, MetaItemKind, NestedMetaItem}; use rustc_hir::{ImplItem, Item, ItemKind, TraitItem}; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, impl_lint_pass}; @@ -489,6 +490,32 @@ declare_clippy_lint! { "item has both inner and outer attributes" } +declare_clippy_lint! { + /// ### What it does + /// Checks for attributes that appear two or more times. + /// + /// ### Why is this bad? + /// Repeating an attribute on the same item (or globally on the same crate) + /// is unnecessary and doesn't have an effect. + /// + /// ### Example + /// ```no_run + /// #[allow(dead_code)] + /// #[allow(dead_code)] + /// fn foo() {} + /// ``` + /// + /// Use instead: + /// ```no_run + /// #[allow(dead_code)] + /// fn foo() {} + /// ``` + #[clippy::version = "1.78.0"] + pub DUPLICATED_ATTRIBUTES, + suspicious, + "duplicated attribute" +} + declare_lint_pass!(Attributes => [ ALLOW_ATTRIBUTES_WITHOUT_REASON, INLINE_ALWAYS, @@ -568,12 +595,18 @@ impl_lint_pass!(EarlyAttributes => [ DEPRECATED_CLIPPY_CFG_ATTR, UNNECESSARY_CLIPPY_CFG, MIXED_ATTRIBUTES_STYLE, + DUPLICATED_ATTRIBUTES, ]); impl EarlyLintPass for EarlyAttributes { + fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &Crate) { + duplicated_attributes::check(cx, &krate.attrs); + } + fn check_item(&mut self, cx: &EarlyContext<'_>, item: &rustc_ast::Item) { empty_line_after::check(cx, item); mixed_attributes_style::check(cx, item); + duplicated_attributes::check(cx, &item.attrs); } fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) { diff --git a/clippy_lints/src/casts/cast_lossless.rs b/clippy_lints/src/casts/cast_lossless.rs index fe2455f4b2395..86f4332d05aad 100644 --- a/clippy_lints/src/casts/cast_lossless.rs +++ b/clippy_lints/src/casts/cast_lossless.rs @@ -1,12 +1,12 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::in_constant; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::{snippet_opt, snippet_with_applicability}; use clippy_utils::ty::is_isize_or_usize; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind}; +use rustc_hir::{Expr, ExprKind, QPath, TyKind}; use rustc_lint::LateContext; -use rustc_middle::ty::{self, FloatTy, Ty}; +use rustc_middle::ty::{self, FloatTy, Ty, UintTy}; use super::{utils, CAST_LOSSLESS}; @@ -16,6 +16,7 @@ pub(super) fn check( cast_op: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>, + cast_to_hir: &rustc_hir::Ty<'_>, msrv: &Msrv, ) { if !should_lint(cx, expr, cast_from, cast_to, msrv) { @@ -24,11 +25,11 @@ pub(super) fn check( // The suggestion is to use a function call, so if the original expression // has parens on the outside, they are no longer needed. - let mut applicability = Applicability::MachineApplicable; + let mut app = Applicability::MachineApplicable; let opt = snippet_opt(cx, cast_op.span.source_callsite()); let sugg = opt.as_ref().map_or_else( || { - applicability = Applicability::HasPlaceholders; + app = Applicability::HasPlaceholders; ".." }, |snip| { @@ -40,10 +41,27 @@ pub(super) fn check( }, ); + // Display the type alias instead of the aliased type. Fixes #11285 + // + // FIXME: Once `lazy_type_alias` is stabilized(?) we should use `rustc_middle` types instead, + // this will allow us to display the right type with `cast_from` as well. + let cast_to_fmt = if let TyKind::Path(QPath::Resolved(None, path)) = cast_to_hir.kind + // It's a bit annoying but the turbofish is optional for types. A type in an `as` cast + // shouldn't have these if they're primitives, which are the only things we deal with. + // + // This could be removed for performance if this check is determined to have a pretty major + // effect. + && path.segments.iter().all(|segment| segment.args.is_none()) + { + snippet_with_applicability(cx, cast_to_hir.span, "..", &mut app) + } else { + cast_to.to_string().into() + }; + let message = if cast_from.is_bool() { - format!("casting `{cast_from:}` to `{cast_to:}` is more cleanly stated with `{cast_to:}::from(_)`") + format!("casting `{cast_from}` to `{cast_to_fmt}` is more cleanly stated with `{cast_to_fmt}::from(_)`") } else { - format!("casting `{cast_from}` to `{cast_to}` may become silently lossy if you later change the type") + format!("casting `{cast_from}` to `{cast_to_fmt}` may become silently lossy if you later change the type") }; span_lint_and_sugg( @@ -52,14 +70,17 @@ pub(super) fn check( expr.span, &message, "try", - format!("{cast_to}::from({sugg})"), - applicability, + format!("{cast_to_fmt}::from({sugg})"), + app, ); } fn should_lint(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>, msrv: &Msrv) -> bool { // Do not suggest using From in consts/statics until it is valid to do so (see #2267). - if in_constant(cx, expr.hir_id) { + // + // If destination is u128, do not lint because source type cannot be larger + // If source is bool, still lint due to the lint message differing (refers to style) + if in_constant(cx, expr.hir_id) || (!cast_from.is_bool() && matches!(cast_to.kind(), ty::Uint(UintTy::U128))) { return false; } diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index 14f2f4a7f59da..063aab282384b 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -791,7 +791,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts { cast_abs_to_unsigned::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv); cast_nan_to_int::check(cx, expr, cast_expr, cast_from, cast_to); } - cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv); + cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to, cast_to_hir, &self.msrv); cast_enum_constructor::check(cx, expr, cast_expr, cast_from); } diff --git a/clippy_lints/src/dbg_macro.rs b/clippy_lints/src/dbg_macro.rs index ec66556cebffa..e229676743195 100644 --- a/clippy_lints/src/dbg_macro.rs +++ b/clippy_lints/src/dbg_macro.rs @@ -1,12 +1,14 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::macros::root_macro_call_first_node; +use clippy_utils::macros::{macro_backtrace, MacroCall}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::{is_in_cfg_test, is_in_test_function}; +use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, Node}; +use rustc_hir::{Expr, ExprKind, HirId, Node}; use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; -use rustc_span::sym; +use rustc_span::{sym, Span, SyntaxContext}; declare_clippy_lint! { /// ### What it does @@ -31,31 +33,38 @@ declare_clippy_lint! { "`dbg!` macro is intended as a debugging tool" } -#[derive(Copy, Clone)] +#[derive(Clone)] pub struct DbgMacro { allow_dbg_in_tests: bool, + /// Tracks the `dbg!` macro callsites that are already checked. + checked_dbg_call_site: FxHashSet, + /// Tracks the previous `SyntaxContext`, to avoid walking the same context chain. + prev_ctxt: SyntaxContext, } impl_lint_pass!(DbgMacro => [DBG_MACRO]); impl DbgMacro { pub fn new(allow_dbg_in_tests: bool) -> Self { - DbgMacro { allow_dbg_in_tests } + DbgMacro { + allow_dbg_in_tests, + checked_dbg_call_site: FxHashSet::default(), + prev_ctxt: SyntaxContext::root(), + } } } impl LateLintPass<'_> for DbgMacro { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { - let Some(macro_call) = root_macro_call_first_node(cx, expr) else { - return; - }; - if cx.tcx.is_diagnostic_item(sym::dbg_macro, macro_call.def_id) { + let cur_syntax_ctxt = expr.span.ctxt(); + + if cur_syntax_ctxt != self.prev_ctxt && + let Some(macro_call) = first_dbg_macro_in_expansion(cx, expr.span) && + !in_external_macro(cx.sess(), macro_call.span) && + self.checked_dbg_call_site.insert(macro_call.span) && // allows `dbg!` in test code if allow-dbg-in-test is set to true in clippy.toml - if self.allow_dbg_in_tests - && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id)) - { - return; - } + !(self.allow_dbg_in_tests && is_in_test(cx, expr.hir_id)) + { let mut applicability = Applicability::MachineApplicable; let (sugg_span, suggestion) = match expr.peel_drop_temps().kind { @@ -101,6 +110,8 @@ impl LateLintPass<'_> for DbgMacro { _ => return, }; + self.prev_ctxt = cur_syntax_ctxt; + span_lint_and_sugg( cx, DBG_MACRO, @@ -112,4 +123,16 @@ impl LateLintPass<'_> for DbgMacro { ); } } + + fn check_crate_post(&mut self, _: &LateContext<'_>) { + self.checked_dbg_call_site = FxHashSet::default(); + } +} + +fn is_in_test(cx: &LateContext<'_>, hir_id: HirId) -> bool { + is_in_test_function(cx.tcx, hir_id) || is_in_cfg_test(cx.tcx, hir_id) +} + +fn first_dbg_macro_in_expansion(cx: &LateContext<'_>, span: Span) -> Option { + macro_backtrace(span).find(|mc| cx.tcx.is_diagnostic_item(sym::dbg_macro, mc.def_id)) } diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 2b324f5f96e81..c8e148598a272 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -54,6 +54,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::attrs::DEPRECATED_CFG_ATTR_INFO, crate::attrs::DEPRECATED_CLIPPY_CFG_ATTR_INFO, crate::attrs::DEPRECATED_SEMVER_INFO, + crate::attrs::DUPLICATED_ATTRIBUTES_INFO, crate::attrs::EMPTY_LINE_AFTER_DOC_COMMENTS_INFO, crate::attrs::EMPTY_LINE_AFTER_OUTER_ATTR_INFO, crate::attrs::INLINE_ALWAYS_INFO, @@ -235,6 +236,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::instant_subtraction::MANUAL_INSTANT_ELAPSED_INFO, crate::instant_subtraction::UNCHECKED_DURATION_SUBTRACTION_INFO, crate::int_plus_one::INT_PLUS_ONE_INFO, + crate::integer_division_remainder_used::INTEGER_DIVISION_REMAINDER_USED_INFO, crate::invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS_INFO, crate::item_name_repetitions::ENUM_VARIANT_NAMES_INFO, crate::item_name_repetitions::MODULE_INCEPTION_INFO, @@ -310,6 +312,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::manual_slice_size_calculation::MANUAL_SLICE_SIZE_CALCULATION_INFO, crate::manual_string_new::MANUAL_STRING_NEW_INFO, crate::manual_strip::MANUAL_STRIP_INFO, + crate::manual_unwrap_or_default::MANUAL_UNWRAP_OR_DEFAULT_INFO, crate::map_unit_fn::OPTION_MAP_UNIT_FN_INFO, crate::map_unit_fn::RESULT_MAP_UNIT_FN_INFO, crate::match_result_ok::MATCH_RESULT_OK_INFO, @@ -353,6 +356,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::CLONE_ON_COPY_INFO, crate::methods::CLONE_ON_REF_PTR_INFO, crate::methods::COLLAPSIBLE_STR_REPLACE_INFO, + crate::methods::CONST_IS_EMPTY_INFO, crate::methods::DRAIN_COLLECT_INFO, crate::methods::ERR_EXPECT_INFO, crate::methods::EXPECT_FUN_CALL_INFO, @@ -750,5 +754,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::write::WRITE_LITERAL_INFO, crate::write::WRITE_WITH_NEWLINE_INFO, crate::zero_div_zero::ZERO_DIVIDED_BY_ZERO_INFO, + crate::zero_repeat_side_effects::ZERO_REPEAT_SIDE_EFFECTS_INFO, crate::zero_sized_map_values::ZERO_SIZED_MAP_VALUES_INFO, ]; diff --git a/clippy_lints/src/doc/markdown.rs b/clippy_lints/src/doc/markdown.rs index d2f147565917f..1add02af31017 100644 --- a/clippy_lints/src/doc/markdown.rs +++ b/clippy_lints/src/doc/markdown.rs @@ -8,7 +8,14 @@ use url::Url; use crate::doc::DOC_MARKDOWN; -pub fn check(cx: &LateContext<'_>, valid_idents: &FxHashSet, text: &str, span: Span, code_level: isize) { +pub fn check( + cx: &LateContext<'_>, + valid_idents: &FxHashSet, + text: &str, + span: Span, + code_level: isize, + blockquote_level: isize, +) { for orig_word in text.split(|c: char| c.is_whitespace() || c == '\'') { // Trim punctuation as in `some comment (see foo::bar).` // ^^ @@ -46,11 +53,11 @@ pub fn check(cx: &LateContext<'_>, valid_idents: &FxHashSet, text: &str, span.parent(), ); - check_word(cx, word, span, code_level); + check_word(cx, word, span, code_level, blockquote_level); } } -fn check_word(cx: &LateContext<'_>, word: &str, span: Span, code_level: isize) { +fn check_word(cx: &LateContext<'_>, word: &str, span: Span, code_level: isize, blockquote_level: isize) { /// Checks if a string is upper-camel-case, i.e., starts with an uppercase and /// contains at least two uppercase letters (`Clippy` is ok) and one lower-case /// letter (`NASA` is ok). @@ -97,7 +104,9 @@ fn check_word(cx: &LateContext<'_>, word: &str, span: Span, code_level: isize) { } // We assume that mixed-case words are not meant to be put inside backticks. (Issue #2343) - if code_level > 0 || (has_underscore(word) && has_hyphen(word)) { + // + // We also assume that backticks are not necessary if inside a quote. (Issue #10262) + if code_level > 0 || blockquote_level > 0 || (has_underscore(word) && has_hyphen(word)) { return; } diff --git a/clippy_lints/src/doc/mod.rs b/clippy_lints/src/doc/mod.rs index 003d26b7b89d9..b135e4e357710 100644 --- a/clippy_lints/src/doc/mod.rs +++ b/clippy_lints/src/doc/mod.rs @@ -7,14 +7,14 @@ use clippy_utils::{is_entrypoint_fn, method_chain_args}; use pulldown_cmark::Event::{ Code, End, FootnoteReference, HardBreak, Html, Rule, SoftBreak, Start, TaskListMarker, Text, }; -use pulldown_cmark::Tag::{CodeBlock, Heading, Item, Link, Paragraph}; +use pulldown_cmark::Tag::{BlockQuote, CodeBlock, Heading, Item, Link, Paragraph}; use pulldown_cmark::{BrokenLink, CodeBlockKind, CowStr, Options}; use rustc_ast::ast::Attribute; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{AnonConst, Expr}; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::nested_filter; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; @@ -538,7 +538,16 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet, attrs: &[ suspicious_doc_comments::check(cx, attrs); - let (fragments, _) = attrs_to_doc_fragments(attrs.iter().map(|attr| (attr, None)), true); + let (fragments, _) = attrs_to_doc_fragments( + attrs.iter().filter_map(|attr| { + if in_external_macro(cx.sess(), attr.span) { + None + } else { + Some((attr, None)) + } + }), + true, + ); let mut doc = fragments.iter().fold(String::new(), |mut acc, fragment| { add_doc_fragment(&mut acc, fragment); acc @@ -602,6 +611,7 @@ fn check_doc<'a, Events: Iterator, Range, Range, isize)> = Vec::new(); let mut paragraph_range = 0..0; let mut code_level = 0; + let mut blockquote_level = 0; for (event, range) in events { match event { @@ -610,8 +620,14 @@ fn check_doc<'a, Events: Iterator, Range blockquote_level += 1, + End(BlockQuote) => blockquote_level -= 1, Start(CodeBlock(ref kind)) => { in_code = true; if let CodeBlockKind::Fenced(lang) = kind { @@ -663,7 +679,7 @@ fn check_doc<'a, Events: Iterator, Range [ELSE_IF_WITHOUT_ELSE]); impl EarlyLintPass for ElseIfWithoutElse { - fn check_expr(&mut self, cx: &EarlyContext<'_>, mut item: &Expr) { + fn check_expr(&mut self, cx: &EarlyContext<'_>, item: &Expr) { if in_external_macro(cx.sess(), item.span) { return; } - while let ExprKind::If(_, _, Some(ref els)) = item.kind { - if let ExprKind::If(_, _, None) = els.kind { - span_lint_and_help( - cx, - ELSE_IF_WITHOUT_ELSE, - els.span, - "`if` expression with an `else if`, but without a final `else`", - None, - "add an `else` block here", - ); - } - - item = els; + if let ExprKind::If(_, _, Some(ref els)) = item.kind + && let ExprKind::If(_, _, None) = els.kind + { + span_lint_and_help( + cx, + ELSE_IF_WITHOUT_ELSE, + els.span, + "`if` expression with an `else if`, but without a final `else`", + None, + "add an `else` block here", + ); } } } diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index ebda2ad83870d..dafbf6c884698 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -358,7 +358,7 @@ struct InsertSearcher<'cx, 'tcx> { can_use_entry: bool, /// Whether this expression is the final expression in this code path. This may be a statement. in_tail_pos: bool, - // Is this expression a single insert. A slightly better suggestion can be made in this case. + /// Is this expression a single insert. A slightly better suggestion can be made in this case. is_single_insert: bool, /// If the visitor has seen the map being used. is_map_used: bool, @@ -431,6 +431,9 @@ impl<'tcx> Visitor<'tcx> for InsertSearcher<'_, 'tcx> { self.is_single_insert = false; self.visit_expr(e); } + if let Some(els) = &l.els { + self.visit_block(els); + } }, StmtKind::Item(_) => { self.allow_insert_closure &= !self.in_tail_pos; diff --git a/clippy_lints/src/functions/mod.rs b/clippy_lints/src/functions/mod.rs index 96da2ec2a1a8b..9cc51fa8cd5dd 100644 --- a/clippy_lints/src/functions/mod.rs +++ b/clippy_lints/src/functions/mod.rs @@ -250,7 +250,7 @@ declare_clippy_lint! { /// /// ### Why is this bad? /// A `Result` is at least as large as the `Err`-variant. While we - /// expect that variant to be seldomly used, the compiler needs to reserve + /// expect that variant to be seldom used, the compiler needs to reserve /// and move that much memory every single time. /// Furthermore, errors are often simply passed up the call-stack, making /// use of the `?`-operator and its type-conversion mechanics. If the diff --git a/clippy_lints/src/integer_division_remainder_used.rs b/clippy_lints/src/integer_division_remainder_used.rs new file mode 100644 index 0000000000000..36dc45ca788da --- /dev/null +++ b/clippy_lints/src/integer_division_remainder_used.rs @@ -0,0 +1,50 @@ +use clippy_utils::diagnostics::span_lint; +use rustc_ast::BinOpKind; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::{self}; +use rustc_session::declare_lint_pass; + +declare_clippy_lint! { + /// ### What it does + /// Checks for the usage of division (/) and remainder (%) operations + /// when performed on any integer types using the default Div and Rem trait implementations. + /// + /// ### Why is this bad? + /// In cryptographic contexts, division can result in timing sidechannel vulnerabilities, + /// and needs to be replaced with constant-time code instead (e.g. Barrett reduction). + /// + /// ### Example + /// ```no_run + /// let my_div = 10 / 2; + /// ``` + /// Use instead: + /// ```no_run + /// let my_div = 10 >> 1; + /// ``` + #[clippy::version = "1.78.0"] + pub INTEGER_DIVISION_REMAINDER_USED, + restriction, + "use of disallowed default division and remainder operations" +} + +declare_lint_pass!(IntegerDivisionRemainderUsed => [INTEGER_DIVISION_REMAINDER_USED]); + +impl LateLintPass<'_> for IntegerDivisionRemainderUsed { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + if let ExprKind::Binary(op, lhs, rhs) = &expr.kind + && let BinOpKind::Div | BinOpKind::Rem = op.node + && let lhs_ty = cx.typeck_results().expr_ty(lhs) + && let rhs_ty = cx.typeck_results().expr_ty(rhs) + && let ty::Int(_) | ty::Uint(_) = lhs_ty.peel_refs().kind() + && let ty::Int(_) | ty::Uint(_) = rhs_ty.peel_refs().kind() + { + span_lint( + cx, + INTEGER_DIVISION_REMAINDER_USED, + expr.span.source_callsite(), + &format!("use of {} has been disallowed in this context", op.node.as_str()), + ); + } + } +} diff --git a/clippy_lints/src/let_if_seq.rs b/clippy_lints/src/let_if_seq.rs index f084d89ccc282..d4ddf76fb8a3a 100644 --- a/clippy_lints/src/let_if_seq.rs +++ b/clippy_lints/src/let_if_seq.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::path_to_local_id; use clippy_utils::source::snippet; use clippy_utils::visitors::is_local_used; @@ -122,9 +122,10 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq { value=snippet(cx, value.span, ""), default=snippet(cx, default.span, ""), ); - span_lint_and_then( + span_lint_hir_and_then( cx, USELESS_LET_IF_SEQ, + local.hir_id, span, "`if _ { .. } else { .. }` is an expression", |diag| { diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index b930175c4d89a..57fac35104272 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -172,6 +172,7 @@ mod init_numbered_fields; mod inline_fn_without_body; mod instant_subtraction; mod int_plus_one; +mod integer_division_remainder_used; mod invalid_upcast_comparisons; mod item_name_repetitions; mod items_after_statements; @@ -211,6 +212,7 @@ mod manual_retain; mod manual_slice_size_calculation; mod manual_string_new; mod manual_strip; +mod manual_unwrap_or_default; mod map_unit_fn; mod match_result_ok; mod matches; @@ -373,6 +375,7 @@ mod visibility; mod wildcard_imports; mod write; mod zero_div_zero; +mod zero_repeat_side_effects; mod zero_sized_map_values; // end lints modules, do not remove this comment, it’s used in `update_lints` @@ -1119,7 +1122,10 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(move |_| Box::new(incompatible_msrv::IncompatibleMsrv::new(msrv()))); store.register_late_pass(|_| Box::new(to_string_trait_impl::ToStringTraitImpl)); store.register_early_pass(|| Box::new(multiple_bound_locations::MultipleBoundLocations)); - store.register_late_pass(|_| Box::new(assigning_clones::AssigningClones)); + store.register_late_pass(move |_| Box::new(assigning_clones::AssigningClones::new(msrv()))); + store.register_late_pass(|_| Box::new(zero_repeat_side_effects::ZeroRepeatSideEffects)); + store.register_late_pass(|_| Box::new(manual_unwrap_or_default::ManualUnwrapOrDefault)); + store.register_late_pass(|_| Box::new(integer_division_remainder_used::IntegerDivisionRemainderUsed)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/loops/needless_range_loop.rs b/clippy_lints/src/loops/needless_range_loop.rs index 47dc3807e624f..cf34c904dfe94 100644 --- a/clippy_lints/src/loops/needless_range_loop.rs +++ b/clippy_lints/src/loops/needless_range_loop.rs @@ -273,7 +273,7 @@ impl<'a, 'tcx> VarVisitor<'a, 'tcx> { } return false; // no need to walk further *on the variable* }, - Res::Def(DefKind::Static{..} | DefKind::Const, ..) => { + Res::Def(DefKind::Static { .. } | DefKind::Const, ..) => { if index_used_directly { self.indexed_directly.insert( seqvar.segments[0].ident.name, diff --git a/clippy_lints/src/loops/never_loop.rs b/clippy_lints/src/loops/never_loop.rs index 6cc79440f39a0..8aae7be459361 100644 --- a/clippy_lints/src/loops/never_loop.rs +++ b/clippy_lints/src/loops/never_loop.rs @@ -255,9 +255,7 @@ fn never_loop_expr<'tcx>( InlineAsmOperand::Const { .. } | InlineAsmOperand::SymFn { .. } | InlineAsmOperand::SymStatic { .. } => { NeverLoopResult::Normal }, - InlineAsmOperand::Label { block } => { - never_loop_block(cx, block, local_labels, main_loop_id) - } + InlineAsmOperand::Label { block } => never_loop_block(cx, block, local_labels, main_loop_id), })), ExprKind::OffsetOf(_, _) | ExprKind::Yield(_, _) diff --git a/clippy_lints/src/loops/unused_enumerate_index.rs b/clippy_lints/src/loops/unused_enumerate_index.rs index dd7fae79d9ba8..31f0f1cfeba31 100644 --- a/clippy_lints/src/loops/unused_enumerate_index.rs +++ b/clippy_lints/src/loops/unused_enumerate_index.rs @@ -1,62 +1,41 @@ use super::UNUSED_ENUMERATE_INDEX; use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; use clippy_utils::source::snippet; -use clippy_utils::{pat_is_wild, sugg}; +use clippy_utils::{match_def_path, pat_is_wild, sugg}; use rustc_hir::def::DefKind; use rustc_hir::{Expr, ExprKind, Pat, PatKind}; use rustc_lint::LateContext; use rustc_middle::ty; /// Checks for the `UNUSED_ENUMERATE_INDEX` lint. -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, arg: &'tcx Expr<'_>, body: &'tcx Expr<'_>) { - let PatKind::Tuple([index, elem], _) = pat.kind else { - return; - }; - - let ExprKind::MethodCall(_method, self_arg, [], _) = arg.kind else { - return; - }; - - let ty = cx.typeck_results().expr_ty(arg); - - if !pat_is_wild(cx, &index.kind, body) { - return; - } - - let name = match *ty.kind() { - ty::Adt(base, _substs) => cx.tcx.def_path_str(base.did()), - _ => return, - }; - - if name != "std::iter::Enumerate" && name != "core::iter::Enumerate" { - return; +/// +/// The lint is also partially implemented in `clippy_lints/src/methods/unused_enumerate_index.rs`. +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'tcx>, arg: &Expr<'_>, body: &'tcx Expr<'tcx>) { + if let PatKind::Tuple([index, elem], _) = pat.kind + && let ExprKind::MethodCall(_method, self_arg, [], _) = arg.kind + && let ty = cx.typeck_results().expr_ty(arg) + && pat_is_wild(cx, &index.kind, body) + && let ty::Adt(base, _) = *ty.kind() + && match_def_path(cx, base.did(), &clippy_utils::paths::CORE_ITER_ENUMERATE_STRUCT) + && let Some((DefKind::AssocFn, call_id)) = cx.typeck_results().type_dependent_def(arg.hir_id) + && match_def_path(cx, call_id, &clippy_utils::paths::CORE_ITER_ENUMERATE_METHOD) + { + span_lint_and_then( + cx, + UNUSED_ENUMERATE_INDEX, + arg.span, + "you seem to use `.enumerate()` and immediately discard the index", + |diag| { + let base_iter = sugg::Sugg::hir(cx, self_arg, "base iter"); + multispan_sugg( + diag, + "remove the `.enumerate()` call", + vec![ + (pat.span, snippet(cx, elem.span, "..").into_owned()), + (arg.span, base_iter.to_string()), + ], + ); + }, + ); } - - let Some((DefKind::AssocFn, call_id)) = cx.typeck_results().type_dependent_def(arg.hir_id) else { - return; - }; - - let call_name = cx.tcx.def_path_str(call_id); - - if call_name != "std::iter::Iterator::enumerate" && call_name != "core::iter::Iterator::enumerate" { - return; - } - - span_lint_and_then( - cx, - UNUSED_ENUMERATE_INDEX, - arg.span, - "you seem to use `.enumerate()` and immediately discard the index", - |diag| { - let base_iter = sugg::Sugg::hir(cx, self_arg, "base iter"); - multispan_sugg( - diag, - "remove the `.enumerate()` call", - vec![ - (pat.span, snippet(cx, elem.span, "..").into_owned()), - (arg.span, base_iter.to_string()), - ], - ); - }, - ); } diff --git a/clippy_lints/src/loops/while_immutable_condition.rs b/clippy_lints/src/loops/while_immutable_condition.rs index 3511d24e8134e..3dff826cb85ce 100644 --- a/clippy_lints/src/loops/while_immutable_condition.rs +++ b/clippy_lints/src/loops/while_immutable_condition.rs @@ -101,7 +101,7 @@ impl<'a, 'tcx> VarCollectorVisitor<'a, 'tcx> { Res::Local(hir_id) => { self.ids.insert(hir_id); }, - Res::Def(DefKind::Static{..}, def_id) => { + Res::Def(DefKind::Static { .. }, def_id) => { let mutable = self.cx.tcx.is_mutable_static(def_id); self.def_ids.insert(def_id, mutable); }, diff --git a/clippy_lints/src/manual_retain.rs b/clippy_lints/src/manual_retain.rs index 6f15fca089eba..3ddb06a1e08a1 100644 --- a/clippy_lints/src/manual_retain.rs +++ b/clippy_lints/src/manual_retain.rs @@ -2,7 +2,7 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; -use clippy_utils::{get_parent_expr, match_def_path, paths, SpanlessEq}; +use clippy_utils::{match_def_path, paths, SpanlessEq}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def_id::DefId; @@ -69,17 +69,16 @@ impl_lint_pass!(ManualRetain => [MANUAL_RETAIN]); impl<'tcx> LateLintPass<'tcx> for ManualRetain { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { - if let Some(parent_expr) = get_parent_expr(cx, expr) - && let Assign(left_expr, collect_expr, _) = &parent_expr.kind + if let Assign(left_expr, collect_expr, _) = &expr.kind && let hir::ExprKind::MethodCall(seg, ..) = &collect_expr.kind && seg.args.is_none() && let hir::ExprKind::MethodCall(_, target_expr, [], _) = &collect_expr.kind && let Some(collect_def_id) = cx.typeck_results().type_dependent_def_id(collect_expr.hir_id) && cx.tcx.is_diagnostic_item(sym::iterator_collect_fn, collect_def_id) { - check_into_iter(cx, left_expr, target_expr, parent_expr.span, &self.msrv); - check_iter(cx, left_expr, target_expr, parent_expr.span, &self.msrv); - check_to_owned(cx, left_expr, target_expr, parent_expr.span, &self.msrv); + check_into_iter(cx, left_expr, target_expr, expr.span, &self.msrv); + check_iter(cx, left_expr, target_expr, expr.span, &self.msrv); + check_to_owned(cx, left_expr, target_expr, expr.span, &self.msrv); } } diff --git a/clippy_lints/src/manual_unwrap_or_default.rs b/clippy_lints/src/manual_unwrap_or_default.rs new file mode 100644 index 0000000000000..ddaf97c463ae7 --- /dev/null +++ b/clippy_lints/src/manual_unwrap_or_default.rs @@ -0,0 +1,181 @@ +use rustc_errors::Applicability; +use rustc_hir::def::Res; +use rustc_hir::{Arm, Expr, ExprKind, HirId, LangItem, MatchSource, Pat, PatKind, QPath}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::declare_lint_pass; +use rustc_span::sym; + +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_default_equivalent; +use clippy_utils::source::snippet_opt; +use clippy_utils::ty::implements_trait; + +declare_clippy_lint! { + /// ### What it does + /// Checks if a `match` or `if let` expression can be simplified using + /// `.unwrap_or_default()`. + /// + /// ### Why is this bad? + /// It can be done in one call with `.unwrap_or_default()`. + /// + /// ### Example + /// ```no_run + /// let x: Option = Some(String::new()); + /// let y: String = match x { + /// Some(v) => v, + /// None => String::new(), + /// }; + /// + /// let x: Option> = Some(Vec::new()); + /// let y: Vec = if let Some(v) = x { + /// v + /// } else { + /// Vec::new() + /// }; + /// ``` + /// Use instead: + /// ```no_run + /// let x: Option = Some(String::new()); + /// let y: String = x.unwrap_or_default(); + /// + /// let x: Option> = Some(Vec::new()); + /// let y: Vec = x.unwrap_or_default(); + /// ``` + #[clippy::version = "1.78.0"] + pub MANUAL_UNWRAP_OR_DEFAULT, + suspicious, + "check if a `match` or `if let` can be simplified with `unwrap_or_default`" +} + +declare_lint_pass!(ManualUnwrapOrDefault => [MANUAL_UNWRAP_OR_DEFAULT]); + +fn get_some<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'tcx>) -> Option { + if let PatKind::TupleStruct(QPath::Resolved(_, path), &[pat], _) = pat.kind + && let Some(def_id) = path.res.opt_def_id() + // Since it comes from a pattern binding, we need to get the parent to actually match + // against it. + && let Some(def_id) = cx.tcx.opt_parent(def_id) + && cx.tcx.lang_items().get(LangItem::OptionSome) == Some(def_id) + { + let mut bindings = Vec::new(); + pat.each_binding(|_, id, _, _| bindings.push(id)); + if let &[id] = bindings.as_slice() { + Some(id) + } else { + None + } + } else { + None + } +} + +fn get_none<'tcx>(cx: &LateContext<'tcx>, arm: &Arm<'tcx>) -> Option<&'tcx Expr<'tcx>> { + if let PatKind::Path(QPath::Resolved(_, path)) = arm.pat.kind + && let Some(def_id) = path.res.opt_def_id() + // Since it comes from a pattern binding, we need to get the parent to actually match + // against it. + && let Some(def_id) = cx.tcx.opt_parent(def_id) + && cx.tcx.lang_items().get(LangItem::OptionNone) == Some(def_id) + { + Some(arm.body) + } else if let PatKind::Wild = arm.pat.kind { + // We consider that the `Some` check will filter it out if it's not right. + Some(arm.body) + } else { + None + } +} + +fn get_some_and_none_bodies<'tcx>( + cx: &LateContext<'tcx>, + arm1: &'tcx Arm<'tcx>, + arm2: &'tcx Arm<'tcx>, +) -> Option<((&'tcx Expr<'tcx>, HirId), &'tcx Expr<'tcx>)> { + if let Some(binding_id) = get_some(cx, arm1.pat) + && let Some(body_none) = get_none(cx, arm2) + { + Some(((arm1.body, binding_id), body_none)) + } else if let Some(binding_id) = get_some(cx, arm2.pat) + && let Some(body_none) = get_none(cx, arm1) + { + Some(((arm2.body, binding_id), body_none)) + } else { + None + } +} + +fn handle_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { + let ExprKind::Match(match_expr, [arm1, arm2], MatchSource::Normal | MatchSource::ForLoopDesugar) = expr.kind else { + return false; + }; + // We don't want conditions on the arms to simplify things. + if arm1.guard.is_none() + && arm2.guard.is_none() + // We check that the returned type implements the `Default` trait. + && let match_ty = cx.typeck_results().expr_ty(expr) + && let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default) + && implements_trait(cx, match_ty, default_trait_id, &[]) + // We now get the bodies for both the `Some` and `None` arms. + && let Some(((body_some, binding_id), body_none)) = get_some_and_none_bodies(cx, arm1, arm2) + // We check that the `Some(x) => x` doesn't do anything apart "returning" the value in `Some`. + && let ExprKind::Path(QPath::Resolved(_, path)) = body_some.peel_blocks().kind + && let Res::Local(local_id) = path.res + && local_id == binding_id + // We now check the `None` arm is calling a method equivalent to `Default::default`. + && let body_none = body_none.peel_blocks() + && is_default_equivalent(cx, body_none) + && let Some(match_expr_snippet) = snippet_opt(cx, match_expr.span) + { + span_lint_and_sugg( + cx, + MANUAL_UNWRAP_OR_DEFAULT, + expr.span, + "match can be simplified with `.unwrap_or_default()`", + "replace it with", + format!("{match_expr_snippet}.unwrap_or_default()"), + Applicability::MachineApplicable, + ); + } + true +} + +fn handle_if_let<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { + if let ExprKind::If(cond, if_block, Some(else_expr)) = expr.kind + && let ExprKind::Let(let_) = cond.kind + && let ExprKind::Block(_, _) = else_expr.kind + // We check that the returned type implements the `Default` trait. + && let match_ty = cx.typeck_results().expr_ty(expr) + && let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default) + && implements_trait(cx, match_ty, default_trait_id, &[]) + && let Some(binding_id) = get_some(cx, let_.pat) + // We check that the `Some(x) => x` doesn't do anything apart "returning" the value in `Some`. + && let ExprKind::Path(QPath::Resolved(_, path)) = if_block.peel_blocks().kind + && let Res::Local(local_id) = path.res + && local_id == binding_id + // We now check the `None` arm is calling a method equivalent to `Default::default`. + && let body_else = else_expr.peel_blocks() + && is_default_equivalent(cx, body_else) + && let Some(if_let_expr_snippet) = snippet_opt(cx, let_.init.span) + { + span_lint_and_sugg( + cx, + MANUAL_UNWRAP_OR_DEFAULT, + expr.span, + "if let can be simplified with `.unwrap_or_default()`", + "replace it with", + format!("{if_let_expr_snippet}.unwrap_or_default()"), + Applicability::MachineApplicable, + ); + } +} + +impl<'tcx> LateLintPass<'tcx> for ManualUnwrapOrDefault { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { + if expr.span.from_expansion() { + return; + } + if !handle_match(cx, expr) { + handle_if_let(cx, expr); + } + } +} diff --git a/clippy_lints/src/matches/single_match.rs b/clippy_lints/src/matches/single_match.rs index 86c414dafccab..a0db8e2db1f8c 100644 --- a/clippy_lints/src/matches/single_match.rs +++ b/clippy_lints/src/matches/single_match.rs @@ -55,23 +55,15 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: }; let ty = cx.typeck_results().expr_ty(ex); - if *ty.kind() != ty::Bool || is_lint_allowed(cx, MATCH_BOOL, ex.hir_id) { - check_single_pattern(cx, ex, arms, expr, els); - check_opt_like(cx, ex, arms, expr, ty, els); + if (*ty.kind() != ty::Bool || is_lint_allowed(cx, MATCH_BOOL, ex.hir_id)) && + (check_single_pattern(arms) || check_opt_like(cx, arms, ty)) { + report_single_pattern(cx, ex, arms, expr, els); } } } -fn check_single_pattern( - cx: &LateContext<'_>, - ex: &Expr<'_>, - arms: &[Arm<'_>], - expr: &Expr<'_>, - els: Option<&Expr<'_>>, -) { - if is_wild(arms[1].pat) { - report_single_pattern(cx, ex, arms, expr, els); - } +fn check_single_pattern(arms: &[Arm<'_>]) -> bool { + is_wild(arms[1].pat) } fn report_single_pattern( @@ -140,19 +132,10 @@ fn report_single_pattern( span_lint_and_sugg(cx, lint, expr.span, msg, "try", sugg, app); } -fn check_opt_like<'a>( - cx: &LateContext<'a>, - ex: &Expr<'_>, - arms: &[Arm<'_>], - expr: &Expr<'_>, - ty: Ty<'a>, - els: Option<&Expr<'_>>, -) { +fn check_opt_like<'a>(cx: &LateContext<'a>, arms: &[Arm<'_>], ty: Ty<'a>) -> bool { // We don't want to lint if the second arm contains an enum which could // have more variants in the future. - if form_exhaustive_matches(cx, ty, arms[0].pat, arms[1].pat) { - report_single_pattern(cx, ex, arms, expr, els); - } + form_exhaustive_matches(cx, ty, arms[0].pat, arms[1].pat) } /// Returns `true` if all of the types in the pattern are enums which we know diff --git a/clippy_lints/src/methods/expect_fun_call.rs b/clippy_lints/src/methods/expect_fun_call.rs index e2c2997594ad9..4d8fb217f7f53 100644 --- a/clippy_lints/src/methods/expect_fun_call.rs +++ b/clippy_lints/src/methods/expect_fun_call.rs @@ -91,7 +91,7 @@ pub(super) fn check<'tcx>( }, hir::ExprKind::Path(ref p) => matches!( cx.qpath_res(p, arg.hir_id), - hir::def::Res::Def(hir::def::DefKind::Const | hir::def::DefKind::Static{..}, _) + hir::def::Res::Def(hir::def::DefKind::Const | hir::def::DefKind::Static { .. }, _) ), _ => false, } diff --git a/clippy_lints/src/methods/is_empty.rs b/clippy_lints/src/methods/is_empty.rs new file mode 100644 index 0000000000000..7fe66062251bb --- /dev/null +++ b/clippy_lints/src/methods/is_empty.rs @@ -0,0 +1,49 @@ +use clippy_utils::consts::constant_is_empty; +use clippy_utils::diagnostics::span_lint; +use clippy_utils::{find_binding_init, path_to_local}; +use rustc_hir::{Expr, HirId}; +use rustc_lint::{LateContext, LintContext}; +use rustc_middle::lint::in_external_macro; +use rustc_span::sym; + +use super::CONST_IS_EMPTY; + +/// Expression whose initialization depend on a constant conditioned by a `#[cfg(…)]` directive will +/// not trigger the lint. +pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, receiver: &Expr<'_>) { + if in_external_macro(cx.sess(), expr.span) || !receiver.span.eq_ctxt(expr.span) { + return; + } + let init_expr = expr_or_init(cx, receiver); + if !receiver.span.eq_ctxt(init_expr.span) { + return; + } + if let Some(init_is_empty) = constant_is_empty(cx, init_expr) { + span_lint( + cx, + CONST_IS_EMPTY, + expr.span, + &format!("this expression always evaluates to {init_is_empty:?}"), + ); + } +} + +fn is_under_cfg(cx: &LateContext<'_>, id: HirId) -> bool { + cx.tcx + .hir() + .parent_id_iter(id) + .any(|id| cx.tcx.hir().attrs(id).iter().any(|attr| attr.has_name(sym::cfg))) +} + +/// Similar to [`clippy_utils::expr_or_init`], but does not go up the chain if the initialization +/// value depends on a `#[cfg(…)]` directive. +fn expr_or_init<'a, 'b, 'tcx: 'b>(cx: &LateContext<'tcx>, mut expr: &'a Expr<'b>) -> &'a Expr<'b> { + while let Some(init) = path_to_local(expr) + .and_then(|id| find_binding_init(cx, id)) + .filter(|init| cx.typeck_results().expr_adjustments(init).is_empty()) + .filter(|init| !is_under_cfg(cx, init.hir_id)) + { + expr = init; + } + expr +} diff --git a/clippy_lints/src/methods/iter_nth.rs b/clippy_lints/src/methods/iter_nth.rs index 121043104058f..5b0b70b4b9659 100644 --- a/clippy_lints/src/methods/iter_nth.rs +++ b/clippy_lints/src/methods/iter_nth.rs @@ -1,10 +1,10 @@ -use super::utils::derefs_to_slice; -use crate::methods::iter_nth_zero; -use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::ty::get_type_diagnostic_name; +use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::symbol::sym; +use rustc_span::Span; use super::ITER_NTH; @@ -12,28 +12,33 @@ pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, iter_recv: &'tcx hir::Expr<'tcx>, - nth_recv: &hir::Expr<'_>, - nth_arg: &hir::Expr<'_>, - is_mut: bool, -) { - let mut_str = if is_mut { "_mut" } else { "" }; - let caller_type = if derefs_to_slice(cx, iter_recv, cx.typeck_results().expr_ty(iter_recv)).is_some() { - "slice" - } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(iter_recv), sym::Vec) { - "`Vec`" - } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(iter_recv), sym::VecDeque) { - "`VecDeque`" - } else { - iter_nth_zero::check(cx, expr, nth_recv, nth_arg); - return; // caller is not a type that we want to lint + iter_method: &str, + iter_span: Span, + nth_span: Span, +) -> bool { + let caller_type = match get_type_diagnostic_name(cx, cx.typeck_results().expr_ty(iter_recv).peel_refs()) { + Some(sym::Vec) => "`Vec`", + Some(sym::VecDeque) => "`VecDeque`", + _ if cx.typeck_results().expr_ty_adjusted(iter_recv).peel_refs().is_slice() => "slice", + // caller is not a type that we want to lint + _ => return false, }; - span_lint_and_help( + span_lint_and_then( cx, ITER_NTH, expr.span, - &format!("called `.iter{mut_str}().nth()` on a {caller_type}"), - None, - &format!("calling `.get{mut_str}()` is both faster and more readable"), + &format!("called `.{iter_method}().nth()` on a {caller_type}"), + |diag| { + let get_method = if iter_method == "iter_mut" { "get_mut" } else { "get" }; + diag.span_suggestion_verbose( + iter_span.to(nth_span), + format!("`{get_method}` is equivalent but more concise"), + get_method, + Applicability::MachineApplicable, + ); + }, ); + + true } diff --git a/clippy_lints/src/methods/map_clone.rs b/clippy_lints/src/methods/map_clone.rs index 27e17b43b01cc..c3c7a3a003307 100644 --- a/clippy_lints/src/methods/map_clone.rs +++ b/clippy_lints/src/methods/map_clone.rs @@ -86,8 +86,11 @@ pub(super) fn check(cx: &LateContext<'_>, e: &hir::Expr<'_>, recv: &hir::Expr<'_ } } }, - hir::ExprKind::Call(call, [_]) => { - if let hir::ExprKind::Path(qpath) = call.kind { + hir::ExprKind::Call(call, args) => { + if let hir::ExprKind::Path(qpath) = call.kind + && let [arg] = args + && ident_eq(name, arg) + { handle_path(cx, call, &qpath, e, recv); } }, @@ -118,7 +121,9 @@ fn handle_path( if let ty::Adt(_, args) = cx.typeck_results().expr_ty(recv).kind() && let args = args.as_slice() && let Some(ty) = args.iter().find_map(|generic_arg| generic_arg.as_type()) - && ty.is_ref() + && let ty::Ref(_, ty, Mutability::Not) = ty.kind() + && let ty::FnDef(_, lst) = cx.typeck_results().expr_ty(arg).kind() + && lst.iter().all(|l| l.as_type() == Some(*ty)) { lint_path(cx, e.span, recv.span, is_copy(cx, ty.peel_refs())); } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 8a24ccea3a1eb..b6c474212cd4b 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -36,6 +36,7 @@ mod inefficient_to_string; mod inspect_for_each; mod into_iter_on_ref; mod is_digit_ascii_radix; +mod is_empty; mod iter_cloned_collect; mod iter_count; mod iter_filter; @@ -118,6 +119,7 @@ mod unnecessary_literal_unwrap; mod unnecessary_result_map_or_else; mod unnecessary_sort_by; mod unnecessary_to_owned; +mod unused_enumerate_index; mod unwrap_expect_used; mod useless_asref; mod utils; @@ -1235,12 +1237,11 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for usage of `.iter().nth()` (and the related - /// `.iter_mut().nth()`) on standard library types with *O*(1) element access. + /// Checks for usage of `.iter().nth()`/`.iter_mut().nth()` on standard library types that have + /// equivalent `.get()`/`.get_mut()` methods. /// /// ### Why is this bad? - /// `.get()` and `.get_mut()` are more efficient and more - /// readable. + /// `.get()` and `.get_mut()` are equivalent but more concise. /// /// ### Example /// ```no_run @@ -1256,7 +1257,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "pre 1.29.0"] pub ITER_NTH, - perf, + style, "using `.iter().nth()` on a standard library type with O(1) element access" } @@ -2848,7 +2849,7 @@ declare_clippy_lint! { /// the file is created from scratch, or ensure `truncate` is /// called so that the truncation behaviour is explicit. `truncate(true)` /// will ensure the file is entirely overwritten with new data, whereas - /// `truncate(false)` will explicitely keep the default behavior. + /// `truncate(false)` will explicitly keep the default behavior. /// /// ### Example /// ```rust,no_run @@ -2862,7 +2863,7 @@ declare_clippy_lint! { /// /// OpenOptions::new().create(true).truncate(true); /// ``` - #[clippy::version = "1.75.0"] + #[clippy::version = "1.77.0"] pub SUSPICIOUS_OPEN_OPTIONS, suspicious, "suspicious combination of options for opening a file" @@ -3182,8 +3183,8 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does /// - /// Checks an argument of `seek` method of `Seek` trait - /// and if it start seek from `SeekFrom::Current(0)`, suggests `stream_position` instead. + /// Checks if the `seek` method of the `Seek` trait is called with `SeekFrom::Current(0)`, + /// and if it is, suggests using `stream_position` instead. /// /// ### Why is this bad? /// @@ -3590,7 +3591,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.73.0"] pub READONLY_WRITE_LOCK, - nursery, + perf, "acquiring a write lock when a read lock would work" } @@ -3816,7 +3817,7 @@ declare_clippy_lint! { /// ```no_run /// let _ = std::iter::empty::>().flatten(); /// ``` - #[clippy::version = "1.76.0"] + #[clippy::version = "1.77.0"] pub RESULT_FILTER_MAP, complexity, "filtering `Result` for `Ok` then force-unwrapping, which can be one type-safe operation" @@ -3825,7 +3826,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does /// Checks for usage of `.filter(Option::is_some)` that may be replaced with a `.flatten()` call. - /// This lint will require additional changes to the follow-up calls as it appects the type. + /// This lint will require additional changes to the follow-up calls as it affects the type. /// /// ### Why is this bad? /// This pattern is often followed by manual unwrapping of the `Option`. The simplification @@ -3842,7 +3843,7 @@ declare_clippy_lint! { /// // example code which does not raise clippy warning /// vec![Some(1)].into_iter().flatten(); /// ``` - #[clippy::version = "1.76.0"] + #[clippy::version = "1.77.0"] pub ITER_FILTER_IS_SOME, pedantic, "filtering an iterator over `Option`s for `Some` can be achieved with `flatten`" @@ -3851,7 +3852,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does /// Checks for usage of `.filter(Result::is_ok)` that may be replaced with a `.flatten()` call. - /// This lint will require additional changes to the follow-up calls as it appects the type. + /// This lint will require additional changes to the follow-up calls as it affects the type. /// /// ### Why is this bad? /// This pattern is often followed by manual unwrapping of `Result`. The simplification @@ -3868,7 +3869,7 @@ declare_clippy_lint! { /// // example code which does not raise clippy warning /// vec![Ok::(1)].into_iter().flatten(); /// ``` - #[clippy::version = "1.76.0"] + #[clippy::version = "1.77.0"] pub ITER_FILTER_IS_OK, pedantic, "filtering an iterator over `Result`s for `Ok` can be achieved with `flatten`" @@ -3895,7 +3896,7 @@ declare_clippy_lint! { /// option.is_some_and(|a| a > 10); /// result.is_ok_and(|a| a > 10); /// ``` - #[clippy::version = "1.76.0"] + #[clippy::version = "1.77.0"] pub MANUAL_IS_VARIANT_AND, pedantic, "using `.map(f).unwrap_or_default()`, which is more succinctly expressed as `is_some_and(f)` or `is_ok_and(f)`" @@ -3925,7 +3926,7 @@ declare_clippy_lint! { /// `"\r\n"`), for example during the parsing of a specific file format in which precisely one newline type is /// valid. /// ``` - #[clippy::version = "1.76.0"] + #[clippy::version = "1.77.0"] pub STR_SPLIT_AT_NEWLINE, pedantic, "splitting a trimmed string at hard-coded newlines" @@ -4044,6 +4045,31 @@ declare_clippy_lint! { "calling `.get().is_some()` or `.get().is_none()` instead of `.contains()` or `.contains_key()`" } +declare_clippy_lint! { + /// ### What it does + /// It identifies calls to `.is_empty()` on constant values. + /// + /// ### Why is this bad? + /// String literals and constant values are known at compile time. Checking if they + /// are empty will always return the same value. This might not be the intention of + /// the expression. + /// + /// ### Example + /// ```no_run + /// let value = ""; + /// if value.is_empty() { + /// println!("the string is empty"); + /// } + /// ``` + /// Use instead: + /// ```no_run + /// println!("the string is empty"); + /// ``` + #[clippy::version = "1.78.0"] + pub CONST_IS_EMPTY, + suspicious, + "is_empty() called on strings known at compile time" +} pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, @@ -4092,6 +4118,7 @@ impl_lint_pass!(Methods => [ CLONE_ON_COPY, CLONE_ON_REF_PTR, COLLAPSIBLE_STR_REPLACE, + CONST_IS_EMPTY, ITER_OVEREAGER_CLONED, CLONED_INSTEAD_OF_COPIED, FLAT_MAP_OPTION, @@ -4403,6 +4430,7 @@ impl Methods { zst_offset::check(cx, expr, recv); }, ("all", [arg]) => { + unused_enumerate_index::check(cx, expr, recv, arg); if let Some(("cloned", recv2, [], _, _)) = method_call(recv) { iter_overeager_cloned::check( cx, @@ -4421,23 +4449,26 @@ impl Methods { unnecessary_lazy_eval::check(cx, expr, recv, arg, "and"); } }, - ("any", [arg]) => match method_call(recv) { - Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check( - cx, - expr, - recv, - recv2, - iter_overeager_cloned::Op::NeedlessMove(arg), - false, - ), - Some(("chars", recv, _, _, _)) - if let ExprKind::Closure(arg) = arg.kind - && let body = cx.tcx.hir().body(arg.body) - && let [param] = body.params => - { - string_lit_chars_any::check(cx, expr, recv, param, peel_blocks(body.value), &self.msrv); - }, - _ => {}, + ("any", [arg]) => { + unused_enumerate_index::check(cx, expr, recv, arg); + match method_call(recv) { + Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check( + cx, + expr, + recv, + recv2, + iter_overeager_cloned::Op::NeedlessMove(arg), + false, + ), + Some(("chars", recv, _, _, _)) + if let ExprKind::Closure(arg) = arg.kind + && let body = cx.tcx.hir().body(arg.body) + && let [param] = body.params => + { + string_lit_chars_any::check(cx, expr, recv, param, peel_blocks(body.value), &self.msrv); + }, + _ => {}, + } }, ("arg", [arg]) => { suspicious_command_arg_space::check(cx, recv, arg, span); @@ -4445,7 +4476,7 @@ impl Methods { ("as_deref" | "as_deref_mut", []) => { needless_option_as_deref::check(cx, expr, recv, name); }, - ("as_bytes" | "is_empty", []) => { + ("as_bytes", []) => { if let Some(("as_str", recv, [], as_str_span, _)) = method_call(recv) { redundant_as_str::check(cx, expr, recv, as_str_span, span); } @@ -4570,14 +4601,17 @@ impl Methods { } }, ("filter_map", [arg]) => { + unused_enumerate_index::check(cx, expr, recv, arg); unnecessary_filter_map::check(cx, expr, arg, name); filter_map_bool_then::check(cx, expr, arg, call_span); filter_map_identity::check(cx, expr, arg, span); }, ("find_map", [arg]) => { + unused_enumerate_index::check(cx, expr, recv, arg); unnecessary_filter_map::check(cx, expr, arg, name); }, ("flat_map", [arg]) => { + unused_enumerate_index::check(cx, expr, recv, arg); flat_map_identity::check(cx, expr, arg, span); flat_map_option::check(cx, expr, arg, span); }, @@ -4599,17 +4633,20 @@ impl Methods { manual_try_fold::check(cx, expr, init, acc, call_span, &self.msrv); unnecessary_fold::check(cx, expr, init, acc, span); }, - ("for_each", [arg]) => match method_call(recv) { - Some(("inspect", _, [_], span2, _)) => inspect_for_each::check(cx, expr, span2), - Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check( - cx, - expr, - recv, - recv2, - iter_overeager_cloned::Op::NeedlessMove(arg), - false, - ), - _ => {}, + ("for_each", [arg]) => { + unused_enumerate_index::check(cx, expr, recv, arg); + match method_call(recv) { + Some(("inspect", _, [_], span2, _)) => inspect_for_each::check(cx, expr, span2), + Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check( + cx, + expr, + recv, + recv2, + iter_overeager_cloned::Op::NeedlessMove(arg), + false, + ), + _ => {}, + } }, ("get", [arg]) => { get_first::check(cx, expr, recv, arg); @@ -4619,6 +4656,12 @@ impl Methods { ("hash", [arg]) => { unit_hash::check(cx, expr, recv, arg); }, + ("is_empty", []) => { + if let Some(("as_str", recv, [], as_str_span, _)) = method_call(recv) { + redundant_as_str::check(cx, expr, recv, as_str_span, span); + } + is_empty::check(cx, expr, recv); + }, ("is_file", []) => filetype_is_file::check(cx, expr, recv), ("is_digit", [radix]) => is_digit_ascii_radix::check(cx, expr, recv, radix, &self.msrv), ("is_none", []) => check_is_some_is_none(cx, expr, recv, call_span, false), @@ -4650,6 +4693,7 @@ impl Methods { }, (name @ ("map" | "map_err"), [m_arg]) => { if name == "map" { + unused_enumerate_index::check(cx, expr, recv, m_arg); map_clone::check(cx, expr, recv, m_arg, &self.msrv); match method_call(recv) { Some((map_name @ ("iter" | "into_iter"), recv2, _, _, _)) => { @@ -4723,8 +4767,11 @@ impl Methods { iter_overeager_cloned::Op::LaterCloned, false, ), - Some(("iter", recv2, [], _, _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, false), - Some(("iter_mut", recv2, [], _, _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, true), + Some((iter_method @ ("iter" | "iter_mut"), iter_recv, [], iter_span, _)) => { + if !iter_nth::check(cx, expr, iter_recv, iter_method, iter_span, span) { + iter_nth_zero::check(cx, expr, recv, n_arg); + } + }, _ => iter_nth_zero::check(cx, expr, recv, n_arg), }, ("ok_or_else", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or"), diff --git a/clippy_lints/src/methods/no_effect_replace.rs b/clippy_lints/src/methods/no_effect_replace.rs index 81df32bdee2bc..a301a5f7d65be 100644 --- a/clippy_lints/src/methods/no_effect_replace.rs +++ b/clippy_lints/src/methods/no_effect_replace.rs @@ -25,6 +25,7 @@ pub(super) fn check<'tcx>( && param1 == param2.as_str() { span_lint(cx, NO_EFFECT_REPLACE, expr.span, "replacing text with itself"); + return; } if SpanlessEq::new(cx).eq_expr(arg1, arg2) { diff --git a/clippy_lints/src/methods/unused_enumerate_index.rs b/clippy_lints/src/methods/unused_enumerate_index.rs new file mode 100644 index 0000000000000..e5cc898612e9a --- /dev/null +++ b/clippy_lints/src/methods/unused_enumerate_index.rs @@ -0,0 +1,135 @@ +use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_hir_and_then}; +use clippy_utils::paths::{CORE_ITER_ENUMERATE_METHOD, CORE_ITER_ENUMERATE_STRUCT}; +use clippy_utils::source::{snippet, snippet_opt}; +use clippy_utils::{expr_or_init, is_trait_method, match_def_path, pat_is_wild}; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind, FnDecl, PatKind, TyKind}; +use rustc_lint::LateContext; +use rustc_middle::ty::AdtDef; +use rustc_span::{sym, Span}; + +use crate::loops::UNUSED_ENUMERATE_INDEX; + +/// Check for the `UNUSED_ENUMERATE_INDEX` lint outside of loops. +/// +/// The lint is declared in `clippy_lints/src/loops/mod.rs`. There, the following pattern is +/// checked: +/// ```ignore +/// for (_, x) in some_iter.enumerate() { +/// // Index is ignored +/// } +/// ``` +/// +/// This `check` function checks for chained method calls constructs where we can detect that the +/// index is unused. Currently, this checks only for the following patterns: +/// ```ignore +/// some_iter.enumerate().map_function(|(_, x)| ..) +/// let x = some_iter.enumerate(); +/// x.map_function(|(_, x)| ..) +/// ``` +/// where `map_function` is one of `all`, `any`, `filter_map`, `find_map`, `flat_map`, `for_each` or +/// `map`. +/// +/// # Preconditions +/// This function must be called not on the `enumerate` call expression itself, but on any of the +/// map functions listed above. It will ensure that `recv` is a `std::iter::Enumerate` instance and +/// that the method call is one of the `std::iter::Iterator` trait. +/// +/// * `call_expr`: The map function call expression +/// * `recv`: The receiver of the call +/// * `closure_arg`: The argument to the map function call containing the closure/function to apply +pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>, closure_arg: &Expr<'_>) { + let recv_ty = cx.typeck_results().expr_ty(recv); + if let Some(recv_ty_defid) = recv_ty.ty_adt_def().map(AdtDef::did) + // If we call a method on a `std::iter::Enumerate` instance + && match_def_path(cx, recv_ty_defid, &CORE_ITER_ENUMERATE_STRUCT) + // If we are calling a method of the `Iterator` trait + && is_trait_method(cx, call_expr, sym::Iterator) + // And the map argument is a closure + && let ExprKind::Closure(closure) = closure_arg.kind + && let closure_body = cx.tcx.hir().body(closure.body) + // And that closure has one argument ... + && let [closure_param] = closure_body.params + // .. which is a tuple of 2 elements + && let PatKind::Tuple([index, elem], ..) = closure_param.pat.kind + // And that the first element (the index) is either `_` or unused in the body + && pat_is_wild(cx, &index.kind, closure_body) + // Try to find the initializer for `recv`. This is needed in case `recv` is a local_binding. In the + // first example below, `expr_or_init` would return `recv`. + // ``` + // iter.enumerate().map(|(_, x)| x) + // ^^^^^^^^^^^^^^^^ `recv`, a call to `std::iter::Iterator::enumerate` + // + // let binding = iter.enumerate(); + // ^^^^^^^^^^^^^^^^ `recv_init_expr` + // binding.map(|(_, x)| x) + // ^^^^^^^ `recv`, not a call to `std::iter::Iterator::enumerate` + // ``` + && let recv_init_expr = expr_or_init(cx, recv) + // Make sure the initializer is a method call. It may be that the `Enumerate` comes from something + // that we cannot control. + // This would for instance happen with: + // ``` + // external_lib::some_function_returning_enumerate().map(|(_, x)| x) + // ``` + && let ExprKind::MethodCall(_, enumerate_recv, _, enumerate_span) = recv_init_expr.kind + && let Some(enumerate_defid) = cx.typeck_results().type_dependent_def_id(recv_init_expr.hir_id) + // Make sure the method call is `std::iter::Iterator::enumerate`. + && match_def_path(cx, enumerate_defid, &CORE_ITER_ENUMERATE_METHOD) + { + // Check if the tuple type was explicit. It may be the type system _needs_ the type of the element + // that would be explicited in the closure. + let new_closure_param = match find_elem_explicit_type_span(closure.fn_decl) { + // We have an explicit type. Get its snippet, that of the binding name, and do `binding: ty`. + // Fallback to `..` if we fail getting either snippet. + Some(ty_span) => snippet_opt(cx, elem.span) + .and_then(|binding_name| snippet_opt(cx, ty_span).map(|ty_name| format!("{binding_name}: {ty_name}"))) + .unwrap_or_else(|| "..".to_string()), + // Otherwise, we have no explicit type. We can replace with the binding name of the element. + None => snippet(cx, elem.span, "..").into_owned(), + }; + + // Suggest removing the tuple from the closure and the preceding call to `enumerate`, whose span we + // can get from the `MethodCall`. + span_lint_hir_and_then( + cx, + UNUSED_ENUMERATE_INDEX, + recv_init_expr.hir_id, + enumerate_span, + "you seem to use `.enumerate()` and immediately discard the index", + |diag| { + multispan_sugg_with_applicability( + diag, + "remove the `.enumerate()` call", + Applicability::MachineApplicable, + vec![ + (closure_param.span, new_closure_param), + ( + enumerate_span.with_lo(enumerate_recv.span.source_callsite().hi()), + String::new(), + ), + ], + ); + }, + ); + } +} + +/// Find the span of the explicit type of the element. +/// +/// # Returns +/// If the tuple argument: +/// * Has no explicit type, returns `None` +/// * Has an explicit tuple type with an implicit element type (`(usize, _)`), returns `None` +/// * Has an explicit tuple type with an explicit element type (`(_, i32)`), returns the span for +/// the element type. +fn find_elem_explicit_type_span(fn_decl: &FnDecl<'_>) -> Option { + if let [tuple_ty] = fn_decl.inputs + && let TyKind::Tup([_idx_ty, elem_ty]) = tuple_ty.kind + && !matches!(elem_ty.kind, TyKind::Err(..) | TyKind::Infer) + { + Some(elem_ty.span) + } else { + None + } +} diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index bf4af7946f470..6878fb3349d4a 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -8,6 +8,7 @@ use clippy_utils::attrs::is_doc_hidden; use clippy_utils::diagnostics::span_lint; use clippy_utils::is_from_proc_macro; +use clippy_utils::source::snippet_opt; use rustc_ast::ast::{self, MetaItem, MetaItemKind}; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; @@ -32,6 +33,13 @@ declare_clippy_lint! { "detects missing documentation for private members" } +macro_rules! note_prev_span_then_ret { + ($prev_span:expr, $span:expr) => {{ + $prev_span = Some($span); + return; + }}; +} + pub struct MissingDoc { /// Whether to **only** check for missing documentation in items visible within the current /// crate. For example, `pub(crate)` items. @@ -39,6 +47,8 @@ pub struct MissingDoc { /// Stack of whether #[doc(hidden)] is set /// at each level which has lint attributes. doc_hidden_stack: Vec, + /// Used to keep tracking of the previous item, field or variants etc, to get the search span. + prev_span: Option, } impl Default for MissingDoc { @@ -54,6 +64,7 @@ impl MissingDoc { Self { crate_items_only, doc_hidden_stack: vec![false], + prev_span: None, } } @@ -108,7 +119,8 @@ impl MissingDoc { let has_doc = attrs .iter() - .any(|a| a.doc_str().is_some() || Self::has_include(a.meta())); + .any(|a| a.doc_str().is_some() || Self::has_include(a.meta())) + || matches!(self.search_span(sp), Some(span) if span_to_snippet_contains_docs(cx, span)); if !has_doc { span_lint( @@ -119,6 +131,32 @@ impl MissingDoc { ); } } + + /// Return a span to search for doc comments manually. + /// + /// # Example + /// ```ignore + /// fn foo() { ... } + /// ^^^^^^^^^^^^^^^^ prev_span + /// ↑ + /// | search_span | + /// ↓ + /// fn bar() { ... } + /// ^^^^^^^^^^^^^^^^ cur_span + /// ``` + fn search_span(&self, cur_span: Span) -> Option { + let prev_span = self.prev_span?; + let start_pos = if prev_span.contains(cur_span) { + // In case when the prev_span is an entire struct, or enum, + // and the current span is a field, or variant, we need to search from + // the starting pos of the previous span. + prev_span.lo() + } else { + prev_span.hi() + }; + let search_span = cur_span.with_lo(start_pos).with_hi(cur_span.lo()); + Some(search_span) + } } impl_lint_pass!(MissingDoc => [MISSING_DOCS_IN_PRIVATE_ITEMS]); @@ -138,6 +176,10 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { self.check_missing_docs_attrs(cx, CRATE_DEF_ID, attrs, cx.tcx.def_span(CRATE_DEF_ID), "the", "crate"); } + fn check_crate_post(&mut self, _: &LateContext<'tcx>) { + self.prev_span = None; + } + fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) { match it.kind { hir::ItemKind::Fn(..) => { @@ -145,7 +187,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { if it.ident.name == sym::main { let at_root = cx.tcx.local_parent(it.owner_id.def_id) == CRATE_DEF_ID; if at_root { - return; + note_prev_span_then_ret!(self.prev_span, it.span); } } }, @@ -164,7 +206,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { | hir::ItemKind::ForeignMod { .. } | hir::ItemKind::GlobalAsm(..) | hir::ItemKind::Impl { .. } - | hir::ItemKind::Use(..) => return, + | hir::ItemKind::Use(..) => note_prev_span_then_ret!(self.prev_span, it.span), }; let (article, desc) = cx.tcx.article_and_description(it.owner_id.to_def_id()); @@ -173,6 +215,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { if !is_from_proc_macro(cx, it) { self.check_missing_docs_attrs(cx, it.owner_id.def_id, attrs, it.span, article, desc); } + self.prev_span = Some(it.span); } fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx hir::TraitItem<'_>) { @@ -182,16 +225,17 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { if !is_from_proc_macro(cx, trait_item) { self.check_missing_docs_attrs(cx, trait_item.owner_id.def_id, attrs, trait_item.span, article, desc); } + self.prev_span = Some(trait_item.span); } fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) { // If the method is an impl for a trait, don't doc. if let Some(cid) = cx.tcx.associated_item(impl_item.owner_id).impl_container(cx.tcx) { if cx.tcx.impl_trait_ref(cid).is_some() { - return; + note_prev_span_then_ret!(self.prev_span, impl_item.span); } } else { - return; + note_prev_span_then_ret!(self.prev_span, impl_item.span); } let (article, desc) = cx.tcx.article_and_description(impl_item.owner_id.to_def_id()); @@ -199,6 +243,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { if !is_from_proc_macro(cx, impl_item) { self.check_missing_docs_attrs(cx, impl_item.owner_id.def_id, attrs, impl_item.span, article, desc); } + self.prev_span = Some(impl_item.span); } fn check_field_def(&mut self, cx: &LateContext<'tcx>, sf: &'tcx hir::FieldDef<'_>) { @@ -208,6 +253,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { self.check_missing_docs_attrs(cx, sf.def_id, attrs, sf.span, "a", "struct field"); } } + self.prev_span = Some(sf.span); } fn check_variant(&mut self, cx: &LateContext<'tcx>, v: &'tcx hir::Variant<'_>) { @@ -215,5 +261,13 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { if !is_from_proc_macro(cx, v) { self.check_missing_docs_attrs(cx, v.def_id, attrs, v.span, "a", "variant"); } + self.prev_span = Some(v.span); } } + +fn span_to_snippet_contains_docs(cx: &LateContext<'_>, search_span: Span) -> bool { + let Some(snippet) = snippet_opt(cx, search_span) else { + return false; + }; + snippet.lines().rev().any(|line| line.trim().starts_with("///")) +} diff --git a/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/clippy_lints/src/multiple_unsafe_ops_per_block.rs index 70fd07cd93ce8..648d780ac0939 100644 --- a/clippy_lints/src/multiple_unsafe_ops_per_block.rs +++ b/clippy_lints/src/multiple_unsafe_ops_per_block.rs @@ -109,7 +109,14 @@ fn collect_unsafe_exprs<'tcx>( ExprKind::Path(QPath::Resolved( _, hir::Path { - res: Res::Def(DefKind::Static{mutability:Mutability::Mut, ..}, _), + res: + Res::Def( + DefKind::Static { + mutability: Mutability::Mut, + .. + }, + _, + ), .. }, )) => { @@ -149,7 +156,13 @@ fn collect_unsafe_exprs<'tcx>( ExprKind::Path(QPath::Resolved( _, hir::Path { - res: Res::Def(DefKind::Static{mutability:Mutability::Mut, ..}, _), + res: Res::Def( + DefKind::Static { + mutability: Mutability::Mut, + .. + }, + _ + ), .. } )) diff --git a/clippy_lints/src/mut_mut.rs b/clippy_lints/src/mut_mut.rs index 72a2cca1e4024..bc7b2c6b7c1b8 100644 --- a/clippy_lints/src/mut_mut.rs +++ b/clippy_lints/src/mut_mut.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::span_lint; +use clippy_utils::diagnostics::{span_lint, span_lint_hir}; use clippy_utils::higher; use rustc_hir as hir; use rustc_hir::intravisit; @@ -35,9 +35,34 @@ impl<'tcx> LateLintPass<'tcx> for MutMut { } fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx hir::Ty<'_>) { - use rustc_hir::intravisit::Visitor; + if in_external_macro(cx.sess(), ty.span) { + return; + } - MutVisitor { cx }.visit_ty(ty); + if let hir::TyKind::Ref( + _, + hir::MutTy { + ty: pty, + mutbl: hir::Mutability::Mut, + }, + ) = ty.kind + { + if let hir::TyKind::Ref( + _, + hir::MutTy { + mutbl: hir::Mutability::Mut, + .. + }, + ) = pty.kind + { + span_lint( + cx, + MUT_MUT, + ty.span, + "generally you want to avoid `&mut &mut _` if possible", + ); + } + } } } @@ -62,17 +87,19 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for MutVisitor<'a, 'tcx> { intravisit::walk_expr(self, body); } else if let hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Mut, e) = expr.kind { if let hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Mut, _) = e.kind { - span_lint( + span_lint_hir( self.cx, MUT_MUT, + expr.hir_id, expr.span, "generally you want to avoid `&mut &mut _` if possible", ); } else if let ty::Ref(_, ty, hir::Mutability::Mut) = self.cx.typeck_results().expr_ty(e).kind() { if ty.peel_refs().is_sized(self.cx.tcx, self.cx.param_env) { - span_lint( + span_lint_hir( self.cx, MUT_MUT, + expr.hir_id, expr.span, "this expression mutably borrows a mutable reference. Consider reborrowing", ); @@ -80,37 +107,4 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for MutVisitor<'a, 'tcx> { } } } - - fn visit_ty(&mut self, ty: &'tcx hir::Ty<'_>) { - if in_external_macro(self.cx.sess(), ty.span) { - return; - } - - if let hir::TyKind::Ref( - _, - hir::MutTy { - ty: pty, - mutbl: hir::Mutability::Mut, - }, - ) = ty.kind - { - if let hir::TyKind::Ref( - _, - hir::MutTy { - mutbl: hir::Mutability::Mut, - .. - }, - ) = pty.kind - { - span_lint( - self.cx, - MUT_MUT, - ty.span, - "generally you want to avoid `&mut &mut _` if possible", - ); - } - } - - intravisit::walk_ty(self, ty); - } } diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index cebd23856565d..6cb84bb78b6d6 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -290,14 +290,21 @@ impl NonCopyConst { promoted: None, }; let param_env = cx.tcx.param_env(def_id).with_reveal_all_normalized(cx.tcx); - let result = cx.tcx.const_eval_global_id_for_typeck(param_env, cid, rustc_span::DUMMY_SP); + let result = cx + .tcx + .const_eval_global_id_for_typeck(param_env, cid, rustc_span::DUMMY_SP); self.is_value_unfrozen_raw(cx, result, ty) } fn is_value_unfrozen_expr<'tcx>(&self, cx: &LateContext<'tcx>, hir_id: HirId, def_id: DefId, ty: Ty<'tcx>) -> bool { let args = cx.typeck_results().node_args(hir_id); - let result = Self::const_eval_resolve(cx.tcx, cx.param_env, ty::UnevaluatedConst::new(def_id, args), rustc_span::DUMMY_SP); + let result = Self::const_eval_resolve( + cx.tcx, + cx.param_env, + ty::UnevaluatedConst::new(def_id, args), + rustc_span::DUMMY_SP, + ); self.is_value_unfrozen_raw(cx, result, ty) } diff --git a/clippy_lints/src/read_zero_byte_vec.rs b/clippy_lints/src/read_zero_byte_vec.rs index d0b37cd92e002..0ebdb031d5a18 100644 --- a/clippy_lints/src/read_zero_byte_vec.rs +++ b/clippy_lints/src/read_zero_byte_vec.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; +use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then}; use clippy_utils::get_enclosing_block; use clippy_utils::higher::{get_vec_init_kind, VecInitKind}; use clippy_utils::source::snippet; @@ -77,37 +77,53 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec { if let Some(expr) = visitor.read_zero_expr { let applicability = Applicability::MaybeIncorrect; match vec_init_kind { - VecInitKind::WithConstCapacity(len) => { - span_lint_and_sugg( + VecInitKind::WithConstCapacity(len) => span_lint_hir_and_then( + cx, + READ_ZERO_BYTE_VEC, + expr.hir_id, + expr.span, + "reading zero byte data to `Vec`", + |diag| { + diag.span_suggestion( + expr.span, + "try", + format!("{}.resize({len}, 0); {}", ident.as_str(), snippet(cx, expr.span, "..")), + applicability, + ); + }, + ), + VecInitKind::WithExprCapacity(hir_id) => { + let e = cx.tcx.hir().expect_expr(hir_id); + span_lint_hir_and_then( cx, READ_ZERO_BYTE_VEC, + expr.hir_id, expr.span, "reading zero byte data to `Vec`", - "try", - format!("{}.resize({len}, 0); {}", ident.as_str(), snippet(cx, expr.span, "..")), - applicability, + |diag| { + diag.span_suggestion( + expr.span, + "try", + format!( + "{}.resize({}, 0); {}", + ident.as_str(), + snippet(cx, e.span, ".."), + snippet(cx, expr.span, "..") + ), + applicability, + ); + }, ); }, - VecInitKind::WithExprCapacity(hir_id) => { - let e = cx.tcx.hir().expect_expr(hir_id); - span_lint_and_sugg( + _ => { + span_lint_hir( cx, READ_ZERO_BYTE_VEC, + expr.hir_id, expr.span, "reading zero byte data to `Vec`", - "try", - format!( - "{}.resize({}, 0); {}", - ident.as_str(), - snippet(cx, e.span, ".."), - snippet(cx, expr.span, "..") - ), - applicability, ); }, - _ => { - span_lint(cx, READ_ZERO_BYTE_VEC, expr.span, "reading zero byte data to `Vec`"); - }, } } } diff --git a/clippy_lints/src/redundant_closure_call.rs b/clippy_lints/src/redundant_closure_call.rs index c2673bc409fa8..435899ddaa788 100644 --- a/clippy_lints/src/redundant_closure_call.rs +++ b/clippy_lints/src/redundant_closure_call.rs @@ -1,5 +1,5 @@ use crate::rustc_lint::LintContext; -use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; +use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir}; use clippy_utils::get_parent_expr; use clippy_utils::sugg::Sugg; use hir::Param; @@ -273,9 +273,10 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { && ident == path.segments[0].ident && count_closure_usage(cx, block, path) == 1 { - span_lint( + span_lint_hir( cx, REDUNDANT_CLOSURE_CALL, + second.hir_id, second.span, "closure called just once immediately after it was declared", ); diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index 196975274674e..8bc24eda46597 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then, span_lint_hir_and_then}; +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; use clippy_utils::source::{snippet_opt, snippet_with_context}; use clippy_utils::sugg::has_enclosing_paren; use clippy_utils::visitors::{for_each_expr_with_closures, Descend}; @@ -380,7 +380,7 @@ fn check_final_expr<'tcx>( return; } - emit_return_lint(cx, ret_span, semi_spans, &replacement); + emit_return_lint(cx, ret_span, semi_spans, &replacement, expr.hir_id); }, ExprKind::If(_, then, else_clause_opt) => { check_block_return(cx, &then.kind, peeled_drop_expr.span, semi_spans.clone()); @@ -415,18 +415,31 @@ fn expr_contains_conjunctive_ifs<'tcx>(expr: &'tcx Expr<'tcx>) -> bool { contains_if(expr, false) } -fn emit_return_lint(cx: &LateContext<'_>, ret_span: Span, semi_spans: Vec, replacement: &RetReplacement<'_>) { +fn emit_return_lint( + cx: &LateContext<'_>, + ret_span: Span, + semi_spans: Vec, + replacement: &RetReplacement<'_>, + at: HirId, +) { if ret_span.from_expansion() { return; } - span_lint_and_then(cx, NEEDLESS_RETURN, ret_span, "unneeded `return` statement", |diag| { - let suggestions = std::iter::once((ret_span, replacement.to_string())) - .chain(semi_spans.into_iter().map(|span| (span, String::new()))) - .collect(); + span_lint_hir_and_then( + cx, + NEEDLESS_RETURN, + at, + ret_span, + "unneeded `return` statement", + |diag| { + let suggestions = std::iter::once((ret_span, replacement.to_string())) + .chain(semi_spans.into_iter().map(|span| (span, String::new()))) + .collect(); - diag.multipart_suggestion_verbose(replacement.sugg_help(), suggestions, replacement.applicability()); - }); + diag.multipart_suggestion_verbose(replacement.sugg_help(), suggestions, replacement.applicability()); + }, + ); } fn last_statement_borrows<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { @@ -452,8 +465,8 @@ fn last_statement_borrows<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) // Go backwards while encountering whitespace and extend the given Span to that point. fn extend_span_to_previous_non_ws(cx: &LateContext<'_>, sp: Span) -> Span { if let Ok(prev_source) = cx.sess().source_map().span_to_prev_source(sp) { - let ws = [' ', '\t', '\n']; - if let Some(non_ws_pos) = prev_source.rfind(|c| !ws.contains(&c)) { + let ws = [b' ', b'\t', b'\n']; + if let Some(non_ws_pos) = prev_source.bytes().rposition(|c| !ws.contains(&c)) { let len = prev_source.len() - non_ws_pos - 1; return sp.with_lo(sp.lo() - BytePos::from_usize(len)); } diff --git a/clippy_lints/src/std_instead_of_core.rs b/clippy_lints/src/std_instead_of_core.rs index c0e4f3c368a8d..cf839941123d1 100644 --- a/clippy_lints/src/std_instead_of_core.rs +++ b/clippy_lints/src/std_instead_of_core.rs @@ -109,6 +109,7 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports { sym::core => (STD_INSTEAD_OF_CORE, "std", "core"), sym::alloc => (STD_INSTEAD_OF_ALLOC, "std", "alloc"), _ => { + self.prev_span = first_segment.ident.span; return; }, }, @@ -116,6 +117,7 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports { if cx.tcx.crate_name(def_id.krate) == sym::core { (ALLOC_INSTEAD_OF_CORE, "alloc", "core") } else { + self.prev_span = first_segment.ident.span; return; } }, diff --git a/clippy_lints/src/thread_local_initializer_can_be_made_const.rs b/clippy_lints/src/thread_local_initializer_can_be_made_const.rs index 1af3733ebfa4b..f8bdb866ca391 100644 --- a/clippy_lints/src/thread_local_initializer_can_be_made_const.rs +++ b/clippy_lints/src/thread_local_initializer_can_be_made_const.rs @@ -37,7 +37,7 @@ declare_clippy_lint! { /// static BUF: String = const { String::new() }; /// } /// ``` - #[clippy::version = "1.76.0"] + #[clippy::version = "1.77.0"] pub THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST, perf, "suggest using `const` in `thread_local!` macro" diff --git a/clippy_lints/src/transmute/mod.rs b/clippy_lints/src/transmute/mod.rs index e47b14bf63b21..3c11b48131051 100644 --- a/clippy_lints/src/transmute/mod.rs +++ b/clippy_lints/src/transmute/mod.rs @@ -514,7 +514,7 @@ declare_clippy_lint! { /// ^^^^ ^^ `bool::then` only executes the closure if the condition is true! /// } /// ``` - #[clippy::version = "1.76.0"] + #[clippy::version = "1.77.0"] pub EAGER_TRANSMUTE, correctness, "eager evaluation of `transmute`" diff --git a/clippy_lints/src/types/mod.rs b/clippy_lints/src/types/mod.rs index bdef82e9c5eed..2ad15ac8312d9 100644 --- a/clippy_lints/src/types/mod.rs +++ b/clippy_lints/src/types/mod.rs @@ -392,6 +392,10 @@ impl<'tcx> LateLintPass<'tcx> for Types { } fn check_field_def(&mut self, cx: &LateContext<'tcx>, field: &hir::FieldDef<'tcx>) { + if field.span.from_expansion() { + return; + } + let is_exported = cx.effective_visibilities.is_exported(field.def_id); self.check_ty( diff --git a/clippy_lints/src/unconditional_recursion.rs b/clippy_lints/src/unconditional_recursion.rs index 224ec475c5107..d638af2b78b36 100644 --- a/clippy_lints/src/unconditional_recursion.rs +++ b/clippy_lints/src/unconditional_recursion.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::{expr_or_init, get_trait_def_id, path_def_id}; +use clippy_utils::{expr_or_init, fn_def_id_with_node_args, path_def_id}; use rustc_ast::BinOpKind; use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; @@ -19,11 +19,11 @@ use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor; declare_clippy_lint! { /// ### What it does - /// Checks that there isn't an infinite recursion in `PartialEq` trait - /// implementation. + /// Checks that there isn't an infinite recursion in trait + /// implementations. /// /// ### Why is this bad? - /// This is a hard to find infinite recursion which will crashing any code + /// This is a hard to find infinite recursion that will crash any code. /// using it. /// /// ### Example @@ -42,7 +42,7 @@ declare_clippy_lint! { /// Use instead: /// /// In such cases, either use `#[derive(PartialEq)]` or don't implement it. - #[clippy::version = "1.76.0"] + #[clippy::version = "1.77.0"] pub UNCONDITIONAL_RECURSION, suspicious, "detect unconditional recursion in some traits implementation" @@ -201,7 +201,6 @@ fn check_partial_eq(cx: &LateContext<'_>, method_span: Span, method_def_id: Loca } } -#[allow(clippy::unnecessary_def_path)] fn check_to_string(cx: &LateContext<'_>, method_span: Span, method_def_id: LocalDefId, name: Ident, expr: &Expr<'_>) { let args = cx .tcx @@ -224,7 +223,7 @@ fn check_to_string(cx: &LateContext<'_>, method_span: Span, method_def_id: Local && let Some(trait_) = impl_.of_trait && let Some(trait_def_id) = trait_.trait_def_id() // The trait is `ToString`. - && Some(trait_def_id) == get_trait_def_id(cx, &["alloc", "string", "ToString"]) + && cx.tcx.is_diagnostic_item(sym::ToString, trait_def_id) { let is_bad = match expr.kind { ExprKind::MethodCall(segment, _receiver, &[_arg], _) if segment.ident.name == name.name => { @@ -291,7 +290,6 @@ where self.map } - #[allow(clippy::unnecessary_def_path)] fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { if self.found_default_call { return; @@ -303,7 +301,7 @@ where && is_default_method_on_current_ty(self.cx.tcx, qpath, self.implemented_ty_id) && let Some(method_def_id) = path_def_id(self.cx, f) && let Some(trait_def_id) = self.cx.tcx.trait_of_item(method_def_id) - && Some(trait_def_id) == get_trait_def_id(self.cx, &["core", "default", "Default"]) + && self.cx.tcx.is_diagnostic_item(sym::Default, trait_def_id) { self.found_default_call = true; span_error(self.cx, self.method_span, expr); @@ -312,10 +310,9 @@ where } impl UnconditionalRecursion { - #[allow(clippy::unnecessary_def_path)] fn init_default_impl_for_type_if_needed(&mut self, cx: &LateContext<'_>) { if self.default_impl_for_type.is_empty() - && let Some(default_trait_id) = get_trait_def_id(cx, &["core", "default", "Default"]) + && let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default) { let impls = cx.tcx.trait_impls_of(default_trait_id); for (ty, impl_def_ids) in impls.non_blanket_impls() { @@ -394,6 +391,34 @@ impl UnconditionalRecursion { } } +fn check_from(cx: &LateContext<'_>, method_span: Span, method_def_id: LocalDefId, expr: &Expr<'_>) { + let Some(sig) = cx + .typeck_results() + .liberated_fn_sigs() + .get(cx.tcx.local_def_id_to_hir_id(method_def_id)) + else { + return; + }; + + // Check if we are calling `Into::into` where the node args match with our `From::from` signature: + // From::from signature: fn(S1) -> S2 + // >::into(s1), node_args=[S1, S2] + // If they do match, then it must mean that it is the blanket impl, + // which calls back into our `From::from` again (`Into` is not specializable). + // rustc's unconditional_recursion already catches calling `From::from` directly + if let Some((fn_def_id, node_args)) = fn_def_id_with_node_args(cx, expr) + && let [s1, s2] = **node_args + && let (Some(s1), Some(s2)) = (s1.as_type(), s2.as_type()) + && let Some(trait_def_id) = cx.tcx.trait_of_item(fn_def_id) + && cx.tcx.is_diagnostic_item(sym::Into, trait_def_id) + && get_impl_trait_def_id(cx, method_def_id) == cx.tcx.get_diagnostic_item(sym::From) + && s1 == sig.inputs()[0] + && s2 == sig.output() + { + span_error(cx, method_span, expr); + } +} + impl<'tcx> LateLintPass<'tcx> for UnconditionalRecursion { fn check_fn( &mut self, @@ -410,10 +435,11 @@ impl<'tcx> LateLintPass<'tcx> for UnconditionalRecursion { // Doesn't have a conditional return. && !has_conditional_return(body, expr) { - if name.name == sym::eq || name.name == sym::ne { - check_partial_eq(cx, method_span, method_def_id, name, expr); - } else if name.name == sym::to_string { - check_to_string(cx, method_span, method_def_id, name, expr); + match name.name { + sym::eq | sym::ne => check_partial_eq(cx, method_span, method_def_id, name, expr), + sym::to_string => check_to_string(cx, method_span, method_def_id, name, expr), + sym::from => check_from(cx, method_span, method_def_id, expr), + _ => {}, } self.check_default_new(cx, decl, body, method_span, method_def_id); } diff --git a/clippy_lints/src/unused_io_amount.rs b/clippy_lints/src/unused_io_amount.rs index 1497d883dfc48..d8c5f1b7382db 100644 --- a/clippy_lints/src/unused_io_amount.rs +++ b/clippy_lints/src/unused_io_amount.rs @@ -1,7 +1,7 @@ -use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::macros::{is_panic, root_macro_call_first_node}; use clippy_utils::{is_res_lang_ctor, is_trait_method, match_trait_method, paths, peel_blocks}; -use hir::{ExprKind, PatKind}; +use hir::{ExprKind, HirId, PatKind}; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -135,22 +135,22 @@ fn check_expr<'a>(cx: &LateContext<'a>, expr: &'a hir::Expr<'a>) { && is_ok_wild_or_dotdot_pattern(cx, pat) && let Some(op) = should_lint(cx, init) => { - emit_lint(cx, cond.span, op, &[pat.span]); + emit_lint(cx, cond.span, cond.hir_id, op, &[pat.span]); }, // we will capture only the case where the match is Ok( ) or Err( ) // prefer to match the minimum possible, and expand later if needed // to avoid false positives on something as used as this hir::ExprKind::Match(expr, [arm1, arm2], hir::MatchSource::Normal) if let Some(op) = should_lint(cx, expr) => { if non_consuming_ok_arm(cx, arm1) && non_consuming_err_arm(cx, arm2) { - emit_lint(cx, expr.span, op, &[arm1.pat.span]); + emit_lint(cx, expr.span, expr.hir_id, op, &[arm1.pat.span]); } if non_consuming_ok_arm(cx, arm2) && non_consuming_err_arm(cx, arm1) { - emit_lint(cx, expr.span, op, &[arm2.pat.span]); + emit_lint(cx, expr.span, expr.hir_id, op, &[arm2.pat.span]); } }, hir::ExprKind::Match(_, _, hir::MatchSource::Normal) => {}, _ if let Some(op) = should_lint(cx, expr) => { - emit_lint(cx, expr.span, op, &[]); + emit_lint(cx, expr.span, expr.hir_id, op, &[]); }, _ => {}, }; @@ -279,7 +279,7 @@ fn check_io_mode(cx: &LateContext<'_>, call: &hir::Expr<'_>) -> Option { } } -fn emit_lint(cx: &LateContext<'_>, span: Span, op: IoOp, wild_cards: &[Span]) { +fn emit_lint(cx: &LateContext<'_>, span: Span, at: HirId, op: IoOp, wild_cards: &[Span]) { let (msg, help) = match op { IoOp::AsyncRead(false) => ( "read amount is not handled", @@ -301,7 +301,7 @@ fn emit_lint(cx: &LateContext<'_>, span: Span, op: IoOp, wild_cards: &[Span]) { IoOp::SyncWrite(true) | IoOp::AsyncWrite(true) => ("written amount is not handled", None), }; - span_lint_and_then(cx, UNUSED_IO_AMOUNT, span, msg, |diag| { + span_lint_hir_and_then(cx, UNUSED_IO_AMOUNT, at, span, msg, |diag| { if let Some(help_str) = help { diag.help(help_str); } diff --git a/clippy_lints/src/unused_peekable.rs b/clippy_lints/src/unused_peekable.rs index f1d0c22b1aec1..3f4ab3e31cfe7 100644 --- a/clippy_lints/src/unused_peekable.rs +++ b/clippy_lints/src/unused_peekable.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::ty::{is_type_diagnostic_item, peel_mid_ty_refs_is_mutable}; use clippy_utils::{fn_def_id, is_trait_method, path_to_local_id, peel_ref_operators}; use rustc_ast::Mutability; @@ -79,13 +79,15 @@ impl<'tcx> LateLintPass<'tcx> for UnusedPeekable { } if !vis.found_peek_call { - span_lint_and_help( + span_lint_hir_and_then( cx, UNUSED_PEEKABLE, + local.hir_id, ident.span, "`peek` never called on `Peekable` iterator", - None, - "consider removing the call to `peekable`", + |diag| { + diag.help("consider removing the call to `peekable`"); + }, ); } } diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index a1b08d105b9d9..b28037db1121e 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -8,11 +8,12 @@ use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{walk_inf, walk_ty, Visitor}; use rustc_hir::{ - self as hir, Expr, ExprKind, FnRetTy, FnSig, GenericArg, GenericArgsParentheses, GenericParam, GenericParamKind, - HirId, Impl, ImplItemKind, Item, ItemKind, Pat, PatKind, Path, QPath, Ty, TyKind, + self as hir, Expr, ExprKind, FnRetTy, FnSig, GenericArgsParentheses, GenericParam, GenericParamKind, HirId, Impl, + ImplItemKind, Item, ItemKind, Pat, PatKind, Path, QPath, Ty, TyKind, }; use rustc_hir_analysis::hir_ty_to_ty; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::Ty as MiddleTy; use rustc_session::impl_lint_pass; use rustc_span::Span; @@ -95,10 +96,9 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { let stack_item = if let ItemKind::Impl(Impl { self_ty, generics, .. }) = item.kind && let TyKind::Path(QPath::Resolved(_, item_path)) = self_ty.kind && let parameters = &item_path.segments.last().expect(SEGMENTS_MSG).args - && parameters.as_ref().map_or(true, |params| { - params.parenthesized == GenericArgsParentheses::No - && !params.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_))) - }) + && parameters + .as_ref() + .map_or(true, |params| params.parenthesized == GenericArgsParentheses::No) && !item.span.from_expansion() && !is_from_proc_macro(cx, item) // expensive, should be last check @@ -226,7 +226,12 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { } else { hir_ty_to_ty(cx.tcx, hir_ty) } - && same_type_and_consts(ty, cx.tcx.type_of(impl_id).instantiate_identity()) + && let impl_ty = cx.tcx.type_of(impl_id).instantiate_identity() + && same_type_and_consts(ty, impl_ty) + // Ensure the type we encounter and the one from the impl have the same lifetime parameters. It may be that + // the lifetime parameters of `ty` are ellided (`impl<'a> Foo<'a> { fn new() -> Self { Foo{..} } }`, in + // which case we must still trigger the lint. + && (has_no_lifetime(ty) || same_lifetimes(ty, impl_ty)) { span_lint(cx, hir_ty.span); } @@ -318,3 +323,37 @@ fn lint_path_to_variant(cx: &LateContext<'_>, path: &Path<'_>) { span_lint(cx, span); } } + +/// Returns `true` if types `a` and `b` have the same lifetime parameters, otherwise returns +/// `false`. +/// +/// This function does not check that types `a` and `b` are the same types. +fn same_lifetimes<'tcx>(a: MiddleTy<'tcx>, b: MiddleTy<'tcx>) -> bool { + use rustc_middle::ty::{Adt, GenericArgKind}; + match (&a.kind(), &b.kind()) { + (&Adt(_, args_a), &Adt(_, args_b)) => { + args_a + .iter() + .zip(args_b.iter()) + .all(|(arg_a, arg_b)| match (arg_a.unpack(), arg_b.unpack()) { + // TODO: Handle inferred lifetimes + (GenericArgKind::Lifetime(inner_a), GenericArgKind::Lifetime(inner_b)) => inner_a == inner_b, + (GenericArgKind::Type(type_a), GenericArgKind::Type(type_b)) => same_lifetimes(type_a, type_b), + _ => true, + }) + }, + _ => a == b, + } +} + +/// Returns `true` if `ty` has no lifetime parameter, otherwise returns `false`. +fn has_no_lifetime(ty: MiddleTy<'_>) -> bool { + use rustc_middle::ty::{Adt, GenericArgKind}; + match ty.kind() { + &Adt(_, args) => !args + .iter() + // TODO: Handle inferred lifetimes + .any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(..))), + _ => true, + } +} diff --git a/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/clippy_lints/src/utils/internal_lints/metadata_collector.rs index 97b509a84f930..1ebe1d6a2c4b6 100644 --- a/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ b/clippy_lints/src/utils/internal_lints/metadata_collector.rs @@ -925,7 +925,7 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for LintResolver<'a, 'hir> { && let (expr_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(expr)) && match_type(self.cx, expr_ty, &paths::LINT) { - if let hir::def::Res::Def(DefKind::Static(..), _) = path.res { + if let hir::def::Res::Def(DefKind::Static { .. }, _) = path.res { let lint_name = last_path_segment(qpath).ident.name; self.lints.push(sym_to_string(lint_name).to_ascii_lowercase()); } else if let Some(local) = get_parent_local(self.cx, expr) { 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 38c832931fc68..f4e277fd0c4cd 100644 --- a/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs +++ b/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs @@ -223,7 +223,7 @@ fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option read_mir_alloc_def_path( + Res::Def(DefKind::Static { .. }, def_id) => read_mir_alloc_def_path( cx, cx.tcx.eval_static_initializer(def_id).ok()?.inner(), cx.tcx.type_of(def_id).instantiate_identity(), diff --git a/clippy_lints/src/wildcard_imports.rs b/clippy_lints/src/wildcard_imports.rs index 5410e8ac11781..436f0cb79fb26 100644 --- a/clippy_lints/src/wildcard_imports.rs +++ b/clippy_lints/src/wildcard_imports.rs @@ -213,7 +213,7 @@ fn is_super_only_import(segments: &[PathSegment<'_>]) -> bool { // Allow skipping imports containing user configured segments, // i.e. "...::utils::...::*" if user put `allowed-wildcard-imports = ["utils"]` in `Clippy.toml` fn is_allowed_via_config(segments: &[PathSegment<'_>], allowed_segments: &FxHashSet) -> bool { - // segment matching need to be exact instead of using 'contains', in case user unintentionaly put + // segment matching need to be exact instead of using 'contains', in case user unintentionally put // a single character in the config thus skipping most of the warnings. segments.iter().any(|seg| allowed_segments.contains(seg.ident.as_str())) } diff --git a/clippy_lints/src/zero_repeat_side_effects.rs b/clippy_lints/src/zero_repeat_side_effects.rs new file mode 100644 index 0000000000000..852d04cd21b2f --- /dev/null +++ b/clippy_lints/src/zero_repeat_side_effects.rs @@ -0,0 +1,154 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::higher::VecArgs; +use clippy_utils::source::snippet; +use clippy_utils::visitors::for_each_expr; +use rustc_ast::LitKind; +use rustc_errors::Applicability; +use rustc_hir::{ExprKind, Node}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::{self, ConstKind, Ty}; +use rustc_session::declare_lint_pass; +use rustc_span::Span; + +declare_clippy_lint! { + /// ### What it does + /// Checks for array or vec initializations which call a function or method, + /// but which have a repeat count of zero. + /// + /// ### Why is this bad? + /// Such an initialization, despite having a repeat length of 0, will still call the inner function. + /// This may not be obvious and as such there may be unintended side effects in code. + /// + /// ### Example + /// ```no_run + /// fn side_effect() -> i32 { + /// println!("side effect"); + /// 10 + /// } + /// let a = [side_effect(); 0]; + /// ``` + /// Use instead: + /// ```no_run + /// fn side_effect() -> i32 { + /// println!("side effect"); + /// 10 + /// } + /// side_effect(); + /// let a: [i32; 0] = []; + /// ``` + #[clippy::version = "1.75.0"] + pub ZERO_REPEAT_SIDE_EFFECTS, + suspicious, + "usage of zero-sized initializations of arrays or vecs causing side effects" +} + +declare_lint_pass!(ZeroRepeatSideEffects => [ZERO_REPEAT_SIDE_EFFECTS]); + +impl LateLintPass<'_> for ZeroRepeatSideEffects { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ rustc_hir::Expr<'_>) { + if let Some(args) = VecArgs::hir(cx, expr) + && let VecArgs::Repeat(inner_expr, len) = args + && let ExprKind::Lit(l) = len.kind + && let LitKind::Int(i, _) = l.node + && i.0 == 0 + { + inner_check(cx, expr, inner_expr, true); + } else if let ExprKind::Repeat(inner_expr, _) = expr.kind + && let ty::Array(_, cst) = cx.typeck_results().expr_ty(expr).kind() + && let ConstKind::Value(ty::ValTree::Leaf(element_count)) = cst.kind() + && let Ok(element_count) = element_count.try_to_target_usize(cx.tcx) + && element_count == 0 + { + inner_check(cx, expr, inner_expr, false); + } + } +} + +fn inner_check(cx: &LateContext<'_>, expr: &'_ rustc_hir::Expr<'_>, inner_expr: &'_ rustc_hir::Expr<'_>, is_vec: bool) { + // check if expr is a call or has a call inside it + if for_each_expr(inner_expr, |x| { + if let ExprKind::Call(_, _) | ExprKind::MethodCall(_, _, _, _) = x.kind { + std::ops::ControlFlow::Break(()) + } else { + std::ops::ControlFlow::Continue(()) + } + }) + .is_some() + { + let parent_hir_node = cx.tcx.parent_hir_node(expr.hir_id); + let return_type = cx.typeck_results().expr_ty(expr); + + if let Node::Local(l) = parent_hir_node { + array_span_lint( + cx, + l.span, + inner_expr.span, + l.pat.span, + Some(return_type), + is_vec, + false, + ); + } else if let Node::Expr(x) = parent_hir_node + && let ExprKind::Assign(l, _, _) = x.kind + { + array_span_lint(cx, x.span, inner_expr.span, l.span, Some(return_type), is_vec, true); + } else { + span_lint_and_sugg( + cx, + ZERO_REPEAT_SIDE_EFFECTS, + expr.span.source_callsite(), + "function or method calls as the initial value in zero-sized array initializers may cause side effects", + "consider using", + format!( + "{{ {}; {}[] as {return_type} }}", + snippet(cx, inner_expr.span.source_callsite(), ".."), + if is_vec { "vec!" } else { "" }, + ), + Applicability::Unspecified, + ); + } + } +} + +fn array_span_lint( + cx: &LateContext<'_>, + expr_span: Span, + func_call_span: Span, + variable_name_span: Span, + expr_ty: Option>, + is_vec: bool, + is_assign: bool, +) { + let has_ty = expr_ty.is_some(); + + span_lint_and_sugg( + cx, + ZERO_REPEAT_SIDE_EFFECTS, + expr_span.source_callsite(), + "function or method calls as the initial value in zero-sized array initializers may cause side effects", + "consider using", + format!( + "{}; {}{}{} = {}[]{}{}", + snippet(cx, func_call_span.source_callsite(), ".."), + if has_ty && !is_assign { "let " } else { "" }, + snippet(cx, variable_name_span.source_callsite(), ".."), + if let Some(ty) = expr_ty + && !is_assign + { + format!(": {ty}") + } else { + String::new() + }, + if is_vec { "vec!" } else { "" }, + if let Some(ty) = expr_ty + && is_assign + { + format!(" as {ty}") + } else { + String::new() + }, + if is_assign { "" } else { ";" } + ), + Applicability::Unspecified, + ); +} diff --git a/clippy_utils/Cargo.toml b/clippy_utils/Cargo.toml index bf55040ddbc11..d2bb719a517f5 100644 --- a/clippy_utils/Cargo.toml +++ b/clippy_utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_utils" -version = "0.1.78" +version = "0.1.79" edition = "2021" publish = false diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index e75d5953faefd..046087d329896 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -10,8 +10,10 @@ use rustc_hir::{BinOp, BinOpKind, Block, ConstBlock, Expr, ExprKind, HirId, Item use rustc_lexer::tokenize; use rustc_lint::LateContext; use rustc_middle::mir::interpret::{alloc_range, Scalar}; +use rustc_middle::mir::ConstValue; use rustc_middle::ty::{self, EarlyBinder, FloatTy, GenericArgsRef, IntTy, List, ScalarInt, Ty, TyCtxt, UintTy}; use rustc_middle::{bug, mir, span_bug}; +use rustc_span::def_id::DefId; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::SyntaxContext; use rustc_target::abi::Size; @@ -307,6 +309,12 @@ impl ConstantSource { } } +/// Attempts to check whether the expression is a constant representing an empty slice, str, array, +/// etc… +pub fn constant_is_empty(lcx: &LateContext<'_>, e: &Expr<'_>) -> Option { + ConstEvalLateContext::new(lcx, lcx.typeck_results()).expr_is_empty(e) +} + /// Attempts to evaluate the expression as a constant. pub fn constant<'tcx>( lcx: &LateContext<'tcx>, @@ -406,7 +414,13 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { match e.kind { ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr(self.lcx.tcx.hir().body(body).value), ExprKind::DropTemps(e) => self.expr(e), - ExprKind::Path(ref qpath) => self.fetch_path(qpath, e.hir_id, self.typeck_results.expr_ty(e)), + ExprKind::Path(ref qpath) => { + self.fetch_path_and_apply(qpath, e.hir_id, self.typeck_results.expr_ty(e), |this, result| { + let result = mir_to_const(this.lcx, result)?; + this.source = ConstantSource::Constant; + Some(result) + }) + }, ExprKind::Block(block, _) => self.block(block), ExprKind::Lit(lit) => { if is_direct_expn_of(e.span, "cfg").is_some() { @@ -472,6 +486,49 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { } } + /// Simple constant folding to determine if an expression is an empty slice, str, array, … + /// `None` will be returned if the constness cannot be determined, or if the resolution + /// leaves the local crate. + pub fn expr_is_empty(&mut self, e: &Expr<'_>) -> Option { + match e.kind { + ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr_is_empty(self.lcx.tcx.hir().body(body).value), + ExprKind::DropTemps(e) => self.expr_is_empty(e), + ExprKind::Path(ref qpath) => { + if !self + .typeck_results + .qpath_res(qpath, e.hir_id) + .opt_def_id() + .is_some_and(DefId::is_local) + { + return None; + } + self.fetch_path_and_apply(qpath, e.hir_id, self.typeck_results.expr_ty(e), |this, result| { + mir_is_empty(this.lcx, result) + }) + }, + ExprKind::Lit(lit) => { + if is_direct_expn_of(e.span, "cfg").is_some() { + None + } else { + match &lit.node { + LitKind::Str(is, _) => Some(is.is_empty()), + LitKind::ByteStr(s, _) | LitKind::CStr(s, _) => Some(s.is_empty()), + _ => None, + } + } + }, + ExprKind::Array(vec) => self.multi(vec).map(|v| v.is_empty()), + ExprKind::Repeat(..) => { + if let ty::Array(_, n) = self.typeck_results.expr_ty(e).kind() { + Some(n.try_eval_target_usize(self.lcx.tcx, self.lcx.param_env)? == 0) + } else { + span_bug!(e.span, "typeck error"); + } + }, + _ => None, + } + } + #[expect(clippy::cast_possible_wrap)] fn constant_not(&self, o: &Constant<'tcx>, ty: Ty<'_>) -> Option> { use self::Constant::{Bool, Int}; @@ -519,8 +576,11 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { vec.iter().map(|elem| self.expr(elem)).collect::>() } - /// Lookup a possibly constant expression from an `ExprKind::Path`. - fn fetch_path(&mut self, qpath: &QPath<'_>, id: HirId, ty: Ty<'tcx>) -> Option> { + /// Lookup a possibly constant expression from an `ExprKind::Path` and apply a function on it. + fn fetch_path_and_apply(&mut self, qpath: &QPath<'_>, id: HirId, ty: Ty<'tcx>, f: F) -> Option + where + F: FnOnce(&mut Self, rustc_middle::mir::Const<'tcx>) -> Option, + { let res = self.typeck_results.qpath_res(qpath, id); match res { Res::Def(DefKind::Const | DefKind::AssocConst, def_id) => { @@ -553,9 +613,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { .const_eval_resolve(self.param_env, mir::UnevaluatedConst::new(def_id, args), qpath.span()) .ok() .map(|val| rustc_middle::mir::Const::from_value(val, ty))?; - let result = mir_to_const(self.lcx, result)?; - self.source = ConstantSource::Constant; - Some(result) + f(self, result) }, _ => None, } @@ -746,7 +804,6 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { } pub fn mir_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> Option> { - use rustc_middle::mir::ConstValue; let mir::Const::Val(val, _) = result else { // We only work on evaluated consts. return None; @@ -794,6 +851,42 @@ pub fn mir_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> } } +fn mir_is_empty<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> Option { + let mir::Const::Val(val, _) = result else { + // We only work on evaluated consts. + return None; + }; + match (val, result.ty().kind()) { + (_, ty::Ref(_, inner_ty, _)) => match inner_ty.kind() { + ty::Str | ty::Slice(_) => { + if let ConstValue::Indirect { alloc_id, offset } = val { + // Get the length from the slice, using the same formula as + // [`ConstValue::try_get_slice_bytes_for_diagnostics`]. + let a = lcx.tcx.global_alloc(alloc_id).unwrap_memory().inner(); + let ptr_size = lcx.tcx.data_layout.pointer_size; + if a.size() < offset + 2 * ptr_size { + // (partially) dangling reference + return None; + } + let len = a + .read_scalar(&lcx.tcx, alloc_range(offset + ptr_size, ptr_size), false) + .ok()? + .to_target_usize(&lcx.tcx) + .ok()?; + Some(len == 0) + } else { + None + } + }, + ty::Array(_, len) => Some(len.try_to_target_usize(lcx.tcx)? == 0), + _ => None, + }, + (ConstValue::Indirect { .. }, ty::Array(_, len)) => Some(len.try_to_target_usize(lcx.tcx)? == 0), + (ConstValue::ZeroSized, _) => Some(true), + _ => None, + } +} + fn field_of_struct<'tcx>( adt_def: ty::AdtDef<'tcx>, lcx: &LateContext<'tcx>, diff --git a/clippy_utils/src/diagnostics.rs b/clippy_utils/src/diagnostics.rs index 6ed46e5dde041..0352696f93eca 100644 --- a/clippy_utils/src/diagnostics.rs +++ b/clippy_utils/src/diagnostics.rs @@ -36,6 +36,20 @@ fn docs_link(diag: &mut Diag<'_, ()>, lint: &'static Lint) { /// Usually it's nicer to provide more context for lint messages. /// Be sure the output is understandable when you use this method. /// +/// NOTE: Lint emissions are always bound to a node in the HIR, which is used to determine +/// the lint level. +/// For the `span_lint` function, the node that was passed into the `LintPass::check_*` function is +/// used. +/// +/// If you're emitting the lint at the span of a different node than the one provided by the +/// `LintPass::check_*` function, consider using [`span_lint_hir`] instead. +/// This is needed for `#[allow]` and `#[expect]` attributes to work on the node +/// highlighted in the displayed warning. +/// +/// If you're unsure which function you should use, you can test if the `#[allow]` attribute works +/// where you would expect it to. +/// If it doesn't, you likely need to use [`span_lint_hir`] instead. +/// /// # Example /// /// ```ignore @@ -61,6 +75,20 @@ pub fn span_lint(cx: &T, lint: &'static Lint, sp: impl Into( /// /// If you change the signature, remember to update the internal lint `CollapsibleCalls` /// +/// NOTE: Lint emissions are always bound to a node in the HIR, which is used to determine +/// the lint level. +/// For the `span_lint_and_note` function, the node that was passed into the `LintPass::check_*` +/// function is used. +/// +/// If you're emitting the lint at the span of a different node than the one provided by the +/// `LintPass::check_*` function, consider using [`span_lint_hir_and_then`] instead. +/// This is needed for `#[allow]` and `#[expect]` attributes to work on the node +/// highlighted in the displayed warning. +/// +/// If you're unsure which function you should use, you can test if the `#[allow]` attribute works +/// where you would expect it to. +/// If it doesn't, you likely need to use [`span_lint_hir_and_then`] instead. +/// /// # Example /// /// ```text @@ -139,6 +181,20 @@ pub fn span_lint_and_note( /// /// If you need to customize your lint output a lot, use this function. /// If you change the signature, remember to update the internal lint `CollapsibleCalls` +/// +/// NOTE: Lint emissions are always bound to a node in the HIR, which is used to determine +/// the lint level. +/// For the `span_lint_and_then` function, the node that was passed into the `LintPass::check_*` +/// function is used. +/// +/// If you're emitting the lint at the span of a different node than the one provided by the +/// `LintPass::check_*` function, consider using [`span_lint_hir_and_then`] instead. +/// This is needed for `#[allow]` and `#[expect]` attributes to work on the node +/// highlighted in the displayed warning. +/// +/// If you're unsure which function you should use, you can test if the `#[allow]` attribute works +/// where you would expect it to. +/// If it doesn't, you likely need to use [`span_lint_hir_and_then`] instead. pub fn span_lint_and_then(cx: &C, lint: &'static Lint, sp: S, msg: &str, f: F) where C: LintContext, @@ -152,6 +208,30 @@ where }); } +/// Like [`span_lint`], but emits the lint at the node identified by the given `HirId`. +/// +/// This is in contrast to [`span_lint`], which always emits the lint at the node that was last +/// passed to the `LintPass::check_*` function. +/// +/// The `HirId` is used for checking lint level attributes and to fulfill lint expectations defined +/// via the `#[expect]` attribute. +/// +/// For example: +/// ```ignore +/// fn f() { /* */ +/// +/// #[allow(clippy::some_lint)] +/// let _x = /* */; +/// } +/// ``` +/// If `some_lint` does its analysis in `LintPass::check_fn` (at ``) and emits a lint at +/// `` using [`span_lint`], then allowing the lint at `` as attempted in the snippet +/// will not work! +/// Even though that is where the warning points at, which would be confusing to users. +/// +/// Instead, use this function and also pass the `HirId` of ``, which will let +/// the compiler check lint level attributes at the place of the expression and +/// the `#[allow]` will work. pub fn span_lint_hir(cx: &LateContext<'_>, lint: &'static Lint, hir_id: HirId, sp: Span, msg: &str) { #[expect(clippy::disallowed_methods)] cx.tcx.node_span_lint(lint, hir_id, sp, msg.to_string(), |diag| { @@ -159,6 +239,30 @@ pub fn span_lint_hir(cx: &LateContext<'_>, lint: &'static Lint, hir_id: HirId, s }); } +/// Like [`span_lint_and_then`], but emits the lint at the node identified by the given `HirId`. +/// +/// This is in contrast to [`span_lint_and_then`], which always emits the lint at the node that was +/// last passed to the `LintPass::check_*` function. +/// +/// The `HirId` is used for checking lint level attributes and to fulfill lint expectations defined +/// via the `#[expect]` attribute. +/// +/// For example: +/// ```ignore +/// fn f() { /* */ +/// +/// #[allow(clippy::some_lint)] +/// let _x = /* */; +/// } +/// ``` +/// If `some_lint` does its analysis in `LintPass::check_fn` (at ``) and emits a lint at +/// `` using [`span_lint`], then allowing the lint at `` as attempted in the snippet +/// will not work! +/// Even though that is where the warning points at, which would be confusing to users. +/// +/// Instead, use this function and also pass the `HirId` of ``, which will let +/// the compiler check lint level attributes at the place of the expression and +/// the `#[allow]` will work. pub fn span_lint_hir_and_then( cx: &LateContext<'_>, lint: &'static Lint, @@ -182,6 +286,20 @@ pub fn span_lint_hir_and_then( /// /// If you change the signature, remember to update the internal lint `CollapsibleCalls` /// +/// NOTE: Lint emissions are always bound to a node in the HIR, which is used to determine +/// the lint level. +/// For the `span_lint_and_sugg` function, the node that was passed into the `LintPass::check_*` +/// function is used. +/// +/// If you're emitting the lint at the span of a different node than the one provided by the +/// `LintPass::check_*` function, consider using [`span_lint_hir_and_then`] instead. +/// This is needed for `#[allow]` and `#[expect]` attributes to work on the node +/// highlighted in the displayed warning. +/// +/// If you're unsure which function you should use, you can test if the `#[allow]` attribute works +/// where you would expect it to. +/// If it doesn't, you likely need to use [`span_lint_hir_and_then`] instead. +/// /// # Example /// /// ```text diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index b4cc747e0e62b..11b56ed47de8e 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -2246,8 +2246,21 @@ pub fn fn_has_unsatisfiable_preds(cx: &LateContext<'_>, did: DefId) -> bool { /// Returns the `DefId` of the callee if the given expression is a function or method call. pub fn fn_def_id(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { + fn_def_id_with_node_args(cx, expr).map(|(did, _)| did) +} + +/// Returns the `DefId` of the callee if the given expression is a function or method call, +/// as well as its node args. +pub fn fn_def_id_with_node_args<'tcx>( + cx: &LateContext<'tcx>, + expr: &Expr<'_>, +) -> Option<(DefId, rustc_ty::GenericArgsRef<'tcx>)> { + let typeck = cx.typeck_results(); match &expr.kind { - ExprKind::MethodCall(..) => cx.typeck_results().type_dependent_def_id(expr.hir_id), + ExprKind::MethodCall(..) => Some(( + typeck.type_dependent_def_id(expr.hir_id)?, + typeck.node_args(expr.hir_id), + )), ExprKind::Call( Expr { kind: ExprKind::Path(qpath), @@ -2259,9 +2272,9 @@ pub fn fn_def_id(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { // Only return Fn-like DefIds, not the DefIds of statics/consts/etc that contain or // deref to fn pointers, dyn Fn, impl Fn - #8850 if let Res::Def(DefKind::Fn | DefKind::Ctor(..) | DefKind::AssocFn, id) = - cx.typeck_results().qpath_res(qpath, *path_hir_id) + typeck.qpath_res(qpath, *path_hir_id) { - Some(id) + Some((id, typeck.node_args(*path_hir_id))) } else { None } diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 987f28192a85d..456b8019e95cc 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -19,6 +19,8 @@ pub const BTREESET_ITER: [&str; 6] = ["alloc", "collections", "btree", "set", "B pub const CLONE_TRAIT_METHOD: [&str; 4] = ["core", "clone", "Clone", "clone"]; pub const CORE_ITER_CLONED: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "cloned"]; pub const CORE_ITER_COPIED: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "copied"]; +pub const CORE_ITER_ENUMERATE_METHOD: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "enumerate"]; +pub const CORE_ITER_ENUMERATE_STRUCT: [&str; 5] = ["core", "iter", "adapters", "enumerate", "Enumerate"]; pub const CORE_ITER_FILTER: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "filter"]; pub const CORE_RESULT_OK_METHOD: [&str; 4] = ["core", "result", "Result", "ok"]; pub const CSTRING_AS_C_STR: [&str; 5] = ["alloc", "ffi", "c_str", "CString", "as_c_str"]; diff --git a/declare_clippy_lint/Cargo.toml b/declare_clippy_lint/Cargo.toml index 296eb8dd34008..9a3a41e1d1ead 100644 --- a/declare_clippy_lint/Cargo.toml +++ b/declare_clippy_lint/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "declare_clippy_lint" -version = "0.1.78" +version = "0.1.79" edition = "2021" publish = false diff --git a/rust-toolchain b/rust-toolchain index 070b62887d5de..a63e66f3214c9 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2024-03-07" +channel = "nightly-2024-03-21" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] diff --git a/tests/ui-internal/disallow_span_lint.stderr b/tests/ui-internal/disallow_span_lint.stderr index ae5d6843406a7..cfc590bed3697 100644 --- a/tests/ui-internal/disallow_span_lint.stderr +++ b/tests/ui-internal/disallow_span_lint.stderr @@ -4,6 +4,7 @@ error: use of a disallowed method `rustc_lint::context::LintContext::span_lint` LL | cx.span_lint(lint, span, msg, |_| {}); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint*` functions instead (from clippy.toml) = note: `-D clippy::disallowed-methods` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::disallowed_methods)]` @@ -12,6 +13,8 @@ error: use of a disallowed method `rustc_middle::ty::context::TyCtxt::node_span_ | LL | tcx.node_span_lint(lint, hir_id, span, msg, |_| {}); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint_hir*` functions instead (from clippy.toml) error: aborting due to 2 previous errors diff --git a/tests/ui-toml/dbg_macro/dbg_macro.fixed b/tests/ui-toml/dbg_macro/dbg_macro.fixed new file mode 100644 index 0000000000000..d42b29ba21a63 --- /dev/null +++ b/tests/ui-toml/dbg_macro/dbg_macro.fixed @@ -0,0 +1,38 @@ +//@compile-flags: --test +#![warn(clippy::dbg_macro)] +#![allow(clippy::unnecessary_operation, clippy::no_effect)] + +fn foo(n: u32) -> u32 { + if let Some(n) = n.checked_sub(4) { n } else { n } +} + +fn factorial(n: u32) -> u32 { + if n <= 1 { + 1 + } else { + n * factorial(n - 1) + } +} + +fn main() { + 42; + foo(3) + factorial(4); + (1, 2, 3, 4, 5); +} + +#[test] +pub fn issue8481() { + dbg!(1); +} + +#[cfg(test)] +fn foo2() { + dbg!(1); +} + +#[cfg(test)] +mod mod1 { + fn func() { + dbg!(1); + } +} diff --git a/tests/ui-toml/dbg_macro/dbg_macro.rs b/tests/ui-toml/dbg_macro/dbg_macro.rs index 67129e6247712..bd189b1576f96 100644 --- a/tests/ui-toml/dbg_macro/dbg_macro.rs +++ b/tests/ui-toml/dbg_macro/dbg_macro.rs @@ -1,6 +1,7 @@ //@compile-flags: --test #![warn(clippy::dbg_macro)] -//@no-rustfix +#![allow(clippy::unnecessary_operation, clippy::no_effect)] + fn foo(n: u32) -> u32 { if let Some(n) = dbg!(n.checked_sub(4)) { n } else { n } } @@ -15,9 +16,7 @@ fn factorial(n: u32) -> u32 { fn main() { dbg!(42); - dbg!(dbg!(dbg!(42))); foo(3) + dbg!(factorial(4)); - dbg!(1, 2, dbg!(3, 4)); dbg!(1, 2, 3, 4, 5); } diff --git a/tests/ui-toml/dbg_macro/dbg_macro.stderr b/tests/ui-toml/dbg_macro/dbg_macro.stderr index 8ffc426be2d9d..129fab5ff97a6 100644 --- a/tests/ui-toml/dbg_macro/dbg_macro.stderr +++ b/tests/ui-toml/dbg_macro/dbg_macro.stderr @@ -1,5 +1,5 @@ error: the `dbg!` macro is intended as a debugging tool - --> tests/ui-toml/dbg_macro/dbg_macro.rs:5:22 + --> tests/ui-toml/dbg_macro/dbg_macro.rs:6:22 | LL | if let Some(n) = dbg!(n.checked_sub(4)) { n } else { n } | ^^^^^^^^^^^^^^^^^^^^^^ @@ -12,7 +12,7 @@ LL | if let Some(n) = n.checked_sub(4) { n } else { n } | ~~~~~~~~~~~~~~~~ error: the `dbg!` macro is intended as a debugging tool - --> tests/ui-toml/dbg_macro/dbg_macro.rs:9:8 + --> tests/ui-toml/dbg_macro/dbg_macro.rs:10:8 | LL | if dbg!(n <= 1) { | ^^^^^^^^^^^^ @@ -23,7 +23,7 @@ LL | if n <= 1 { | ~~~~~~ error: the `dbg!` macro is intended as a debugging tool - --> tests/ui-toml/dbg_macro/dbg_macro.rs:10:9 + --> tests/ui-toml/dbg_macro/dbg_macro.rs:11:9 | LL | dbg!(1) | ^^^^^^^ @@ -34,7 +34,7 @@ LL | 1 | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui-toml/dbg_macro/dbg_macro.rs:12:9 + --> tests/ui-toml/dbg_macro/dbg_macro.rs:13:9 | LL | dbg!(n * factorial(n - 1)) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -45,7 +45,7 @@ LL | n * factorial(n - 1) | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui-toml/dbg_macro/dbg_macro.rs:17:5 + --> tests/ui-toml/dbg_macro/dbg_macro.rs:18:5 | LL | dbg!(42); | ^^^^^^^^ @@ -55,17 +55,6 @@ help: remove the invocation before committing it to a version control system LL | 42; | ~~ -error: the `dbg!` macro is intended as a debugging tool - --> tests/ui-toml/dbg_macro/dbg_macro.rs:18:5 - | -LL | dbg!(dbg!(dbg!(42))); - | ^^^^^^^^^^^^^^^^^^^^ - | -help: remove the invocation before committing it to a version control system - | -LL | dbg!(dbg!(42)); - | ~~~~~~~~~~~~~~ - error: the `dbg!` macro is intended as a debugging tool --> tests/ui-toml/dbg_macro/dbg_macro.rs:19:14 | @@ -80,17 +69,6 @@ LL | foo(3) + factorial(4); error: the `dbg!` macro is intended as a debugging tool --> tests/ui-toml/dbg_macro/dbg_macro.rs:20:5 | -LL | dbg!(1, 2, dbg!(3, 4)); - | ^^^^^^^^^^^^^^^^^^^^^^ - | -help: remove the invocation before committing it to a version control system - | -LL | (1, 2, dbg!(3, 4)); - | ~~~~~~~~~~~~~~~~~~ - -error: the `dbg!` macro is intended as a debugging tool - --> tests/ui-toml/dbg_macro/dbg_macro.rs:21:5 - | LL | dbg!(1, 2, 3, 4, 5); | ^^^^^^^^^^^^^^^^^^^ | @@ -99,5 +77,5 @@ help: remove the invocation before committing it to a version control system LL | (1, 2, 3, 4, 5); | ~~~~~~~~~~~~~~~ -error: aborting due to 9 previous errors +error: aborting due to 7 previous errors diff --git a/tests/ui/allow_attributes_without_reason.rs b/tests/ui/allow_attributes_without_reason.rs index 663c2eb2c3794..523148d658698 100644 --- a/tests/ui/allow_attributes_without_reason.rs +++ b/tests/ui/allow_attributes_without_reason.rs @@ -1,7 +1,7 @@ //@aux-build:proc_macros.rs #![feature(lint_reasons)] #![deny(clippy::allow_attributes_without_reason)] -#![allow(unfulfilled_lint_expectations)] +#![allow(unfulfilled_lint_expectations, clippy::duplicated_attributes)] extern crate proc_macros; use proc_macros::{external, with_span}; diff --git a/tests/ui/allow_attributes_without_reason.stderr b/tests/ui/allow_attributes_without_reason.stderr index 3c81233bf7777..770a771ec3d15 100644 --- a/tests/ui/allow_attributes_without_reason.stderr +++ b/tests/ui/allow_attributes_without_reason.stderr @@ -1,8 +1,8 @@ error: `allow` attribute without specifying a reason --> tests/ui/allow_attributes_without_reason.rs:4:1 | -LL | #![allow(unfulfilled_lint_expectations)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![allow(unfulfilled_lint_expectations, clippy::duplicated_attributes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: try adding a reason at the end with `, reason = ".."` note: the lint level is defined here diff --git a/tests/ui/assigning_clones.fixed b/tests/ui/assigning_clones.fixed index c66e0c1f6028c..160f3b9466316 100644 --- a/tests/ui/assigning_clones.fixed +++ b/tests/ui/assigning_clones.fixed @@ -128,6 +128,19 @@ fn ignore_generic_clone(a: &mut T, b: &T) { *a = b.clone(); } +#[clippy::msrv = "1.62"] +fn msrv_1_62(mut a: String, b: String, c: &str) { + a.clone_from(&b); + // Should not be linted, as clone_into wasn't stabilized until 1.63 + a = c.to_owned(); +} + +#[clippy::msrv = "1.63"] +fn msrv_1_63(mut a: String, b: String, c: &str) { + a.clone_from(&b); + c.clone_into(&mut a); +} + macro_rules! clone_inside { ($a:expr, $b: expr) => { $a = $b.clone(); diff --git a/tests/ui/assigning_clones.rs b/tests/ui/assigning_clones.rs index b9f994d3e034c..14ba1d4db9a83 100644 --- a/tests/ui/assigning_clones.rs +++ b/tests/ui/assigning_clones.rs @@ -128,6 +128,19 @@ fn ignore_generic_clone(a: &mut T, b: &T) { *a = b.clone(); } +#[clippy::msrv = "1.62"] +fn msrv_1_62(mut a: String, b: String, c: &str) { + a = b.clone(); + // Should not be linted, as clone_into wasn't stabilized until 1.63 + a = c.to_owned(); +} + +#[clippy::msrv = "1.63"] +fn msrv_1_63(mut a: String, b: String, c: &str) { + a = b.clone(); + a = c.to_owned(); +} + macro_rules! clone_inside { ($a:expr, $b: expr) => { $a = $b.clone(); diff --git a/tests/ui/assigning_clones.stderr b/tests/ui/assigning_clones.stderr index b76323f360634..ba59f067431a7 100644 --- a/tests/ui/assigning_clones.stderr +++ b/tests/ui/assigning_clones.stderr @@ -67,41 +67,59 @@ error: assigning the result of `Clone::clone()` may be inefficient LL | a = b.clone(); | ^^^^^^^^^^^^^ help: use `clone_from()`: `a.clone_from(&b)` +error: assigning the result of `Clone::clone()` may be inefficient + --> tests/ui/assigning_clones.rs:133:5 + | +LL | a = b.clone(); + | ^^^^^^^^^^^^^ help: use `clone_from()`: `a.clone_from(&b)` + +error: assigning the result of `Clone::clone()` may be inefficient + --> tests/ui/assigning_clones.rs:140:5 + | +LL | a = b.clone(); + | ^^^^^^^^^^^^^ help: use `clone_from()`: `a.clone_from(&b)` + +error: assigning the result of `ToOwned::to_owned()` may be inefficient + --> tests/ui/assigning_clones.rs:141:5 + | +LL | a = c.to_owned(); + | ^^^^^^^^^^^^^^^^ help: use `clone_into()`: `c.clone_into(&mut a)` + error: assigning the result of `ToOwned::to_owned()` may be inefficient - --> tests/ui/assigning_clones.rs:145:5 + --> tests/ui/assigning_clones.rs:158:5 | LL | *mut_string = ref_str.to_owned(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ref_str.clone_into(mut_string)` error: assigning the result of `ToOwned::to_owned()` may be inefficient - --> tests/ui/assigning_clones.rs:149:5 + --> tests/ui/assigning_clones.rs:162:5 | LL | mut_string = ref_str.to_owned(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ref_str.clone_into(&mut mut_string)` error: assigning the result of `ToOwned::to_owned()` may be inefficient - --> tests/ui/assigning_clones.rs:170:5 + --> tests/ui/assigning_clones.rs:183:5 | LL | **mut_box_string = ref_str.to_owned(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ref_str.clone_into(&mut (*mut_box_string))` error: assigning the result of `ToOwned::to_owned()` may be inefficient - --> tests/ui/assigning_clones.rs:174:5 + --> tests/ui/assigning_clones.rs:187:5 | LL | **mut_box_string = ref_str.to_owned(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ref_str.clone_into(&mut (*mut_box_string))` error: assigning the result of `ToOwned::to_owned()` may be inefficient - --> tests/ui/assigning_clones.rs:178:5 + --> tests/ui/assigning_clones.rs:191:5 | LL | *mut_thing = ToOwned::to_owned(ref_str); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ToOwned::clone_into(ref_str, mut_thing)` error: assigning the result of `ToOwned::to_owned()` may be inefficient - --> tests/ui/assigning_clones.rs:182:5 + --> tests/ui/assigning_clones.rs:195:5 | LL | mut_thing = ToOwned::to_owned(ref_str); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ToOwned::clone_into(ref_str, &mut mut_thing)` -error: aborting due to 17 previous errors +error: aborting due to 20 previous errors diff --git a/tests/ui/auxiliary/proc_macro_attr.rs b/tests/ui/auxiliary/proc_macro_attr.rs index 75f7a20f961b6..a6f3b164c9ba1 100644 --- a/tests/ui/auxiliary/proc_macro_attr.rs +++ b/tests/ui/auxiliary/proc_macro_attr.rs @@ -11,8 +11,8 @@ use quote::{quote, quote_spanned}; use syn::spanned::Spanned; use syn::token::Star; use syn::{ - parse_macro_input, parse_quote, FnArg, ImplItem, ItemFn, ItemImpl, ItemTrait, Lifetime, Pat, PatIdent, PatType, - Signature, TraitItem, Type, + parse_macro_input, parse_quote, FnArg, ImplItem, ItemFn, ItemImpl, ItemStruct, ItemTrait, Lifetime, Pat, PatIdent, + PatType, Signature, TraitItem, Type, Visibility, }; #[proc_macro_attribute] @@ -101,9 +101,7 @@ pub fn fake_main(_attr: TokenStream, item: TokenStream) -> TokenStream { let mut item = parse_macro_input!(item as ItemFn); let span = item.block.brace_token.span; - if item.sig.asyncness.is_some() { - item.sig.asyncness = None; - } + item.sig.asyncness = None; let crate_name = quote! { fake_crate }; let block = item.block; @@ -128,7 +126,7 @@ pub fn fake_main(_attr: TokenStream, item: TokenStream) -> TokenStream { #[proc_macro_attribute] pub fn fake_desugar_await(_args: TokenStream, input: TokenStream) -> TokenStream { - let mut async_fn = syn::parse_macro_input!(input as syn::ItemFn); + let mut async_fn = parse_macro_input!(input as syn::ItemFn); for stmt in &mut async_fn.block.stmts { if let syn::Stmt::Expr(syn::Expr::Match(syn::ExprMatch { expr: scrutinee, .. }), _) = stmt { @@ -145,3 +143,36 @@ pub fn fake_desugar_await(_args: TokenStream, input: TokenStream) -> TokenStream quote!(#async_fn).into() } + +#[proc_macro_attribute] +pub fn rewrite_struct(_args: TokenStream, input: TokenStream) -> TokenStream { + let mut item_struct = parse_macro_input!(input as syn::ItemStruct); + // remove struct attributes including doc comments. + item_struct.attrs = vec![]; + if let Visibility::Public(token) = item_struct.vis { + // set vis to `pub(crate)` to trigger `missing_docs_in_private_items` lint. + let new_vis: Visibility = syn::parse_quote_spanned!(token.span() => pub(crate)); + item_struct.vis = new_vis; + } + if let syn::Fields::Named(fields) = &mut item_struct.fields { + for field in &mut fields.named { + // remove all attributes from fields as well. + field.attrs = vec![]; + } + } + + quote!(#item_struct).into() +} + +#[proc_macro_attribute] +pub fn with_empty_docs(_attr: TokenStream, input: TokenStream) -> TokenStream { + let item = parse_macro_input!(input as syn::Item); + let attrs: Vec = vec![]; + let doc_comment = ""; + quote! { + #(#attrs)* + #[doc = #doc_comment] + #item + } + .into() +} diff --git a/tests/ui/await_holding_lock.rs b/tests/ui/await_holding_lock.rs index 27b57b6481368..8e5510e6cd01c 100644 --- a/tests/ui/await_holding_lock.rs +++ b/tests/ui/await_holding_lock.rs @@ -1,4 +1,5 @@ #![warn(clippy::await_holding_lock)] +#![allow(clippy::readonly_write_lock)] // When adding or modifying a test, please do the same for parking_lot::Mutex. mod std_mutex { diff --git a/tests/ui/await_holding_lock.stderr b/tests/ui/await_holding_lock.stderr index e58436345b5c7..0af48a36acca1 100644 --- a/tests/ui/await_holding_lock.stderr +++ b/tests/ui/await_holding_lock.stderr @@ -1,12 +1,12 @@ error: this `MutexGuard` is held across an `await` point - --> tests/ui/await_holding_lock.rs:9:13 + --> tests/ui/await_holding_lock.rs:10:13 | LL | let guard = x.lock().unwrap(); | ^^^^^ | = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await note: these are all the `await` points this lock is held through - --> tests/ui/await_holding_lock.rs:11:15 + --> tests/ui/await_holding_lock.rs:12:15 | LL | baz().await | ^^^^^ @@ -14,40 +14,40 @@ LL | baz().await = help: to override `-D warnings` add `#[allow(clippy::await_holding_lock)]` error: this `MutexGuard` is held across an `await` point - --> tests/ui/await_holding_lock.rs:25:13 + --> tests/ui/await_holding_lock.rs:26:13 | LL | let guard = x.read().unwrap(); | ^^^^^ | = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await note: these are all the `await` points this lock is held through - --> tests/ui/await_holding_lock.rs:27:15 + --> tests/ui/await_holding_lock.rs:28:15 | LL | baz().await | ^^^^^ error: this `MutexGuard` is held across an `await` point - --> tests/ui/await_holding_lock.rs:31:13 + --> tests/ui/await_holding_lock.rs:32:13 | LL | let mut guard = x.write().unwrap(); | ^^^^^^^^^ | = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await note: these are all the `await` points this lock is held through - --> tests/ui/await_holding_lock.rs:33:15 + --> tests/ui/await_holding_lock.rs:34:15 | LL | baz().await | ^^^^^ error: this `MutexGuard` is held across an `await` point - --> tests/ui/await_holding_lock.rs:53:13 + --> tests/ui/await_holding_lock.rs:54:13 | LL | let guard = x.lock().unwrap(); | ^^^^^ | = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await note: these are all the `await` points this lock is held through - --> tests/ui/await_holding_lock.rs:56:28 + --> tests/ui/await_holding_lock.rs:57:28 | LL | let second = baz().await; | ^^^^^ @@ -56,79 +56,79 @@ LL | let third = baz().await; | ^^^^^ error: this `MutexGuard` is held across an `await` point - --> tests/ui/await_holding_lock.rs:67:17 + --> tests/ui/await_holding_lock.rs:68:17 | LL | let guard = x.lock().unwrap(); | ^^^^^ | = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await note: these are all the `await` points this lock is held through - --> tests/ui/await_holding_lock.rs:69:19 + --> tests/ui/await_holding_lock.rs:70:19 | LL | baz().await | ^^^^^ error: this `MutexGuard` is held across an `await` point - --> tests/ui/await_holding_lock.rs:80:17 + --> tests/ui/await_holding_lock.rs:81:17 | LL | let guard = x.lock().unwrap(); | ^^^^^ | = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await note: these are all the `await` points this lock is held through - --> tests/ui/await_holding_lock.rs:82:19 + --> tests/ui/await_holding_lock.rs:83:19 | LL | baz().await | ^^^^^ error: this `MutexGuard` is held across an `await` point - --> tests/ui/await_holding_lock.rs:93:13 + --> tests/ui/await_holding_lock.rs:94:13 | LL | let guard = x.lock(); | ^^^^^ | = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await note: these are all the `await` points this lock is held through - --> tests/ui/await_holding_lock.rs:95:15 + --> tests/ui/await_holding_lock.rs:96:15 | LL | baz().await | ^^^^^ error: this `MutexGuard` is held across an `await` point - --> tests/ui/await_holding_lock.rs:109:13 + --> tests/ui/await_holding_lock.rs:110:13 | LL | let guard = x.read(); | ^^^^^ | = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await note: these are all the `await` points this lock is held through - --> tests/ui/await_holding_lock.rs:111:15 + --> tests/ui/await_holding_lock.rs:112:15 | LL | baz().await | ^^^^^ error: this `MutexGuard` is held across an `await` point - --> tests/ui/await_holding_lock.rs:115:13 + --> tests/ui/await_holding_lock.rs:116:13 | LL | let mut guard = x.write(); | ^^^^^^^^^ | = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await note: these are all the `await` points this lock is held through - --> tests/ui/await_holding_lock.rs:117:15 + --> tests/ui/await_holding_lock.rs:118:15 | LL | baz().await | ^^^^^ error: this `MutexGuard` is held across an `await` point - --> tests/ui/await_holding_lock.rs:137:13 + --> tests/ui/await_holding_lock.rs:138:13 | LL | let guard = x.lock(); | ^^^^^ | = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await note: these are all the `await` points this lock is held through - --> tests/ui/await_holding_lock.rs:140:28 + --> tests/ui/await_holding_lock.rs:141:28 | LL | let second = baz().await; | ^^^^^ @@ -137,40 +137,40 @@ LL | let third = baz().await; | ^^^^^ error: this `MutexGuard` is held across an `await` point - --> tests/ui/await_holding_lock.rs:151:17 + --> tests/ui/await_holding_lock.rs:152:17 | LL | let guard = x.lock(); | ^^^^^ | = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await note: these are all the `await` points this lock is held through - --> tests/ui/await_holding_lock.rs:153:19 + --> tests/ui/await_holding_lock.rs:154:19 | LL | baz().await | ^^^^^ error: this `MutexGuard` is held across an `await` point - --> tests/ui/await_holding_lock.rs:164:17 + --> tests/ui/await_holding_lock.rs:165:17 | LL | let guard = x.lock(); | ^^^^^ | = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await note: these are all the `await` points this lock is held through - --> tests/ui/await_holding_lock.rs:166:19 + --> tests/ui/await_holding_lock.rs:167:19 | LL | baz().await | ^^^^^ error: this `MutexGuard` is held across an `await` point - --> tests/ui/await_holding_lock.rs:185:9 + --> tests/ui/await_holding_lock.rs:186:9 | LL | let mut guard = x.lock().unwrap(); | ^^^^^^^^^ | = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await note: these are all the `await` points this lock is held through - --> tests/ui/await_holding_lock.rs:189:11 + --> tests/ui/await_holding_lock.rs:190:11 | LL | baz().await; | ^^^^^ diff --git a/tests/ui/bool_assert_comparison.fixed b/tests/ui/bool_assert_comparison.fixed index 63b8e27e1c6c5..b05166a055ee3 100644 --- a/tests/ui/bool_assert_comparison.fixed +++ b/tests/ui/bool_assert_comparison.fixed @@ -1,4 +1,4 @@ -#![allow(unused, clippy::assertions_on_constants)] +#![allow(unused, clippy::assertions_on_constants, clippy::const_is_empty)] #![warn(clippy::bool_assert_comparison)] use std::ops::Not; diff --git a/tests/ui/bool_assert_comparison.rs b/tests/ui/bool_assert_comparison.rs index 58f81fedb7959..dc51fcf1d36b9 100644 --- a/tests/ui/bool_assert_comparison.rs +++ b/tests/ui/bool_assert_comparison.rs @@ -1,4 +1,4 @@ -#![allow(unused, clippy::assertions_on_constants)] +#![allow(unused, clippy::assertions_on_constants, clippy::const_is_empty)] #![warn(clippy::bool_assert_comparison)] use std::ops::Not; diff --git a/tests/ui/cast_lossless_bool.fixed b/tests/ui/cast_lossless_bool.fixed index a4ce1c6f928e7..51a38a60cf6b2 100644 --- a/tests/ui/cast_lossless_bool.fixed +++ b/tests/ui/cast_lossless_bool.fixed @@ -1,6 +1,8 @@ #![allow(dead_code)] #![warn(clippy::cast_lossless)] +type U8 = u8; + fn main() { // Test clippy::cast_lossless with casts to integer types let _ = u8::from(true); @@ -19,6 +21,8 @@ fn main() { // Test with an expression wrapped in parens let _ = u16::from(true | false); + + let _ = U8::from(true); } // The lint would suggest using `u32::from(input)` here but the `XX::from` function is not const, diff --git a/tests/ui/cast_lossless_bool.rs b/tests/ui/cast_lossless_bool.rs index e5b1c30c10350..cb307bd68e43e 100644 --- a/tests/ui/cast_lossless_bool.rs +++ b/tests/ui/cast_lossless_bool.rs @@ -1,6 +1,8 @@ #![allow(dead_code)] #![warn(clippy::cast_lossless)] +type U8 = u8; + fn main() { // Test clippy::cast_lossless with casts to integer types let _ = true as u8; @@ -19,6 +21,8 @@ fn main() { // Test with an expression wrapped in parens let _ = (true | false) as u16; + + let _ = true as U8; } // The lint would suggest using `u32::from(input)` here but the `XX::from` function is not const, diff --git a/tests/ui/cast_lossless_bool.stderr b/tests/ui/cast_lossless_bool.stderr index 792b30b7a38b3..b47b35461f686 100644 --- a/tests/ui/cast_lossless_bool.stderr +++ b/tests/ui/cast_lossless_bool.stderr @@ -1,5 +1,5 @@ error: casting `bool` to `u8` is more cleanly stated with `u8::from(_)` - --> tests/ui/cast_lossless_bool.rs:6:13 + --> tests/ui/cast_lossless_bool.rs:8:13 | LL | let _ = true as u8; | ^^^^^^^^^^ help: try: `u8::from(true)` @@ -8,82 +8,88 @@ LL | let _ = true as u8; = help: to override `-D warnings` add `#[allow(clippy::cast_lossless)]` error: casting `bool` to `u16` is more cleanly stated with `u16::from(_)` - --> tests/ui/cast_lossless_bool.rs:7:13 + --> tests/ui/cast_lossless_bool.rs:9:13 | LL | let _ = true as u16; | ^^^^^^^^^^^ help: try: `u16::from(true)` error: casting `bool` to `u32` is more cleanly stated with `u32::from(_)` - --> tests/ui/cast_lossless_bool.rs:8:13 + --> tests/ui/cast_lossless_bool.rs:10:13 | LL | let _ = true as u32; | ^^^^^^^^^^^ help: try: `u32::from(true)` error: casting `bool` to `u64` is more cleanly stated with `u64::from(_)` - --> tests/ui/cast_lossless_bool.rs:9:13 + --> tests/ui/cast_lossless_bool.rs:11:13 | LL | let _ = true as u64; | ^^^^^^^^^^^ help: try: `u64::from(true)` error: casting `bool` to `u128` is more cleanly stated with `u128::from(_)` - --> tests/ui/cast_lossless_bool.rs:10:13 + --> tests/ui/cast_lossless_bool.rs:12:13 | LL | let _ = true as u128; | ^^^^^^^^^^^^ help: try: `u128::from(true)` error: casting `bool` to `usize` is more cleanly stated with `usize::from(_)` - --> tests/ui/cast_lossless_bool.rs:11:13 + --> tests/ui/cast_lossless_bool.rs:13:13 | LL | let _ = true as usize; | ^^^^^^^^^^^^^ help: try: `usize::from(true)` error: casting `bool` to `i8` is more cleanly stated with `i8::from(_)` - --> tests/ui/cast_lossless_bool.rs:13:13 + --> tests/ui/cast_lossless_bool.rs:15:13 | LL | let _ = true as i8; | ^^^^^^^^^^ help: try: `i8::from(true)` error: casting `bool` to `i16` is more cleanly stated with `i16::from(_)` - --> tests/ui/cast_lossless_bool.rs:14:13 + --> tests/ui/cast_lossless_bool.rs:16:13 | LL | let _ = true as i16; | ^^^^^^^^^^^ help: try: `i16::from(true)` error: casting `bool` to `i32` is more cleanly stated with `i32::from(_)` - --> tests/ui/cast_lossless_bool.rs:15:13 + --> tests/ui/cast_lossless_bool.rs:17:13 | LL | let _ = true as i32; | ^^^^^^^^^^^ help: try: `i32::from(true)` error: casting `bool` to `i64` is more cleanly stated with `i64::from(_)` - --> tests/ui/cast_lossless_bool.rs:16:13 + --> tests/ui/cast_lossless_bool.rs:18:13 | LL | let _ = true as i64; | ^^^^^^^^^^^ help: try: `i64::from(true)` error: casting `bool` to `i128` is more cleanly stated with `i128::from(_)` - --> tests/ui/cast_lossless_bool.rs:17:13 + --> tests/ui/cast_lossless_bool.rs:19:13 | LL | let _ = true as i128; | ^^^^^^^^^^^^ help: try: `i128::from(true)` error: casting `bool` to `isize` is more cleanly stated with `isize::from(_)` - --> tests/ui/cast_lossless_bool.rs:18:13 + --> tests/ui/cast_lossless_bool.rs:20:13 | LL | let _ = true as isize; | ^^^^^^^^^^^^^ help: try: `isize::from(true)` error: casting `bool` to `u16` is more cleanly stated with `u16::from(_)` - --> tests/ui/cast_lossless_bool.rs:21:13 + --> tests/ui/cast_lossless_bool.rs:23:13 | LL | let _ = (true | false) as u16; | ^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::from(true | false)` +error: casting `bool` to `U8` is more cleanly stated with `U8::from(_)` + --> tests/ui/cast_lossless_bool.rs:25:13 + | +LL | let _ = true as U8; + | ^^^^^^^^^^ help: try: `U8::from(true)` + error: casting `bool` to `u8` is more cleanly stated with `u8::from(_)` - --> tests/ui/cast_lossless_bool.rs:49:13 + --> tests/ui/cast_lossless_bool.rs:53:13 | LL | let _ = true as u8; | ^^^^^^^^^^ help: try: `u8::from(true)` -error: aborting due to 14 previous errors +error: aborting due to 15 previous errors diff --git a/tests/ui/cast_lossless_float.fixed b/tests/ui/cast_lossless_float.fixed index f4f2e4773a533..96a67b1945ca6 100644 --- a/tests/ui/cast_lossless_float.fixed +++ b/tests/ui/cast_lossless_float.fixed @@ -1,11 +1,16 @@ #![allow(clippy::no_effect, clippy::unnecessary_operation, dead_code)] #![warn(clippy::cast_lossless)] +type F32 = f32; +type F64 = f64; + fn main() { // Test clippy::cast_lossless with casts to floating-point types let x0 = 1i8; let _ = f32::from(x0); let _ = f64::from(x0); + let _ = F32::from(x0); + let _ = F64::from(x0); let x1 = 1u8; let _ = f32::from(x1); let _ = f64::from(x1); diff --git a/tests/ui/cast_lossless_float.rs b/tests/ui/cast_lossless_float.rs index fdd88ed36fc63..d37b2c1d920ea 100644 --- a/tests/ui/cast_lossless_float.rs +++ b/tests/ui/cast_lossless_float.rs @@ -1,11 +1,16 @@ #![allow(clippy::no_effect, clippy::unnecessary_operation, dead_code)] #![warn(clippy::cast_lossless)] +type F32 = f32; +type F64 = f64; + fn main() { // Test clippy::cast_lossless with casts to floating-point types let x0 = 1i8; let _ = x0 as f32; let _ = x0 as f64; + let _ = x0 as F32; + let _ = x0 as F64; let x1 = 1u8; let _ = x1 as f32; let _ = x1 as f64; diff --git a/tests/ui/cast_lossless_float.stderr b/tests/ui/cast_lossless_float.stderr index e70f81eb91fc7..ad7de760adfb8 100644 --- a/tests/ui/cast_lossless_float.stderr +++ b/tests/ui/cast_lossless_float.stderr @@ -1,5 +1,5 @@ error: casting `i8` to `f32` may become silently lossy if you later change the type - --> tests/ui/cast_lossless_float.rs:7:13 + --> tests/ui/cast_lossless_float.rs:10:13 | LL | let _ = x0 as f32; | ^^^^^^^^^ help: try: `f32::from(x0)` @@ -8,64 +8,76 @@ LL | let _ = x0 as f32; = help: to override `-D warnings` add `#[allow(clippy::cast_lossless)]` error: casting `i8` to `f64` may become silently lossy if you later change the type - --> tests/ui/cast_lossless_float.rs:8:13 + --> tests/ui/cast_lossless_float.rs:11:13 | LL | let _ = x0 as f64; | ^^^^^^^^^ help: try: `f64::from(x0)` +error: casting `i8` to `F32` may become silently lossy if you later change the type + --> tests/ui/cast_lossless_float.rs:12:13 + | +LL | let _ = x0 as F32; + | ^^^^^^^^^ help: try: `F32::from(x0)` + +error: casting `i8` to `F64` may become silently lossy if you later change the type + --> tests/ui/cast_lossless_float.rs:13:13 + | +LL | let _ = x0 as F64; + | ^^^^^^^^^ help: try: `F64::from(x0)` + error: casting `u8` to `f32` may become silently lossy if you later change the type - --> tests/ui/cast_lossless_float.rs:10:13 + --> tests/ui/cast_lossless_float.rs:15:13 | LL | let _ = x1 as f32; | ^^^^^^^^^ help: try: `f32::from(x1)` error: casting `u8` to `f64` may become silently lossy if you later change the type - --> tests/ui/cast_lossless_float.rs:11:13 + --> tests/ui/cast_lossless_float.rs:16:13 | LL | let _ = x1 as f64; | ^^^^^^^^^ help: try: `f64::from(x1)` error: casting `i16` to `f32` may become silently lossy if you later change the type - --> tests/ui/cast_lossless_float.rs:13:13 + --> tests/ui/cast_lossless_float.rs:18:13 | LL | let _ = x2 as f32; | ^^^^^^^^^ help: try: `f32::from(x2)` error: casting `i16` to `f64` may become silently lossy if you later change the type - --> tests/ui/cast_lossless_float.rs:14:13 + --> tests/ui/cast_lossless_float.rs:19:13 | LL | let _ = x2 as f64; | ^^^^^^^^^ help: try: `f64::from(x2)` error: casting `u16` to `f32` may become silently lossy if you later change the type - --> tests/ui/cast_lossless_float.rs:16:13 + --> tests/ui/cast_lossless_float.rs:21:13 | LL | let _ = x3 as f32; | ^^^^^^^^^ help: try: `f32::from(x3)` error: casting `u16` to `f64` may become silently lossy if you later change the type - --> tests/ui/cast_lossless_float.rs:17:13 + --> tests/ui/cast_lossless_float.rs:22:13 | LL | let _ = x3 as f64; | ^^^^^^^^^ help: try: `f64::from(x3)` error: casting `i32` to `f64` may become silently lossy if you later change the type - --> tests/ui/cast_lossless_float.rs:19:13 + --> tests/ui/cast_lossless_float.rs:24:13 | LL | let _ = x4 as f64; | ^^^^^^^^^ help: try: `f64::from(x4)` error: casting `u32` to `f64` may become silently lossy if you later change the type - --> tests/ui/cast_lossless_float.rs:21:13 + --> tests/ui/cast_lossless_float.rs:26:13 | LL | let _ = x5 as f64; | ^^^^^^^^^ help: try: `f64::from(x5)` error: casting `f32` to `f64` may become silently lossy if you later change the type - --> tests/ui/cast_lossless_float.rs:24:13 + --> tests/ui/cast_lossless_float.rs:29:13 | LL | let _ = 1.0f32 as f64; | ^^^^^^^^^^^^^ help: try: `f64::from(1.0f32)` -error: aborting due to 11 previous errors +error: aborting due to 13 previous errors diff --git a/tests/ui/cast_lossless_integer.fixed b/tests/ui/cast_lossless_integer.fixed index 5e7e545e764a5..291556a977410 100644 --- a/tests/ui/cast_lossless_integer.fixed +++ b/tests/ui/cast_lossless_integer.fixed @@ -1,6 +1,9 @@ #![allow(clippy::no_effect, clippy::unnecessary_operation, dead_code)] #![warn(clippy::cast_lossless)] +type I64 = i64; +type U128 = u128; + fn main() { // Test clippy::cast_lossless with casts to integer types let _ = i16::from(1i8); @@ -24,6 +27,13 @@ fn main() { // Test with an expression wrapped in parens let _ = u16::from(1u8 + 1u8); + + let _ = I64::from(1i8); + + // Do not lint if destination type is u128 + // see https://github.com/rust-lang/rust-clippy/issues/12492 + let _ = 1u8 as u128; + let _ = 1u8 as U128; } // The lint would suggest using `f64::from(input)` here but the `XX::from` function is not const, diff --git a/tests/ui/cast_lossless_integer.rs b/tests/ui/cast_lossless_integer.rs index 0d69ddbd586a5..a917c7a371d8a 100644 --- a/tests/ui/cast_lossless_integer.rs +++ b/tests/ui/cast_lossless_integer.rs @@ -1,6 +1,9 @@ #![allow(clippy::no_effect, clippy::unnecessary_operation, dead_code)] #![warn(clippy::cast_lossless)] +type I64 = i64; +type U128 = u128; + fn main() { // Test clippy::cast_lossless with casts to integer types let _ = 1i8 as i16; @@ -24,6 +27,13 @@ fn main() { // Test with an expression wrapped in parens let _ = (1u8 + 1u8) as u16; + + let _ = 1i8 as I64; + + // Do not lint if destination type is u128 + // see https://github.com/rust-lang/rust-clippy/issues/12492 + let _ = 1u8 as u128; + let _ = 1u8 as U128; } // The lint would suggest using `f64::from(input)` here but the `XX::from` function is not const, diff --git a/tests/ui/cast_lossless_integer.stderr b/tests/ui/cast_lossless_integer.stderr index 43d4ce3ce9161..aaece9392856f 100644 --- a/tests/ui/cast_lossless_integer.stderr +++ b/tests/ui/cast_lossless_integer.stderr @@ -1,5 +1,5 @@ error: casting `i8` to `i16` may become silently lossy if you later change the type - --> tests/ui/cast_lossless_integer.rs:6:13 + --> tests/ui/cast_lossless_integer.rs:9:13 | LL | let _ = 1i8 as i16; | ^^^^^^^^^^ help: try: `i16::from(1i8)` @@ -8,124 +8,130 @@ LL | let _ = 1i8 as i16; = help: to override `-D warnings` add `#[allow(clippy::cast_lossless)]` error: casting `i8` to `i32` may become silently lossy if you later change the type - --> tests/ui/cast_lossless_integer.rs:7:13 + --> tests/ui/cast_lossless_integer.rs:10:13 | LL | let _ = 1i8 as i32; | ^^^^^^^^^^ help: try: `i32::from(1i8)` error: casting `i8` to `i64` may become silently lossy if you later change the type - --> tests/ui/cast_lossless_integer.rs:8:13 + --> tests/ui/cast_lossless_integer.rs:11:13 | LL | let _ = 1i8 as i64; | ^^^^^^^^^^ help: try: `i64::from(1i8)` error: casting `u8` to `i16` may become silently lossy if you later change the type - --> tests/ui/cast_lossless_integer.rs:9:13 + --> tests/ui/cast_lossless_integer.rs:12:13 | LL | let _ = 1u8 as i16; | ^^^^^^^^^^ help: try: `i16::from(1u8)` error: casting `u8` to `i32` may become silently lossy if you later change the type - --> tests/ui/cast_lossless_integer.rs:10:13 + --> tests/ui/cast_lossless_integer.rs:13:13 | LL | let _ = 1u8 as i32; | ^^^^^^^^^^ help: try: `i32::from(1u8)` error: casting `u8` to `i64` may become silently lossy if you later change the type - --> tests/ui/cast_lossless_integer.rs:11:13 + --> tests/ui/cast_lossless_integer.rs:14:13 | LL | let _ = 1u8 as i64; | ^^^^^^^^^^ help: try: `i64::from(1u8)` error: casting `u8` to `u16` may become silently lossy if you later change the type - --> tests/ui/cast_lossless_integer.rs:12:13 + --> tests/ui/cast_lossless_integer.rs:15:13 | LL | let _ = 1u8 as u16; | ^^^^^^^^^^ help: try: `u16::from(1u8)` error: casting `u8` to `u32` may become silently lossy if you later change the type - --> tests/ui/cast_lossless_integer.rs:13:13 + --> tests/ui/cast_lossless_integer.rs:16:13 | LL | let _ = 1u8 as u32; | ^^^^^^^^^^ help: try: `u32::from(1u8)` error: casting `u8` to `u64` may become silently lossy if you later change the type - --> tests/ui/cast_lossless_integer.rs:14:13 + --> tests/ui/cast_lossless_integer.rs:17:13 | LL | let _ = 1u8 as u64; | ^^^^^^^^^^ help: try: `u64::from(1u8)` error: casting `i16` to `i32` may become silently lossy if you later change the type - --> tests/ui/cast_lossless_integer.rs:15:13 + --> tests/ui/cast_lossless_integer.rs:18:13 | LL | let _ = 1i16 as i32; | ^^^^^^^^^^^ help: try: `i32::from(1i16)` error: casting `i16` to `i64` may become silently lossy if you later change the type - --> tests/ui/cast_lossless_integer.rs:16:13 + --> tests/ui/cast_lossless_integer.rs:19:13 | LL | let _ = 1i16 as i64; | ^^^^^^^^^^^ help: try: `i64::from(1i16)` error: casting `u16` to `i32` may become silently lossy if you later change the type - --> tests/ui/cast_lossless_integer.rs:17:13 + --> tests/ui/cast_lossless_integer.rs:20:13 | LL | let _ = 1u16 as i32; | ^^^^^^^^^^^ help: try: `i32::from(1u16)` error: casting `u16` to `i64` may become silently lossy if you later change the type - --> tests/ui/cast_lossless_integer.rs:18:13 + --> tests/ui/cast_lossless_integer.rs:21:13 | LL | let _ = 1u16 as i64; | ^^^^^^^^^^^ help: try: `i64::from(1u16)` error: casting `u16` to `u32` may become silently lossy if you later change the type - --> tests/ui/cast_lossless_integer.rs:19:13 + --> tests/ui/cast_lossless_integer.rs:22:13 | LL | let _ = 1u16 as u32; | ^^^^^^^^^^^ help: try: `u32::from(1u16)` error: casting `u16` to `u64` may become silently lossy if you later change the type - --> tests/ui/cast_lossless_integer.rs:20:13 + --> tests/ui/cast_lossless_integer.rs:23:13 | LL | let _ = 1u16 as u64; | ^^^^^^^^^^^ help: try: `u64::from(1u16)` error: casting `i32` to `i64` may become silently lossy if you later change the type - --> tests/ui/cast_lossless_integer.rs:21:13 + --> tests/ui/cast_lossless_integer.rs:24:13 | LL | let _ = 1i32 as i64; | ^^^^^^^^^^^ help: try: `i64::from(1i32)` error: casting `u32` to `i64` may become silently lossy if you later change the type - --> tests/ui/cast_lossless_integer.rs:22:13 + --> tests/ui/cast_lossless_integer.rs:25:13 | LL | let _ = 1u32 as i64; | ^^^^^^^^^^^ help: try: `i64::from(1u32)` error: casting `u32` to `u64` may become silently lossy if you later change the type - --> tests/ui/cast_lossless_integer.rs:23:13 + --> tests/ui/cast_lossless_integer.rs:26:13 | LL | let _ = 1u32 as u64; | ^^^^^^^^^^^ help: try: `u64::from(1u32)` error: casting `u8` to `u16` may become silently lossy if you later change the type - --> tests/ui/cast_lossless_integer.rs:26:13 + --> tests/ui/cast_lossless_integer.rs:29:13 | LL | let _ = (1u8 + 1u8) as u16; | ^^^^^^^^^^^^^^^^^^ help: try: `u16::from(1u8 + 1u8)` +error: casting `i8` to `I64` may become silently lossy if you later change the type + --> tests/ui/cast_lossless_integer.rs:31:13 + | +LL | let _ = 1i8 as I64; + | ^^^^^^^^^^ help: try: `I64::from(1i8)` + error: casting `i8` to `i32` may become silently lossy if you later change the type - --> tests/ui/cast_lossless_integer.rs:60:13 + --> tests/ui/cast_lossless_integer.rs:70:13 | LL | let _ = sign_cast!(x, u8, i8) as i32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::from(sign_cast!(x, u8, i8))` error: casting `i8` to `i32` may become silently lossy if you later change the type - --> tests/ui/cast_lossless_integer.rs:61:13 + --> tests/ui/cast_lossless_integer.rs:71:13 | LL | let _ = (sign_cast!(x, u8, i8) + 1) as i32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::from(sign_cast!(x, u8, i8) + 1)` -error: aborting due to 21 previous errors +error: aborting due to 22 previous errors diff --git a/tests/ui/const_is_empty.rs b/tests/ui/const_is_empty.rs new file mode 100644 index 0000000000000..ae37a82e4f936 --- /dev/null +++ b/tests/ui/const_is_empty.rs @@ -0,0 +1,174 @@ +#![feature(inline_const)] +#![warn(clippy::const_is_empty)] +#![allow(clippy::needless_late_init, unused_must_use)] + +fn test_literal() { + if "".is_empty() { + //~^ERROR: this expression always evaluates to true + } + if "foobar".is_empty() { + //~^ERROR: this expression always evaluates to false + } +} + +fn test_byte_literal() { + if b"".is_empty() { + //~^ERROR: this expression always evaluates to true + } + if b"foobar".is_empty() { + //~^ERROR: this expression always evaluates to false + } +} + +fn test_no_mut() { + let mut empty = ""; + if empty.is_empty() { + // No lint because it is mutable + } +} + +fn test_propagated() { + let empty = ""; + let non_empty = "foobar"; + let empty2 = empty; + let non_empty2 = non_empty; + if empty2.is_empty() { + //~^ERROR: this expression always evaluates to true + } + if non_empty2.is_empty() { + //~^ERROR: this expression always evaluates to false + } +} + +const EMPTY_STR: &str = ""; +const NON_EMPTY_STR: &str = "foo"; +const EMPTY_BSTR: &[u8] = b""; +const NON_EMPTY_BSTR: &[u8] = b"foo"; +const EMPTY_U8_SLICE: &[u8] = &[]; +const NON_EMPTY_U8_SLICE: &[u8] = &[1, 2]; +const EMPTY_SLICE: &[u32] = &[]; +const NON_EMPTY_SLICE: &[u32] = &[1, 2]; +const NON_EMPTY_SLICE_REPEAT: &[u32] = &[1; 2]; +const EMPTY_ARRAY: [u32; 0] = []; +const EMPTY_ARRAY_REPEAT: [u32; 0] = [1; 0]; +const NON_EMPTY_ARRAY: [u32; 2] = [1, 2]; +const NON_EMPTY_ARRAY_REPEAT: [u32; 2] = [1; 2]; +const EMPTY_REF_ARRAY: &[u32; 0] = &[]; +const NON_EMPTY_REF_ARRAY: &[u32; 3] = &[1, 2, 3]; + +fn test_from_const() { + let _ = EMPTY_STR.is_empty(); + //~^ ERROR: this expression always evaluates to true + let _ = NON_EMPTY_STR.is_empty(); + //~^ ERROR: this expression always evaluates to false + let _ = EMPTY_BSTR.is_empty(); + //~^ ERROR: this expression always evaluates to true + let _ = NON_EMPTY_BSTR.is_empty(); + //~^ ERROR: this expression always evaluates to false + let _ = EMPTY_ARRAY.is_empty(); + //~^ ERROR: this expression always evaluates to true + let _ = EMPTY_ARRAY_REPEAT.is_empty(); + //~^ ERROR: this expression always evaluates to true + let _ = EMPTY_U8_SLICE.is_empty(); + //~^ ERROR: this expression always evaluates to true + let _ = NON_EMPTY_U8_SLICE.is_empty(); + //~^ ERROR: this expression always evaluates to false + let _ = NON_EMPTY_ARRAY.is_empty(); + //~^ ERROR: this expression always evaluates to false + let _ = NON_EMPTY_ARRAY_REPEAT.is_empty(); + //~^ ERROR: this expression always evaluates to false + let _ = EMPTY_REF_ARRAY.is_empty(); + //~^ ERROR: this expression always evaluates to true + let _ = NON_EMPTY_REF_ARRAY.is_empty(); + //~^ ERROR: this expression always evaluates to false + let _ = EMPTY_SLICE.is_empty(); + //~^ ERROR: this expression always evaluates to true + let _ = NON_EMPTY_SLICE.is_empty(); + //~^ ERROR: this expression always evaluates to false + let _ = NON_EMPTY_SLICE_REPEAT.is_empty(); + //~^ ERROR: this expression always evaluates to false +} + +fn main() { + let value = "foobar"; + let _ = value.is_empty(); + //~^ ERROR: this expression always evaluates to false + let x = value; + let _ = x.is_empty(); + //~^ ERROR: this expression always evaluates to false + let _ = "".is_empty(); + //~^ ERROR: this expression always evaluates to true + let _ = b"".is_empty(); + //~^ ERROR: this expression always evaluates to true +} + +fn str_from_arg(var: &str) { + var.is_empty(); + // Do not lint, we know nothiny about var +} + +fn update_str() { + let mut value = "duck"; + value = "penguin"; + + let _ = value.is_empty(); + // Do not lint since value is mutable +} + +fn macros() { + // Content from Macro + let file = include_str!("const_is_empty.rs"); + let _ = file.is_empty(); + // No lint because initializer comes from a macro result + + let var = env!("PATH"); + let _ = var.is_empty(); + // No lint because initializer comes from a macro result +} + +fn conditional_value() { + let value; + + if true { + value = "hey"; + } else { + value = "hej"; + } + + let _ = value.is_empty(); + // Do not lint, current constant folding is too simple to detect this +} + +fn cfg_conditioned() { + #[cfg(test)] + let val = ""; + #[cfg(not(test))] + let val = "foo"; + + let _ = val.is_empty(); + // Do not lint, value depend on a #[cfg(…)] directive +} + +fn not_cfg_conditioned() { + let val = ""; + #[cfg(not(target_os = "inexistent"))] + let _ = val.is_empty(); + //~^ ERROR: this expression always evaluates to true +} + +const fn const_rand() -> &'static str { + "17" +} + +fn const_expressions() { + let _ = const { if true { "1" } else { "2" } }.is_empty(); + // Do not lint, we do not recurse into boolean expressions + + let _ = const_rand().is_empty(); + // Do not lint, we do not recurse into functions +} + +fn constant_from_external_crate() { + let _ = std::env::consts::EXE_EXTENSION.is_empty(); + // Do not lint, `exe_ext` comes from the `std` crate +} diff --git a/tests/ui/const_is_empty.stderr b/tests/ui/const_is_empty.stderr new file mode 100644 index 0000000000000..0e09da77bb469 --- /dev/null +++ b/tests/ui/const_is_empty.stderr @@ -0,0 +1,161 @@ +error: this expression always evaluates to true + --> tests/ui/const_is_empty.rs:6:8 + | +LL | if "".is_empty() { + | ^^^^^^^^^^^^^ + | + = note: `-D clippy::const-is-empty` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::const_is_empty)]` + +error: this expression always evaluates to false + --> tests/ui/const_is_empty.rs:9:8 + | +LL | if "foobar".is_empty() { + | ^^^^^^^^^^^^^^^^^^^ + +error: this expression always evaluates to true + --> tests/ui/const_is_empty.rs:15:8 + | +LL | if b"".is_empty() { + | ^^^^^^^^^^^^^^ + +error: this expression always evaluates to false + --> tests/ui/const_is_empty.rs:18:8 + | +LL | if b"foobar".is_empty() { + | ^^^^^^^^^^^^^^^^^^^^ + +error: this expression always evaluates to true + --> tests/ui/const_is_empty.rs:35:8 + | +LL | if empty2.is_empty() { + | ^^^^^^^^^^^^^^^^^ + +error: this expression always evaluates to false + --> tests/ui/const_is_empty.rs:38:8 + | +LL | if non_empty2.is_empty() { + | ^^^^^^^^^^^^^^^^^^^^^ + +error: this expression always evaluates to true + --> tests/ui/const_is_empty.rs:60:13 + | +LL | let _ = EMPTY_STR.is_empty(); + | ^^^^^^^^^^^^^^^^^^^^ + +error: this expression always evaluates to false + --> tests/ui/const_is_empty.rs:62:13 + | +LL | let _ = NON_EMPTY_STR.is_empty(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: this expression always evaluates to true + --> tests/ui/const_is_empty.rs:64:13 + | +LL | let _ = EMPTY_BSTR.is_empty(); + | ^^^^^^^^^^^^^^^^^^^^^ + +error: this expression always evaluates to false + --> tests/ui/const_is_empty.rs:66:13 + | +LL | let _ = NON_EMPTY_BSTR.is_empty(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: this expression always evaluates to true + --> tests/ui/const_is_empty.rs:68:13 + | +LL | let _ = EMPTY_ARRAY.is_empty(); + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: this expression always evaluates to true + --> tests/ui/const_is_empty.rs:70:13 + | +LL | let _ = EMPTY_ARRAY_REPEAT.is_empty(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: this expression always evaluates to true + --> tests/ui/const_is_empty.rs:72:13 + | +LL | let _ = EMPTY_U8_SLICE.is_empty(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: this expression always evaluates to false + --> tests/ui/const_is_empty.rs:74:13 + | +LL | let _ = NON_EMPTY_U8_SLICE.is_empty(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: this expression always evaluates to false + --> tests/ui/const_is_empty.rs:76:13 + | +LL | let _ = NON_EMPTY_ARRAY.is_empty(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: this expression always evaluates to false + --> tests/ui/const_is_empty.rs:78:13 + | +LL | let _ = NON_EMPTY_ARRAY_REPEAT.is_empty(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: this expression always evaluates to true + --> tests/ui/const_is_empty.rs:80:13 + | +LL | let _ = EMPTY_REF_ARRAY.is_empty(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: this expression always evaluates to false + --> tests/ui/const_is_empty.rs:82:13 + | +LL | let _ = NON_EMPTY_REF_ARRAY.is_empty(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: this expression always evaluates to true + --> tests/ui/const_is_empty.rs:84:13 + | +LL | let _ = EMPTY_SLICE.is_empty(); + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: this expression always evaluates to false + --> tests/ui/const_is_empty.rs:86:13 + | +LL | let _ = NON_EMPTY_SLICE.is_empty(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: this expression always evaluates to false + --> tests/ui/const_is_empty.rs:88:13 + | +LL | let _ = NON_EMPTY_SLICE_REPEAT.is_empty(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: this expression always evaluates to false + --> tests/ui/const_is_empty.rs:94:13 + | +LL | let _ = value.is_empty(); + | ^^^^^^^^^^^^^^^^ + +error: this expression always evaluates to false + --> tests/ui/const_is_empty.rs:97:13 + | +LL | let _ = x.is_empty(); + | ^^^^^^^^^^^^ + +error: this expression always evaluates to true + --> tests/ui/const_is_empty.rs:99:13 + | +LL | let _ = "".is_empty(); + | ^^^^^^^^^^^^^ + +error: this expression always evaluates to true + --> tests/ui/const_is_empty.rs:101:13 + | +LL | let _ = b"".is_empty(); + | ^^^^^^^^^^^^^^ + +error: this expression always evaluates to true + --> tests/ui/const_is_empty.rs:155:13 + | +LL | let _ = val.is_empty(); + | ^^^^^^^^^^^^^^ + +error: aborting due to 26 previous errors + diff --git a/tests/ui/crashes/ice-12491.fixed b/tests/ui/crashes/ice-12491.fixed new file mode 100644 index 0000000000000..4ea480b0663ca --- /dev/null +++ b/tests/ui/crashes/ice-12491.fixed @@ -0,0 +1,7 @@ +#![warn(clippy::needless_return)] + +fn main() { + if (true) { + // anything一些中文 + } +} diff --git a/tests/ui/crashes/ice-12491.rs b/tests/ui/crashes/ice-12491.rs new file mode 100644 index 0000000000000..60add6afa2c4f --- /dev/null +++ b/tests/ui/crashes/ice-12491.rs @@ -0,0 +1,8 @@ +#![warn(clippy::needless_return)] + +fn main() { + if (true) { + // anything一些中文 + return; + } +} diff --git a/tests/ui/crashes/ice-12491.stderr b/tests/ui/crashes/ice-12491.stderr new file mode 100644 index 0000000000000..7cc418898e881 --- /dev/null +++ b/tests/ui/crashes/ice-12491.stderr @@ -0,0 +1,19 @@ +error: unneeded `return` statement + --> tests/ui/crashes/ice-12491.rs:5:24 + | +LL | // anything一些中文 + | ____________________________^ +LL | | return; + | |______________^ + | + = note: `-D clippy::needless-return` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_return)]` +help: remove `return` + | +LL - // anything一些中文 +LL - return; +LL + // anything一些中文 + | + +error: aborting due to 1 previous error + diff --git a/tests/ui/dbg_macro/dbg_macro.fixed b/tests/ui/dbg_macro/dbg_macro.fixed new file mode 100644 index 0000000000000..e352519142332 --- /dev/null +++ b/tests/ui/dbg_macro/dbg_macro.fixed @@ -0,0 +1,111 @@ +#![warn(clippy::dbg_macro)] +#![allow(clippy::unnecessary_operation, clippy::no_effect)] + +fn foo(n: u32) -> u32 { + if let Some(n) = n.checked_sub(4) { n } else { n } + //~^ ERROR: the `dbg!` macro is intended as a debugging tool +} +fn bar(_: ()) {} + +fn factorial(n: u32) -> u32 { + if n <= 1 { + //~^ ERROR: the `dbg!` macro is intended as a debugging tool + 1 + //~^ ERROR: the `dbg!` macro is intended as a debugging tool + } else { + n * factorial(n - 1) + //~^ ERROR: the `dbg!` macro is intended as a debugging tool + } +} + +fn main() { + 42; + //~^ ERROR: the `dbg!` macro is intended as a debugging tool + foo(3) + factorial(4); + //~^ ERROR: the `dbg!` macro is intended as a debugging tool + (1, 2, 3, 4, 5); + //~^ ERROR: the `dbg!` macro is intended as a debugging tool +} + +fn issue9914() { + macro_rules! foo { + ($x:expr) => { + $x; + }; + } + macro_rules! foo2 { + ($x:expr) => { + $x; + }; + } + macro_rules! expand_to_dbg { + () => { + + //~^ ERROR: the `dbg!` macro is intended as a debugging tool + }; + } + + + //~^ ERROR: the `dbg!` macro is intended as a debugging tool + #[allow(clippy::let_unit_value)] + let _ = (); + //~^ ERROR: the `dbg!` macro is intended as a debugging tool + bar(()); + //~^ ERROR: the `dbg!` macro is intended as a debugging tool + foo!(()); + //~^ ERROR: the `dbg!` macro is intended as a debugging tool + foo2!(foo!(())); + //~^ ERROR: the `dbg!` macro is intended as a debugging tool + expand_to_dbg!(); +} + +mod issue7274 { + trait Thing<'b> { + fn foo(&self); + } + + macro_rules! define_thing { + ($thing:ident, $body:expr) => { + impl<'a> Thing<'a> for $thing { + fn foo<'b>(&self) { + $body + } + } + }; + } + + struct MyThing; + define_thing!(MyThing, { + 2; + //~^ ERROR: the `dbg!` macro is intended as a debugging tool + }); +} + +#[test] +pub fn issue8481() { + 1; + //~^ ERROR: the `dbg!` macro is intended as a debugging tool +} + +#[cfg(test)] +fn foo2() { + 1; + //~^ ERROR: the `dbg!` macro is intended as a debugging tool +} + +#[cfg(test)] +mod mod1 { + fn func() { + 1; + //~^ ERROR: the `dbg!` macro is intended as a debugging tool + } +} + +mod issue12131 { + fn dbg_in_print(s: &str) { + println!("dbg: {:?}", s); + //~^ ERROR: the `dbg!` macro is intended as a debugging tool + print!("{}", s); + //~^ ERROR: the `dbg!` macro is intended as a debugging tool + } +} diff --git a/tests/ui/dbg_macro/dbg_macro.rs b/tests/ui/dbg_macro/dbg_macro.rs index 3f4770c63d014..80606c2db054a 100644 --- a/tests/ui/dbg_macro/dbg_macro.rs +++ b/tests/ui/dbg_macro/dbg_macro.rs @@ -1,9 +1,5 @@ -//@no-rustfix - #![warn(clippy::dbg_macro)] - -#[path = "auxiliary/submodule.rs"] -mod submodule; +#![allow(clippy::unnecessary_operation, clippy::no_effect)] fn foo(n: u32) -> u32 { if let Some(n) = dbg!(n.checked_sub(4)) { n } else { n } @@ -25,12 +21,8 @@ fn factorial(n: u32) -> u32 { fn main() { dbg!(42); //~^ ERROR: the `dbg!` macro is intended as a debugging tool - dbg!(dbg!(dbg!(42))); - //~^ ERROR: the `dbg!` macro is intended as a debugging tool foo(3) + dbg!(factorial(4)); //~^ ERROR: the `dbg!` macro is intended as a debugging tool - dbg!(1, 2, dbg!(3, 4)); - //~^ ERROR: the `dbg!` macro is intended as a debugging tool dbg!(1, 2, 3, 4, 5); //~^ ERROR: the `dbg!` macro is intended as a debugging tool } @@ -49,6 +41,7 @@ fn issue9914() { macro_rules! expand_to_dbg { () => { dbg!(); + //~^ ERROR: the `dbg!` macro is intended as a debugging tool }; } @@ -107,3 +100,12 @@ mod mod1 { //~^ ERROR: the `dbg!` macro is intended as a debugging tool } } + +mod issue12131 { + fn dbg_in_print(s: &str) { + println!("dbg: {:?}", dbg!(s)); + //~^ ERROR: the `dbg!` macro is intended as a debugging tool + print!("{}", dbg!(s)); + //~^ ERROR: the `dbg!` macro is intended as a debugging tool + } +} diff --git a/tests/ui/dbg_macro/dbg_macro.stderr b/tests/ui/dbg_macro/dbg_macro.stderr index 5ad0bbfed9422..86667701da0f3 100644 --- a/tests/ui/dbg_macro/dbg_macro.stderr +++ b/tests/ui/dbg_macro/dbg_macro.stderr @@ -1,30 +1,18 @@ error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/auxiliary/submodule.rs:2:5 - | -LL | dbg!(); - | ^^^^^^^ - | - = note: `-D clippy::dbg-macro` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::dbg_macro)]` -help: remove the invocation before committing it to a version control system - | -LL - dbg!(); -LL + - | - -error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:9:22 + --> tests/ui/dbg_macro/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: to override `-D warnings` add `#[allow(clippy::dbg_macro)]` 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: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:15:8 + --> tests/ui/dbg_macro/dbg_macro.rs:11:8 | LL | if dbg!(n <= 1) { | ^^^^^^^^^^^^ @@ -35,7 +23,7 @@ LL | if n <= 1 { | ~~~~~~ error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:17:9 + --> tests/ui/dbg_macro/dbg_macro.rs:13:9 | LL | dbg!(1) | ^^^^^^^ @@ -46,7 +34,7 @@ LL | 1 | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:20:9 + --> tests/ui/dbg_macro/dbg_macro.rs:16:9 | LL | dbg!(n * factorial(n - 1)) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -57,7 +45,7 @@ LL | n * factorial(n - 1) | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:26:5 + --> tests/ui/dbg_macro/dbg_macro.rs:22:5 | LL | dbg!(42); | ^^^^^^^^ @@ -68,18 +56,7 @@ LL | 42; | ~~ error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:28:5 - | -LL | dbg!(dbg!(dbg!(42))); - | ^^^^^^^^^^^^^^^^^^^^ - | -help: remove the invocation before committing it to a version control system - | -LL | dbg!(dbg!(42)); - | ~~~~~~~~~~~~~~ - -error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:30:14 + --> tests/ui/dbg_macro/dbg_macro.rs:24:14 | LL | foo(3) + dbg!(factorial(4)); | ^^^^^^^^^^^^^^^^^^ @@ -90,18 +67,7 @@ LL | foo(3) + factorial(4); | ~~~~~~~~~~~~ error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:32:5 - | -LL | dbg!(1, 2, dbg!(3, 4)); - | ^^^^^^^^^^^^^^^^^^^^^^ - | -help: remove the invocation before committing it to a version control system - | -LL | (1, 2, dbg!(3, 4)); - | ~~~~~~~~~~~~~~~~~~ - -error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:34:5 + --> tests/ui/dbg_macro/dbg_macro.rs:26:5 | LL | dbg!(1, 2, 3, 4, 5); | ^^^^^^^^^^^^^^^^^^^ @@ -112,7 +78,7 @@ LL | (1, 2, 3, 4, 5); | ~~~~~~~~~~~~~~~ error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:55:5 + --> tests/ui/dbg_macro/dbg_macro.rs:48:5 | LL | dbg!(); | ^^^^^^^ @@ -124,7 +90,7 @@ LL + | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:58:13 + --> tests/ui/dbg_macro/dbg_macro.rs:51:13 | LL | let _ = dbg!(); | ^^^^^^ @@ -135,7 +101,7 @@ LL | let _ = (); | ~~ error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:60:9 + --> tests/ui/dbg_macro/dbg_macro.rs:53:9 | LL | bar(dbg!()); | ^^^^^^ @@ -146,7 +112,7 @@ LL | bar(()); | ~~ error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:62:10 + --> tests/ui/dbg_macro/dbg_macro.rs:55:10 | LL | foo!(dbg!()); | ^^^^^^ @@ -157,7 +123,7 @@ LL | foo!(()); | ~~ error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:64:16 + --> tests/ui/dbg_macro/dbg_macro.rs:57:16 | LL | foo2!(foo!(dbg!())); | ^^^^^^ @@ -168,7 +134,23 @@ LL | foo2!(foo!(())); | ~~ error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:86:9 + --> tests/ui/dbg_macro/dbg_macro.rs:43:13 + | +LL | dbg!(); + | ^^^^^^^ +... +LL | expand_to_dbg!(); + | ---------------- in this macro invocation + | + = note: this error originates in the macro `expand_to_dbg` (in Nightly builds, run with -Z macro-backtrace for more info) +help: remove the invocation before committing it to a version control system + | +LL - dbg!(); +LL + + | + +error: the `dbg!` macro is intended as a debugging tool + --> tests/ui/dbg_macro/dbg_macro.rs:79:9 | LL | dbg!(2); | ^^^^^^^ @@ -179,7 +161,7 @@ LL | 2; | ~ error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:93:5 + --> tests/ui/dbg_macro/dbg_macro.rs:86:5 | LL | dbg!(1); | ^^^^^^^ @@ -190,7 +172,7 @@ LL | 1; | ~ error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:99:5 + --> tests/ui/dbg_macro/dbg_macro.rs:92:5 | LL | dbg!(1); | ^^^^^^^ @@ -201,7 +183,7 @@ LL | 1; | ~ error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:106:9 + --> tests/ui/dbg_macro/dbg_macro.rs:99:9 | LL | dbg!(1); | ^^^^^^^ @@ -211,5 +193,27 @@ help: remove the invocation before committing it to a version control system LL | 1; | ~ +error: the `dbg!` macro is intended as a debugging tool + --> tests/ui/dbg_macro/dbg_macro.rs:106:31 + | +LL | println!("dbg: {:?}", dbg!(s)); + | ^^^^^^^ + | +help: remove the invocation before committing it to a version control system + | +LL | println!("dbg: {:?}", s); + | ~ + +error: the `dbg!` macro is intended as a debugging tool + --> tests/ui/dbg_macro/dbg_macro.rs:108:22 + | +LL | print!("{}", dbg!(s)); + | ^^^^^^^ + | +help: remove the invocation before committing it to a version control system + | +LL | print!("{}", s); + | ~ + error: aborting due to 19 previous errors diff --git a/tests/ui/dbg_macro/dbg_macro_unfixable.rs b/tests/ui/dbg_macro/dbg_macro_unfixable.rs new file mode 100644 index 0000000000000..0e83766ccaec7 --- /dev/null +++ b/tests/ui/dbg_macro/dbg_macro_unfixable.rs @@ -0,0 +1,12 @@ +//@no-rustfix +#![warn(clippy::dbg_macro)] + +#[path = "auxiliary/submodule.rs"] +mod submodule; + +fn main() { + dbg!(dbg!(dbg!(42))); + //~^ ERROR: the `dbg!` macro is intended as a debugging tool + dbg!(1, 2, dbg!(3, 4)); + //~^ ERROR: the `dbg!` macro is intended as a debugging tool +} diff --git a/tests/ui/dbg_macro/dbg_macro_unfixable.stderr b/tests/ui/dbg_macro/dbg_macro_unfixable.stderr new file mode 100644 index 0000000000000..d21595c2fcd42 --- /dev/null +++ b/tests/ui/dbg_macro/dbg_macro_unfixable.stderr @@ -0,0 +1,71 @@ +error: the `dbg!` macro is intended as a debugging tool + --> tests/ui/dbg_macro/auxiliary/submodule.rs:2:5 + | +LL | dbg!(); + | ^^^^^^^ + | + = note: `-D clippy::dbg-macro` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::dbg_macro)]` +help: remove the invocation before committing it to a version control system + | +LL - dbg!(); +LL + + | + +error: the `dbg!` macro is intended as a debugging tool + --> tests/ui/dbg_macro/dbg_macro_unfixable.rs:8:5 + | +LL | dbg!(dbg!(dbg!(42))); + | ^^^^^^^^^^^^^^^^^^^^ + | +help: remove the invocation before committing it to a version control system + | +LL | dbg!(dbg!(42)); + | ~~~~~~~~~~~~~~ + +error: the `dbg!` macro is intended as a debugging tool + --> tests/ui/dbg_macro/dbg_macro_unfixable.rs:8:10 + | +LL | dbg!(dbg!(dbg!(42))); + | ^^^^^^^^^^^^^^ + | +help: remove the invocation before committing it to a version control system + | +LL | dbg!(dbg!(42)); + | ~~~~~~~~ + +error: the `dbg!` macro is intended as a debugging tool + --> tests/ui/dbg_macro/dbg_macro_unfixable.rs:8:15 + | +LL | dbg!(dbg!(dbg!(42))); + | ^^^^^^^^ + | +help: remove the invocation before committing it to a version control system + | +LL | dbg!(dbg!(42)); + | ~~ + +error: the `dbg!` macro is intended as a debugging tool + --> tests/ui/dbg_macro/dbg_macro_unfixable.rs:10:5 + | +LL | dbg!(1, 2, dbg!(3, 4)); + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the invocation before committing it to a version control system + | +LL | (1, 2, dbg!(3, 4)); + | ~~~~~~~~~~~~~~~~~~ + +error: the `dbg!` macro is intended as a debugging tool + --> tests/ui/dbg_macro/dbg_macro_unfixable.rs:10:16 + | +LL | dbg!(1, 2, dbg!(3, 4)); + | ^^^^^^^^^^ + | +help: remove the invocation before committing it to a version control system + | +LL | dbg!(1, 2, (3, 4)); + | ~~~~~~ + +error: aborting due to 6 previous errors + diff --git a/tests/ui/doc/issue_10262.fixed b/tests/ui/doc/issue_10262.fixed new file mode 100644 index 0000000000000..5d067736d556c --- /dev/null +++ b/tests/ui/doc/issue_10262.fixed @@ -0,0 +1,12 @@ +#![warn(clippy::doc_markdown)] + +// Should only warn for the first line! +/// `AviSynth` documentation: +//~^ ERROR: item in documentation is missing backticks +/// +/// > AvisynthPluginInit3 may be called more than once with different IScriptEnvironments. +/// +///
bla AvisynthPluginInit3 bla
+/// +/// bla AvisynthPluginInit3 bla +pub struct Foo; diff --git a/tests/ui/doc/issue_10262.rs b/tests/ui/doc/issue_10262.rs new file mode 100644 index 0000000000000..e2cbd938d5d79 --- /dev/null +++ b/tests/ui/doc/issue_10262.rs @@ -0,0 +1,12 @@ +#![warn(clippy::doc_markdown)] + +// Should only warn for the first line! +/// AviSynth documentation: +//~^ ERROR: item in documentation is missing backticks +/// +/// > AvisynthPluginInit3 may be called more than once with different IScriptEnvironments. +/// +///
bla AvisynthPluginInit3 bla
+/// +/// bla AvisynthPluginInit3 bla +pub struct Foo; diff --git a/tests/ui/doc/issue_10262.stderr b/tests/ui/doc/issue_10262.stderr new file mode 100644 index 0000000000000..f43d9551e94e0 --- /dev/null +++ b/tests/ui/doc/issue_10262.stderr @@ -0,0 +1,15 @@ +error: item in documentation is missing backticks + --> tests/ui/doc/issue_10262.rs:4:5 + | +LL | /// AviSynth documentation: + | ^^^^^^^^ + | + = note: `-D clippy::doc-markdown` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::doc_markdown)]` +help: try + | +LL | /// `AviSynth` documentation: + | ~~~~~~~~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/duplicated_attributes.rs b/tests/ui/duplicated_attributes.rs new file mode 100644 index 0000000000000..0f036c684c1ca --- /dev/null +++ b/tests/ui/duplicated_attributes.rs @@ -0,0 +1,17 @@ +#![warn(clippy::duplicated_attributes)] +#![cfg(any(unix, windows))] +#![allow(dead_code)] +#![allow(dead_code)] //~ ERROR: duplicated attribute +#![cfg(any(unix, windows))] +//~^ ERROR: duplicated attribute +//~| ERROR: duplicated attribute + +#[cfg(any(unix, windows, target_os = "linux"))] +#[allow(dead_code)] +#[allow(dead_code)] //~ ERROR: duplicated attribute +#[cfg(any(unix, windows, target_os = "linux"))] +//~^ ERROR: duplicated attribute +//~| ERROR: duplicated attribute +fn foo() {} + +fn main() {} diff --git a/tests/ui/duplicated_attributes.stderr b/tests/ui/duplicated_attributes.stderr new file mode 100644 index 0000000000000..1c6578dbb43a7 --- /dev/null +++ b/tests/ui/duplicated_attributes.stderr @@ -0,0 +1,123 @@ +error: duplicated attribute + --> tests/ui/duplicated_attributes.rs:4:10 + | +LL | #![allow(dead_code)] + | ^^^^^^^^^ + | +note: first defined here + --> tests/ui/duplicated_attributes.rs:3:10 + | +LL | #![allow(dead_code)] + | ^^^^^^^^^ +help: remove this attribute + --> tests/ui/duplicated_attributes.rs:4:10 + | +LL | #![allow(dead_code)] + | ^^^^^^^^^ + = note: `-D clippy::duplicated-attributes` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::duplicated_attributes)]` + +error: duplicated attribute + --> tests/ui/duplicated_attributes.rs:5:12 + | +LL | #![cfg(any(unix, windows))] + | ^^^^ + | +note: first defined here + --> tests/ui/duplicated_attributes.rs:2:12 + | +LL | #![cfg(any(unix, windows))] + | ^^^^ +help: remove this attribute + --> tests/ui/duplicated_attributes.rs:5:12 + | +LL | #![cfg(any(unix, windows))] + | ^^^^ + +error: duplicated attribute + --> tests/ui/duplicated_attributes.rs:5:18 + | +LL | #![cfg(any(unix, windows))] + | ^^^^^^^ + | +note: first defined here + --> tests/ui/duplicated_attributes.rs:2:18 + | +LL | #![cfg(any(unix, windows))] + | ^^^^^^^ +help: remove this attribute + --> tests/ui/duplicated_attributes.rs:5:18 + | +LL | #![cfg(any(unix, windows))] + | ^^^^^^^ + +error: duplicated attribute + --> tests/ui/duplicated_attributes.rs:11:9 + | +LL | #[allow(dead_code)] + | ^^^^^^^^^ + | +note: first defined here + --> tests/ui/duplicated_attributes.rs:10:9 + | +LL | #[allow(dead_code)] + | ^^^^^^^^^ +help: remove this attribute + --> tests/ui/duplicated_attributes.rs:11:9 + | +LL | #[allow(dead_code)] + | ^^^^^^^^^ + +error: duplicated attribute + --> tests/ui/duplicated_attributes.rs:12:11 + | +LL | #[cfg(any(unix, windows, target_os = "linux"))] + | ^^^^ + | +note: first defined here + --> tests/ui/duplicated_attributes.rs:9:11 + | +LL | #[cfg(any(unix, windows, target_os = "linux"))] + | ^^^^ +help: remove this attribute + --> tests/ui/duplicated_attributes.rs:12:11 + | +LL | #[cfg(any(unix, windows, target_os = "linux"))] + | ^^^^ + +error: duplicated attribute + --> tests/ui/duplicated_attributes.rs:12:17 + | +LL | #[cfg(any(unix, windows, target_os = "linux"))] + | ^^^^^^^ + | +note: first defined here + --> tests/ui/duplicated_attributes.rs:9:17 + | +LL | #[cfg(any(unix, windows, target_os = "linux"))] + | ^^^^^^^ +help: remove this attribute + --> tests/ui/duplicated_attributes.rs:12:17 + | +LL | #[cfg(any(unix, windows, target_os = "linux"))] + | ^^^^^^^ + +error: duplicated attribute + --> tests/ui/duplicated_attributes.rs:12:26 + | +LL | #[cfg(any(unix, windows, target_os = "linux"))] + | ^^^^^^^^^^^^^^^^^^^ + | +note: first defined here + --> tests/ui/duplicated_attributes.rs:9:26 + | +LL | #[cfg(any(unix, windows, target_os = "linux"))] + | ^^^^^^^^^^^^^^^^^^^ +help: remove this attribute + --> tests/ui/duplicated_attributes.rs:12:26 + | +LL | #[cfg(any(unix, windows, target_os = "linux"))] + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 7 previous errors + diff --git a/tests/ui/else_if_without_else.rs b/tests/ui/else_if_without_else.rs index e7786f7dd27da..b04c22fa2aed6 100644 --- a/tests/ui/else_if_without_else.rs +++ b/tests/ui/else_if_without_else.rs @@ -1,7 +1,5 @@ -//@compile-flags: -Zdeduplicate-diagnostics=yes - -#![warn(clippy::all)] #![warn(clippy::else_if_without_else)] +#![allow(clippy::collapsible_else_if)] fn bla1() -> bool { unimplemented!() @@ -12,6 +10,12 @@ fn bla2() -> bool { fn bla3() -> bool { unimplemented!() } +fn bla4() -> bool { + unimplemented!() +} +fn bla5() -> bool { + unimplemented!() +} fn main() { if bla1() { @@ -57,4 +61,62 @@ fn main() { //~^ ERROR: `if` expression with an `else if`, but without a final `else` println!("else if 2"); } + + if bla1() { + println!("if"); + } else if bla2() { + println!("else if 1"); + } else if bla3() { + println!("else if 2"); + } else if bla4() { + println!("else if 3"); + } else if bla5() { + println!("else if 4"); + } else { + println!("else"); + } + + if bla1() { + println!("if"); + } else if bla2() { + println!("else if 1"); + } else if bla3() { + println!("else if 2"); + } else if bla4() { + println!("else if 3"); + } else if bla5() { + //~^ ERROR: `if` expression with an `else if`, but without a final `else` + println!("else if 4"); + } + + if bla1() { + println!("if"); + } else if bla2() { + println!("else if 1"); + } else { + if bla3() { + println!("else if 2"); + } else if bla4() { + println!("else if 3"); + } else if bla5() { + println!("else if 4"); + } else { + println!("else"); + } + } + + if bla1() { + println!("if"); + } else if bla2() { + println!("else if 1"); + } else { + if bla3() { + println!("else if 2"); + } else if bla4() { + println!("else if 3"); + } else if bla5() { + //~^ ERROR: `if` expression with an `else if`, but without a final `else` + println!("else if 4"); + } + } } diff --git a/tests/ui/else_if_without_else.stderr b/tests/ui/else_if_without_else.stderr index 3bb840f39e78f..bc7174852293a 100644 --- a/tests/ui/else_if_without_else.stderr +++ b/tests/ui/else_if_without_else.stderr @@ -1,5 +1,5 @@ error: `if` expression with an `else if`, but without a final `else` - --> tests/ui/else_if_without_else.rs:47:12 + --> tests/ui/else_if_without_else.rs:51:12 | LL | } else if bla2() { | ____________^ @@ -13,7 +13,7 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::else_if_without_else)]` error: `if` expression with an `else if`, but without a final `else` - --> tests/ui/else_if_without_else.rs:56:12 + --> tests/ui/else_if_without_else.rs:60:12 | LL | } else if bla3() { | ____________^ @@ -24,5 +24,29 @@ LL | | } | = help: add an `else` block here -error: aborting due to 2 previous errors +error: `if` expression with an `else if`, but without a final `else` + --> tests/ui/else_if_without_else.rs:87:12 + | +LL | } else if bla5() { + | ____________^ +LL | | +LL | | println!("else if 4"); +LL | | } + | |_____^ + | + = help: add an `else` block here + +error: `if` expression with an `else if`, but without a final `else` + --> tests/ui/else_if_without_else.rs:117:16 + | +LL | } else if bla5() { + | ________________^ +LL | | +LL | | println!("else if 4"); +LL | | } + | |_________^ + | + = help: add an `else` block here + +error: aborting due to 4 previous errors diff --git a/tests/ui/empty_docs.rs b/tests/ui/empty_docs.rs index 272fab7d5ca1a..00e64eebc5fba 100644 --- a/tests/ui/empty_docs.rs +++ b/tests/ui/empty_docs.rs @@ -1,6 +1,9 @@ +//@aux-build:proc_macro_attr.rs + #![allow(unused)] #![warn(clippy::empty_docs)] #![allow(clippy::mixed_attributes_style)] +#![feature(extern_types)] mod outer { //! @@ -67,3 +70,17 @@ mod outer { y: i32, } } + +mod issue_12377 { + use proc_macro_attr::with_empty_docs; + + #[with_empty_docs] + extern "C" { + type Test; + } + + #[with_empty_docs] + struct Foo { + a: u8, + } +} diff --git a/tests/ui/empty_docs.stderr b/tests/ui/empty_docs.stderr index f12aead6aa75e..28ebea22c5db8 100644 --- a/tests/ui/empty_docs.stderr +++ b/tests/ui/empty_docs.stderr @@ -1,5 +1,5 @@ error: empty doc comment - --> tests/ui/empty_docs.rs:6:5 + --> tests/ui/empty_docs.rs:9:5 | LL | //! | ^^^ @@ -9,7 +9,7 @@ LL | //! = help: to override `-D warnings` add `#[allow(clippy::empty_docs)]` error: empty doc comment - --> tests/ui/empty_docs.rs:14:5 + --> tests/ui/empty_docs.rs:17:5 | LL | /// | ^^^ @@ -17,7 +17,7 @@ LL | /// = help: consider removing or filling it error: empty doc comment - --> tests/ui/empty_docs.rs:16:9 + --> tests/ui/empty_docs.rs:19:9 | LL | /// | ^^^ @@ -25,7 +25,7 @@ LL | /// = help: consider removing or filling it error: empty doc comment - --> tests/ui/empty_docs.rs:27:5 + --> tests/ui/empty_docs.rs:30:5 | LL | #[doc = ""] | ^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | #[doc = ""] = help: consider removing or filling it error: empty doc comment - --> tests/ui/empty_docs.rs:30:5 + --> tests/ui/empty_docs.rs:33:5 | LL | / #[doc = ""] LL | | #[doc = ""] @@ -42,7 +42,7 @@ LL | | #[doc = ""] = help: consider removing or filling it error: empty doc comment - --> tests/ui/empty_docs.rs:37:5 + --> tests/ui/empty_docs.rs:40:5 | LL | /// | ^^^ @@ -50,7 +50,7 @@ LL | /// = help: consider removing or filling it error: empty doc comment - --> tests/ui/empty_docs.rs:50:13 + --> tests/ui/empty_docs.rs:53:13 | LL | /*! */ | ^^^^^^ @@ -58,7 +58,7 @@ LL | /*! */ = help: consider removing or filling it error: empty doc comment - --> tests/ui/empty_docs.rs:58:13 + --> tests/ui/empty_docs.rs:61:13 | LL | /// | ^^^ @@ -66,7 +66,7 @@ LL | /// = help: consider removing or filling it error: empty doc comment - --> tests/ui/empty_docs.rs:66:9 + --> tests/ui/empty_docs.rs:69:9 | LL | /// | ^^^ diff --git a/tests/ui/empty_line_after_doc_comments.rs b/tests/ui/empty_line_after_doc_comments.rs index e843770f57854..dd78491749c77 100644 --- a/tests/ui/empty_line_after_doc_comments.rs +++ b/tests/ui/empty_line_after_doc_comments.rs @@ -1,6 +1,6 @@ //@aux-build:proc_macro_attr.rs #![warn(clippy::empty_line_after_doc_comments)] -#![allow(clippy::assertions_on_constants)] +#![allow(clippy::assertions_on_constants, clippy::duplicated_attributes)] #![feature(custom_inner_attributes)] #![rustfmt::skip] diff --git a/tests/ui/empty_line_after_outer_attribute.rs b/tests/ui/empty_line_after_outer_attribute.rs index 269e66ea0a816..f147cf2cd5d1e 100644 --- a/tests/ui/empty_line_after_outer_attribute.rs +++ b/tests/ui/empty_line_after_outer_attribute.rs @@ -1,6 +1,6 @@ //@aux-build:proc_macro_attr.rs #![warn(clippy::empty_line_after_outer_attr)] -#![allow(clippy::assertions_on_constants)] +#![allow(clippy::assertions_on_constants, clippy::duplicated_attributes)] #![feature(custom_inner_attributes)] #![rustfmt::skip] diff --git a/tests/ui/entry.fixed b/tests/ui/entry.fixed index 71ec13f461060..abdfae2a3e133 100644 --- a/tests/ui/entry.fixed +++ b/tests/ui/entry.fixed @@ -176,4 +176,14 @@ pub fn issue_11935() { } } +fn issue12489(map: &mut HashMap) -> Option<()> { + if let std::collections::hash_map::Entry::Vacant(e) = map.entry(1) { + let Some(1) = Some(2) else { + return None; + }; + e.insert(42); + } + Some(()) +} + fn main() {} diff --git a/tests/ui/entry.rs b/tests/ui/entry.rs index 86092b7c055a7..7774f99a2a226 100644 --- a/tests/ui/entry.rs +++ b/tests/ui/entry.rs @@ -180,4 +180,14 @@ pub fn issue_11935() { } } +fn issue12489(map: &mut HashMap) -> Option<()> { + if !map.contains_key(&1) { + let Some(1) = Some(2) else { + return None; + }; + map.insert(1, 42); + } + Some(()) +} + fn main() {} diff --git a/tests/ui/entry.stderr b/tests/ui/entry.stderr index ef4c36bcf546c..fb4676766066a 100644 --- a/tests/ui/entry.stderr +++ b/tests/ui/entry.stderr @@ -214,5 +214,26 @@ LL + v LL + }); | -error: aborting due to 10 previous errors +error: usage of `contains_key` followed by `insert` on a `HashMap` + --> tests/ui/entry.rs:184:5 + | +LL | / if !map.contains_key(&1) { +LL | | let Some(1) = Some(2) else { +LL | | return None; +LL | | }; +LL | | map.insert(1, 42); +LL | | } + | |_____^ + | +help: try + | +LL ~ if let std::collections::hash_map::Entry::Vacant(e) = map.entry(1) { +LL + let Some(1) = Some(2) else { +LL + return None; +LL + }; +LL + e.insert(42); +LL + } + | + +error: aborting due to 11 previous errors diff --git a/tests/ui/integer_division_remainder_used.rs b/tests/ui/integer_division_remainder_used.rs new file mode 100644 index 0000000000000..5d1b02095d181 --- /dev/null +++ b/tests/ui/integer_division_remainder_used.rs @@ -0,0 +1,41 @@ +#![warn(clippy::integer_division_remainder_used)] +#![allow(unused_variables)] +#![allow(clippy::op_ref)] + +struct CustomOps(pub i32); +impl std::ops::Div for CustomOps { + type Output = Self; + + fn div(self, rhs: Self) -> Self::Output { + Self(self.0 / rhs.0) + } +} +impl std::ops::Rem for CustomOps { + type Output = Self; + + fn rem(self, rhs: Self) -> Self::Output { + Self(self.0 % rhs.0) + } +} + +fn main() { + // should trigger + let a = 10; + let b = 5; + let c = a / b; + let d = a % b; + let e = &a / b; + let f = a % &b; + let g = &a / &b; + let h = &10 % b; + let i = a / &4; + + // should not trigger on custom Div and Rem + let w = CustomOps(3); + let x = CustomOps(4); + let y = w / x; + + let w = CustomOps(3); + let x = CustomOps(4); + let z = w % x; +} diff --git a/tests/ui/integer_division_remainder_used.stderr b/tests/ui/integer_division_remainder_used.stderr new file mode 100644 index 0000000000000..8adfda28893da --- /dev/null +++ b/tests/ui/integer_division_remainder_used.stderr @@ -0,0 +1,59 @@ +error: use of / has been disallowed in this context + --> tests/ui/integer_division_remainder_used.rs:10:14 + | +LL | Self(self.0 / rhs.0) + | ^^^^^^^^^^^^^^ + | + = note: `-D clippy::integer-division-remainder-used` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::integer_division_remainder_used)]` + +error: use of % has been disallowed in this context + --> tests/ui/integer_division_remainder_used.rs:17:14 + | +LL | Self(self.0 % rhs.0) + | ^^^^^^^^^^^^^^ + +error: use of / has been disallowed in this context + --> tests/ui/integer_division_remainder_used.rs:25:13 + | +LL | let c = a / b; + | ^^^^^ + +error: use of % has been disallowed in this context + --> tests/ui/integer_division_remainder_used.rs:26:13 + | +LL | let d = a % b; + | ^^^^^ + +error: use of / has been disallowed in this context + --> tests/ui/integer_division_remainder_used.rs:27:13 + | +LL | let e = &a / b; + | ^^^^^^ + +error: use of % has been disallowed in this context + --> tests/ui/integer_division_remainder_used.rs:28:13 + | +LL | let f = a % &b; + | ^^^^^^ + +error: use of / has been disallowed in this context + --> tests/ui/integer_division_remainder_used.rs:29:13 + | +LL | let g = &a / &b; + | ^^^^^^^ + +error: use of % has been disallowed in this context + --> tests/ui/integer_division_remainder_used.rs:30:13 + | +LL | let h = &10 % b; + | ^^^^^^^ + +error: use of / has been disallowed in this context + --> tests/ui/integer_division_remainder_used.rs:31:13 + | +LL | let i = a / &4; + | ^^^^^^ + +error: aborting due to 9 previous errors + diff --git a/tests/ui/iter_nth.fixed b/tests/ui/iter_nth.fixed new file mode 100644 index 0000000000000..aff3731a88372 --- /dev/null +++ b/tests/ui/iter_nth.fixed @@ -0,0 +1,60 @@ +//@aux-build:option_helpers.rs + +#![warn(clippy::iter_nth)] +#![allow(clippy::useless_vec)] + +#[macro_use] +extern crate option_helpers; + +use option_helpers::IteratorFalsePositives; +use std::collections::VecDeque; + +/// Struct to generate false positives for things with `.iter()`. +#[derive(Copy, Clone)] +struct HasIter; + +impl HasIter { + fn iter(self) -> IteratorFalsePositives { + IteratorFalsePositives { foo: 0 } + } + + fn iter_mut(self) -> IteratorFalsePositives { + IteratorFalsePositives { foo: 0 } + } +} + +/// Checks implementation of `ITER_NTH` lint. +fn iter_nth() { + let mut some_vec = vec![0, 1, 2, 3]; + let mut boxed_slice: Box<[u8]> = Box::new([0, 1, 2, 3]); + let mut some_vec_deque: VecDeque<_> = some_vec.iter().cloned().collect(); + + { + // Make sure we lint `.iter()` for relevant types. + let bad_vec = some_vec.get(3); + let bad_slice = &some_vec[..].get(3); + let bad_boxed_slice = boxed_slice.get(3); + let bad_vec_deque = some_vec_deque.get(3); + } + + { + // Make sure we lint `.iter_mut()` for relevant types. + let bad_vec = some_vec.get_mut(3); + } + { + let bad_slice = &some_vec[..].get_mut(3); + } + { + let bad_vec_deque = some_vec_deque.get_mut(3); + } + + let vec_ref = &Vec::::new(); + vec_ref.get(3); + + // Make sure we don't lint for non-relevant types. + let false_positive = HasIter; + let ok = false_positive.iter().nth(3); + let ok_mut = false_positive.iter_mut().nth(3); +} + +fn main() {} diff --git a/tests/ui/iter_nth.rs b/tests/ui/iter_nth.rs index 7c567bb81d88a..89d68044dddac 100644 --- a/tests/ui/iter_nth.rs +++ b/tests/ui/iter_nth.rs @@ -48,6 +48,9 @@ fn iter_nth() { let bad_vec_deque = some_vec_deque.iter_mut().nth(3); } + let vec_ref = &Vec::::new(); + vec_ref.iter().nth(3); + // Make sure we don't lint for non-relevant types. let false_positive = HasIter; let ok = false_positive.iter().nth(3); diff --git a/tests/ui/iter_nth.stderr b/tests/ui/iter_nth.stderr index c5dd0c99727be..178463f534754 100644 --- a/tests/ui/iter_nth.stderr +++ b/tests/ui/iter_nth.stderr @@ -4,9 +4,12 @@ error: called `.iter().nth()` on a `Vec` LL | let bad_vec = some_vec.iter().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^ | - = help: calling `.get()` is both faster and more readable = note: `-D clippy::iter-nth` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::iter_nth)]` +help: `get` is equivalent but more concise + | +LL | let bad_vec = some_vec.get(3); + | ~~~ error: called `.iter().nth()` on a slice --> tests/ui/iter_nth.rs:35:26 @@ -14,7 +17,10 @@ error: called `.iter().nth()` on a slice LL | let bad_slice = &some_vec[..].iter().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: calling `.get()` is both faster and more readable +help: `get` is equivalent but more concise + | +LL | let bad_slice = &some_vec[..].get(3); + | ~~~ error: called `.iter().nth()` on a slice --> tests/ui/iter_nth.rs:36:31 @@ -22,7 +28,10 @@ error: called `.iter().nth()` on a slice LL | let bad_boxed_slice = boxed_slice.iter().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: calling `.get()` is both faster and more readable +help: `get` is equivalent but more concise + | +LL | let bad_boxed_slice = boxed_slice.get(3); + | ~~~ error: called `.iter().nth()` on a `VecDeque` --> tests/ui/iter_nth.rs:37:29 @@ -30,7 +39,10 @@ error: called `.iter().nth()` on a `VecDeque` LL | let bad_vec_deque = some_vec_deque.iter().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: calling `.get()` is both faster and more readable +help: `get` is equivalent but more concise + | +LL | let bad_vec_deque = some_vec_deque.get(3); + | ~~~ error: called `.iter_mut().nth()` on a `Vec` --> tests/ui/iter_nth.rs:42:23 @@ -38,7 +50,10 @@ error: called `.iter_mut().nth()` on a `Vec` LL | let bad_vec = some_vec.iter_mut().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: calling `.get_mut()` is both faster and more readable +help: `get_mut` is equivalent but more concise + | +LL | let bad_vec = some_vec.get_mut(3); + | ~~~~~~~ error: called `.iter_mut().nth()` on a slice --> tests/ui/iter_nth.rs:45:26 @@ -46,7 +61,10 @@ error: called `.iter_mut().nth()` on a slice LL | let bad_slice = &some_vec[..].iter_mut().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: calling `.get_mut()` is both faster and more readable +help: `get_mut` is equivalent but more concise + | +LL | let bad_slice = &some_vec[..].get_mut(3); + | ~~~~~~~ error: called `.iter_mut().nth()` on a `VecDeque` --> tests/ui/iter_nth.rs:48:29 @@ -54,7 +72,21 @@ error: called `.iter_mut().nth()` on a `VecDeque` LL | let bad_vec_deque = some_vec_deque.iter_mut().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: calling `.get_mut()` is both faster and more readable +help: `get_mut` is equivalent but more concise + | +LL | let bad_vec_deque = some_vec_deque.get_mut(3); + | ~~~~~~~ + +error: called `.iter().nth()` on a `Vec` + --> tests/ui/iter_nth.rs:52:5 + | +LL | vec_ref.iter().nth(3); + | ^^^^^^^^^^^^^^^^^^^^^ + | +help: `get` is equivalent but more concise + | +LL | vec_ref.get(3); + | ~~~ -error: aborting due to 7 previous errors +error: aborting due to 8 previous errors diff --git a/tests/ui/len_zero.fixed b/tests/ui/len_zero.fixed index 745fc7e1a8b36..c16d7a2661615 100644 --- a/tests/ui/len_zero.fixed +++ b/tests/ui/len_zero.fixed @@ -1,5 +1,11 @@ #![warn(clippy::len_zero)] -#![allow(dead_code, unused, clippy::needless_if, clippy::len_without_is_empty)] +#![allow( + dead_code, + unused, + clippy::needless_if, + clippy::len_without_is_empty, + clippy::const_is_empty +)] extern crate core; use core::ops::Deref; diff --git a/tests/ui/len_zero.rs b/tests/ui/len_zero.rs index 048ad2f4fd34d..5c49a5abf812f 100644 --- a/tests/ui/len_zero.rs +++ b/tests/ui/len_zero.rs @@ -1,5 +1,11 @@ #![warn(clippy::len_zero)] -#![allow(dead_code, unused, clippy::needless_if, clippy::len_without_is_empty)] +#![allow( + dead_code, + unused, + clippy::needless_if, + clippy::len_without_is_empty, + clippy::const_is_empty +)] extern crate core; use core::ops::Deref; diff --git a/tests/ui/len_zero.stderr b/tests/ui/len_zero.stderr index b1f04c94de665..dd07a85d62cac 100644 --- a/tests/ui/len_zero.stderr +++ b/tests/ui/len_zero.stderr @@ -1,5 +1,5 @@ error: length comparison to zero - --> tests/ui/len_zero.rs:82:8 + --> tests/ui/len_zero.rs:88:8 | LL | if x.len() == 0 { | ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `x.is_empty()` @@ -8,13 +8,13 @@ LL | if x.len() == 0 { = help: to override `-D warnings` add `#[allow(clippy::len_zero)]` error: length comparison to zero - --> tests/ui/len_zero.rs:86:8 + --> tests/ui/len_zero.rs:92:8 | LL | if "".len() == 0 {} | ^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `"".is_empty()` error: comparison to empty slice - --> tests/ui/len_zero.rs:95:20 + --> tests/ui/len_zero.rs:101:20 | LL | println!("{}", *s1 == ""); | ^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s1.is_empty()` @@ -23,121 +23,121 @@ LL | println!("{}", *s1 == ""); = help: to override `-D warnings` add `#[allow(clippy::comparison_to_empty)]` error: comparison to empty slice - --> tests/ui/len_zero.rs:96:20 + --> tests/ui/len_zero.rs:102:20 | LL | println!("{}", **s2 == ""); | ^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s2.is_empty()` error: comparison to empty slice - --> tests/ui/len_zero.rs:97:20 + --> tests/ui/len_zero.rs:103:20 | LL | println!("{}", ***s3 == ""); | ^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s3.is_empty()` error: comparison to empty slice - --> tests/ui/len_zero.rs:98:20 + --> tests/ui/len_zero.rs:104:20 | LL | println!("{}", ****s4 == ""); | ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s4.is_empty()` error: comparison to empty slice - --> tests/ui/len_zero.rs:99:20 + --> tests/ui/len_zero.rs:105:20 | LL | println!("{}", *****s5 == ""); | ^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s5.is_empty()` error: comparison to empty slice - --> tests/ui/len_zero.rs:100:20 + --> tests/ui/len_zero.rs:106:20 | LL | println!("{}", ******(s6) == ""); | ^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `(s6).is_empty()` error: comparison to empty slice - --> tests/ui/len_zero.rs:103:20 + --> tests/ui/len_zero.rs:109:20 | LL | println!("{}", &**d2s == ""); | ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `(**d2s).is_empty()` error: length comparison to zero - --> tests/ui/len_zero.rs:118:8 + --> tests/ui/len_zero.rs:124:8 | LL | if has_is_empty.len() == 0 { | ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()` error: length comparison to zero - --> tests/ui/len_zero.rs:121:8 + --> tests/ui/len_zero.rs:127:8 | LL | if has_is_empty.len() != 0 { | ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()` error: length comparison to zero - --> tests/ui/len_zero.rs:124:8 + --> tests/ui/len_zero.rs:130:8 | LL | if has_is_empty.len() > 0 { | ^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()` error: length comparison to one - --> tests/ui/len_zero.rs:127:8 + --> tests/ui/len_zero.rs:133:8 | LL | if has_is_empty.len() < 1 { | ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()` error: length comparison to one - --> tests/ui/len_zero.rs:130:8 + --> tests/ui/len_zero.rs:136:8 | LL | if has_is_empty.len() >= 1 { | ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()` error: length comparison to zero - --> tests/ui/len_zero.rs:141:8 + --> tests/ui/len_zero.rs:147:8 | LL | if 0 == has_is_empty.len() { | ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()` error: length comparison to zero - --> tests/ui/len_zero.rs:144:8 + --> tests/ui/len_zero.rs:150:8 | LL | if 0 != has_is_empty.len() { | ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()` error: length comparison to zero - --> tests/ui/len_zero.rs:147:8 + --> tests/ui/len_zero.rs:153:8 | LL | if 0 < has_is_empty.len() { | ^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()` error: length comparison to one - --> tests/ui/len_zero.rs:150:8 + --> tests/ui/len_zero.rs:156:8 | LL | if 1 <= has_is_empty.len() { | ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()` error: length comparison to one - --> tests/ui/len_zero.rs:153:8 + --> tests/ui/len_zero.rs:159:8 | LL | if 1 > has_is_empty.len() { | ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()` error: length comparison to zero - --> tests/ui/len_zero.rs:167:8 + --> tests/ui/len_zero.rs:173:8 | LL | if with_is_empty.len() == 0 { | ^^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `with_is_empty.is_empty()` error: length comparison to zero - --> tests/ui/len_zero.rs:179:6 + --> tests/ui/len_zero.rs:185:6 | LL | (has_is_empty.len() > 0).then(|| println!("This can happen.")); | ^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()` error: length comparison to zero - --> tests/ui/len_zero.rs:180:6 + --> tests/ui/len_zero.rs:186:6 | LL | (has_is_empty.len() == 0).then(|| println!("Or this!")); | ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()` error: length comparison to zero - --> tests/ui/len_zero.rs:184:8 + --> tests/ui/len_zero.rs:190:8 | LL | if b.len() != 0 {} | ^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!b.is_empty()` diff --git a/tests/ui/let_if_seq.rs b/tests/ui/let_if_seq.rs index 9869d945299e0..a29d35880b8df 100644 --- a/tests/ui/let_if_seq.rs +++ b/tests/ui/let_if_seq.rs @@ -57,6 +57,17 @@ fn early_return() -> u8 { foo } +fn allow_works() -> i32 { + #[allow(clippy::useless_let_if_seq)] + let x; + if true { + x = 1; + } else { + x = 2; + } + x +} + fn main() { early_return(); issue975(); diff --git a/tests/ui/let_if_seq.stderr b/tests/ui/let_if_seq.stderr index 87ad20dc27ee3..41930108fb1ab 100644 --- a/tests/ui/let_if_seq.stderr +++ b/tests/ui/let_if_seq.stderr @@ -1,5 +1,5 @@ error: `if _ { .. } else { .. }` is an expression - --> tests/ui/let_if_seq.rs:66:5 + --> tests/ui/let_if_seq.rs:77:5 | LL | / let mut foo = 0; LL | | @@ -14,7 +14,7 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::useless_let_if_seq)]` error: `if _ { .. } else { .. }` is an expression - --> tests/ui/let_if_seq.rs:73:5 + --> tests/ui/let_if_seq.rs:84:5 | LL | / let mut bar = 0; LL | | @@ -28,7 +28,7 @@ LL | | } = note: you might not need `mut` at all error: `if _ { .. } else { .. }` is an expression - --> tests/ui/let_if_seq.rs:83:5 + --> tests/ui/let_if_seq.rs:94:5 | LL | / let quz; LL | | @@ -40,7 +40,7 @@ LL | | } | |_____^ help: it is more idiomatic to write: `let quz = if f() { 42 } else { 0 };` error: `if _ { .. } else { .. }` is an expression - --> tests/ui/let_if_seq.rs:113:5 + --> tests/ui/let_if_seq.rs:124:5 | LL | / let mut baz = 0; LL | | diff --git a/tests/ui/manual_let_else.rs b/tests/ui/manual_let_else.rs index 1fb252e3f97b6..2b36c3f3c2fb6 100644 --- a/tests/ui/manual_let_else.rs +++ b/tests/ui/manual_let_else.rs @@ -8,7 +8,8 @@ clippy::never_loop, clippy::needless_if, clippy::diverging_sub_expression, - clippy::single_match + clippy::single_match, + clippy::manual_unwrap_or_default )] #![warn(clippy::manual_let_else)] //@no-rustfix diff --git a/tests/ui/manual_let_else.stderr b/tests/ui/manual_let_else.stderr index 7012c6b889144..55a410982adfd 100644 --- a/tests/ui/manual_let_else.stderr +++ b/tests/ui/manual_let_else.stderr @@ -1,5 +1,5 @@ error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:28:5 + --> tests/ui/manual_let_else.rs:29:5 | LL | let v = if let Some(v_some) = g() { v_some } else { return }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { return };` @@ -8,7 +8,7 @@ LL | let v = if let Some(v_some) = g() { v_some } else { return }; = help: to override `-D warnings` add `#[allow(clippy::manual_let_else)]` error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:31:5 + --> tests/ui/manual_let_else.rs:32:5 | LL | / let v = if let Some(v_some) = g() { LL | | @@ -26,7 +26,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:38:5 + --> tests/ui/manual_let_else.rs:39:5 | LL | / let v = if let Some(v) = g() { LL | | @@ -47,25 +47,25 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:50:9 + --> tests/ui/manual_let_else.rs:51:9 | LL | let v = if let Some(v_some) = g() { v_some } else { continue }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { continue };` error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:52:9 + --> tests/ui/manual_let_else.rs:53:9 | LL | let v = if let Some(v_some) = g() { v_some } else { break }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { break };` error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:57:5 + --> tests/ui/manual_let_else.rs:58:5 | LL | let v = if let Some(v_some) = g() { v_some } else { panic!() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { panic!() };` error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:61:5 + --> tests/ui/manual_let_else.rs:62:5 | LL | / let v = if let Some(v_some) = g() { LL | | @@ -83,7 +83,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:69:5 + --> tests/ui/manual_let_else.rs:70:5 | LL | / let v = if let Some(v_some) = g() { LL | | @@ -101,7 +101,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:77:5 + --> tests/ui/manual_let_else.rs:78:5 | LL | / let v = if let Some(v_some) = g() { LL | | @@ -121,7 +121,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:86:5 + --> tests/ui/manual_let_else.rs:87:5 | LL | / let v = if let Some(v_some) = g() { LL | | @@ -141,7 +141,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:95:5 + --> tests/ui/manual_let_else.rs:96:5 | LL | / let v = if let Some(v_some) = g() { LL | | @@ -168,7 +168,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:111:5 + --> tests/ui/manual_let_else.rs:112:5 | LL | / let v = if let Some(v_some) = g() { LL | | @@ -190,7 +190,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:122:5 + --> tests/ui/manual_let_else.rs:123:5 | LL | / let v = if let Some(v_some) = g() { LL | | @@ -217,7 +217,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:138:5 + --> tests/ui/manual_let_else.rs:139:5 | LL | / let v = if let Some(v_some) = g() { LL | | @@ -239,7 +239,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:149:5 + --> tests/ui/manual_let_else.rs:150:5 | LL | / let v = if let Some(v_some) = g() { LL | | @@ -257,7 +257,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:157:5 + --> tests/ui/manual_let_else.rs:158:5 | LL | / let v = if let Some(v_some) = g() { LL | | @@ -278,7 +278,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:167:5 + --> tests/ui/manual_let_else.rs:168:5 | LL | / let v = if let Some(v_some) = g() { LL | | @@ -299,7 +299,7 @@ LL + } }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:177:5 + --> tests/ui/manual_let_else.rs:178:5 | LL | / let v = if let Some(v_some) = g() { LL | | @@ -328,7 +328,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:195:5 + --> tests/ui/manual_let_else.rs:196:5 | LL | / let (v, w) = if let Some(v_some) = g().map(|v| (v, 42)) { LL | | @@ -346,7 +346,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:203:5 + --> tests/ui/manual_let_else.rs:204:5 | LL | / let (w, S { v }) = if let (Some(v_some), w_some) = (g().map(|_| S { v: 0 }), 0) { LL | | @@ -364,7 +364,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:213:13 + --> tests/ui/manual_let_else.rs:214:13 | LL | let $n = if let Some(v) = $e { v } else { return }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some($n) = g() else { return };` @@ -375,19 +375,19 @@ LL | create_binding_if_some!(w, g()); = note: this error originates in the macro `create_binding_if_some` (in Nightly builds, run with -Z macro-backtrace for more info) error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:222:5 + --> tests/ui/manual_let_else.rs:223:5 | LL | let v = if let Variant::A(a, 0) = e() { a } else { return }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Variant::A(v, 0) = e() else { return };` error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:226:5 + --> tests/ui/manual_let_else.rs:227:5 | LL | let mut v = if let Variant::B(b) = e() { b } else { return }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Variant::B(mut v) = e() else { return };` error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:231:5 + --> tests/ui/manual_let_else.rs:232:5 | LL | / let v = if let Ok(Some(Variant::B(b))) | Err(Some(Variant::A(b, _))) = nested { LL | | @@ -405,19 +405,19 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:238:5 + --> tests/ui/manual_let_else.rs:239:5 | LL | let v = if let Variant::A(.., a) = e() { a } else { return }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Variant::A(.., v) = e() else { return };` error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:242:5 + --> tests/ui/manual_let_else.rs:243:5 | LL | let w = if let (Some(v), ()) = (g(), ()) { v } else { return }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let (Some(w), ()) = (g(), ()) else { return };` error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:246:5 + --> tests/ui/manual_let_else.rs:247:5 | LL | / let w = if let Some(S { v: x }) = Some(S { v: 0 }) { LL | | @@ -435,7 +435,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:254:5 + --> tests/ui/manual_let_else.rs:255:5 | LL | / let v = if let Some(S { v: x }) = Some(S { v: 0 }) { LL | | @@ -453,7 +453,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:262:5 + --> tests/ui/manual_let_else.rs:263:5 | LL | / let (x, S { v }, w) = if let Some(U { v, w, x }) = None::>> { LL | | @@ -471,7 +471,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:379:5 + --> tests/ui/manual_let_else.rs:380:5 | LL | / let _ = match ff { LL | | @@ -481,7 +481,7 @@ LL | | }; | |______^ help: consider writing: `let Some(_) = ff else { macro_call!() };` error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:456:9 + --> tests/ui/manual_let_else.rs:457:9 | LL | let v = if let Some(v_some) = g() { v_some } else { return }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { return };` diff --git a/tests/ui/manual_retain.fixed b/tests/ui/manual_retain.fixed index e359dfbb98c80..5540029bf6b1f 100644 --- a/tests/ui/manual_retain.fixed +++ b/tests/ui/manual_retain.fixed @@ -1,5 +1,3 @@ -//@compile-flags: -Zdeduplicate-diagnostics=yes - #![warn(clippy::manual_retain)] #![allow(unused, clippy::redundant_clone)] use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, VecDeque}; diff --git a/tests/ui/manual_retain.rs b/tests/ui/manual_retain.rs index 931814f08b7c2..cee641d9d65f9 100644 --- a/tests/ui/manual_retain.rs +++ b/tests/ui/manual_retain.rs @@ -1,5 +1,3 @@ -//@compile-flags: -Zdeduplicate-diagnostics=yes - #![warn(clippy::manual_retain)] #![allow(unused, clippy::redundant_clone)] use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, VecDeque}; diff --git a/tests/ui/manual_retain.stderr b/tests/ui/manual_retain.stderr index fdbbc53e4df6d..c25c804df7581 100644 --- a/tests/ui/manual_retain.stderr +++ b/tests/ui/manual_retain.stderr @@ -1,5 +1,5 @@ error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:27:5 + --> tests/ui/manual_retain.rs:25:5 | LL | binary_heap = binary_heap.into_iter().filter(|x| x % 2 == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `binary_heap.retain(|x| x % 2 == 0)` @@ -8,43 +8,43 @@ LL | binary_heap = binary_heap.into_iter().filter(|x| x % 2 == 0).collect(); = help: to override `-D warnings` add `#[allow(clippy::manual_retain)]` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:28:5 + --> tests/ui/manual_retain.rs:26:5 | LL | binary_heap = binary_heap.iter().filter(|&x| x % 2 == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `binary_heap.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:29:5 + --> tests/ui/manual_retain.rs:27:5 | LL | binary_heap = binary_heap.iter().filter(|&x| x % 2 == 0).cloned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `binary_heap.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:33:5 + --> tests/ui/manual_retain.rs:31:5 | LL | tuples = tuples.iter().filter(|(ref x, ref y)| *x == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(ref x, ref y)| *x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:34:5 + --> tests/ui/manual_retain.rs:32:5 | LL | tuples = tuples.iter().filter(|(x, y)| *x == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(x, y)| *x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:64:5 + --> tests/ui/manual_retain.rs:62:5 | LL | btree_map = btree_map.into_iter().filter(|(k, _)| k % 2 == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_map.retain(|k, _| k % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:65:5 + --> tests/ui/manual_retain.rs:63:5 | LL | btree_map = btree_map.into_iter().filter(|(_, v)| v % 2 == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_map.retain(|_, &mut v| v % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:66:5 + --> tests/ui/manual_retain.rs:64:5 | LL | / btree_map = btree_map LL | | .into_iter() @@ -53,49 +53,49 @@ LL | | .collect(); | |__________________^ help: consider calling `.retain()` instead: `btree_map.retain(|k, &mut v| (k % 2 == 0) && (v % 2 == 0))` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:91:5 + --> tests/ui/manual_retain.rs:89:5 | LL | btree_set = btree_set.iter().filter(|&x| x % 2 == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_set.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:92:5 + --> tests/ui/manual_retain.rs:90:5 | LL | btree_set = btree_set.iter().filter(|&x| x % 2 == 0).cloned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_set.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:93:5 + --> tests/ui/manual_retain.rs:91:5 | LL | btree_set = btree_set.into_iter().filter(|x| x % 2 == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_set.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:97:5 + --> tests/ui/manual_retain.rs:95:5 | LL | tuples = tuples.iter().filter(|(ref x, ref y)| *x == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(ref x, ref y)| *x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:98:5 + --> tests/ui/manual_retain.rs:96:5 | LL | tuples = tuples.iter().filter(|(x, y)| *x == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(x, y)| *x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:128:5 + --> tests/ui/manual_retain.rs:126:5 | LL | hash_map = hash_map.into_iter().filter(|(k, _)| k % 2 == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_map.retain(|k, _| k % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:129:5 + --> tests/ui/manual_retain.rs:127:5 | LL | hash_map = hash_map.into_iter().filter(|(_, v)| v % 2 == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_map.retain(|_, &mut v| v % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:130:5 + --> tests/ui/manual_retain.rs:128:5 | LL | / hash_map = hash_map LL | | .into_iter() @@ -104,133 +104,133 @@ LL | | .collect(); | |__________________^ help: consider calling `.retain()` instead: `hash_map.retain(|k, &mut v| (k % 2 == 0) && (v % 2 == 0))` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:154:5 + --> tests/ui/manual_retain.rs:152:5 | LL | hash_set = hash_set.into_iter().filter(|x| x % 2 == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_set.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:155:5 + --> tests/ui/manual_retain.rs:153:5 | LL | hash_set = hash_set.iter().filter(|&x| x % 2 == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_set.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:156:5 + --> tests/ui/manual_retain.rs:154:5 | LL | hash_set = hash_set.iter().filter(|&x| x % 2 == 0).cloned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_set.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:160:5 + --> tests/ui/manual_retain.rs:158:5 | LL | tuples = tuples.iter().filter(|(ref x, ref y)| *x == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(ref x, ref y)| *x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:161:5 + --> tests/ui/manual_retain.rs:159:5 | LL | tuples = tuples.iter().filter(|(x, y)| *x == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(x, y)| *x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:190:5 + --> tests/ui/manual_retain.rs:188:5 | LL | s = s.chars().filter(|&c| c != 'o').to_owned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `s.retain(|c| c != 'o')` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:202:5 + --> tests/ui/manual_retain.rs:200:5 | LL | vec = vec.iter().filter(|&x| x % 2 == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:203:5 + --> tests/ui/manual_retain.rs:201:5 | LL | vec = vec.iter().filter(|&x| x % 2 == 0).cloned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:204:5 + --> tests/ui/manual_retain.rs:202:5 | LL | vec = vec.into_iter().filter(|x| x % 2 == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:208:5 + --> tests/ui/manual_retain.rs:206:5 | LL | tuples = tuples.iter().filter(|(ref x, ref y)| *x == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(ref x, ref y)| *x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:209:5 + --> tests/ui/manual_retain.rs:207:5 | LL | tuples = tuples.iter().filter(|(x, y)| *x == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(x, y)| *x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:231:5 + --> tests/ui/manual_retain.rs:229:5 | LL | vec_deque = vec_deque.iter().filter(|&x| x % 2 == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec_deque.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:232:5 + --> tests/ui/manual_retain.rs:230:5 | LL | vec_deque = vec_deque.iter().filter(|&x| x % 2 == 0).cloned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec_deque.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:233:5 + --> tests/ui/manual_retain.rs:231:5 | LL | vec_deque = vec_deque.into_iter().filter(|x| x % 2 == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec_deque.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:290:5 + --> tests/ui/manual_retain.rs:288:5 | LL | vec = vec.into_iter().filter(|(x, y)| *x == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|(x, y)| *x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:294:5 + --> tests/ui/manual_retain.rs:292:5 | LL | tuples = tuples.into_iter().filter(|(_, n)| *n > 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(_, n)| *n > 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:311:5 + --> tests/ui/manual_retain.rs:309:5 | LL | vec = vec.iter().filter(|&&x| x == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|&x| x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:312:5 + --> tests/ui/manual_retain.rs:310:5 | LL | vec = vec.iter().filter(|&&x| x == 0).cloned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|&x| x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:313:5 + --> tests/ui/manual_retain.rs:311:5 | LL | vec = vec.into_iter().filter(|&x| x == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|&x| x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:316:5 + --> tests/ui/manual_retain.rs:314:5 | LL | vec = vec.iter().filter(|&x| *x == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|x| *x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:317:5 + --> tests/ui/manual_retain.rs:315:5 | LL | vec = vec.iter().filter(|&x| *x == 0).cloned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|x| *x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:318:5 + --> tests/ui/manual_retain.rs:316:5 | LL | vec = vec.into_iter().filter(|x| *x == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|x| *x == 0)` diff --git a/tests/ui/manual_unwrap_or.fixed b/tests/ui/manual_unwrap_or.fixed index 737d4c90dca45..dffd44b6a7c1b 100644 --- a/tests/ui/manual_unwrap_or.fixed +++ b/tests/ui/manual_unwrap_or.fixed @@ -1,5 +1,10 @@ #![allow(dead_code)] -#![allow(unused_variables, clippy::unnecessary_wraps, clippy::unnecessary_literal_unwrap)] +#![allow( + unused_variables, + clippy::unnecessary_wraps, + clippy::unnecessary_literal_unwrap, + clippy::manual_unwrap_or_default +)] fn option_unwrap_or() { // int case diff --git a/tests/ui/manual_unwrap_or.rs b/tests/ui/manual_unwrap_or.rs index f59fb87529f81..67427132c1a85 100644 --- a/tests/ui/manual_unwrap_or.rs +++ b/tests/ui/manual_unwrap_or.rs @@ -1,5 +1,10 @@ #![allow(dead_code)] -#![allow(unused_variables, clippy::unnecessary_wraps, clippy::unnecessary_literal_unwrap)] +#![allow( + unused_variables, + clippy::unnecessary_wraps, + clippy::unnecessary_literal_unwrap, + clippy::manual_unwrap_or_default +)] fn option_unwrap_or() { // int case diff --git a/tests/ui/manual_unwrap_or.stderr b/tests/ui/manual_unwrap_or.stderr index 511b79881ac3f..33a099680ce0e 100644 --- a/tests/ui/manual_unwrap_or.stderr +++ b/tests/ui/manual_unwrap_or.stderr @@ -1,5 +1,5 @@ error: this pattern reimplements `Option::unwrap_or` - --> tests/ui/manual_unwrap_or.rs:6:5 + --> tests/ui/manual_unwrap_or.rs:11:5 | LL | / match Some(1) { LL | | Some(i) => i, @@ -11,7 +11,7 @@ LL | | }; = help: to override `-D warnings` add `#[allow(clippy::manual_unwrap_or)]` error: this pattern reimplements `Option::unwrap_or` - --> tests/ui/manual_unwrap_or.rs:12:5 + --> tests/ui/manual_unwrap_or.rs:17:5 | LL | / match Some(1) { LL | | None => 42, @@ -20,7 +20,7 @@ LL | | }; | |_____^ help: replace with: `Some(1).unwrap_or(42)` error: this pattern reimplements `Option::unwrap_or` - --> tests/ui/manual_unwrap_or.rs:18:5 + --> tests/ui/manual_unwrap_or.rs:23:5 | LL | / match Some(1) { LL | | Some(i) => i, @@ -29,7 +29,7 @@ LL | | }; | |_____^ help: replace with: `Some(1).unwrap_or(1 + 42)` error: this pattern reimplements `Option::unwrap_or` - --> tests/ui/manual_unwrap_or.rs:25:5 + --> tests/ui/manual_unwrap_or.rs:30:5 | LL | / match Some(1) { LL | | Some(i) => i, @@ -50,7 +50,7 @@ LL ~ }); | error: this pattern reimplements `Option::unwrap_or` - --> tests/ui/manual_unwrap_or.rs:35:5 + --> tests/ui/manual_unwrap_or.rs:40:5 | LL | / match Some("Bob") { LL | | Some(i) => i, @@ -59,7 +59,7 @@ LL | | }; | |_____^ help: replace with: `Some("Bob").unwrap_or("Alice")` error: this pattern reimplements `Result::unwrap_or` - --> tests/ui/manual_unwrap_or.rs:85:5 + --> tests/ui/manual_unwrap_or.rs:90:5 | LL | / match Ok::(1) { LL | | Ok(i) => i, @@ -68,7 +68,7 @@ LL | | }; | |_____^ help: replace with: `Ok::(1).unwrap_or(42)` error: this pattern reimplements `Result::unwrap_or` - --> tests/ui/manual_unwrap_or.rs:92:5 + --> tests/ui/manual_unwrap_or.rs:97:5 | LL | / match a { LL | | Ok(i) => i, @@ -77,7 +77,7 @@ LL | | }; | |_____^ help: replace with: `a.unwrap_or(42)` error: this pattern reimplements `Result::unwrap_or` - --> tests/ui/manual_unwrap_or.rs:98:5 + --> tests/ui/manual_unwrap_or.rs:103:5 | LL | / match Ok(1) as Result { LL | | Ok(i) => i, @@ -86,7 +86,7 @@ LL | | }; | |_____^ help: replace with: `(Ok(1) as Result).unwrap_or(42)` error: this pattern reimplements `Option::unwrap_or` - --> tests/ui/manual_unwrap_or.rs:111:5 + --> tests/ui/manual_unwrap_or.rs:116:5 | LL | / match s.method() { LL | | Some(i) => i, @@ -95,7 +95,7 @@ LL | | }; | |_____^ help: replace with: `s.method().unwrap_or(42)` error: this pattern reimplements `Result::unwrap_or` - --> tests/ui/manual_unwrap_or.rs:117:5 + --> tests/ui/manual_unwrap_or.rs:122:5 | LL | / match Ok::(1) { LL | | Err(_) => 42, @@ -104,7 +104,7 @@ LL | | }; | |_____^ help: replace with: `Ok::(1).unwrap_or(42)` error: this pattern reimplements `Result::unwrap_or` - --> tests/ui/manual_unwrap_or.rs:123:5 + --> tests/ui/manual_unwrap_or.rs:128:5 | LL | / match Ok::(1) { LL | | Ok(i) => i, @@ -113,7 +113,7 @@ LL | | }; | |_____^ help: replace with: `Ok::(1).unwrap_or(1 + 42)` error: this pattern reimplements `Result::unwrap_or` - --> tests/ui/manual_unwrap_or.rs:130:5 + --> tests/ui/manual_unwrap_or.rs:135:5 | LL | / match Ok::(1) { LL | | Ok(i) => i, @@ -134,7 +134,7 @@ LL ~ }); | error: this pattern reimplements `Result::unwrap_or` - --> tests/ui/manual_unwrap_or.rs:140:5 + --> tests/ui/manual_unwrap_or.rs:145:5 | LL | / match Ok::<&str, &str>("Bob") { LL | | Ok(i) => i, @@ -143,7 +143,7 @@ LL | | }; | |_____^ help: replace with: `Ok::<&str, &str>("Bob").unwrap_or("Alice")` error: this pattern reimplements `Option::unwrap_or` - --> tests/ui/manual_unwrap_or.rs:200:17 + --> tests/ui/manual_unwrap_or.rs:205:17 | LL | let _ = match some_macro!() { | _________________^ diff --git a/tests/ui/manual_unwrap_or_default.fixed b/tests/ui/manual_unwrap_or_default.fixed new file mode 100644 index 0000000000000..c8456805ee6ed --- /dev/null +++ b/tests/ui/manual_unwrap_or_default.fixed @@ -0,0 +1,19 @@ +#![warn(clippy::manual_unwrap_or_default)] +#![allow(clippy::unnecessary_literal_unwrap)] + +fn main() { + let x: Option> = None; + x.unwrap_or_default(); + + let x: Option> = None; + x.unwrap_or_default(); + + let x: Option = None; + x.unwrap_or_default(); + + let x: Option> = None; + x.unwrap_or_default(); + + let x: Option> = None; + x.unwrap_or_default(); +} diff --git a/tests/ui/manual_unwrap_or_default.rs b/tests/ui/manual_unwrap_or_default.rs new file mode 100644 index 0000000000000..820717be53a88 --- /dev/null +++ b/tests/ui/manual_unwrap_or_default.rs @@ -0,0 +1,40 @@ +#![warn(clippy::manual_unwrap_or_default)] +#![allow(clippy::unnecessary_literal_unwrap)] + +fn main() { + let x: Option> = None; + match x { + //~^ ERROR: match can be simplified with `.unwrap_or_default()` + Some(v) => v, + None => Vec::default(), + }; + + let x: Option> = None; + match x { + //~^ ERROR: match can be simplified with `.unwrap_or_default()` + Some(v) => v, + _ => Vec::default(), + }; + + let x: Option = None; + match x { + //~^ ERROR: match can be simplified with `.unwrap_or_default()` + Some(v) => v, + None => String::new(), + }; + + let x: Option> = None; + match x { + //~^ ERROR: match can be simplified with `.unwrap_or_default()` + None => Vec::default(), + Some(v) => v, + }; + + let x: Option> = None; + if let Some(v) = x { + //~^ ERROR: if let can be simplified with `.unwrap_or_default()` + v + } else { + Vec::default() + }; +} diff --git a/tests/ui/manual_unwrap_or_default.stderr b/tests/ui/manual_unwrap_or_default.stderr new file mode 100644 index 0000000000000..f4eb658358842 --- /dev/null +++ b/tests/ui/manual_unwrap_or_default.stderr @@ -0,0 +1,56 @@ +error: match can be simplified with `.unwrap_or_default()` + --> tests/ui/manual_unwrap_or_default.rs:6:5 + | +LL | / match x { +LL | | +LL | | Some(v) => v, +LL | | None => Vec::default(), +LL | | }; + | |_____^ help: replace it with: `x.unwrap_or_default()` + | + = note: `-D clippy::manual-unwrap-or-default` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_unwrap_or_default)]` + +error: match can be simplified with `.unwrap_or_default()` + --> tests/ui/manual_unwrap_or_default.rs:13:5 + | +LL | / match x { +LL | | +LL | | Some(v) => v, +LL | | _ => Vec::default(), +LL | | }; + | |_____^ help: replace it with: `x.unwrap_or_default()` + +error: match can be simplified with `.unwrap_or_default()` + --> tests/ui/manual_unwrap_or_default.rs:20:5 + | +LL | / match x { +LL | | +LL | | Some(v) => v, +LL | | None => String::new(), +LL | | }; + | |_____^ help: replace it with: `x.unwrap_or_default()` + +error: match can be simplified with `.unwrap_or_default()` + --> tests/ui/manual_unwrap_or_default.rs:27:5 + | +LL | / match x { +LL | | +LL | | None => Vec::default(), +LL | | Some(v) => v, +LL | | }; + | |_____^ help: replace it with: `x.unwrap_or_default()` + +error: if let can be simplified with `.unwrap_or_default()` + --> tests/ui/manual_unwrap_or_default.rs:34:5 + | +LL | / if let Some(v) = x { +LL | | +LL | | v +LL | | } else { +LL | | Vec::default() +LL | | }; + | |_____^ help: replace it with: `x.unwrap_or_default()` + +error: aborting due to 5 previous errors + diff --git a/tests/ui/map_clone.fixed b/tests/ui/map_clone.fixed index 395eea69294dd..e58b6b2f19ea3 100644 --- a/tests/ui/map_clone.fixed +++ b/tests/ui/map_clone.fixed @@ -6,7 +6,8 @@ clippy::redundant_clone, clippy::redundant_closure, clippy::useless_asref, - clippy::useless_vec + clippy::useless_vec, + clippy::empty_loop )] fn main() { @@ -117,4 +118,17 @@ fn main() { let y = x.as_ref().map(|x| String::clone(x)); let x: Result = Ok(String::new()); let y = x.as_ref().map(|x| String::clone(x)); + + // Issue #12271 + { + // Don't lint these + let x: Option<&u8> = None; + let y = x.map(|x| String::clone(loop {})); + let x: Option<&u8> = None; + let y = x.map(|x| u8::clone(loop {})); + let x: Vec<&u8> = vec![]; + let y = x.into_iter().map(|x| String::clone(loop {})); + let x: Vec<&u8> = vec![]; + let y = x.into_iter().map(|x| u8::clone(loop {})); + } } diff --git a/tests/ui/map_clone.rs b/tests/ui/map_clone.rs index 82a103edf5a9c..e642e4046f8b7 100644 --- a/tests/ui/map_clone.rs +++ b/tests/ui/map_clone.rs @@ -6,7 +6,8 @@ clippy::redundant_clone, clippy::redundant_closure, clippy::useless_asref, - clippy::useless_vec + clippy::useless_vec, + clippy::empty_loop )] fn main() { @@ -117,4 +118,17 @@ fn main() { let y = x.as_ref().map(|x| String::clone(x)); let x: Result = Ok(String::new()); let y = x.as_ref().map(|x| String::clone(x)); + + // Issue #12271 + { + // Don't lint these + let x: Option<&u8> = None; + let y = x.map(|x| String::clone(loop {})); + let x: Option<&u8> = None; + let y = x.map(|x| u8::clone(loop {})); + let x: Vec<&u8> = vec![]; + let y = x.into_iter().map(|x| String::clone(loop {})); + let x: Vec<&u8> = vec![]; + let y = x.into_iter().map(|x| u8::clone(loop {})); + } } diff --git a/tests/ui/map_clone.stderr b/tests/ui/map_clone.stderr index 1a26a26a4cacb..d9e025de4abe9 100644 --- a/tests/ui/map_clone.stderr +++ b/tests/ui/map_clone.stderr @@ -1,5 +1,5 @@ error: you are using an explicit closure for copying elements - --> tests/ui/map_clone.rs:13:22 + --> tests/ui/map_clone.rs:14:22 | LL | let _: Vec = vec![5_i8; 6].iter().map(|x| *x).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `vec![5_i8; 6].iter().copied()` @@ -8,85 +8,85 @@ LL | let _: Vec = vec![5_i8; 6].iter().map(|x| *x).collect(); = help: to override `-D warnings` add `#[allow(clippy::map_clone)]` error: you are using an explicit closure for cloning elements - --> tests/ui/map_clone.rs:14:26 + --> tests/ui/map_clone.rs:15:26 | LL | let _: Vec = vec![String::new()].iter().map(|x| x.clone()).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `vec![String::new()].iter().cloned()` error: you are using an explicit closure for copying elements - --> tests/ui/map_clone.rs:15:23 + --> tests/ui/map_clone.rs:16:23 | LL | let _: Vec = vec![42, 43].iter().map(|&x| x).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `vec![42, 43].iter().copied()` error: you are using an explicit closure for copying elements - --> tests/ui/map_clone.rs:17:26 + --> tests/ui/map_clone.rs:18:26 | LL | let _: Option = Some(&16).map(|b| *b); | ^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `Some(&16).copied()` error: you are using an explicit closure for copying elements - --> tests/ui/map_clone.rs:18:25 + --> tests/ui/map_clone.rs:19:25 | LL | let _: Option = Some(&1).map(|x| x.clone()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `Some(&1).copied()` error: you are needlessly cloning iterator elements - --> tests/ui/map_clone.rs:29:29 + --> tests/ui/map_clone.rs:30:29 | LL | let _ = std::env::args().map(|v| v.clone()); | ^^^^^^^^^^^^^^^^^^^ help: remove the `map` call error: you are explicitly cloning with `.map()` - --> tests/ui/map_clone.rs:68:13 + --> tests/ui/map_clone.rs:69:13 | LL | let y = x.map(|x| String::clone(x)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `x.cloned()` error: you are explicitly cloning with `.map()` - --> tests/ui/map_clone.rs:70:13 + --> tests/ui/map_clone.rs:71:13 | LL | let y = x.map(Clone::clone); | ^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `x.cloned()` error: you are explicitly cloning with `.map()` - --> tests/ui/map_clone.rs:73:13 + --> tests/ui/map_clone.rs:74:13 | LL | let y = x.map(String::clone); | ^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `x.cloned()` error: you are explicitly cloning with `.map()` - --> tests/ui/map_clone.rs:79:13 + --> tests/ui/map_clone.rs:80:13 | LL | let y = x.map(|x| u32::clone(x)); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `x.copied()` error: you are explicitly cloning with `.map()` - --> tests/ui/map_clone.rs:82:13 + --> tests/ui/map_clone.rs:83:13 | LL | let y = x.map(|x| Clone::clone(x)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `x.copied()` error: you are explicitly cloning with `.map()` - --> tests/ui/map_clone.rs:94:13 + --> tests/ui/map_clone.rs:95:13 | LL | let y = x.map(|x| String::clone(x)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `x.cloned()` error: you are explicitly cloning with `.map()` - --> tests/ui/map_clone.rs:97:13 + --> tests/ui/map_clone.rs:98:13 | LL | let y = x.map(|x| Clone::clone(x)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `x.cloned()` error: you are explicitly cloning with `.map()` - --> tests/ui/map_clone.rs:103:13 + --> tests/ui/map_clone.rs:104:13 | LL | let y = x.map(|x| u32::clone(x)); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `x.copied()` error: you are explicitly cloning with `.map()` - --> tests/ui/map_clone.rs:106:13 + --> tests/ui/map_clone.rs:107:13 | LL | let y = x.map(|x| Clone::clone(x)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `x.copied()` diff --git a/tests/ui/match_result_ok.fixed b/tests/ui/match_result_ok.fixed index 8d7cddc0ad749..76b26f5e4386d 100644 --- a/tests/ui/match_result_ok.fixed +++ b/tests/ui/match_result_ok.fixed @@ -1,6 +1,6 @@ #![warn(clippy::match_result_ok)] #![allow(dead_code)] -#![allow(clippy::boxed_local, clippy::uninlined_format_args)] +#![allow(clippy::boxed_local, clippy::uninlined_format_args, clippy::manual_unwrap_or_default)] // Checking `if` cases diff --git a/tests/ui/match_result_ok.rs b/tests/ui/match_result_ok.rs index 9a18b813aca30..d6f2475ba79c8 100644 --- a/tests/ui/match_result_ok.rs +++ b/tests/ui/match_result_ok.rs @@ -1,6 +1,6 @@ #![warn(clippy::match_result_ok)] #![allow(dead_code)] -#![allow(clippy::boxed_local, clippy::uninlined_format_args)] +#![allow(clippy::boxed_local, clippy::uninlined_format_args, clippy::manual_unwrap_or_default)] // Checking `if` cases diff --git a/tests/ui/missing_doc.rs b/tests/ui/missing_doc.rs index 9bfad3b96cffd..9c936d7fa23e1 100644 --- a/tests/ui/missing_doc.rs +++ b/tests/ui/missing_doc.rs @@ -1,5 +1,6 @@ //@needs-asm-support //@aux-build: proc_macros.rs +//@aux-build: proc_macro_attr.rs #![warn(clippy::missing_docs_in_private_items)] // When denying at the crate level, be sure to not get random warnings from the @@ -8,6 +9,8 @@ //! Some garbage docs for the crate here #![doc = "More garbage"] +#[macro_use] +extern crate proc_macro_attr; extern crate proc_macros; use proc_macros::with_span; @@ -112,3 +115,12 @@ with_span!(span pub enum FooPm3 { A, B(u32), C { field: u32 }}); with_span!(span pub fn foo_pm() {}); with_span!(span pub static FOO_PM: u32 = 0;); with_span!(span pub const FOO2_PM: u32 = 0;); + +// issue #12197 +// Undocumented field originated inside of spanned proc-macro attribute +/// Some dox for struct. +#[rewrite_struct] +pub struct Test { + /// Dox + a: u8, +} diff --git a/tests/ui/missing_doc.stderr b/tests/ui/missing_doc.stderr index 7e66e2097e90f..ef0f96a5b7130 100644 --- a/tests/ui/missing_doc.stderr +++ b/tests/ui/missing_doc.stderr @@ -1,5 +1,5 @@ error: missing documentation for a type alias - --> tests/ui/missing_doc.rs:16:1 + --> tests/ui/missing_doc.rs:19:1 | LL | type Typedef = String; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -8,19 +8,19 @@ LL | type Typedef = String; = help: to override `-D warnings` add `#[allow(clippy::missing_docs_in_private_items)]` error: missing documentation for a module - --> tests/ui/missing_doc.rs:19:1 + --> tests/ui/missing_doc.rs:22:1 | LL | mod module_no_dox {} | ^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> tests/ui/missing_doc.rs:25:1 + --> tests/ui/missing_doc.rs:28:1 | LL | fn foo3() {} | ^^^^^^^^^^^^ error: missing documentation for an enum - --> tests/ui/missing_doc.rs:39:1 + --> tests/ui/missing_doc.rs:42:1 | LL | / enum Baz { LL | | BazA { a: isize, b: isize }, @@ -29,43 +29,43 @@ LL | | } | |_^ error: missing documentation for a variant - --> tests/ui/missing_doc.rs:40:5 + --> tests/ui/missing_doc.rs:43:5 | LL | BazA { a: isize, b: isize }, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a struct field - --> tests/ui/missing_doc.rs:40:12 + --> tests/ui/missing_doc.rs:43:12 | LL | BazA { a: isize, b: isize }, | ^^^^^^^^ error: missing documentation for a struct field - --> tests/ui/missing_doc.rs:40:22 + --> tests/ui/missing_doc.rs:43:22 | LL | BazA { a: isize, b: isize }, | ^^^^^^^^ error: missing documentation for a variant - --> tests/ui/missing_doc.rs:41:5 + --> tests/ui/missing_doc.rs:44:5 | LL | BarB, | ^^^^ error: missing documentation for a constant - --> tests/ui/missing_doc.rs:65:1 + --> tests/ui/missing_doc.rs:68:1 | LL | const FOO: u32 = 0; | ^^^^^^^^^^^^^^^^^^^ error: missing documentation for a static - --> tests/ui/missing_doc.rs:74:1 + --> tests/ui/missing_doc.rs:77:1 | LL | static BAR: u32 = 0; | ^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a module - --> tests/ui/missing_doc.rs:83:1 + --> tests/ui/missing_doc.rs:86:1 | LL | / mod internal_impl { LL | | /// dox @@ -77,13 +77,13 @@ LL | | } | |_^ error: missing documentation for a function - --> tests/ui/missing_doc.rs:88:5 + --> tests/ui/missing_doc.rs:91:5 | LL | fn undocumented3() {} | ^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> tests/ui/missing_doc.rs:94:9 + --> tests/ui/missing_doc.rs:97:9 | LL | fn also_undocumented2() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/mixed_attributes_style.rs b/tests/ui/mixed_attributes_style.rs index ad93e3019fa65..4f89aa8a5e552 100644 --- a/tests/ui/mixed_attributes_style.rs +++ b/tests/ui/mixed_attributes_style.rs @@ -1,4 +1,5 @@ #![warn(clippy::mixed_attributes_style)] +#![allow(clippy::duplicated_attributes)] #[allow(unused)] //~ ERROR: item has both inner and outer attributes fn foo1() { diff --git a/tests/ui/mixed_attributes_style.stderr b/tests/ui/mixed_attributes_style.stderr index d1d5cd3f47f31..ed798073cb7c7 100644 --- a/tests/ui/mixed_attributes_style.stderr +++ b/tests/ui/mixed_attributes_style.stderr @@ -1,5 +1,5 @@ error: item has both inner and outer attributes - --> tests/ui/mixed_attributes_style.rs:3:1 + --> tests/ui/mixed_attributes_style.rs:4:1 | LL | / #[allow(unused)] LL | | fn foo1() { @@ -10,7 +10,7 @@ LL | | #![allow(unused)] = help: to override `-D warnings` add `#[allow(clippy::mixed_attributes_style)]` error: item has both inner and outer attributes - --> tests/ui/mixed_attributes_style.rs:17:1 + --> tests/ui/mixed_attributes_style.rs:18:1 | LL | / /// linux LL | | @@ -19,7 +19,7 @@ LL | | //! windows | |_______________^ error: item has both inner and outer attributes - --> tests/ui/mixed_attributes_style.rs:32:1 + --> tests/ui/mixed_attributes_style.rs:33:1 | LL | / #[allow(unused)] LL | | mod bar { diff --git a/tests/ui/mut_mut.rs b/tests/ui/mut_mut.rs index 288b003405d15..4c45bc9802654 100644 --- a/tests/ui/mut_mut.rs +++ b/tests/ui/mut_mut.rs @@ -1,5 +1,4 @@ //@aux-build:proc_macros.rs -//@compile-flags: -Zdeduplicate-diagnostics=yes #![warn(clippy::mut_mut)] #![allow(unused)] @@ -82,3 +81,8 @@ mod issue9035 { fn bar(_: &mut impl Display) {} } + +fn allow_works() { + #[allow(clippy::mut_mut)] + let _ = &mut &mut 1; +} diff --git a/tests/ui/mut_mut.stderr b/tests/ui/mut_mut.stderr index 73f2410a252ea..42853fdc008c1 100644 --- a/tests/ui/mut_mut.stderr +++ b/tests/ui/mut_mut.stderr @@ -1,5 +1,5 @@ error: generally you want to avoid `&mut &mut _` if possible - --> tests/ui/mut_mut.rs:16:11 + --> tests/ui/mut_mut.rs:15:11 | LL | fn fun(x: &mut &mut u32) -> bool { | ^^^^^^^^^^^^^ @@ -8,13 +8,13 @@ LL | fn fun(x: &mut &mut u32) -> bool { = help: to override `-D warnings` add `#[allow(clippy::mut_mut)]` error: generally you want to avoid `&mut &mut _` if possible - --> tests/ui/mut_mut.rs:33:17 + --> tests/ui/mut_mut.rs:32:17 | LL | let mut x = &mut &mut 1u32; | ^^^^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> tests/ui/mut_mut.rs:48:25 + --> tests/ui/mut_mut.rs:47:25 | LL | let mut z = inline!(&mut $(&mut 3u32)); | ^ @@ -22,37 +22,37 @@ LL | let mut z = inline!(&mut $(&mut 3u32)); = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) error: this expression mutably borrows a mutable reference. Consider reborrowing - --> tests/ui/mut_mut.rs:35:21 + --> tests/ui/mut_mut.rs:34:21 | LL | let mut y = &mut x; | ^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> tests/ui/mut_mut.rs:39:32 + --> tests/ui/mut_mut.rs:38:32 | LL | let y: &mut &mut u32 = &mut &mut 2; | ^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> tests/ui/mut_mut.rs:39:16 + --> tests/ui/mut_mut.rs:38:16 | LL | let y: &mut &mut u32 = &mut &mut 2; | ^^^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> tests/ui/mut_mut.rs:44:37 + --> tests/ui/mut_mut.rs:43:37 | LL | let y: &mut &mut &mut u32 = &mut &mut &mut 2; | ^^^^^^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> tests/ui/mut_mut.rs:44:16 + --> tests/ui/mut_mut.rs:43:16 | LL | let y: &mut &mut &mut u32 = &mut &mut &mut 2; | ^^^^^^^^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> tests/ui/mut_mut.rs:44:21 + --> tests/ui/mut_mut.rs:43:21 | LL | let y: &mut &mut &mut u32 = &mut &mut &mut 2; | ^^^^^^^^^^^^^ diff --git a/tests/ui/needless_bitwise_bool.fixed b/tests/ui/needless_bitwise_bool.fixed index 201f8a4c19de5..a8176618c1f23 100644 --- a/tests/ui/needless_bitwise_bool.fixed +++ b/tests/ui/needless_bitwise_bool.fixed @@ -1,4 +1,5 @@ #![warn(clippy::needless_bitwise_bool)] +#![allow(clippy::const_is_empty)] fn returns_bool() -> bool { true diff --git a/tests/ui/needless_bitwise_bool.rs b/tests/ui/needless_bitwise_bool.rs index b0e5014b74b74..f190eb2b76e76 100644 --- a/tests/ui/needless_bitwise_bool.rs +++ b/tests/ui/needless_bitwise_bool.rs @@ -1,4 +1,5 @@ #![warn(clippy::needless_bitwise_bool)] +#![allow(clippy::const_is_empty)] fn returns_bool() -> bool { true diff --git a/tests/ui/needless_bitwise_bool.stderr b/tests/ui/needless_bitwise_bool.stderr index f29d4492540f9..9f14646c3e5ae 100644 --- a/tests/ui/needless_bitwise_bool.stderr +++ b/tests/ui/needless_bitwise_bool.stderr @@ -1,5 +1,5 @@ error: use of bitwise operator instead of lazy operator between booleans - --> tests/ui/needless_bitwise_bool.rs:22:8 + --> tests/ui/needless_bitwise_bool.rs:23:8 | LL | if y & !x { | ^^^^^^ help: try: `y && !x` diff --git a/tests/ui/needless_return.fixed b/tests/ui/needless_return.fixed index f9eb39d49382c..2575f2449e181 100644 --- a/tests/ui/needless_return.fixed +++ b/tests/ui/needless_return.fixed @@ -316,4 +316,11 @@ fn test_match_as_stmt() { }; } +fn allow_works() -> i32 { + #[allow(clippy::needless_return, clippy::match_single_binding)] + match () { + () => return 42, + } +} + fn main() {} diff --git a/tests/ui/needless_return.rs b/tests/ui/needless_return.rs index 4dd2e22ea9fe6..04f21834d8853 100644 --- a/tests/ui/needless_return.rs +++ b/tests/ui/needless_return.rs @@ -326,4 +326,11 @@ fn test_match_as_stmt() { }; } +fn allow_works() -> i32 { + #[allow(clippy::needless_return, clippy::match_single_binding)] + match () { + () => return 42, + } +} + fn main() {} diff --git a/tests/ui/no_effect_replace.rs b/tests/ui/no_effect_replace.rs index 2a940d87fb944..e4fd5caae2a5d 100644 --- a/tests/ui/no_effect_replace.rs +++ b/tests/ui/no_effect_replace.rs @@ -1,5 +1,3 @@ -//@compile-flags: -Zdeduplicate-diagnostics=yes - #![warn(clippy::no_effect_replace)] fn main() { diff --git a/tests/ui/no_effect_replace.stderr b/tests/ui/no_effect_replace.stderr index ad2dcd2cc9b35..ded86c5c5b8d2 100644 --- a/tests/ui/no_effect_replace.stderr +++ b/tests/ui/no_effect_replace.stderr @@ -1,5 +1,5 @@ error: replacing text with itself - --> tests/ui/no_effect_replace.rs:6:13 + --> tests/ui/no_effect_replace.rs:4:13 | LL | let _ = "12345".replace('1', "1"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,43 +8,43 @@ LL | let _ = "12345".replace('1', "1"); = help: to override `-D warnings` add `#[allow(clippy::no_effect_replace)]` error: replacing text with itself - --> tests/ui/no_effect_replace.rs:9:13 + --> tests/ui/no_effect_replace.rs:7:13 | LL | let _ = "12345".replace("12", "12"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: replacing text with itself - --> tests/ui/no_effect_replace.rs:11:13 + --> tests/ui/no_effect_replace.rs:9:13 | LL | let _ = String::new().replace("12", "12"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: replacing text with itself - --> tests/ui/no_effect_replace.rs:14:13 + --> tests/ui/no_effect_replace.rs:12:13 | LL | let _ = "12345".replacen('1', "1", 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: replacing text with itself - --> tests/ui/no_effect_replace.rs:16:13 + --> tests/ui/no_effect_replace.rs:14:13 | LL | let _ = "12345".replacen("12", "12", 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: replacing text with itself - --> tests/ui/no_effect_replace.rs:18:13 + --> tests/ui/no_effect_replace.rs:16:13 | LL | let _ = String::new().replacen("12", "12", 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: replacing text with itself - --> tests/ui/no_effect_replace.rs:25:13 + --> tests/ui/no_effect_replace.rs:23:13 | LL | let _ = "hello".replace(&x.f(), &x.f()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: replacing text with itself - --> tests/ui/no_effect_replace.rs:29:13 + --> tests/ui/no_effect_replace.rs:27:13 | LL | let _ = "hello".replace(&y(), &y()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/option_if_let_else.fixed b/tests/ui/option_if_let_else.fixed index d443334bb0592..eeab801b7da81 100644 --- a/tests/ui/option_if_let_else.fixed +++ b/tests/ui/option_if_let_else.fixed @@ -3,7 +3,8 @@ clippy::ref_option_ref, clippy::equatable_if_let, clippy::let_unit_value, - clippy::redundant_locals + clippy::redundant_locals, + clippy::manual_unwrap_or_default )] fn bad1(string: Option<&str>) -> (bool, &str) { diff --git a/tests/ui/option_if_let_else.rs b/tests/ui/option_if_let_else.rs index 317c35bf8427b..3e5b96d7c3162 100644 --- a/tests/ui/option_if_let_else.rs +++ b/tests/ui/option_if_let_else.rs @@ -3,7 +3,8 @@ clippy::ref_option_ref, clippy::equatable_if_let, clippy::let_unit_value, - clippy::redundant_locals + clippy::redundant_locals, + clippy::manual_unwrap_or_default )] fn bad1(string: Option<&str>) -> (bool, &str) { diff --git a/tests/ui/option_if_let_else.stderr b/tests/ui/option_if_let_else.stderr index a794dca762f17..f5359a0c34f99 100644 --- a/tests/ui/option_if_let_else.stderr +++ b/tests/ui/option_if_let_else.stderr @@ -1,5 +1,5 @@ error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:10:5 + --> tests/ui/option_if_let_else.rs:11:5 | LL | / if let Some(x) = string { LL | | (true, x) @@ -12,19 +12,19 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::option_if_let_else)]` error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:28:13 + --> tests/ui/option_if_let_else.rs:29:13 | LL | let _ = if let Some(s) = *string { s.len() } else { 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `string.map_or(0, |s| s.len())` error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:29:13 + --> tests/ui/option_if_let_else.rs:30:13 | LL | let _ = if let Some(s) = &num { s } else { &0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)` error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:30:13 + --> tests/ui/option_if_let_else.rs:31:13 | LL | let _ = if let Some(s) = &mut num { | _____________^ @@ -44,13 +44,13 @@ LL ~ }); | error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:36:13 + --> tests/ui/option_if_let_else.rs:37:13 | LL | let _ = if let Some(ref s) = num { s } else { &0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)` error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:37:13 + --> tests/ui/option_if_let_else.rs:38:13 | LL | let _ = if let Some(mut s) = num { | _____________^ @@ -70,7 +70,7 @@ LL ~ }); | error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:43:13 + --> tests/ui/option_if_let_else.rs:44:13 | LL | let _ = if let Some(ref mut s) = num { | _____________^ @@ -90,7 +90,7 @@ LL ~ }); | error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:52:5 + --> tests/ui/option_if_let_else.rs:53:5 | LL | / if let Some(x) = arg { LL | | let y = x * x; @@ -109,7 +109,7 @@ LL + }) | error: use Option::map_or_else instead of an if let/else - --> tests/ui/option_if_let_else.rs:65:13 + --> tests/ui/option_if_let_else.rs:66:13 | LL | let _ = if let Some(x) = arg { | _____________^ @@ -121,7 +121,7 @@ LL | | }; | |_____^ help: try: `arg.map_or_else(side_effect, |x| x)` error: use Option::map_or_else instead of an if let/else - --> tests/ui/option_if_let_else.rs:74:13 + --> tests/ui/option_if_let_else.rs:75:13 | LL | let _ = if let Some(x) = arg { | _____________^ @@ -144,7 +144,7 @@ LL ~ }, |x| x * x * x * x); | error: use Option::map_or_else instead of an if let/else - --> tests/ui/option_if_let_else.rs:107:13 + --> tests/ui/option_if_let_else.rs:108:13 | LL | / if let Some(idx) = s.find('.') { LL | | vec![s[..idx].to_string(), s[idx..].to_string()] @@ -154,7 +154,7 @@ LL | | } | |_____________^ help: try: `s.find('.').map_or_else(|| vec![s.to_string()], |idx| vec![s[..idx].to_string(), s[idx..].to_string()])` error: use Option::map_or_else instead of an if let/else - --> tests/ui/option_if_let_else.rs:118:5 + --> tests/ui/option_if_let_else.rs:119:5 | LL | / if let Ok(binding) = variable { LL | | println!("Ok {binding}"); @@ -177,13 +177,13 @@ LL + }) | error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:142:13 + --> tests/ui/option_if_let_else.rs:143:13 | LL | let _ = if let Some(x) = optional { x + 2 } else { 5 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `optional.map_or(5, |x| x + 2)` error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:152:13 + --> tests/ui/option_if_let_else.rs:153:13 | LL | let _ = if let Some(x) = Some(0) { | _____________^ @@ -205,13 +205,13 @@ LL ~ }); | error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:180:13 + --> tests/ui/option_if_let_else.rs:181:13 | LL | let _ = if let Some(x) = Some(0) { s.len() + x } else { s.len() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(0).map_or(s.len(), |x| s.len() + x)` error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:184:13 + --> tests/ui/option_if_let_else.rs:185:13 | LL | let _ = if let Some(x) = Some(0) { | _____________^ @@ -231,7 +231,7 @@ LL ~ }); | error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:223:13 + --> tests/ui/option_if_let_else.rs:224:13 | LL | let _ = match s { | _____________^ @@ -241,7 +241,7 @@ LL | | }; | |_____^ help: try: `s.map_or(1, |string| string.len())` error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:227:13 + --> tests/ui/option_if_let_else.rs:228:13 | LL | let _ = match Some(10) { | _____________^ @@ -251,7 +251,7 @@ LL | | }; | |_____^ help: try: `Some(10).map_or(5, |a| a + 1)` error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:233:13 + --> tests/ui/option_if_let_else.rs:234:13 | LL | let _ = match res { | _____________^ @@ -261,7 +261,7 @@ LL | | }; | |_____^ help: try: `res.map_or(1, |a| a + 1)` error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:237:13 + --> tests/ui/option_if_let_else.rs:238:13 | LL | let _ = match res { | _____________^ @@ -271,13 +271,13 @@ LL | | }; | |_____^ help: try: `res.map_or(1, |a| a + 1)` error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:241:13 + --> tests/ui/option_if_let_else.rs:242:13 | LL | let _ = if let Ok(a) = res { a + 1 } else { 5 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `res.map_or(5, |a| a + 1)` error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:258:17 + --> tests/ui/option_if_let_else.rs:259:17 | LL | let _ = match initial { | _________________^ @@ -287,7 +287,7 @@ LL | | }; | |_________^ help: try: `initial.as_ref().map_or(42, |value| do_something(value))` error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:265:17 + --> tests/ui/option_if_let_else.rs:266:17 | LL | let _ = match initial { | _________________^ @@ -297,7 +297,7 @@ LL | | }; | |_________^ help: try: `initial.as_mut().map_or(42, |value| do_something2(value))` error: use Option::map_or_else instead of an if let/else - --> tests/ui/option_if_let_else.rs:288:24 + --> tests/ui/option_if_let_else.rs:289:24 | LL | let mut _hashmap = if let Some(hm) = &opt { | ________________________^ @@ -308,7 +308,7 @@ LL | | }; | |_____^ help: try: `opt.as_ref().map_or_else(HashMap::new, |hm| hm.clone())` error: use Option::map_or_else instead of an if let/else - --> tests/ui/option_if_let_else.rs:294:19 + --> tests/ui/option_if_let_else.rs:295:19 | LL | let mut _hm = if let Some(hm) = &opt { hm.clone() } else { new_map!() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.as_ref().map_or_else(|| new_map!(), |hm| hm.clone())` diff --git a/tests/ui/option_option.rs b/tests/ui/option_option.rs index 2f6e4d7614549..42f03aae7bb82 100644 --- a/tests/ui/option_option.rs +++ b/tests/ui/option_option.rs @@ -1,7 +1,5 @@ -//@compile-flags: -Zdeduplicate-diagnostics=yes - #![deny(clippy::option_option)] -#![allow(clippy::unnecessary_wraps)] +#![allow(clippy::unnecessary_wraps, clippy::manual_unwrap_or_default)] const C: Option> = None; //~^ ERROR: consider using `Option` instead of `Option>` or a custom enum if diff --git a/tests/ui/option_option.stderr b/tests/ui/option_option.stderr index 76cb9ae944c26..0cd048e400e40 100644 --- a/tests/ui/option_option.stderr +++ b/tests/ui/option_option.stderr @@ -1,77 +1,77 @@ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> tests/ui/option_option.rs:6:10 + --> tests/ui/option_option.rs:4:10 | LL | const C: Option> = None; | ^^^^^^^^^^^^^^^^^^^ | note: the lint level is defined here - --> tests/ui/option_option.rs:3:9 + --> tests/ui/option_option.rs:1:9 | LL | #![deny(clippy::option_option)] | ^^^^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> tests/ui/option_option.rs:8:11 + --> tests/ui/option_option.rs:6:11 | LL | static S: Option> = None; | ^^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> tests/ui/option_option.rs:11:13 + --> tests/ui/option_option.rs:9:13 | LL | fn input(_: Option>) {} | ^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> tests/ui/option_option.rs:14:16 + --> tests/ui/option_option.rs:12:16 | LL | fn output() -> Option> { | ^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> tests/ui/option_option.rs:19:27 + --> tests/ui/option_option.rs:17:27 | LL | fn output_nested() -> Vec>> { | ^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> tests/ui/option_option.rs:25:30 + --> tests/ui/option_option.rs:23:30 | LL | fn output_nested_nested() -> Option>> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> tests/ui/option_option.rs:31:8 + --> tests/ui/option_option.rs:29:8 | LL | x: Option>, | ^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> tests/ui/option_option.rs:36:23 + --> tests/ui/option_option.rs:34:23 | LL | fn struct_fn() -> Option> { | ^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> tests/ui/option_option.rs:43:22 + --> tests/ui/option_option.rs:41:22 | LL | fn trait_fn() -> Option>; | ^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> tests/ui/option_option.rs:48:11 + --> tests/ui/option_option.rs:46:11 | LL | Tuple(Option>), | ^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> tests/ui/option_option.rs:50:17 + --> tests/ui/option_option.rs:48:17 | LL | Struct { x: Option> }, | ^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> tests/ui/option_option.rs:92:14 + --> tests/ui/option_option.rs:90:14 | LL | foo: Option>>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/read_zero_byte_vec.rs b/tests/ui/read_zero_byte_vec.rs index fd5a88a37a66c..68acf4334699b 100644 --- a/tests/ui/read_zero_byte_vec.rs +++ b/tests/ui/read_zero_byte_vec.rs @@ -112,4 +112,10 @@ async fn test_tokio(r: &mut R) { //~^ ERROR: reading zero byte data to `Vec` } +fn allow_works(mut f: F) { + let mut data = Vec::with_capacity(100); + #[allow(clippy::read_zero_byte_vec)] + f.read(&mut data).unwrap(); +} + fn main() {} diff --git a/tests/ui/redundant_as_str.fixed b/tests/ui/redundant_as_str.fixed index 4185b402226c0..708a1cc91506d 100644 --- a/tests/ui/redundant_as_str.fixed +++ b/tests/ui/redundant_as_str.fixed @@ -1,4 +1,5 @@ #![warn(clippy::redundant_as_str)] +#![allow(clippy::const_is_empty)] fn main() { let string = "Hello, world!".to_owned(); diff --git a/tests/ui/redundant_as_str.rs b/tests/ui/redundant_as_str.rs index 7a74d8a55ded7..257af591ceffb 100644 --- a/tests/ui/redundant_as_str.rs +++ b/tests/ui/redundant_as_str.rs @@ -1,4 +1,5 @@ #![warn(clippy::redundant_as_str)] +#![allow(clippy::const_is_empty)] fn main() { let string = "Hello, world!".to_owned(); diff --git a/tests/ui/redundant_as_str.stderr b/tests/ui/redundant_as_str.stderr index f086de5fedebb..f5379d701db82 100644 --- a/tests/ui/redundant_as_str.stderr +++ b/tests/ui/redundant_as_str.stderr @@ -1,5 +1,5 @@ error: this `as_str` is redundant and can be removed as the method immediately following exists on `String` too - --> tests/ui/redundant_as_str.rs:7:29 + --> tests/ui/redundant_as_str.rs:8:29 | LL | let _redundant = string.as_str().as_bytes(); | ^^^^^^^^^^^^^^^^^ help: try: `as_bytes` @@ -8,7 +8,7 @@ LL | let _redundant = string.as_str().as_bytes(); = help: to override `-D warnings` add `#[allow(clippy::redundant_as_str)]` error: this `as_str` is redundant and can be removed as the method immediately following exists on `String` too - --> tests/ui/redundant_as_str.rs:8:29 + --> tests/ui/redundant_as_str.rs:9:29 | LL | let _redundant = string.as_str().is_empty(); | ^^^^^^^^^^^^^^^^^ help: try: `is_empty` diff --git a/tests/ui/rename.fixed b/tests/ui/rename.fixed index f4ff0f0b88bdc..24d0f79754289 100644 --- a/tests/ui/rename.fixed +++ b/tests/ui/rename.fixed @@ -2,6 +2,7 @@ // Use that command to update this file and do not edit by hand. // Manual edits will be overwritten. +#![allow(clippy::duplicated_attributes)] #![allow(clippy::almost_complete_range)] #![allow(clippy::disallowed_names)] #![allow(clippy::blocks_in_conditions)] diff --git a/tests/ui/rename.rs b/tests/ui/rename.rs index 0df1098f5fb6f..be8da2fa1a38e 100644 --- a/tests/ui/rename.rs +++ b/tests/ui/rename.rs @@ -2,6 +2,7 @@ // Use that command to update this file and do not edit by hand. // Manual edits will be overwritten. +#![allow(clippy::duplicated_attributes)] #![allow(clippy::almost_complete_range)] #![allow(clippy::disallowed_names)] #![allow(clippy::blocks_in_conditions)] diff --git a/tests/ui/rename.stderr b/tests/ui/rename.stderr index e6659b109e520..777ac20153da3 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` - --> tests/ui/rename.rs:55:9 + --> tests/ui/rename.rs:56:9 | LL | #![warn(clippy::almost_complete_letter_range)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range` @@ -8,343 +8,343 @@ LL | #![warn(clippy::almost_complete_letter_range)] = help: to override `-D warnings` add `#[allow(renamed_and_removed_lints)]` error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names` - --> tests/ui/rename.rs:56:9 + --> tests/ui/rename.rs:57: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_conditions` - --> tests/ui/rename.rs:57:9 + --> tests/ui/rename.rs:58:9 | LL | #![warn(clippy::block_in_if_condition_expr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions` error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_conditions` - --> tests/ui/rename.rs:58:9 + --> tests/ui/rename.rs:59:9 | LL | #![warn(clippy::block_in_if_condition_stmt)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions` error: lint `clippy::blocks_in_if_conditions` has been renamed to `clippy::blocks_in_conditions` - --> tests/ui/rename.rs:59:9 + --> tests/ui/rename.rs:60:9 | LL | #![warn(clippy::blocks_in_if_conditions)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions` error: lint `clippy::box_vec` has been renamed to `clippy::box_collection` - --> tests/ui/rename.rs:60:9 + --> tests/ui/rename.rs:61: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` - --> tests/ui/rename.rs:61:9 + --> tests/ui/rename.rs:62: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` - --> tests/ui/rename.rs:62:9 + --> tests/ui/rename.rs:63: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` - --> tests/ui/rename.rs:63:9 + --> tests/ui/rename.rs:64: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` - --> tests/ui/rename.rs:64:9 + --> tests/ui/rename.rs:65: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` - --> tests/ui/rename.rs:65:9 + --> tests/ui/rename.rs:66: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` - --> tests/ui/rename.rs:66:9 + --> tests/ui/rename.rs:67: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` - --> tests/ui/rename.rs:67:9 + --> tests/ui/rename.rs:68: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` - --> tests/ui/rename.rs:68:9 + --> tests/ui/rename.rs:69:9 | LL | #![warn(clippy::if_let_some_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok` error: lint `clippy::incorrect_clone_impl_on_copy_type` has been renamed to `clippy::non_canonical_clone_impl` - --> tests/ui/rename.rs:69:9 + --> tests/ui/rename.rs:70:9 | LL | #![warn(clippy::incorrect_clone_impl_on_copy_type)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_clone_impl` error: lint `clippy::incorrect_partial_ord_impl_on_ord_type` has been renamed to `clippy::non_canonical_partial_ord_impl` - --> tests/ui/rename.rs:70:9 + --> tests/ui/rename.rs:71:9 | LL | #![warn(clippy::incorrect_partial_ord_impl_on_ord_type)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_partial_ord_impl` error: lint `clippy::integer_arithmetic` has been renamed to `clippy::arithmetic_side_effects` - --> tests/ui/rename.rs:71:9 + --> tests/ui/rename.rs:72:9 | LL | #![warn(clippy::integer_arithmetic)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::arithmetic_side_effects` error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr` - --> tests/ui/rename.rs:72:9 + --> tests/ui/rename.rs:73: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` - --> tests/ui/rename.rs:73:9 + --> tests/ui/rename.rs:74: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` - --> tests/ui/rename.rs:74:9 + --> tests/ui/rename.rs:75: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` - --> tests/ui/rename.rs:75:9 + --> tests/ui/rename.rs:76: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` - --> tests/ui/rename.rs:76:9 + --> tests/ui/rename.rs:77: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` - --> tests/ui/rename.rs:77:9 + --> tests/ui/rename.rs:78: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` - --> tests/ui/rename.rs:78:9 + --> tests/ui/rename.rs:79: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` - --> tests/ui/rename.rs:79:9 + --> tests/ui/rename.rs:80: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` - --> tests/ui/rename.rs:80:9 + --> tests/ui/rename.rs:81: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` - --> tests/ui/rename.rs:81:9 + --> tests/ui/rename.rs:82: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` - --> tests/ui/rename.rs:82:9 + --> tests/ui/rename.rs:83: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` - --> tests/ui/rename.rs:83:9 + --> tests/ui/rename.rs:84: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` - --> tests/ui/rename.rs:84:9 + --> tests/ui/rename.rs:85: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` - --> tests/ui/rename.rs:85:9 + --> tests/ui/rename.rs:86:9 | LL | #![warn(clippy::to_string_in_display)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl` error: lint `clippy::unwrap_or_else_default` has been renamed to `clippy::unwrap_or_default` - --> tests/ui/rename.rs:86:9 + --> tests/ui/rename.rs:87:9 | LL | #![warn(clippy::unwrap_or_else_default)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_or_default` error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters` - --> tests/ui/rename.rs:87:9 + --> tests/ui/rename.rs:88:9 | LL | #![warn(clippy::zero_width_space)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters` error: lint `clippy::cast_ref_to_mut` has been renamed to `invalid_reference_casting` - --> tests/ui/rename.rs:88:9 + --> tests/ui/rename.rs:89:9 | LL | #![warn(clippy::cast_ref_to_mut)] | ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_reference_casting` error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op` - --> tests/ui/rename.rs:89:9 + --> tests/ui/rename.rs:90:9 | LL | #![warn(clippy::clone_double_ref)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op` error: lint `clippy::cmp_nan` has been renamed to `invalid_nan_comparisons` - --> tests/ui/rename.rs:90:9 + --> tests/ui/rename.rs:91:9 | LL | #![warn(clippy::cmp_nan)] | ^^^^^^^^^^^^^^^ help: use the new name: `invalid_nan_comparisons` error: lint `clippy::drop_bounds` has been renamed to `drop_bounds` - --> tests/ui/rename.rs:91:9 + --> tests/ui/rename.rs:92:9 | LL | #![warn(clippy::drop_bounds)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds` error: lint `clippy::drop_copy` has been renamed to `dropping_copy_types` - --> tests/ui/rename.rs:92:9 + --> tests/ui/rename.rs:93:9 | LL | #![warn(clippy::drop_copy)] | ^^^^^^^^^^^^^^^^^ help: use the new name: `dropping_copy_types` error: lint `clippy::drop_ref` has been renamed to `dropping_references` - --> tests/ui/rename.rs:93:9 + --> tests/ui/rename.rs:94:9 | LL | #![warn(clippy::drop_ref)] | ^^^^^^^^^^^^^^^^ help: use the new name: `dropping_references` error: lint `clippy::fn_null_check` has been renamed to `useless_ptr_null_checks` - --> tests/ui/rename.rs:94:9 + --> tests/ui/rename.rs:95:9 | LL | #![warn(clippy::fn_null_check)] | ^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `useless_ptr_null_checks` error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles` - --> tests/ui/rename.rs:95:9 + --> tests/ui/rename.rs:96: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` - --> tests/ui/rename.rs:96:9 + --> tests/ui/rename.rs:97: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` - --> tests/ui/rename.rs:97:9 + --> tests/ui/rename.rs:98:9 | LL | #![warn(clippy::for_loops_over_fallibles)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::forget_copy` has been renamed to `forgetting_copy_types` - --> tests/ui/rename.rs:98:9 + --> tests/ui/rename.rs:99:9 | LL | #![warn(clippy::forget_copy)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_copy_types` error: lint `clippy::forget_ref` has been renamed to `forgetting_references` - --> tests/ui/rename.rs:99:9 + --> tests/ui/rename.rs:100:9 | LL | #![warn(clippy::forget_ref)] | ^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_references` error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter` - --> tests/ui/rename.rs:100:9 + --> tests/ui/rename.rs:101: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` - --> tests/ui/rename.rs:101:9 + --> tests/ui/rename.rs:102: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` - --> tests/ui/rename.rs:102:9 + --> tests/ui/rename.rs:103:9 | LL | #![warn(clippy::invalid_ref)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value` error: lint `clippy::invalid_utf8_in_unchecked` has been renamed to `invalid_from_utf8_unchecked` - --> tests/ui/rename.rs:103:9 + --> tests/ui/rename.rs:104:9 | LL | #![warn(clippy::invalid_utf8_in_unchecked)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_from_utf8_unchecked` error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop` - --> tests/ui/rename.rs:104:9 + --> tests/ui/rename.rs:105: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` - --> tests/ui/rename.rs:105:9 + --> tests/ui/rename.rs:106: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` - --> tests/ui/rename.rs:106:9 + --> tests/ui/rename.rs:107: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` - --> tests/ui/rename.rs:107:9 + --> tests/ui/rename.rs:108: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` - --> tests/ui/rename.rs:108:9 + --> tests/ui/rename.rs:109:9 | LL | #![warn(clippy::temporary_cstring_as_ptr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr` error: lint `clippy::undropped_manually_drops` has been renamed to `undropped_manually_drops` - --> tests/ui/rename.rs:109:9 + --> tests/ui/rename.rs:110:9 | LL | #![warn(clippy::undropped_manually_drops)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `undropped_manually_drops` error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints` - --> tests/ui/rename.rs:110:9 + --> tests/ui/rename.rs:111: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` - --> tests/ui/rename.rs:111:9 + --> tests/ui/rename.rs:112:9 | LL | #![warn(clippy::unused_label)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels` error: lint `clippy::vtable_address_comparisons` has been renamed to `ambiguous_wide_pointer_comparisons` - --> tests/ui/rename.rs:112:9 + --> tests/ui/rename.rs:113:9 | LL | #![warn(clippy::vtable_address_comparisons)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `ambiguous_wide_pointer_comparisons` diff --git a/tests/ui/single_match.fixed b/tests/ui/single_match.fixed index 6df64eb405354..acd70416d8bf0 100644 --- a/tests/ui/single_match.fixed +++ b/tests/ui/single_match.fixed @@ -1,12 +1,11 @@ -//@compile-flags: -Zdeduplicate-diagnostics=yes - #![warn(clippy::single_match)] #![allow( unused, clippy::uninlined_format_args, clippy::needless_if, clippy::redundant_guards, - clippy::redundant_pattern_matching + clippy::redundant_pattern_matching, + clippy::manual_unwrap_or_default )] fn dummy() {} diff --git a/tests/ui/single_match.rs b/tests/ui/single_match.rs index 4f005f4e04f5c..bde7819981089 100644 --- a/tests/ui/single_match.rs +++ b/tests/ui/single_match.rs @@ -1,12 +1,11 @@ -//@compile-flags: -Zdeduplicate-diagnostics=yes - #![warn(clippy::single_match)] #![allow( unused, clippy::uninlined_format_args, clippy::needless_if, clippy::redundant_guards, - clippy::redundant_pattern_matching + clippy::redundant_pattern_matching, + clippy::manual_unwrap_or_default )] fn dummy() {} diff --git a/tests/ui/single_match.stderr b/tests/ui/single_match.stderr index 651d0b4911d95..a249c120ee4a4 100644 --- a/tests/ui/single_match.stderr +++ b/tests/ui/single_match.stderr @@ -1,5 +1,5 @@ error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match.rs:16:5 + --> tests/ui/single_match.rs:15:5 | LL | / match x { LL | | Some(y) => { @@ -19,7 +19,7 @@ LL ~ }; | error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match.rs:24:5 + --> tests/ui/single_match.rs:23:5 | LL | / match x { LL | | // Note the missing block braces. @@ -31,7 +31,7 @@ LL | | } | |_____^ help: try: `if let Some(y) = x { println!("{:?}", y) }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match.rs:33:5 + --> tests/ui/single_match.rs:32:5 | LL | / match z { LL | | (2..=3, 7..=9) => dummy(), @@ -40,7 +40,7 @@ LL | | }; | |_____^ help: try: `if let (2..=3, 7..=9) = z { dummy() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match.rs:62:5 + --> tests/ui/single_match.rs:61:5 | LL | / match x { LL | | Some(y) => dummy(), @@ -49,7 +49,7 @@ LL | | }; | |_____^ help: try: `if let Some(y) = x { dummy() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match.rs:67:5 + --> tests/ui/single_match.rs:66:5 | LL | / match y { LL | | Ok(y) => dummy(), @@ -58,7 +58,7 @@ LL | | }; | |_____^ help: try: `if let Ok(y) = y { dummy() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match.rs:74:5 + --> tests/ui/single_match.rs:73:5 | LL | / match c { LL | | Cow::Borrowed(..) => dummy(), @@ -67,7 +67,7 @@ LL | | }; | |_____^ help: try: `if let Cow::Borrowed(..) = c { dummy() }` error: you seem to be trying to use `match` for an equality check. Consider using `if` - --> tests/ui/single_match.rs:95:5 + --> tests/ui/single_match.rs:94:5 | LL | / match x { LL | | "test" => println!(), @@ -76,7 +76,7 @@ LL | | } | |_____^ help: try: `if x == "test" { println!() }` error: you seem to be trying to use `match` for an equality check. Consider using `if` - --> tests/ui/single_match.rs:108:5 + --> tests/ui/single_match.rs:107:5 | LL | / match x { LL | | Foo::A => println!(), @@ -85,7 +85,7 @@ LL | | } | |_____^ help: try: `if x == Foo::A { println!() }` error: you seem to be trying to use `match` for an equality check. Consider using `if` - --> tests/ui/single_match.rs:114:5 + --> tests/ui/single_match.rs:113:5 | LL | / match x { LL | | FOO_C => println!(), @@ -94,7 +94,7 @@ LL | | } | |_____^ help: try: `if x == FOO_C { println!() }` error: you seem to be trying to use `match` for an equality check. Consider using `if` - --> tests/ui/single_match.rs:119:5 + --> tests/ui/single_match.rs:118:5 | LL | / match &&x { LL | | Foo::A => println!(), @@ -103,7 +103,7 @@ LL | | } | |_____^ help: try: `if x == Foo::A { println!() }` error: you seem to be trying to use `match` for an equality check. Consider using `if` - --> tests/ui/single_match.rs:125:5 + --> tests/ui/single_match.rs:124:5 | LL | / match &x { LL | | Foo::A => println!(), @@ -112,7 +112,7 @@ LL | | } | |_____^ help: try: `if x == &Foo::A { println!() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match.rs:142:5 + --> tests/ui/single_match.rs:141:5 | LL | / match x { LL | | Bar::A => println!(), @@ -121,7 +121,7 @@ LL | | } | |_____^ help: try: `if let Bar::A = x { println!() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match.rs:150:5 + --> tests/ui/single_match.rs:149:5 | LL | / match x { LL | | None => println!(), @@ -130,7 +130,7 @@ LL | | }; | |_____^ help: try: `if let None = x { println!() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match.rs:172:5 + --> tests/ui/single_match.rs:171:5 | LL | / match x { LL | | (Some(_), _) => {}, @@ -139,7 +139,7 @@ LL | | } | |_____^ help: try: `if let (Some(_), _) = x {}` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match.rs:178:5 + --> tests/ui/single_match.rs:177:5 | LL | / match x { LL | | (Some(E::V), _) => todo!(), @@ -148,7 +148,7 @@ LL | | } | |_____^ help: try: `if let (Some(E::V), _) = x { todo!() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match.rs:184:5 + --> tests/ui/single_match.rs:183:5 | LL | / match (Some(42), Some(E::V), Some(42)) { LL | | (.., Some(E::V), _) => {}, @@ -157,7 +157,7 @@ LL | | } | |_____^ help: try: `if let (.., Some(E::V), _) = (Some(42), Some(E::V), Some(42)) {}` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match.rs:256:5 + --> tests/ui/single_match.rs:255:5 | LL | / match bar { LL | | Some(v) => unsafe { @@ -177,7 +177,7 @@ LL + } } | error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match.rs:264:5 + --> tests/ui/single_match.rs:263:5 | LL | / match bar { LL | | #[rustfmt::skip] diff --git a/tests/ui/single_match_else.fixed b/tests/ui/single_match_else.fixed index 2970f5485fae9..e840adf0fa34b 100644 --- a/tests/ui/single_match_else.fixed +++ b/tests/ui/single_match_else.fixed @@ -1,5 +1,4 @@ //@aux-build: proc_macros.rs -//@compile-flags: -Zdeduplicate-diagnostics=yes #![warn(clippy::single_match_else)] #![allow(unused, clippy::needless_return, clippy::no_effect, clippy::uninlined_format_args)] diff --git a/tests/ui/single_match_else.rs b/tests/ui/single_match_else.rs index 26974b2a48ab4..430c4da20f12a 100644 --- a/tests/ui/single_match_else.rs +++ b/tests/ui/single_match_else.rs @@ -1,5 +1,4 @@ //@aux-build: proc_macros.rs -//@compile-flags: -Zdeduplicate-diagnostics=yes #![warn(clippy::single_match_else)] #![allow(unused, clippy::needless_return, clippy::no_effect, clippy::uninlined_format_args)] diff --git a/tests/ui/single_match_else.stderr b/tests/ui/single_match_else.stderr index 48c74c0caeaed..f8f88379d6d12 100644 --- a/tests/ui/single_match_else.stderr +++ b/tests/ui/single_match_else.stderr @@ -1,5 +1,5 @@ error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match_else.rs:18:13 + --> tests/ui/single_match_else.rs:17:13 | LL | let _ = match ExprNode::Butterflies { | _____________^ @@ -22,7 +22,7 @@ LL ~ }; | error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match_else.rs:83:5 + --> tests/ui/single_match_else.rs:82:5 | LL | / match Some(1) { LL | | Some(a) => println!("${:?}", a), @@ -42,7 +42,7 @@ LL + } | error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match_else.rs:92:5 + --> tests/ui/single_match_else.rs:91:5 | LL | / match Some(1) { LL | | Some(a) => println!("${:?}", a), @@ -62,7 +62,7 @@ LL + } | error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match_else.rs:102:5 + --> tests/ui/single_match_else.rs:101:5 | LL | / match Result::::Ok(1) { LL | | Ok(a) => println!("${:?}", a), @@ -82,7 +82,7 @@ LL + } | error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match_else.rs:111:5 + --> tests/ui/single_match_else.rs:110:5 | LL | / match Cow::from("moo") { LL | | Cow::Owned(a) => println!("${:?}", a), @@ -102,7 +102,7 @@ LL + } | error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match_else.rs:121:5 + --> tests/ui/single_match_else.rs:120:5 | LL | / match bar { LL | | Some(v) => unsafe { @@ -125,7 +125,7 @@ LL + } | error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match_else.rs:132:5 + --> tests/ui/single_match_else.rs:131:5 | LL | / match bar { LL | | Some(v) => { @@ -149,7 +149,7 @@ LL + } } | error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match_else.rs:144:5 + --> tests/ui/single_match_else.rs:143:5 | LL | / match bar { LL | | Some(v) => unsafe { @@ -173,7 +173,7 @@ LL + } } | error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match_else.rs:156:5 + --> tests/ui/single_match_else.rs:155:5 | LL | / match bar { LL | | #[rustfmt::skip] diff --git a/tests/ui/std_instead_of_core.fixed b/tests/ui/std_instead_of_core.fixed index 0a734a65d2976..ec4ae2ea13c53 100644 --- a/tests/ui/std_instead_of_core.fixed +++ b/tests/ui/std_instead_of_core.fixed @@ -17,7 +17,7 @@ fn std_instead_of_core() { use ::core::hash::Hash; //~^ ERROR: used import from `std` instead of `core` // Don't lint on `env` macro - use core::env; + use std::env; // Multiple imports use core::fmt::{Debug, Result}; diff --git a/tests/ui/std_instead_of_core.stderr b/tests/ui/std_instead_of_core.stderr index ee42b474a32e3..8f920511cc5d0 100644 --- a/tests/ui/std_instead_of_core.stderr +++ b/tests/ui/std_instead_of_core.stderr @@ -13,12 +13,6 @@ error: used import from `std` instead of `core` LL | use ::std::hash::Hash; | ^^^ help: consider importing the item from `core`: `core` -error: used import from `std` instead of `core` - --> tests/ui/std_instead_of_core.rs:20:9 - | -LL | use std::env; - | ^^^ help: consider importing the item from `core`: `core` - error: used import from `std` instead of `core` --> tests/ui/std_instead_of_core.rs:23:9 | @@ -85,5 +79,5 @@ LL | use alloc::slice::from_ref; = note: `-D clippy::alloc-instead-of-core` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::alloc_instead_of_core)]` -error: aborting due to 13 previous errors +error: aborting due to 12 previous errors diff --git a/tests/ui/unconditional_recursion.rs b/tests/ui/unconditional_recursion.rs index 35275e81ded5c..70b390b00e272 100644 --- a/tests/ui/unconditional_recursion.rs +++ b/tests/ui/unconditional_recursion.rs @@ -1,7 +1,11 @@ //@no-rustfix #![warn(clippy::unconditional_recursion)] -#![allow(clippy::partialeq_ne_impl, clippy::default_constructed_unit_structs)] +#![allow( + clippy::partialeq_ne_impl, + clippy::default_constructed_unit_structs, + clippy::only_used_in_recursion +)] enum Foo { A, @@ -350,4 +354,48 @@ mod issue12154 { } } +// From::from -> Into::into -> From::from +struct BadFromTy1<'a>(&'a ()); +struct BadIntoTy1<'b>(&'b ()); +impl<'a> From> for BadIntoTy1<'static> { + fn from(f: BadFromTy1<'a>) -> Self { + f.into() + } +} + +// Using UFCS syntax +struct BadFromTy2<'a>(&'a ()); +struct BadIntoTy2<'b>(&'b ()); +impl<'a> From> for BadIntoTy2<'static> { + fn from(f: BadFromTy2<'a>) -> Self { + Into::into(f) + } +} + +// Different Into impl (>), so no infinite recursion +struct BadFromTy3; +impl From for i32 { + fn from(f: BadFromTy3) -> Self { + Into::into(1i16) + } +} + +// A conditional return that ends the recursion +struct BadFromTy4; +impl From for i32 { + fn from(f: BadFromTy4) -> Self { + if true { + return 42; + } + f.into() + } +} + +// Types differ in refs, don't lint +impl From<&BadFromTy4> for i32 { + fn from(f: &BadFromTy4) -> Self { + BadFromTy4.into() + } +} + fn main() {} diff --git a/tests/ui/unconditional_recursion.stderr b/tests/ui/unconditional_recursion.stderr index 3fd6c91000eab..03c27bd8ed8aa 100644 --- a/tests/ui/unconditional_recursion.stderr +++ b/tests/ui/unconditional_recursion.stderr @@ -1,5 +1,5 @@ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:42:5 + --> tests/ui/unconditional_recursion.rs:46:5 | LL | fn ne(&self, other: &Self) -> bool { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing @@ -12,7 +12,7 @@ LL | self.ne(other) = help: to override `-D warnings` add `#[allow(unconditional_recursion)]` error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:46:5 + --> tests/ui/unconditional_recursion.rs:50:5 | LL | fn eq(&self, other: &Self) -> bool { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing @@ -23,7 +23,7 @@ LL | self.eq(other) = help: a `loop` may express intention better if this is on purpose error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:211:5 + --> tests/ui/unconditional_recursion.rs:215:5 | LL | fn to_string(&self) -> String { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing @@ -34,7 +34,7 @@ LL | self.to_string() = help: a `loop` may express intention better if this is on purpose error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:221:5 + --> tests/ui/unconditional_recursion.rs:225:5 | LL | fn to_string(&self) -> String { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing @@ -45,7 +45,7 @@ LL | x.to_string() = help: a `loop` may express intention better if this is on purpose error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:232:5 + --> tests/ui/unconditional_recursion.rs:236:5 | LL | fn to_string(&self) -> String { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing @@ -56,7 +56,7 @@ LL | (self as &Self).to_string() = help: a `loop` may express intention better if this is on purpose error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:12:5 + --> tests/ui/unconditional_recursion.rs:16:5 | LL | / fn ne(&self, other: &Self) -> bool { LL | | @@ -65,7 +65,7 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:14:9 + --> tests/ui/unconditional_recursion.rs:18:9 | LL | self != other | ^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL | self != other = help: to override `-D warnings` add `#[allow(clippy::unconditional_recursion)]` error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:16:5 + --> tests/ui/unconditional_recursion.rs:20:5 | LL | / fn eq(&self, other: &Self) -> bool { LL | | @@ -82,13 +82,13 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:18:9 + --> tests/ui/unconditional_recursion.rs:22:9 | LL | self == other | ^^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:28:5 + --> tests/ui/unconditional_recursion.rs:32:5 | LL | / fn ne(&self, other: &Self) -> bool { LL | | self != &Foo2::B // no error here @@ -96,13 +96,13 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:29:9 + --> tests/ui/unconditional_recursion.rs:33:9 | LL | self != &Foo2::B // no error here | ^^^^^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:31:5 + --> tests/ui/unconditional_recursion.rs:35:5 | LL | / fn eq(&self, other: &Self) -> bool { LL | | self == &Foo2::B // no error here @@ -110,13 +110,13 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:32:9 + --> tests/ui/unconditional_recursion.rs:36:9 | LL | self == &Foo2::B // no error here | ^^^^^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:42:5 + --> tests/ui/unconditional_recursion.rs:46:5 | LL | / fn ne(&self, other: &Self) -> bool { LL | | @@ -125,27 +125,13 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:44:9 + --> tests/ui/unconditional_recursion.rs:48:9 | LL | self.ne(other) | ^^^^^^^^^^^^^^ -error: parameter is only used in recursion - --> tests/ui/unconditional_recursion.rs:42:18 - | -LL | fn ne(&self, other: &Self) -> bool { - | ^^^^^ help: if this is intentional, prefix it with an underscore: `_other` - | -note: parameter used here - --> tests/ui/unconditional_recursion.rs:44:17 - | -LL | self.ne(other) - | ^^^^^ - = note: `-D clippy::only-used-in-recursion` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::only_used_in_recursion)]` - error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:46:5 + --> tests/ui/unconditional_recursion.rs:50:5 | LL | / fn eq(&self, other: &Self) -> bool { LL | | @@ -154,25 +140,13 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:48:9 + --> tests/ui/unconditional_recursion.rs:52:9 | LL | self.eq(other) | ^^^^^^^^^^^^^^ -error: parameter is only used in recursion - --> tests/ui/unconditional_recursion.rs:46:18 - | -LL | fn eq(&self, other: &Self) -> bool { - | ^^^^^ help: if this is intentional, prefix it with an underscore: `_other` - | -note: parameter used here - --> tests/ui/unconditional_recursion.rs:48:17 - | -LL | self.eq(other) - | ^^^^^ - error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:90:5 + --> tests/ui/unconditional_recursion.rs:94:5 | LL | / fn ne(&self, other: &Self) -> bool { LL | | @@ -181,13 +155,13 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:92:9 + --> tests/ui/unconditional_recursion.rs:96:9 | LL | other != self | ^^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:94:5 + --> tests/ui/unconditional_recursion.rs:98:5 | LL | / fn eq(&self, other: &Self) -> bool { LL | | @@ -196,13 +170,13 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:96:9 + --> tests/ui/unconditional_recursion.rs:100:9 | LL | other == self | ^^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:104:5 + --> tests/ui/unconditional_recursion.rs:108:5 | LL | / fn ne(&self, other: &Self) -> bool { LL | | @@ -211,13 +185,13 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:106:9 + --> tests/ui/unconditional_recursion.rs:110:9 | LL | other != other | ^^^^^^^^^^^^^^ error: equal expressions as operands to `!=` - --> tests/ui/unconditional_recursion.rs:106:9 + --> tests/ui/unconditional_recursion.rs:110:9 | LL | other != other | ^^^^^^^^^^^^^^ @@ -225,7 +199,7 @@ LL | other != other = note: `#[deny(clippy::eq_op)]` on by default error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:108:5 + --> tests/ui/unconditional_recursion.rs:112:5 | LL | / fn eq(&self, other: &Self) -> bool { LL | | @@ -234,19 +208,19 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:110:9 + --> tests/ui/unconditional_recursion.rs:114:9 | LL | other == other | ^^^^^^^^^^^^^^ error: equal expressions as operands to `==` - --> tests/ui/unconditional_recursion.rs:110:9 + --> tests/ui/unconditional_recursion.rs:114:9 | LL | other == other | ^^^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:117:5 + --> tests/ui/unconditional_recursion.rs:121:5 | LL | / fn ne(&self, _other: &Self) -> bool { LL | | @@ -255,19 +229,19 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:119:9 + --> tests/ui/unconditional_recursion.rs:123:9 | LL | self != self | ^^^^^^^^^^^^ error: equal expressions as operands to `!=` - --> tests/ui/unconditional_recursion.rs:119:9 + --> tests/ui/unconditional_recursion.rs:123:9 | LL | self != self | ^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:121:5 + --> tests/ui/unconditional_recursion.rs:125:5 | LL | / fn eq(&self, _other: &Self) -> bool { LL | | @@ -276,19 +250,19 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:123:9 + --> tests/ui/unconditional_recursion.rs:127:9 | LL | self == self | ^^^^^^^^^^^^ error: equal expressions as operands to `==` - --> tests/ui/unconditional_recursion.rs:123:9 + --> tests/ui/unconditional_recursion.rs:127:9 | LL | self == self | ^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:149:13 + --> tests/ui/unconditional_recursion.rs:153:13 | LL | / fn eq(&self, other: &Self) -> bool { LL | | @@ -300,7 +274,7 @@ LL | impl_partial_eq!(S5); | -------------------- in this macro invocation | note: recursive call site - --> tests/ui/unconditional_recursion.rs:151:17 + --> tests/ui/unconditional_recursion.rs:155:17 | LL | self == other | ^^^^^^^^^^^^^ @@ -310,7 +284,7 @@ LL | impl_partial_eq!(S5); = note: this error originates in the macro `impl_partial_eq` (in Nightly builds, run with -Z macro-backtrace for more info) error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:178:5 + --> tests/ui/unconditional_recursion.rs:182:5 | LL | / fn eq(&self, other: &Self) -> bool { LL | | @@ -321,13 +295,13 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:182:9 + --> tests/ui/unconditional_recursion.rs:186:9 | LL | mine == theirs | ^^^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:247:5 + --> tests/ui/unconditional_recursion.rs:251:5 | LL | / fn new() -> Self { LL | | @@ -336,13 +310,13 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:249:9 + --> tests/ui/unconditional_recursion.rs:253:9 | LL | Self::default() | ^^^^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:286:5 + --> tests/ui/unconditional_recursion.rs:290:5 | LL | / fn eq(&self, other: &Self) -> bool { LL | | @@ -353,10 +327,38 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:290:9 + --> tests/ui/unconditional_recursion.rs:294:9 | LL | mine.eq(theirs) | ^^^^^^^^^^^^^^^ +error: function cannot return without recursing + --> tests/ui/unconditional_recursion.rs:361:5 + | +LL | / fn from(f: BadFromTy1<'a>) -> Self { +LL | | f.into() +LL | | } + | |_____^ + | +note: recursive call site + --> tests/ui/unconditional_recursion.rs:362:9 + | +LL | f.into() + | ^^^^^^^^ + +error: function cannot return without recursing + --> tests/ui/unconditional_recursion.rs:370:5 + | +LL | / fn from(f: BadFromTy2<'a>) -> Self { +LL | | Into::into(f) +LL | | } + | |_____^ + | +note: recursive call site + --> tests/ui/unconditional_recursion.rs:371:9 + | +LL | Into::into(f) + | ^^^^^^^^^^^^^ + error: aborting due to 27 previous errors diff --git a/tests/ui/unused_enumerate_index.fixed b/tests/ui/unused_enumerate_index.fixed index d079807ab5877..cffd02b0acc8c 100644 --- a/tests/ui/unused_enumerate_index.fixed +++ b/tests/ui/unused_enumerate_index.fixed @@ -1,8 +1,12 @@ -#![allow(unused)] +#![allow(unused, clippy::map_identity)] #![warn(clippy::unused_enumerate_index)] use std::iter::Enumerate; +fn get_enumerate() -> Enumerate> { + vec![1].into_iter().enumerate() +} + fn main() { let v = [1, 2, 3]; for x in v.iter() { @@ -55,4 +59,48 @@ fn main() { for x in dummy { println!("{x}"); } + + let _ = vec![1, 2, 3].into_iter().map(|x| println!("{x}")); + + let p = vec![1, 2, 3].into_iter(); + p.map(|x| println!("{x}")); + + // This shouldn't trigger the lint. `get_enumerate` may come from an external library on which we + // have no control. + let p = get_enumerate(); + p.map(|(_, x)| println!("{x}")); + + // This shouldn't trigger the lint. The `enumerate` call is in a different context. + macro_rules! mac { + () => { + [1].iter().enumerate() + }; + } + _ = mac!().map(|(_, v)| v); + + macro_rules! mac2 { + () => { + [1].iter() + }; + } + _ = mac2!().map(|_v| {}); + + // This shouldn't trigger the lint because of the `allow`. + #[allow(clippy::unused_enumerate_index)] + let v = [1].iter().enumerate(); + v.map(|(_, _x)| {}); + + // This should keep the explicit type of `x`. + let v = [1, 2, 3].iter().copied(); + let x = v.map(|x: i32| x).sum::(); + assert_eq!(x, 6); + + // This should keep the explicit type of `x`. + let v = [1, 2, 3].iter().copied(); + let x = v.map(|x: i32| x).sum::(); + assert_eq!(x, 6); + + let v = [1, 2, 3].iter().copied(); + let x = v.map(|x| x).sum::(); + assert_eq!(x, 6); } diff --git a/tests/ui/unused_enumerate_index.rs b/tests/ui/unused_enumerate_index.rs index 2d524da763270..f2b5f8b912476 100644 --- a/tests/ui/unused_enumerate_index.rs +++ b/tests/ui/unused_enumerate_index.rs @@ -1,8 +1,12 @@ -#![allow(unused)] +#![allow(unused, clippy::map_identity)] #![warn(clippy::unused_enumerate_index)] use std::iter::Enumerate; +fn get_enumerate() -> Enumerate> { + vec![1].into_iter().enumerate() +} + fn main() { let v = [1, 2, 3]; for (_, x) in v.iter().enumerate() { @@ -55,4 +59,48 @@ fn main() { for (_, x) in dummy.enumerate() { println!("{x}"); } + + let _ = vec![1, 2, 3].into_iter().enumerate().map(|(_, x)| println!("{x}")); + + let p = vec![1, 2, 3].into_iter().enumerate(); + p.map(|(_, x)| println!("{x}")); + + // This shouldn't trigger the lint. `get_enumerate` may come from an external library on which we + // have no control. + let p = get_enumerate(); + p.map(|(_, x)| println!("{x}")); + + // This shouldn't trigger the lint. The `enumerate` call is in a different context. + macro_rules! mac { + () => { + [1].iter().enumerate() + }; + } + _ = mac!().map(|(_, v)| v); + + macro_rules! mac2 { + () => { + [1].iter() + }; + } + _ = mac2!().enumerate().map(|(_, _v)| {}); + + // This shouldn't trigger the lint because of the `allow`. + #[allow(clippy::unused_enumerate_index)] + let v = [1].iter().enumerate(); + v.map(|(_, _x)| {}); + + // This should keep the explicit type of `x`. + let v = [1, 2, 3].iter().copied().enumerate(); + let x = v.map(|(_, x): (usize, i32)| x).sum::(); + assert_eq!(x, 6); + + // This should keep the explicit type of `x`. + let v = [1, 2, 3].iter().copied().enumerate(); + let x = v.map(|(_, x): (_, i32)| x).sum::(); + assert_eq!(x, 6); + + let v = [1, 2, 3].iter().copied().enumerate(); + let x = v.map(|(_, x)| x).sum::(); + assert_eq!(x, 6); } diff --git a/tests/ui/unused_enumerate_index.stderr b/tests/ui/unused_enumerate_index.stderr index 7bd7d29117e24..6ec07dcbff0a3 100644 --- a/tests/ui/unused_enumerate_index.stderr +++ b/tests/ui/unused_enumerate_index.stderr @@ -1,5 +1,5 @@ error: you seem to use `.enumerate()` and immediately discard the index - --> tests/ui/unused_enumerate_index.rs:8:19 + --> tests/ui/unused_enumerate_index.rs:12:19 | LL | for (_, x) in v.iter().enumerate() { | ^^^^^^^^^^^^^^^^^^^^ @@ -12,7 +12,7 @@ LL | for x in v.iter() { | ~ ~~~~~~~~ error: you seem to use `.enumerate()` and immediately discard the index - --> tests/ui/unused_enumerate_index.rs:55:19 + --> tests/ui/unused_enumerate_index.rs:59:19 | LL | for (_, x) in dummy.enumerate() { | ^^^^^^^^^^^^^^^^^ @@ -22,5 +22,77 @@ help: remove the `.enumerate()` call LL | for x in dummy { | ~ ~~~~~ -error: aborting due to 2 previous errors +error: you seem to use `.enumerate()` and immediately discard the index + --> tests/ui/unused_enumerate_index.rs:63:39 + | +LL | let _ = vec![1, 2, 3].into_iter().enumerate().map(|(_, x)| println!("{x}")); + | ^^^^^^^^^^^ + | +help: remove the `.enumerate()` call + | +LL - let _ = vec![1, 2, 3].into_iter().enumerate().map(|(_, x)| println!("{x}")); +LL + let _ = vec![1, 2, 3].into_iter().map(|x| println!("{x}")); + | + +error: you seem to use `.enumerate()` and immediately discard the index + --> tests/ui/unused_enumerate_index.rs:65:39 + | +LL | let p = vec![1, 2, 3].into_iter().enumerate(); + | ^^^^^^^^^^^ + | +help: remove the `.enumerate()` call + | +LL ~ let p = vec![1, 2, 3].into_iter(); +LL ~ p.map(|x| println!("{x}")); + | + +error: you seem to use `.enumerate()` and immediately discard the index + --> tests/ui/unused_enumerate_index.rs:86:17 + | +LL | _ = mac2!().enumerate().map(|(_, _v)| {}); + | ^^^^^^^^^^^ + | +help: remove the `.enumerate()` call + | +LL - _ = mac2!().enumerate().map(|(_, _v)| {}); +LL + _ = mac2!().map(|_v| {}); + | + +error: you seem to use `.enumerate()` and immediately discard the index + --> tests/ui/unused_enumerate_index.rs:94:39 + | +LL | let v = [1, 2, 3].iter().copied().enumerate(); + | ^^^^^^^^^^^ + | +help: remove the `.enumerate()` call + | +LL ~ let v = [1, 2, 3].iter().copied(); +LL ~ let x = v.map(|x: i32| x).sum::(); + | + +error: you seem to use `.enumerate()` and immediately discard the index + --> tests/ui/unused_enumerate_index.rs:99:39 + | +LL | let v = [1, 2, 3].iter().copied().enumerate(); + | ^^^^^^^^^^^ + | +help: remove the `.enumerate()` call + | +LL ~ let v = [1, 2, 3].iter().copied(); +LL ~ let x = v.map(|x: i32| x).sum::(); + | + +error: you seem to use `.enumerate()` and immediately discard the index + --> tests/ui/unused_enumerate_index.rs:103:39 + | +LL | let v = [1, 2, 3].iter().copied().enumerate(); + | ^^^^^^^^^^^ + | +help: remove the `.enumerate()` call + | +LL ~ let v = [1, 2, 3].iter().copied(); +LL ~ let x = v.map(|x| x).sum::(); + | + +error: aborting due to 8 previous errors diff --git a/tests/ui/unused_io_amount.rs b/tests/ui/unused_io_amount.rs index 7e5a10c911bf1..f5b200d5ffed9 100644 --- a/tests/ui/unused_io_amount.rs +++ b/tests/ui/unused_io_amount.rs @@ -271,5 +271,10 @@ pub fn wildcards(rdr: &mut dyn std::io::Read) { } } } +fn allow_works(mut f: F) { + let mut data = Vec::with_capacity(100); + #[allow(clippy::unused_io_amount)] + f.read(&mut data).unwrap(); +} fn main() {} diff --git a/tests/ui/unused_peekable.rs b/tests/ui/unused_peekable.rs index 131b51e01b6f0..5865bba43508b 100644 --- a/tests/ui/unused_peekable.rs +++ b/tests/ui/unused_peekable.rs @@ -174,3 +174,9 @@ fn valid() { let mut peekable = std::iter::empty::().peekable(); takes_dyn(&mut peekable); } + +fn allow_works() { + #[allow(clippy::unused_peekable)] + let iter = [1, 2, 3].iter().peekable(); + iter; +} diff --git a/tests/ui/use_self.fixed b/tests/ui/use_self.fixed index 787dd3ec7e680..6ea7857a238da 100644 --- a/tests/ui/use_self.fixed +++ b/tests/ui/use_self.fixed @@ -6,7 +6,8 @@ clippy::should_implement_trait, clippy::upper_case_acronyms, clippy::from_over_into, - clippy::self_named_constructors + clippy::self_named_constructors, + clippy::needless_lifetimes )] #[macro_use] @@ -53,6 +54,7 @@ mod better { } mod lifetimes { + #[derive(Clone, Copy)] struct Foo<'a> { foo_str: &'a str, } @@ -68,11 +70,19 @@ mod lifetimes { Foo { foo_str: "foo" } } - // FIXME: the lint does not handle lifetimed struct - // `Self` should be applicable here - fn clone(&self) -> Foo<'a> { + fn clone(&self) -> Self { Foo { foo_str: self.foo_str } } + + // Cannot replace with `Self` because the lifetime is not `'a`. + fn eq<'b>(&self, other: Foo<'b>) -> bool { + let x: Foo<'_> = other; + self.foo_str == other.foo_str + } + + fn f(&self) -> Foo<'_> { + *self + } } } diff --git a/tests/ui/use_self.rs b/tests/ui/use_self.rs index 39e182faea677..338cc00e45a81 100644 --- a/tests/ui/use_self.rs +++ b/tests/ui/use_self.rs @@ -6,7 +6,8 @@ clippy::should_implement_trait, clippy::upper_case_acronyms, clippy::from_over_into, - clippy::self_named_constructors + clippy::self_named_constructors, + clippy::needless_lifetimes )] #[macro_use] @@ -53,6 +54,7 @@ mod better { } mod lifetimes { + #[derive(Clone, Copy)] struct Foo<'a> { foo_str: &'a str, } @@ -68,11 +70,19 @@ mod lifetimes { Foo { foo_str: "foo" } } - // FIXME: the lint does not handle lifetimed struct - // `Self` should be applicable here fn clone(&self) -> Foo<'a> { Foo { foo_str: self.foo_str } } + + // Cannot replace with `Self` because the lifetime is not `'a`. + fn eq<'b>(&self, other: Foo<'b>) -> bool { + let x: Foo<'_> = other; + self.foo_str == other.foo_str + } + + fn f(&self) -> Foo<'_> { + *self + } } } diff --git a/tests/ui/use_self.stderr b/tests/ui/use_self.stderr index 8d045f05ed286..d7aa8410a47be 100644 --- a/tests/ui/use_self.stderr +++ b/tests/ui/use_self.stderr @@ -1,5 +1,5 @@ error: unnecessary structure name repetition - --> tests/ui/use_self.rs:21:21 + --> tests/ui/use_self.rs:22:21 | LL | fn new() -> Foo { | ^^^ help: use the applicable keyword: `Self` @@ -8,250 +8,256 @@ LL | fn new() -> Foo { = help: to override `-D warnings` add `#[allow(clippy::use_self)]` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:22:13 + --> tests/ui/use_self.rs:23:13 | LL | Foo {} | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:24:22 + --> tests/ui/use_self.rs:25:22 | LL | fn test() -> Foo { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:25:13 + --> tests/ui/use_self.rs:26:13 | LL | Foo::new() | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:30:25 + --> tests/ui/use_self.rs:31:25 | LL | fn default() -> Foo { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:31:13 + --> tests/ui/use_self.rs:32:13 | LL | Foo::new() | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:96:24 + --> tests/ui/use_self.rs:73:28 + | +LL | fn clone(&self) -> Foo<'a> { + | ^^^^^^^ help: use the applicable keyword: `Self` + +error: unnecessary structure name repetition + --> tests/ui/use_self.rs:106:24 | LL | fn bad(foos: &[Foo]) -> impl Iterator { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:96:55 + --> tests/ui/use_self.rs:106:55 | LL | fn bad(foos: &[Foo]) -> impl Iterator { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:111:13 + --> tests/ui/use_self.rs:121:13 | LL | TS(0) | ^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:146:29 + --> tests/ui/use_self.rs:156:29 | LL | fn bar() -> Bar { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:147:21 + --> tests/ui/use_self.rs:157:21 | LL | Bar { foo: Foo {} } | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:158:21 + --> tests/ui/use_self.rs:168:21 | LL | fn baz() -> Foo { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:159:13 + --> tests/ui/use_self.rs:169:13 | LL | Foo {} | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:176:21 + --> tests/ui/use_self.rs:186:21 | LL | let _ = Enum::B(42); | ^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:177:21 + --> tests/ui/use_self.rs:187:21 | LL | let _ = Enum::C { field: true }; | ^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:178:21 + --> tests/ui/use_self.rs:188:21 | LL | let _ = Enum::A; | ^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:220:13 + --> tests/ui/use_self.rs:230:13 | LL | nested::A::fun_1(); | ^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:221:13 + --> tests/ui/use_self.rs:231:13 | LL | nested::A::A; | ^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:223:13 + --> tests/ui/use_self.rs:233:13 | LL | nested::A {}; | ^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:242:13 + --> tests/ui/use_self.rs:252:13 | LL | TestStruct::from_something() | ^^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:256:25 + --> tests/ui/use_self.rs:266:25 | LL | async fn g() -> S { | ^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:257:13 + --> tests/ui/use_self.rs:267:13 | LL | S {} | ^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:261:16 + --> tests/ui/use_self.rs:271:16 | LL | &p[S::A..S::B] | ^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:261:22 + --> tests/ui/use_self.rs:271:22 | LL | &p[S::A..S::B] | ^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:284:29 + --> tests/ui/use_self.rs:294:29 | LL | fn foo(value: T) -> Foo { | ^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:285:13 + --> tests/ui/use_self.rs:295:13 | LL | Foo:: { value } | ^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:457:13 + --> tests/ui/use_self.rs:467:13 | LL | A::new::(submod::B {}) | ^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:494:13 + --> tests/ui/use_self.rs:504:13 | LL | S2::new() | ^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:531:17 + --> tests/ui/use_self.rs:541:17 | LL | Foo::Bar => unimplemented!(), | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:532:17 + --> tests/ui/use_self.rs:542:17 | LL | Foo::Baz => unimplemented!(), | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:538:20 + --> tests/ui/use_self.rs:548:20 | LL | if let Foo::Bar = self { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:562:17 + --> tests/ui/use_self.rs:572:17 | LL | Something::Num(n) => *n, | ^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:563:17 + --> tests/ui/use_self.rs:573:17 | LL | Something::TupleNums(n, _m) => *n, | ^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:564:17 + --> tests/ui/use_self.rs:574:17 | LL | Something::StructNums { one, two: _ } => *one, | ^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:570:17 + --> tests/ui/use_self.rs:580:17 | LL | crate::issue8845::Something::Num(n) => *n, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:571:17 + --> tests/ui/use_self.rs:581:17 | LL | crate::issue8845::Something::TupleNums(n, _m) => *n, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:572:17 + --> tests/ui/use_self.rs:582:17 | LL | crate::issue8845::Something::StructNums { one, two: _ } => *one, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:588:17 + --> tests/ui/use_self.rs:598:17 | LL | let Foo(x) = self; | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:593:17 + --> tests/ui/use_self.rs:603:17 | LL | let crate::issue8845::Foo(x) = self; | ^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:600:17 + --> tests/ui/use_self.rs:610:17 | LL | let Bar { x, .. } = self; | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:605:17 + --> tests/ui/use_self.rs:615:17 | LL | let crate::issue8845::Bar { x, .. } = self; | ^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:644:17 + --> tests/ui/use_self.rs:654:17 | LL | E::A => {}, | ^ help: use the applicable keyword: `Self` -error: aborting due to 42 previous errors +error: aborting due to 43 previous errors diff --git a/tests/ui/zero_repeat_side_effects.fixed b/tests/ui/zero_repeat_side_effects.fixed new file mode 100644 index 0000000000000..6f13252192640 --- /dev/null +++ b/tests/ui/zero_repeat_side_effects.fixed @@ -0,0 +1,60 @@ +#![warn(clippy::zero_repeat_side_effects)] +#![allow(clippy::unnecessary_operation)] +#![allow(clippy::useless_vec)] +#![allow(clippy::needless_late_init)] + +fn f() -> i32 { + println!("side effect"); + 10 +} + +fn main() { + const N: usize = 0; + const M: usize = 1; + + // should trigger + + // on arrays + f(); let a: [i32; 0] = []; + f(); let a: [i32; 0] = []; + let mut b; + f(); b = [] as [i32; 0]; + f(); b = [] as [i32; 0]; + + // on vecs + // vecs dont support infering value of consts + f(); let c: std::vec::Vec = vec![]; + let d; + f(); d = vec![] as std::vec::Vec; + + // for macros + println!("side effect"); let e: [(); 0] = []; + + // for nested calls + { f() }; let g: [i32; 0] = []; + + // as function param + drop({ f(); vec![] as std::vec::Vec }); + + // when singled out/not part of assignment/local + { f(); vec![] as std::vec::Vec }; + { f(); [] as [i32; 0] }; + { f(); [] as [i32; 0] }; + + // should not trigger + + // on arrays with > 0 repeat + let a = [f(); 1]; + let a = [f(); M]; + let mut b; + b = [f(); 1]; + b = [f(); M]; + + // on vecs with > 0 repeat + let c = vec![f(); 1]; + let d; + d = vec![f(); 1]; + + // as function param + drop(vec![f(); 1]); +} diff --git a/tests/ui/zero_repeat_side_effects.rs b/tests/ui/zero_repeat_side_effects.rs new file mode 100644 index 0000000000000..9d9c367375a71 --- /dev/null +++ b/tests/ui/zero_repeat_side_effects.rs @@ -0,0 +1,60 @@ +#![warn(clippy::zero_repeat_side_effects)] +#![allow(clippy::unnecessary_operation)] +#![allow(clippy::useless_vec)] +#![allow(clippy::needless_late_init)] + +fn f() -> i32 { + println!("side effect"); + 10 +} + +fn main() { + const N: usize = 0; + const M: usize = 1; + + // should trigger + + // on arrays + let a = [f(); 0]; + let a = [f(); N]; + let mut b; + b = [f(); 0]; + b = [f(); N]; + + // on vecs + // vecs dont support infering value of consts + let c = vec![f(); 0]; + let d; + d = vec![f(); 0]; + + // for macros + let e = [println!("side effect"); 0]; + + // for nested calls + let g = [{ f() }; 0]; + + // as function param + drop(vec![f(); 0]); + + // when singled out/not part of assignment/local + vec![f(); 0]; + [f(); 0]; + [f(); N]; + + // should not trigger + + // on arrays with > 0 repeat + let a = [f(); 1]; + let a = [f(); M]; + let mut b; + b = [f(); 1]; + b = [f(); M]; + + // on vecs with > 0 repeat + let c = vec![f(); 1]; + let d; + d = vec![f(); 1]; + + // as function param + drop(vec![f(); 1]); +} diff --git a/tests/ui/zero_repeat_side_effects.stderr b/tests/ui/zero_repeat_side_effects.stderr new file mode 100644 index 0000000000000..afdc60542534d --- /dev/null +++ b/tests/ui/zero_repeat_side_effects.stderr @@ -0,0 +1,77 @@ +error: function or method calls as the initial value in zero-sized array initializers may cause side effects + --> tests/ui/zero_repeat_side_effects.rs:18:5 + | +LL | let a = [f(); 0]; + | ^^^^^^^^^^^^^^^^^ help: consider using: `f(); let a: [i32; 0] = [];` + | + = note: `-D clippy::zero-repeat-side-effects` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::zero_repeat_side_effects)]` + +error: function or method calls as the initial value in zero-sized array initializers may cause side effects + --> tests/ui/zero_repeat_side_effects.rs:19:5 + | +LL | let a = [f(); N]; + | ^^^^^^^^^^^^^^^^^ help: consider using: `f(); let a: [i32; 0] = [];` + +error: function or method calls as the initial value in zero-sized array initializers may cause side effects + --> tests/ui/zero_repeat_side_effects.rs:21:5 + | +LL | b = [f(); 0]; + | ^^^^^^^^^^^^ help: consider using: `f(); b = [] as [i32; 0]` + +error: function or method calls as the initial value in zero-sized array initializers may cause side effects + --> tests/ui/zero_repeat_side_effects.rs:22:5 + | +LL | b = [f(); N]; + | ^^^^^^^^^^^^ help: consider using: `f(); b = [] as [i32; 0]` + +error: function or method calls as the initial value in zero-sized array initializers may cause side effects + --> tests/ui/zero_repeat_side_effects.rs:26:5 + | +LL | let c = vec![f(); 0]; + | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f(); let c: std::vec::Vec = vec![];` + +error: function or method calls as the initial value in zero-sized array initializers may cause side effects + --> tests/ui/zero_repeat_side_effects.rs:28:5 + | +LL | d = vec![f(); 0]; + | ^^^^^^^^^^^^^^^^ help: consider using: `f(); d = vec![] as std::vec::Vec` + +error: function or method calls as the initial value in zero-sized array initializers may cause side effects + --> tests/ui/zero_repeat_side_effects.rs:31:5 + | +LL | let e = [println!("side effect"); 0]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `println!("side effect"); let e: [(); 0] = [];` + +error: function or method calls as the initial value in zero-sized array initializers may cause side effects + --> tests/ui/zero_repeat_side_effects.rs:34:5 + | +LL | let g = [{ f() }; 0]; + | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `{ f() }; let g: [i32; 0] = [];` + +error: function or method calls as the initial value in zero-sized array initializers may cause side effects + --> tests/ui/zero_repeat_side_effects.rs:37:10 + | +LL | drop(vec![f(); 0]); + | ^^^^^^^^^^^^ help: consider using: `{ f(); vec![] as std::vec::Vec }` + +error: function or method calls as the initial value in zero-sized array initializers may cause side effects + --> tests/ui/zero_repeat_side_effects.rs:40:5 + | +LL | vec![f(); 0]; + | ^^^^^^^^^^^^ help: consider using: `{ f(); vec![] as std::vec::Vec }` + +error: function or method calls as the initial value in zero-sized array initializers may cause side effects + --> tests/ui/zero_repeat_side_effects.rs:41:5 + | +LL | [f(); 0]; + | ^^^^^^^^ help: consider using: `{ f(); [] as [i32; 0] }` + +error: function or method calls as the initial value in zero-sized array initializers may cause side effects + --> tests/ui/zero_repeat_side_effects.rs:42:5 + | +LL | [f(); N]; + | ^^^^^^^^ help: consider using: `{ f(); [] as [i32; 0] }` + +error: aborting due to 12 previous errors + diff --git a/triagebot.toml b/triagebot.toml index 1a81394af10d5..d455d967e30c0 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -19,7 +19,7 @@ new_pr = true [assign] contributing_url = "https://github.com/rust-lang/rust-clippy/blob/master/CONTRIBUTING.md" -users_on_vacation = ["xFrednet"] +users_on_vacation = [] [assign.owners] "/.github" = ["@flip1995"] From 75390b9f7f2e25f0c3f831a63035bab7cfd98685 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Fri, 15 Mar 2024 03:21:55 +0100 Subject: [PATCH 09/24] Rename AstConv to HIR ty lowering This includes updating astconv-related items and a few local variables. --- clippy_lints/src/implicit_hasher.rs | 4 ++-- clippy_lints/src/implied_bounds_in_impls.rs | 4 ++-- clippy_lints/src/types/redundant_allocation.rs | 4 ++-- clippy_lints/src/types/vec_box.rs | 6 +++--- clippy_lints/src/unconditional_recursion.rs | 4 ++-- clippy_lints/src/uninhabited_references.rs | 4 ++-- clippy_lints/src/use_self.rs | 4 ++-- clippy_lints/src/zero_sized_map_values.rs | 4 ++-- 8 files changed, 17 insertions(+), 17 deletions(-) diff --git a/clippy_lints/src/implicit_hasher.rs b/clippy_lints/src/implicit_hasher.rs index a79bf66ae0133..8acb138332cfb 100644 --- a/clippy_lints/src/implicit_hasher.rs +++ b/clippy_lints/src/implicit_hasher.rs @@ -5,7 +5,7 @@ use rustc_errors::Diag; use rustc_hir as hir; use rustc_hir::intravisit::{walk_body, walk_expr, walk_inf, walk_ty, Visitor}; use rustc_hir::{Body, Expr, ExprKind, GenericArg, Item, ItemKind, QPath, TyKind}; -use rustc_hir_analysis::hir_ty_to_ty; +use rustc_hir_analysis::lower_ty; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{Ty, TypeckResults}; @@ -227,7 +227,7 @@ impl<'tcx> ImplicitHasherType<'tcx> { .collect(); let params_len = params.len(); - let ty = hir_ty_to_ty(cx.tcx, hir_ty); + let ty = lower_ty(cx.tcx, hir_ty); if is_type_diagnostic_item(cx, ty, sym::HashMap) && params_len == 2 { Some(ImplicitHasherType::HashMap( diff --git a/clippy_lints/src/implied_bounds_in_impls.rs b/clippy_lints/src/implied_bounds_in_impls.rs index 74582f7f1de23..9f4d7b51271b0 100644 --- a/clippy_lints/src/implied_bounds_in_impls.rs +++ b/clippy_lints/src/implied_bounds_in_impls.rs @@ -6,7 +6,7 @@ use rustc_hir::{ GenericArg, GenericBound, GenericBounds, ItemKind, PredicateOrigin, TraitBoundModifier, TyKind, TypeBinding, WherePredicate, }; -use rustc_hir_analysis::hir_ty_to_ty; +use rustc_hir_analysis::lower_ty; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, ClauseKind, Generics, Ty, TyCtxt}; use rustc_session::declare_lint_pass; @@ -146,7 +146,7 @@ fn try_resolve_type<'tcx>( index: usize, ) -> Option> { match args.get(index - 1) { - Some(GenericArg::Type(ty)) => Some(hir_ty_to_ty(tcx, ty)), + Some(GenericArg::Type(ty)) => Some(lower_ty(tcx, ty)), Some(_) => None, None => Some(tcx.type_of(generics.params[index].def_id).skip_binder()), } diff --git a/clippy_lints/src/types/redundant_allocation.rs b/clippy_lints/src/types/redundant_allocation.rs index a0d609501a0c0..9729c971672c4 100644 --- a/clippy_lints/src/types/redundant_allocation.rs +++ b/clippy_lints/src/types/redundant_allocation.rs @@ -4,7 +4,7 @@ use clippy_utils::{path_def_id, qpath_generic_tys}; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; use rustc_hir::{self as hir, QPath, TyKind}; -use rustc_hir_analysis::hir_ty_to_ty; +use rustc_hir_analysis::lower_ty; use rustc_lint::LateContext; use rustc_middle::ty::TypeVisitableExt; use rustc_span::symbol::sym; @@ -59,7 +59,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>, qpath: // Reallocation of a fat pointer causes it to become thin. `hir_ty_to_ty` is safe to use // here because `mod.rs` guarantees this lint is only run on types outside of bodies and // is not run on locals. - let ty = hir_ty_to_ty(cx.tcx, hir_ty); + let ty = lower_ty(cx.tcx, hir_ty); if ty.has_escaping_bound_vars() || !ty.is_sized(cx.tcx, cx.param_env) { return false; } diff --git a/clippy_lints/src/types/vec_box.rs b/clippy_lints/src/types/vec_box.rs index 7926738d68f1a..29996a6f783e1 100644 --- a/clippy_lints/src/types/vec_box.rs +++ b/clippy_lints/src/types/vec_box.rs @@ -4,7 +4,7 @@ use clippy_utils::source::snippet; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; use rustc_hir::{self as hir, GenericArg, LangItem, QPath, TyKind}; -use rustc_hir_analysis::hir_ty_to_ty; +use rustc_hir_analysis::lower_ty; use rustc_lint::LateContext; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::TypeVisitableExt; @@ -35,7 +35,7 @@ pub(super) fn check<'tcx>( && let Some(GenericArg::Type(boxed_ty)) = last.args.first() // extract allocator from the Box for later && let boxed_alloc_ty = last.args.get(1) - && let ty_ty = hir_ty_to_ty(cx.tcx, boxed_ty) + && let ty_ty = lower_ty(cx.tcx, boxed_ty) && !ty_ty.has_escaping_bound_vars() && ty_ty.is_sized(cx.tcx, cx.param_env) && let Ok(ty_ty_size) = cx.layout_of(ty_ty).map(|l| l.size.bytes()) @@ -55,7 +55,7 @@ pub(super) fn check<'tcx>( } }, (Some(GenericArg::Type(l)), Some(GenericArg::Type(r))) => - hir_ty_to_ty(cx.tcx, l) == hir_ty_to_ty(cx.tcx, r), + lower_ty(cx.tcx, l) == lower_ty(cx.tcx, r), _ => false } { diff --git a/clippy_lints/src/unconditional_recursion.rs b/clippy_lints/src/unconditional_recursion.rs index d638af2b78b36..8764e3006c6b9 100644 --- a/clippy_lints/src/unconditional_recursion.rs +++ b/clippy_lints/src/unconditional_recursion.rs @@ -7,7 +7,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{walk_body, walk_expr, FnKind, Visitor}; use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirId, Item, ItemKind, Node, QPath, TyKind}; -use rustc_hir_analysis::hir_ty_to_ty; +use rustc_hir_analysis::lower_ty; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::map::Map; use rustc_middle::hir::nested_filter; @@ -74,7 +74,7 @@ fn get_hir_ty_def_id<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: rustc_hir::Ty<'tcx>) -> Op match qpath { QPath::Resolved(_, path) => path.res.opt_def_id(), QPath::TypeRelative(_, _) => { - let ty = hir_ty_to_ty(tcx, &hir_ty); + let ty = lower_ty(tcx, &hir_ty); match ty.kind() { ty::Alias(ty::Projection, proj) => { diff --git a/clippy_lints/src/uninhabited_references.rs b/clippy_lints/src/uninhabited_references.rs index 6732a43a19ec5..88039372ebd2c 100644 --- a/clippy_lints/src/uninhabited_references.rs +++ b/clippy_lints/src/uninhabited_references.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint; use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, Expr, ExprKind, FnDecl, FnRetTy, TyKind, UnOp}; -use rustc_hir_analysis::hir_ty_to_ty; +use rustc_hir_analysis::lower_ty; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; @@ -71,7 +71,7 @@ impl LateLintPass<'_> for UninhabitedReferences { } if let FnRetTy::Return(hir_ty) = fndecl.output && let TyKind::Ref(_, mut_ty) = hir_ty.kind - && hir_ty_to_ty(cx.tcx, mut_ty.ty).is_privately_uninhabited(cx.tcx, cx.param_env) + && lower_ty(cx.tcx, mut_ty.ty).is_privately_uninhabited(cx.tcx, cx.param_env) { span_lint( cx, diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index b28037db1121e..dfa816963bc07 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -11,7 +11,7 @@ use rustc_hir::{ self as hir, Expr, ExprKind, FnRetTy, FnSig, GenericArgsParentheses, GenericParam, GenericParamKind, HirId, Impl, ImplItemKind, Item, ItemKind, Pat, PatKind, Path, QPath, Ty, TyKind, }; -use rustc_hir_analysis::hir_ty_to_ty; +use rustc_hir_analysis::lower_ty; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty as MiddleTy; use rustc_session::impl_lint_pass; @@ -224,7 +224,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { && let ty = if in_body > 0 { cx.typeck_results().node_type(hir_ty.hir_id) } else { - hir_ty_to_ty(cx.tcx, hir_ty) + lower_ty(cx.tcx, hir_ty) } && let impl_ty = cx.tcx.type_of(impl_id).instantiate_identity() && same_type_and_consts(ty, impl_ty) diff --git a/clippy_lints/src/zero_sized_map_values.rs b/clippy_lints/src/zero_sized_map_values.rs index 4aaf3b0a0b674..d1f7c6417c7e1 100644 --- a/clippy_lints/src/zero_sized_map_values.rs +++ b/clippy_lints/src/zero_sized_map_values.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::{is_normalizable, is_type_diagnostic_item}; use rustc_hir::{self as hir, HirId, ItemKind, Node}; -use rustc_hir_analysis::hir_ty_to_ty; +use rustc_hir_analysis::lower_ty; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf as _; use rustc_middle::ty::{Adt, Ty, TypeVisitableExt}; @@ -91,5 +91,5 @@ fn ty_from_hir_ty<'tcx>(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>) -> Ty<'t None } }) - .unwrap_or_else(|| hir_ty_to_ty(cx.tcx, hir_ty)) + .unwrap_or_else(|| lower_ty(cx.tcx, hir_ty)) } From b7026f87f52f75ebcb7c0de0c1bf56b714d4b73f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Sun, 11 Feb 2024 09:22:52 +0100 Subject: [PATCH 10/24] Update (doc) comments Several (doc) comments were super outdated or didn't provide enough context. Some doc comments shoved everything in a single paragraph without respecting the fact that the first paragraph should be a single sentence because rustdoc treats these as item descriptions / synopses on module pages. --- book/src/development/type_checking.md | 10 +++++----- clippy_lints/src/types/redundant_allocation.rs | 2 +- clippy_lints/src/use_self.rs | 2 +- tests/ui/crashes/ice-6179.rs | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/book/src/development/type_checking.md b/book/src/development/type_checking.md index 136b3fd027057..e6da4322a1793 100644 --- a/book/src/development/type_checking.md +++ b/book/src/development/type_checking.md @@ -118,10 +118,10 @@ Here the HIR sees the types without "thinking" about them, it knows that the fun an `u32`. As far as `hir::Ty` is concerned those might be different types. But at the `ty::Ty` level the compiler understands that they're the same type, in-depth lifetimes, etc... -To get from a `hir::Ty` to a `ty::Ty`, you can use the [`hir_ty_to_ty`][hir_ty_to_ty] function outside of bodies or +To get from a `hir::Ty` to a `ty::Ty`, you can use the [`lower_ty`][lower_ty] function outside of bodies or the [`TypeckResults::node_type()`][node_type] method inside of bodies. -> **Warning**: Don't use `hir_ty_to_ty` inside of bodies, because this can cause ICEs. +> **Warning**: Don't use `lower_ty` inside of bodies, because this can cause ICEs. ## Creating Types programmatically @@ -162,6 +162,6 @@ in this chapter: [Ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html [TyKind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/ty_kind/enum.TyKind.html [TypeckResults]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html -[middle_ty]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_middle/ty/struct.Ty.html -[hir_ty]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_hir/struct.Ty.html -[hir_ty_to_ty]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_hir_analysis/fn.hir_ty_to_ty.html +[middle_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html +[hir_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/struct.Ty.html +[lower_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_analysis/fn.lower_ty.html diff --git a/clippy_lints/src/types/redundant_allocation.rs b/clippy_lints/src/types/redundant_allocation.rs index 9729c971672c4..37437cbfbec4a 100644 --- a/clippy_lints/src/types/redundant_allocation.rs +++ b/clippy_lints/src/types/redundant_allocation.rs @@ -56,7 +56,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>, qpath: }; let inner_span = match qpath_generic_tys(inner_qpath).next() { Some(hir_ty) => { - // Reallocation of a fat pointer causes it to become thin. `hir_ty_to_ty` is safe to use + // Reallocation of a fat pointer causes it to become thin. `lower_ty` is safe to use // here because `mod.rs` guarantees this lint is only run on types outside of bodies and // is not run on locals. let ty = lower_ty(cx.tcx, hir_ty); diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index dfa816963bc07..a6b411d6c0f97 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -193,7 +193,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { } fn check_body(&mut self, _: &LateContext<'_>, _: &hir::Body<'_>) { - // `hir_ty_to_ty` cannot be called in `Body`s or it will panic (sometimes). But in bodies + // `lower_ty` cannot be called in `Body`s or it will panic (sometimes). But in bodies // we can use `cx.typeck_results.node_type(..)` to get the `ty::Ty` from a `hir::Ty`. // However the `node_type()` method can *only* be called in bodies. if let Some(&mut StackItem::Check { ref mut in_body, .. }) = self.stack.last_mut() { diff --git a/tests/ui/crashes/ice-6179.rs b/tests/ui/crashes/ice-6179.rs index fffc0f7d0d4f2..91160eef03df9 100644 --- a/tests/ui/crashes/ice-6179.rs +++ b/tests/ui/crashes/ice-6179.rs @@ -1,5 +1,5 @@ //! This is a minimal reproducer for the ICE in https://github.com/rust-lang/rust-clippy/pull/6179. -//! The ICE is mainly caused by using `hir_ty_to_ty`. See the discussion in the PR for details. +//! The ICE is mainly caused by using `lower_ty`. See the discussion in the PR for details. #![warn(clippy::use_self)] #![allow(dead_code, clippy::let_with_type_underscore)] From 0b810866ef8ffe4125f9c7aebb7d8b3792d2b7f1 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 21 Mar 2024 16:50:21 -0400 Subject: [PATCH 11/24] Eagerly convert some ctors to use their specialized ctors --- clippy_lints/src/methods/unnecessary_to_owned.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index c234e4f9b110c..6e525b5ff9301 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -336,12 +336,9 @@ fn check_other_call_arg<'tcx>( && let Some((n_refs, receiver_ty)) = if n_refs > 0 || is_copy(cx, receiver_ty) { Some((n_refs, receiver_ty)) } else if trait_predicate.def_id() != deref_trait_id { - Some((1, Ty::new_ref(cx.tcx, + Some((1, Ty::new_imm_ref(cx.tcx, cx.tcx.lifetimes.re_erased, - ty::TypeAndMut { - ty: receiver_ty, - mutbl: Mutability::Not, - }, + receiver_ty, ))) } else { None From c92b350581583c251dcd447f92fc20d362d34834 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 21 Mar 2024 17:11:06 -0400 Subject: [PATCH 12/24] Programmatically convert some of the pat ctors --- .../src/casts/cast_slice_different_sizes.rs | 2 +- clippy_lints/src/casts/ptr_as_ptr.rs | 4 ++-- clippy_lints/src/casts/ref_as_ptr.rs | 2 +- clippy_lints/src/from_raw_with_void_ptr.rs | 2 +- clippy_lints/src/functions/must_use.rs | 2 +- .../src/functions/not_unsafe_ptr_arg_deref.rs | 2 +- .../src/matches/significant_drop_in_scrutinee.rs | 2 +- clippy_lints/src/methods/zst_offset.rs | 2 +- clippy_lints/src/mutex_atomic.rs | 2 +- clippy_lints/src/non_send_fields_in_send_ty.rs | 4 ++-- clippy_lints/src/significant_drop_tightening.rs | 2 +- clippy_lints/src/size_of_in_element_count.rs | 2 +- .../src/transmute/transmute_ptr_to_ptr.rs | 2 +- .../src/transmute/transmute_undefined_repr.rs | 16 ++++++++-------- clippy_lints/src/transmute/useless_transmute.rs | 2 +- clippy_lints/src/transmute/wrong_transmute.rs | 2 +- clippy_utils/src/consts.rs | 2 +- clippy_utils/src/lib.rs | 4 ++-- clippy_utils/src/ty.rs | 2 +- 19 files changed, 29 insertions(+), 29 deletions(-) diff --git a/clippy_lints/src/casts/cast_slice_different_sizes.rs b/clippy_lints/src/casts/cast_slice_different_sizes.rs index a31943f002180..76d5c3291790b 100644 --- a/clippy_lints/src/casts/cast_slice_different_sizes.rs +++ b/clippy_lints/src/casts/cast_slice_different_sizes.rs @@ -87,7 +87,7 @@ fn is_child_of_cast(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { /// the type is one of those slices fn get_raw_slice_ty_mut(ty: Ty<'_>) -> Option> { match ty.kind() { - ty::RawPtr(TypeAndMut { ty: slice_ty, mutbl }) => match slice_ty.kind() { + ty::RawPtr(slice_ty, mutbl) => match slice_ty.kind() { ty::Slice(ty) => Some(TypeAndMut { ty: *ty, mutbl: *mutbl }), _ => None, }, diff --git a/clippy_lints/src/casts/ptr_as_ptr.rs b/clippy_lints/src/casts/ptr_as_ptr.rs index 35e36e9ef3f5f..5182c6179e68d 100644 --- a/clippy_lints/src/casts/ptr_as_ptr.rs +++ b/clippy_lints/src/casts/ptr_as_ptr.rs @@ -33,8 +33,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Msrv) { if let ExprKind::Cast(cast_expr, cast_to_hir_ty) = expr.kind && let (cast_from, cast_to) = (cx.typeck_results().expr_ty(cast_expr), cx.typeck_results().expr_ty(expr)) - && let ty::RawPtr(TypeAndMut { mutbl: from_mutbl, .. }) = cast_from.kind() - && let ty::RawPtr(TypeAndMut { ty: to_pointee_ty, mutbl: to_mutbl }) = cast_to.kind() + && let ty::RawPtr(_, from_mutbl) = cast_from.kind() + && let ty::RawPtr(to_pointee_ty, to_mutbl) = cast_to.kind() && matches!((from_mutbl, to_mutbl), (Mutability::Not, Mutability::Not) | (Mutability::Mut, Mutability::Mut)) // The `U` in `pointer::cast` have to be `Sized` diff --git a/clippy_lints/src/casts/ref_as_ptr.rs b/clippy_lints/src/casts/ref_as_ptr.rs index 9d5a486336d5f..a999b4e438844 100644 --- a/clippy_lints/src/casts/ref_as_ptr.rs +++ b/clippy_lints/src/casts/ref_as_ptr.rs @@ -21,7 +21,7 @@ pub(super) fn check<'tcx>( ); if matches!(cast_from.kind(), ty::Ref(..)) - && let ty::RawPtr(TypeAndMut { mutbl: to_mutbl, .. }) = cast_to.kind() + && let ty::RawPtr(_, to_mutbl) = cast_to.kind() && let Some(use_cx) = expr_use_ctxt(cx, expr) // TODO: only block the lint if `cast_expr` is a temporary && !matches!(use_cx.node, ExprUseNode::Local(_) | ExprUseNode::ConstStatic(_)) diff --git a/clippy_lints/src/from_raw_with_void_ptr.rs b/clippy_lints/src/from_raw_with_void_ptr.rs index c8d10dc4b9298..1c91a377b1aa6 100644 --- a/clippy_lints/src/from_raw_with_void_ptr.rs +++ b/clippy_lints/src/from_raw_with_void_ptr.rs @@ -44,7 +44,7 @@ impl LateLintPass<'_> for FromRawWithVoidPtr { && seg.ident.name == sym!(from_raw) && let Some(type_str) = path_def_id(cx, ty).and_then(|id| def_id_matches_type(cx, id)) && let arg_kind = cx.typeck_results().expr_ty(arg).kind() - && let RawPtr(TypeAndMut { ty, .. }) = arg_kind + && let ty::RawPtr(ty, _) = arg_kind && is_c_void(cx, *ty) { let msg = format!("creating a `{type_str}` from a void raw pointer"); diff --git a/clippy_lints/src/functions/must_use.rs b/clippy_lints/src/functions/must_use.rs index 3aaf63ce340ab..d752d010f9fe4 100644 --- a/clippy_lints/src/functions/must_use.rs +++ b/clippy_lints/src/functions/must_use.rs @@ -207,7 +207,7 @@ fn is_mutable_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, tys: &mut DefIdSet) }, ty::Tuple(args) => args.iter().any(|ty| is_mutable_ty(cx, ty, tys)), ty::Array(ty, _) | ty::Slice(ty) => is_mutable_ty(cx, ty, tys), - ty::RawPtr(ty::TypeAndMut { ty, mutbl }) | ty::Ref(_, ty, mutbl) => { + ty::RawPtr(ty, mutbl) | ty::Ref(_, ty, mutbl) => { mutbl == hir::Mutability::Mut || is_mutable_ty(cx, ty, tys) }, // calling something constitutes a side effect, so return true on all callables diff --git a/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs b/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs index f2aa7b597a79b..2d757883f2662 100644 --- a/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs +++ b/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs @@ -75,7 +75,7 @@ fn check_raw_ptr<'tcx>( } fn raw_ptr_arg(cx: &LateContext<'_>, arg: &hir::Param<'_>) -> Option { - if let (&hir::PatKind::Binding(_, id, _, _), Some(&ty::RawPtr(_))) = ( + if let (&hir::PatKind::Binding(_, id, _, _), Some(&ty::RawPtr(_, _))) = ( &arg.pat.kind, cx.maybe_typeck_results() .map(|typeck_results| typeck_results.pat_ty(arg.pat).kind()), diff --git a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs index b770ad0ddb5cc..10c3203725a81 100644 --- a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs +++ b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs @@ -149,7 +149,7 @@ impl<'a, 'tcx> SigDropChecker<'a, 'tcx> { false }, rustc_middle::ty::Array(ty, _) - | rustc_middle::ty::RawPtr(TypeAndMut { ty, .. }) + | rustc_middle::ty::RawPtr(ty, _) | rustc_middle::ty::Ref(_, ty, _) | rustc_middle::ty::Slice(ty) => self.has_sig_drop_attr(cx, *ty), _ => false, diff --git a/clippy_lints/src/methods/zst_offset.rs b/clippy_lints/src/methods/zst_offset.rs index 0b829d99aef89..d33021c2a7bf8 100644 --- a/clippy_lints/src/methods/zst_offset.rs +++ b/clippy_lints/src/methods/zst_offset.rs @@ -6,7 +6,7 @@ use rustc_middle::ty; use super::ZST_OFFSET; pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) { - if let ty::RawPtr(ty::TypeAndMut { ty, .. }) = cx.typeck_results().expr_ty(recv).kind() + if let ty::RawPtr(ty, _) = cx.typeck_results().expr_ty(recv).kind() && let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(*ty)) && layout.is_zst() { diff --git a/clippy_lints/src/mutex_atomic.rs b/clippy_lints/src/mutex_atomic.rs index 4ae4fc9b09616..61243c8373168 100644 --- a/clippy_lints/src/mutex_atomic.rs +++ b/clippy_lints/src/mutex_atomic.rs @@ -127,7 +127,7 @@ fn get_atomic_name(ty: Ty<'_>) -> Option<&'static str> { IntTy::I128 => None, } }, - ty::RawPtr(_) => Some("AtomicPtr"), + ty::RawPtr(_, _) => Some("AtomicPtr"), _ => None, } } diff --git a/clippy_lints/src/non_send_fields_in_send_ty.rs b/clippy_lints/src/non_send_fields_in_send_ty.rs index 793a3a9545cd9..408216229a41c 100644 --- a/clippy_lints/src/non_send_fields_in_send_ty.rs +++ b/clippy_lints/src/non_send_fields_in_send_ty.rs @@ -219,7 +219,7 @@ fn ty_allowed_with_raw_pointer_heuristic<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'t } }, // Raw pointers are `!Send` but allowed by the heuristic - ty::RawPtr(_) => true, + ty::RawPtr(_, _) => true, _ => false, } } @@ -229,7 +229,7 @@ fn contains_pointer_like<'tcx>(cx: &LateContext<'tcx>, target_ty: Ty<'tcx>) -> b for ty_node in target_ty.walk() { if let GenericArgKind::Type(inner_ty) = ty_node.unpack() { match inner_ty.kind() { - ty::RawPtr(_) => { + ty::RawPtr(_, _) => { return true; }, ty::Adt(adt_def, _) => { diff --git a/clippy_lints/src/significant_drop_tightening.rs b/clippy_lints/src/significant_drop_tightening.rs index f8726aa173a9b..57470f950da02 100644 --- a/clippy_lints/src/significant_drop_tightening.rs +++ b/clippy_lints/src/significant_drop_tightening.rs @@ -199,7 +199,7 @@ impl<'cx, 'others, 'tcx> AttrChecker<'cx, 'others, 'tcx> { false }, rustc_middle::ty::Array(ty, _) - | rustc_middle::ty::RawPtr(TypeAndMut { ty, .. }) + | rustc_middle::ty::RawPtr(ty, _) | rustc_middle::ty::Ref(_, ty, _) | rustc_middle::ty::Slice(ty) => self.has_sig_drop_attr(*ty), _ => false, diff --git a/clippy_lints/src/size_of_in_element_count.rs b/clippy_lints/src/size_of_in_element_count.rs index 756e47cbdf0a4..c26ce1272ff86 100644 --- a/clippy_lints/src/size_of_in_element_count.rs +++ b/clippy_lints/src/size_of_in_element_count.rs @@ -107,7 +107,7 @@ fn get_pointee_ty_and_count_expr<'tcx>( && METHODS.iter().any(|m| *m == method_ident) // Get the pointee type - && let ty::RawPtr(TypeAndMut { ty: pointee_ty, .. }) = + && let ty::RawPtr(pointee_ty, _) = cx.typeck_results().expr_ty(ptr_self).kind() { return Some((*pointee_ty, count)); diff --git a/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs b/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs index 4ae4359eea0b0..84fa201639ac3 100644 --- a/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs +++ b/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs @@ -16,7 +16,7 @@ pub(super) fn check<'tcx>( arg: &'tcx Expr<'_>, ) -> bool { match (&from_ty.kind(), &to_ty.kind()) { - (ty::RawPtr(_), ty::RawPtr(to_ty)) => { + (ty::RawPtr(_, _), ty::RawPtr(to_ty)) => { span_lint_and_then( cx, TRANSMUTE_PTR_TO_PTR, diff --git a/clippy_lints/src/transmute/transmute_undefined_repr.rs b/clippy_lints/src/transmute/transmute_undefined_repr.rs index a6f03c85b4f63..44b5f460737da 100644 --- a/clippy_lints/src/transmute/transmute_undefined_repr.rs +++ b/clippy_lints/src/transmute/transmute_undefined_repr.rs @@ -45,8 +45,8 @@ pub(super) fn check<'tcx>( // ptr <-> ptr (ReducedTy::Other(from_sub_ty), ReducedTy::Other(to_sub_ty)) - if matches!(from_sub_ty.kind(), ty::Ref(..) | ty::RawPtr(_)) - && matches!(to_sub_ty.kind(), ty::Ref(..) | ty::RawPtr(_)) => + if matches!(from_sub_ty.kind(), ty::Ref(..) | ty::RawPtr(_, _)) + && matches!(to_sub_ty.kind(), ty::Ref(..) | ty::RawPtr(_, _)) => { from_ty = from_sub_ty; to_ty = to_sub_ty; @@ -196,21 +196,21 @@ fn reduce_refs<'tcx>(cx: &LateContext<'tcx>, mut from_ty: Ty<'tcx>, mut to_ty: T let (from_fat_ptr, to_fat_ptr) = loop { break match (from_ty.kind(), to_ty.kind()) { ( - &(ty::Ref(_, from_sub_ty, _) | ty::RawPtr(TypeAndMut { ty: from_sub_ty, .. })), - &(ty::Ref(_, to_sub_ty, _) | ty::RawPtr(TypeAndMut { ty: to_sub_ty, .. })), + &(ty::Ref(_, from_sub_ty, _) | ty::RawPtr(from_sub_ty, _)), + &(ty::Ref(_, to_sub_ty, _) | ty::RawPtr(to_sub_ty, _)), ) => { - from_raw_ptr = matches!(*from_ty.kind(), ty::RawPtr(_)); + from_raw_ptr = matches!(*from_ty.kind(), ty::RawPtr(_, _)); from_ty = from_sub_ty; - to_raw_ptr = matches!(*to_ty.kind(), ty::RawPtr(_)); + to_raw_ptr = matches!(*to_ty.kind(), ty::RawPtr(_, _)); to_ty = to_sub_ty; continue; }, - (&(ty::Ref(_, unsized_ty, _) | ty::RawPtr(TypeAndMut { ty: unsized_ty, .. })), _) + (&(ty::Ref(_, unsized_ty, _) | ty::RawPtr(unsized_ty, _)), _) if !unsized_ty.is_sized(cx.tcx, cx.param_env) => { (true, false) }, - (_, &(ty::Ref(_, unsized_ty, _) | ty::RawPtr(TypeAndMut { ty: unsized_ty, .. }))) + (_, &(ty::Ref(_, unsized_ty, _) | ty::RawPtr(unsized_ty, _))) if !unsized_ty.is_sized(cx.tcx, cx.param_env) => { (false, true) diff --git a/clippy_lints/src/transmute/useless_transmute.rs b/clippy_lints/src/transmute/useless_transmute.rs index 088c8fda87a3a..f3d3516755c0b 100644 --- a/clippy_lints/src/transmute/useless_transmute.rs +++ b/clippy_lints/src/transmute/useless_transmute.rs @@ -53,7 +53,7 @@ pub(super) fn check<'tcx>( } true }, - (ty::Int(_) | ty::Uint(_), ty::RawPtr(_)) => { + (ty::Int(_) | ty::Uint(_), ty::RawPtr(_, _)) => { span_lint_and_then( cx, USELESS_TRANSMUTE, diff --git a/clippy_lints/src/transmute/wrong_transmute.rs b/clippy_lints/src/transmute/wrong_transmute.rs index d1965565b9261..ed815884a7640 100644 --- a/clippy_lints/src/transmute/wrong_transmute.rs +++ b/clippy_lints/src/transmute/wrong_transmute.rs @@ -8,7 +8,7 @@ use rustc_middle::ty::{self, Ty}; /// Returns `true` if it's triggered, otherwise returns `false`. pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx>, to_ty: Ty<'tcx>) -> bool { match (&from_ty.kind(), &to_ty.kind()) { - (ty::Float(_) | ty::Char, ty::Ref(..) | ty::RawPtr(_)) => { + (ty::Float(_) | ty::Char, ty::Ref(..) | ty::RawPtr(_, _)) => { span_lint( cx, WRONG_TRANSMUTE, diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 046087d329896..6b86630339fb5 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -819,7 +819,7 @@ pub fn mir_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> ty::Float(FloatTy::F64) => Some(Constant::F64(f64::from_bits( int.try_into().expect("invalid f64 bit representation"), ))), - ty::RawPtr(_) => Some(Constant::RawPtr(int.assert_bits(int.size()))), + ty::RawPtr(_, _) => Some(Constant::RawPtr(int.assert_bits(int.size()))), _ => None, }, (_, ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Str) => { diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 11b56ed47de8e..e90317f5524a3 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1040,7 +1040,7 @@ pub fn capture_local_usage(cx: &LateContext<'_>, e: &Expr<'_>) -> CaptureKind { .get(child_id) .map_or(&[][..], |x| &**x) { - if let rustc_ty::RawPtr(TypeAndMut { mutbl: mutability, .. }) | rustc_ty::Ref(_, _, mutability) = + if let rustc_ty::RawPtr(_, mutability) | rustc_ty::Ref(_, _, mutability) = *adjust.last().map_or(target, |a| a.target).kind() { return CaptureKind::Ref(mutability); @@ -3235,7 +3235,7 @@ fn get_path_to_ty<'tcx>(tcx: TyCtxt<'tcx>, from: LocalDefId, ty: Ty<'tcx>, args: rustc_ty::Array(..) | rustc_ty::Dynamic(..) | rustc_ty::Never - | rustc_ty::RawPtr(_) + | rustc_ty::RawPtr(_, _) | rustc_ty::Ref(..) | rustc_ty::Slice(_) | rustc_ty::Tuple(_) => format!("<{}>", EarlyBinder::bind(ty).instantiate(tcx, args)), diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 801452e444c6a..97ce755adbbe6 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -321,7 +321,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { match ty.kind() { ty::Adt(adt, _) => cx.tcx.has_attr(adt.did(), sym::must_use), ty::Foreign(did) => cx.tcx.has_attr(*did, sym::must_use), - ty::Slice(ty) | ty::Array(ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) => { + ty::Slice(ty) | ty::Array(ty, _) | ty::RawPtr(ty, _) | ty::Ref(_, ty, _) => { // for the Array case we don't need to care for the len == 0 case // because we don't want to lint functions returning empty arrays is_must_use_ty(cx, *ty) From f9ad628acd819bb38de972edc777246311f021f7 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 21 Mar 2024 17:42:46 -0400 Subject: [PATCH 13/24] And the tools too --- clippy_lints/src/casts/as_ptr_cast_mut.rs | 11 +++-------- clippy_lints/src/casts/cast_ptr_alignment.rs | 10 +++++----- .../src/casts/cast_slice_from_raw_parts.rs | 4 ++-- clippy_lints/src/casts/ptr_as_ptr.rs | 2 +- clippy_lints/src/casts/ptr_cast_constness.rs | 12 +++--------- clippy_lints/src/casts/ref_as_ptr.rs | 2 +- clippy_lints/src/from_raw_with_void_ptr.rs | 4 ++-- clippy_lints/src/loops/explicit_iter_loop.rs | 6 +++--- clippy_lints/src/mut_reference.rs | 4 +--- .../src/significant_drop_tightening.rs | 2 +- clippy_lints/src/size_of_in_element_count.rs | 2 +- .../src/transmute/crosspointer_transmute.rs | 6 +++--- .../src/transmute/transmute_ptr_to_ptr.rs | 4 ++-- .../src/transmute/transmute_ptr_to_ref.rs | 4 ++-- .../src/transmute/transmute_ref_to_ref.rs | 18 +++++------------- .../src/transmute/transmute_undefined_repr.rs | 2 +- .../src/transmute/useless_transmute.rs | 13 ++++--------- clippy_utils/src/lib.rs | 2 +- 18 files changed, 41 insertions(+), 67 deletions(-) diff --git a/clippy_lints/src/casts/as_ptr_cast_mut.rs b/clippy_lints/src/casts/as_ptr_cast_mut.rs index 8bfb7383f1480..a667ea04af0ac 100644 --- a/clippy_lints/src/casts/as_ptr_cast_mut.rs +++ b/clippy_lints/src/casts/as_ptr_cast_mut.rs @@ -4,18 +4,13 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::mir::Mutability; -use rustc_middle::ty::{self, Ty, TypeAndMut}; +use rustc_middle::ty::{self, Ty}; use super::AS_PTR_CAST_MUT; pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_to: Ty<'_>) { - if let ty::RawPtr(TypeAndMut { - mutbl: Mutability::Mut, - ty: ptrty, - }) = cast_to.kind() - && let ty::RawPtr(TypeAndMut { - mutbl: Mutability::Not, .. - }) = cx.typeck_results().node_type(cast_expr.hir_id).kind() + if let ty::RawPtr(ptrty, Mutability::Mut) = cast_to.kind() + && let ty::RawPtr(_, Mutability::Not) = cx.typeck_results().node_type(cast_expr.hir_id).kind() && let ExprKind::MethodCall(method_name, receiver, [], _) = cast_expr.peel_blocks().kind && method_name.ident.name == rustc_span::sym::as_ptr && let Some(as_ptr_did) = cx diff --git a/clippy_lints/src/casts/cast_ptr_alignment.rs b/clippy_lints/src/casts/cast_ptr_alignment.rs index f12f03fbe7946..4d1a0f678f4b0 100644 --- a/clippy_lints/src/casts/cast_ptr_alignment.rs +++ b/clippy_lints/src/casts/cast_ptr_alignment.rs @@ -33,13 +33,13 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { } fn lint_cast_ptr_alignment<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, cast_from: Ty<'tcx>, cast_to: Ty<'tcx>) { - if let ty::RawPtr(from_ptr_ty) = &cast_from.kind() - && let ty::RawPtr(to_ptr_ty) = &cast_to.kind() - && let Ok(from_layout) = cx.layout_of(from_ptr_ty.ty) - && let Ok(to_layout) = cx.layout_of(to_ptr_ty.ty) + if let ty::RawPtr(from_ptr_ty, _) = *cast_from.kind() + && let ty::RawPtr(to_ptr_ty, _) = *cast_to.kind() + && let Ok(from_layout) = cx.layout_of(from_ptr_ty) + && let Ok(to_layout) = cx.layout_of(to_ptr_ty) && from_layout.align.abi < to_layout.align.abi // with c_void, we inherently need to trust the user - && !is_c_void(cx, from_ptr_ty.ty) + && !is_c_void(cx, from_ptr_ty) // when casting from a ZST, we don't know enough to properly lint && !from_layout.is_zst() && !is_used_as_unaligned(cx, expr) diff --git a/clippy_lints/src/casts/cast_slice_from_raw_parts.rs b/clippy_lints/src/casts/cast_slice_from_raw_parts.rs index 3db1e3e6d97e5..48629b6c5ccd4 100644 --- a/clippy_lints/src/casts/cast_slice_from_raw_parts.rs +++ b/clippy_lints/src/casts/cast_slice_from_raw_parts.rs @@ -25,8 +25,8 @@ fn raw_parts_kind(cx: &LateContext<'_>, did: DefId) -> Option { pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_to: Ty<'_>, msrv: &Msrv) { if msrv.meets(msrvs::PTR_SLICE_RAW_PARTS) - && let ty::RawPtr(ptrty) = cast_to.kind() - && let ty::Slice(_) = ptrty.ty.kind() + && let ty::RawPtr(ptrty, _) = cast_to.kind() + && let ty::Slice(_) = ptrty.kind() && let ExprKind::Call(fun, [ptr_arg, len_arg]) = cast_expr.peel_blocks().kind && let ExprKind::Path(ref qpath) = fun.kind && let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id() diff --git a/clippy_lints/src/casts/ptr_as_ptr.rs b/clippy_lints/src/casts/ptr_as_ptr.rs index 5182c6179e68d..5a121e6a7eb3a 100644 --- a/clippy_lints/src/casts/ptr_as_ptr.rs +++ b/clippy_lints/src/casts/ptr_as_ptr.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Mutability, QPath, TyKind}; use rustc_hir_pretty::qpath_to_string; use rustc_lint::LateContext; -use rustc_middle::ty::{self, TypeAndMut}; +use rustc_middle::ty; use rustc_span::sym; use super::PTR_AS_PTR; diff --git a/clippy_lints/src/casts/ptr_cast_constness.rs b/clippy_lints/src/casts/ptr_cast_constness.rs index ff069860a116e..e88146331cae1 100644 --- a/clippy_lints/src/casts/ptr_cast_constness.rs +++ b/clippy_lints/src/casts/ptr_cast_constness.rs @@ -4,7 +4,7 @@ use clippy_utils::sugg::Sugg; use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability}; use rustc_lint::LateContext; -use rustc_middle::ty::{self, Ty, TypeAndMut}; +use rustc_middle::ty::{self, Ty}; use super::PTR_CAST_CONSTNESS; @@ -17,14 +17,8 @@ pub(super) fn check<'tcx>( msrv: &Msrv, ) { if msrv.meets(msrvs::POINTER_CAST_CONSTNESS) - && let ty::RawPtr(TypeAndMut { - mutbl: from_mutbl, - ty: from_ty, - }) = cast_from.kind() - && let ty::RawPtr(TypeAndMut { - mutbl: to_mutbl, - ty: to_ty, - }) = cast_to.kind() + && let ty::RawPtr(from_ty, from_mutbl) = cast_from.kind() + && let ty::RawPtr(to_ty, to_mutbl) = cast_to.kind() && matches!( (from_mutbl, to_mutbl), (Mutability::Not, Mutability::Mut) | (Mutability::Mut, Mutability::Not) diff --git a/clippy_lints/src/casts/ref_as_ptr.rs b/clippy_lints/src/casts/ref_as_ptr.rs index a999b4e438844..662737a14a4da 100644 --- a/clippy_lints/src/casts/ref_as_ptr.rs +++ b/clippy_lints/src/casts/ref_as_ptr.rs @@ -5,7 +5,7 @@ use clippy_utils::{expr_use_ctxt, is_no_std_crate, ExprUseNode}; use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability, Ty, TyKind}; use rustc_lint::LateContext; -use rustc_middle::ty::{self, TypeAndMut}; +use rustc_middle::ty; use super::REF_AS_PTR; diff --git a/clippy_lints/src/from_raw_with_void_ptr.rs b/clippy_lints/src/from_raw_with_void_ptr.rs index 1c91a377b1aa6..286ba2306c922 100644 --- a/clippy_lints/src/from_raw_with_void_ptr.rs +++ b/clippy_lints/src/from_raw_with_void_ptr.rs @@ -4,7 +4,7 @@ use clippy_utils::ty::is_c_void; use rustc_hir::def_id::DefId; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::{RawPtr, TypeAndMut}; +use rustc_middle::ty::{RawPtr}; use rustc_session::declare_lint_pass; use rustc_span::sym; @@ -44,7 +44,7 @@ impl LateLintPass<'_> for FromRawWithVoidPtr { && seg.ident.name == sym!(from_raw) && let Some(type_str) = path_def_id(cx, ty).and_then(|id| def_id_matches_type(cx, id)) && let arg_kind = cx.typeck_results().expr_ty(arg).kind() - && let ty::RawPtr(ty, _) = arg_kind + && let RawPtr(ty, _) = arg_kind && is_c_void(cx, *ty) { let msg = format!("creating a `{type_str}` from a void raw pointer"); diff --git a/clippy_lints/src/loops/explicit_iter_loop.rs b/clippy_lints/src/loops/explicit_iter_loop.rs index 814ccaa36f5aa..eea5f2a94ea60 100644 --- a/clippy_lints/src/loops/explicit_iter_loop.rs +++ b/clippy_lints/src/loops/explicit_iter_loop.rs @@ -10,7 +10,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability}; use rustc_lint::LateContext; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; -use rustc_middle::ty::{self, EarlyBinder, Ty, TypeAndMut}; +use rustc_middle::ty::{self, EarlyBinder, Ty}; use rustc_span::sym; pub(super) fn check( @@ -160,7 +160,7 @@ fn is_ref_iterable<'tcx>( let self_ty = if mutbl.is_mut() { self_ty } else { - Ty::new_ref(cx.tcx, region, TypeAndMut { ty, mutbl }) + Ty::new_ref(cx.tcx, region, ty, mutbl) }; if implements_trait(cx, self_ty, trait_id, &[]) && let Some(ty) = @@ -175,7 +175,7 @@ fn is_ref_iterable<'tcx>( && !self_ty.is_ref() { // Attempt to borrow - let self_ty = Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, TypeAndMut { ty: self_ty, mutbl }); + let self_ty = Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, self_ty, mutbl); if implements_trait(cx, self_ty, trait_id, &[]) && let Some(ty) = make_normalized_projection(cx.tcx, cx.param_env, trait_id, sym!(IntoIter), [self_ty]) && ty == res_ty diff --git a/clippy_lints/src/mut_reference.rs b/clippy_lints/src/mut_reference.rs index f905a4e5b64c6..14a1e6be7388d 100644 --- a/clippy_lints/src/mut_reference.rs +++ b/clippy_lints/src/mut_reference.rs @@ -84,9 +84,7 @@ fn check_arguments<'tcx>( for (argument, parameter) in iter::zip(arguments, parameters) { match parameter.kind() { ty::Ref(_, _, Mutability::Not) - | ty::RawPtr(ty::TypeAndMut { - mutbl: Mutability::Not, .. - }) => { + | ty::RawPtr(_, Mutability::Not) => { if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, _) = argument.kind { span_lint( cx, diff --git a/clippy_lints/src/significant_drop_tightening.rs b/clippy_lints/src/significant_drop_tightening.rs index 57470f950da02..d3540bc8e1c38 100644 --- a/clippy_lints/src/significant_drop_tightening.rs +++ b/clippy_lints/src/significant_drop_tightening.rs @@ -7,7 +7,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{self as hir}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::ty::{GenericArgKind, Ty, TypeAndMut}; +use rustc_middle::ty::{GenericArgKind, Ty}; use rustc_session::impl_lint_pass; use rustc_span::symbol::Ident; use rustc_span::{sym, Span, DUMMY_SP}; diff --git a/clippy_lints/src/size_of_in_element_count.rs b/clippy_lints/src/size_of_in_element_count.rs index c26ce1272ff86..01f0e3cfadbd4 100644 --- a/clippy_lints/src/size_of_in_element_count.rs +++ b/clippy_lints/src/size_of_in_element_count.rs @@ -4,7 +4,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::{self, Ty, TypeAndMut}; +use rustc_middle::ty::{self, Ty}; use rustc_session::declare_lint_pass; use rustc_span::sym; diff --git a/clippy_lints/src/transmute/crosspointer_transmute.rs b/clippy_lints/src/transmute/crosspointer_transmute.rs index c4b9d82fc735b..102aee1cb9599 100644 --- a/clippy_lints/src/transmute/crosspointer_transmute.rs +++ b/clippy_lints/src/transmute/crosspointer_transmute.rs @@ -7,8 +7,8 @@ use rustc_middle::ty::{self, Ty}; /// Checks for `crosspointer_transmute` lint. /// Returns `true` if it's triggered, otherwise returns `false`. pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx>, to_ty: Ty<'tcx>) -> bool { - match (&from_ty.kind(), &to_ty.kind()) { - (ty::RawPtr(from_ptr), _) if from_ptr.ty == to_ty => { + match (*from_ty.kind(), *to_ty.kind()) { + (ty::RawPtr(from_ptr_ty, _), _) if from_ptr_ty == to_ty => { span_lint( cx, CROSSPOINTER_TRANSMUTE, @@ -17,7 +17,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty ); true }, - (_, ty::RawPtr(to_ptr)) if to_ptr.ty == from_ty => { + (_, ty::RawPtr(to_ptr_ty, _)) if to_ptr_ty == from_ty => { span_lint( cx, CROSSPOINTER_TRANSMUTE, diff --git a/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs b/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs index 84fa201639ac3..1476ea8e7a4ee 100644 --- a/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs +++ b/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs @@ -16,7 +16,7 @@ pub(super) fn check<'tcx>( arg: &'tcx Expr<'_>, ) -> bool { match (&from_ty.kind(), &to_ty.kind()) { - (ty::RawPtr(_, _), ty::RawPtr(to_ty)) => { + (ty::RawPtr(_, _), ty::RawPtr(to_ty, to_mutbl)) => { span_lint_and_then( cx, TRANSMUTE_PTR_TO_PTR, @@ -24,7 +24,7 @@ pub(super) fn check<'tcx>( "transmute from a pointer to a pointer", |diag| { if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) { - let sugg = arg.as_ty(Ty::new_ptr(cx.tcx, *to_ty)); + let sugg = arg.as_ty(Ty::new_ptr(cx.tcx, *to_ty, *to_mutbl)); diag.span_suggestion(e.span, "try", sugg, Applicability::Unspecified); } }, diff --git a/clippy_lints/src/transmute/transmute_ptr_to_ref.rs b/clippy_lints/src/transmute/transmute_ptr_to_ref.rs index 4ab3afbe71436..cf78709583cf5 100644 --- a/clippy_lints/src/transmute/transmute_ptr_to_ref.rs +++ b/clippy_lints/src/transmute/transmute_ptr_to_ref.rs @@ -20,7 +20,7 @@ pub(super) fn check<'tcx>( msrv: &Msrv, ) -> bool { match (&from_ty.kind(), &to_ty.kind()) { - (ty::RawPtr(from_ptr_ty), ty::Ref(_, to_ref_ty, mutbl)) => { + (ty::RawPtr(from_ptr_ty, _), ty::Ref(_, to_ref_ty, mutbl)) => { span_lint_and_then( cx, TRANSMUTE_PTR_TO_REF, @@ -44,7 +44,7 @@ pub(super) fn check<'tcx>( } else { sugg::make_unop(deref, arg.as_ty(format!("{cast} {ty_snip}"))).to_string() } - } else if from_ptr_ty.ty == *to_ref_ty { + } else if *from_ptr_ty == *to_ref_ty { if from_ptr_ty.has_erased_regions() { if msrv.meets(msrvs::POINTER_CAST) { format!("{deref}{}.cast::<{to_ref_ty}>()", arg.maybe_par()) diff --git a/clippy_lints/src/transmute/transmute_ref_to_ref.rs b/clippy_lints/src/transmute/transmute_ref_to_ref.rs index 6c885ebdea11d..73321c56f3fec 100644 --- a/clippy_lints/src/transmute/transmute_ref_to_ref.rs +++ b/clippy_lints/src/transmute/transmute_ref_to_ref.rs @@ -19,7 +19,7 @@ pub(super) fn check<'tcx>( ) -> bool { let mut triggered = false; - if let (ty::Ref(_, ty_from, from_mutbl), ty::Ref(_, ty_to, to_mutbl)) = (&from_ty.kind(), &to_ty.kind()) { + if let (ty::Ref(_, ty_from, from_mutbl), ty::Ref(_, ty_to, to_mutbl)) = (*from_ty.kind(), *to_ty.kind()) { if let ty::Slice(slice_ty) = *ty_from.kind() && ty_to.is_str() && let ty::Uint(ty::UintTy::U8) = slice_ty.kind() @@ -27,7 +27,7 @@ pub(super) fn check<'tcx>( { let Some(top_crate) = std_or_core(cx) else { return true }; - let postfix = if *from_mutbl == Mutability::Mut { "_mut" } else { "" }; + let postfix = if from_mutbl == Mutability::Mut { "_mut" } else { "" }; let snippet = snippet(cx, arg.span, ".."); @@ -53,18 +53,10 @@ pub(super) fn check<'tcx>( "transmute from a reference to a reference", |diag| { if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) { - let ty_from_and_mut = ty::TypeAndMut { - ty: *ty_from, - mutbl: *from_mutbl, - }; - let ty_to_and_mut = ty::TypeAndMut { - ty: *ty_to, - mutbl: *to_mutbl, - }; let sugg_paren = arg - .as_ty(Ty::new_ptr(cx.tcx, ty_from_and_mut)) - .as_ty(Ty::new_ptr(cx.tcx, ty_to_and_mut)); - let sugg = if *to_mutbl == Mutability::Mut { + .as_ty(Ty::new_ptr(cx.tcx, ty_from, from_mutbl)) + .as_ty(Ty::new_ptr(cx.tcx, ty_to, to_mutbl)); + let sugg = if to_mutbl == Mutability::Mut { sugg_paren.mut_addr_deref() } else { sugg_paren.addr_deref() diff --git a/clippy_lints/src/transmute/transmute_undefined_repr.rs b/clippy_lints/src/transmute/transmute_undefined_repr.rs index 44b5f460737da..33c4031fa8759 100644 --- a/clippy_lints/src/transmute/transmute_undefined_repr.rs +++ b/clippy_lints/src/transmute/transmute_undefined_repr.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::is_c_void; use rustc_hir::Expr; use rustc_lint::LateContext; -use rustc_middle::ty::{self, GenericArgsRef, IntTy, Ty, TypeAndMut, UintTy}; +use rustc_middle::ty::{self, GenericArgsRef, IntTy, Ty, UintTy}; #[expect(clippy::too_many_lines)] pub(super) fn check<'tcx>( diff --git a/clippy_lints/src/transmute/useless_transmute.rs b/clippy_lints/src/transmute/useless_transmute.rs index f3d3516755c0b..70628f3d4f414 100644 --- a/clippy_lints/src/transmute/useless_transmute.rs +++ b/clippy_lints/src/transmute/useless_transmute.rs @@ -15,7 +15,7 @@ pub(super) fn check<'tcx>( to_ty: Ty<'tcx>, arg: &'tcx Expr<'_>, ) -> bool { - match (&from_ty.kind(), &to_ty.kind()) { + match (*from_ty.kind(), *to_ty.kind()) { _ if from_ty == to_ty && !from_ty.has_erased_regions() => { span_lint( cx, @@ -25,7 +25,7 @@ pub(super) fn check<'tcx>( ); true }, - (ty::Ref(_, rty, rty_mutbl), ty::RawPtr(ptr_ty)) => { + (ty::Ref(_, rty, rty_mutbl), ty::RawPtr(ptr_ty, ptr_mutbl)) => { // No way to give the correct suggestion here. Avoid linting for now. if !rty.has_erased_regions() { span_lint_and_then( @@ -35,15 +35,10 @@ pub(super) fn check<'tcx>( "transmute from a reference to a pointer", |diag| { if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) { - let rty_and_mut = ty::TypeAndMut { - ty: *rty, - mutbl: *rty_mutbl, - }; - - let sugg = if *ptr_ty == rty_and_mut { + let sugg = if ptr_ty == rty && rty_mutbl == ptr_mutbl { arg.as_ty(to_ty) } else { - arg.as_ty(Ty::new_ptr(cx.tcx, rty_and_mut)).as_ty(to_ty) + arg.as_ty(Ty::new_ptr(cx.tcx, rty, rty_mutbl)).as_ty(to_ty) }; diag.span_suggestion(e.span, "try", sugg, Applicability::Unspecified); diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index e90317f5524a3..a526ba97af67e 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -112,7 +112,7 @@ use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::{ self as rustc_ty, Binder, BorrowKind, ClosureKind, EarlyBinder, FloatTy, GenericArgsRef, IntTy, ParamEnv, - ParamEnvAnd, Ty, TyCtxt, TypeAndMut, TypeVisitableExt, UintTy, UpvarCapture, + ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt, UintTy, UpvarCapture, }; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::SourceMap; From 6b04fc24fc4ade1a03b9c47596fb3ec14a3349c2 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 21 Mar 2024 15:49:17 -0400 Subject: [PATCH 14/24] Fix clippy --- clippy_lints/src/derive.rs | 4 ++-- clippy_lints/src/eta_reduction.rs | 4 ++-- clippy_lints/src/methods/unnecessary_to_owned.rs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index f0f2c7d6658f1..c554edc8fceba 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -11,7 +11,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::traits::Reveal; use rustc_middle::ty::{ - self, ClauseKind, GenericArgKind, GenericParamDefKind, ImplPolarity, ParamEnv, ToPredicate, TraitPredicate, Ty, + self, ClauseKind, GenericArgKind, GenericParamDefKind, ParamEnv, ToPredicate, TraitPredicate, Ty, TyCtxt, }; use rustc_session::declare_lint_pass; @@ -502,7 +502,7 @@ fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) -> params.iter().filter(|&&(_, needs_eq)| needs_eq).map(|&(param, _)| { ClauseKind::Trait(TraitPredicate { trait_ref: ty::TraitRef::new(tcx, eq_trait_id, [tcx.mk_param_from_def(param)]), - polarity: ImplPolarity::Positive, + polarity: ty::PredicatePolarity::Positive, }) .to_predicate(tcx) }), diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index 40be71a0e5d61..eccfc31fdd3e3 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -9,7 +9,7 @@ use rustc_hir::{BindingAnnotation, Expr, ExprKind, FnRetTy, Param, PatKind, QPat use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{ - self, Binder, ClosureArgs, ClosureKind, FnSig, GenericArg, GenericArgKind, ImplPolarity, List, Region, RegionKind, + self, Binder, ClosureArgs, ClosureKind, FnSig, GenericArg, GenericArgKind, List, Region, RegionKind, Ty, TypeVisitableExt, TypeckResults, }; use rustc_session::declare_lint_pass; @@ -173,7 +173,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction { if let Ok((ClosureKind::FnMut, _)) = cx.tcx.infer_ctxt().build().type_implements_fn_trait( cx.param_env, Binder::bind_with_vars(callee_ty_adjusted, List::empty()), - ImplPolarity::Positive, + ty::PredicatePolarity::Positive, ) && path_to_local(callee).map_or(false, |l| { local_used_in(cx, l, args) || local_used_after_expr(cx, l, expr) }) { diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index c234e4f9b110c..abf717126fbf4 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -18,7 +18,7 @@ use rustc_lint::LateContext; use rustc_middle::mir::Mutability; use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref}; use rustc_middle::ty::{ - self, ClauseKind, GenericArg, GenericArgKind, GenericArgsRef, ImplPolarity, ParamTy, ProjectionPredicate, + self, ClauseKind, GenericArg, GenericArgKind, GenericArgsRef, ParamTy, ProjectionPredicate, TraitPredicate, Ty, }; use rustc_span::{sym, Symbol}; @@ -669,7 +669,7 @@ fn check_borrow_predicate<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { && let Some(borrow_id) = cx.tcx.get_diagnostic_item(sym::Borrow) && cx.tcx.predicates_of(method_def_id).predicates.iter().any(|(pred, _)| { if let ClauseKind::Trait(trait_pred) = pred.kind().skip_binder() - && trait_pred.polarity == ImplPolarity::Positive + && trait_pred.polarity == ty::PredicatePolarity::Positive && trait_pred.trait_ref.def_id == borrow_id { true From bd9efd5265115956d9a0eec09c34f95898643603 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 20 Mar 2024 17:50:31 +0100 Subject: [PATCH 15/24] Rename `hir::Local` into `hir::LetStmt` --- clippy_lints/src/box_default.rs | 4 ++-- clippy_lints/src/collection_is_never_read.rs | 6 +++--- clippy_lints/src/let_underscore.rs | 4 ++-- clippy_lints/src/let_with_type_underscore.rs | 4 ++-- clippy_lints/src/loops/utils.rs | 4 ++-- clippy_lints/src/loops/while_let_loop.rs | 4 ++-- clippy_lints/src/loops/while_let_on_iterator.rs | 4 ++-- clippy_lints/src/manual_hash_one.rs | 4 ++-- .../src/matches/infallible_destructuring_match.rs | 4 ++-- clippy_lints/src/matches/mod.rs | 4 ++-- clippy_lints/src/methods/needless_collect.rs | 4 ++-- clippy_lints/src/methods/str_splitn.rs | 4 ++-- clippy_lints/src/mixed_read_write_in_expression.rs | 4 ++-- clippy_lints/src/mut_key.rs | 2 +- clippy_lints/src/needless_late_init.rs | 10 +++++----- clippy_lints/src/question_mark.rs | 4 ++-- clippy_lints/src/read_zero_byte_vec.rs | 4 ++-- clippy_lints/src/redundant_locals.rs | 4 ++-- clippy_lints/src/redundant_type_annotations.rs | 2 +- clippy_lints/src/reserve_after_initialization.rs | 4 ++-- clippy_lints/src/types/mod.rs | 4 ++-- clippy_lints/src/undocumented_unsafe_blocks.rs | 8 ++++---- clippy_lints/src/unit_types/let_unit_value.rs | 4 ++-- clippy_lints/src/unit_types/mod.rs | 4 ++-- clippy_lints/src/unused_peekable.rs | 4 ++-- clippy_lints/src/vec.rs | 6 +++--- clippy_lints/src/vec_init_then_push.rs | 4 ++-- clippy_utils/src/lib.rs | 14 +++++++------- 28 files changed, 66 insertions(+), 66 deletions(-) diff --git a/clippy_lints/src/box_default.rs b/clippy_lints/src/box_default.rs index 66206d1a059b9..a950de4bd2235 100644 --- a/clippy_lints/src/box_default.rs +++ b/clippy_lints/src/box_default.rs @@ -6,7 +6,7 @@ use clippy_utils::{is_default_equivalent, path_def_id}; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::intravisit::{walk_ty, Visitor}; -use rustc_hir::{Block, Expr, ExprKind, Local, Node, QPath, Ty, TyKind}; +use rustc_hir::{Block, Expr, ExprKind, LetStmt, Node, QPath, Ty, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::print::with_forced_trimmed_paths; @@ -139,7 +139,7 @@ impl<'tcx> Visitor<'tcx> for InferVisitor { fn given_type(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { match cx.tcx.parent_hir_node(expr.hir_id) { - Node::Local(Local { ty: Some(ty), .. }) => { + Node::Local(LetStmt { ty: Some(ty), .. }) => { let mut v = InferVisitor::default(); v.visit_ty(ty); !v.0 diff --git a/clippy_lints/src/collection_is_never_read.rs b/clippy_lints/src/collection_is_never_read.rs index d820413e11129..e921b9b46a674 100644 --- a/clippy_lints/src/collection_is_never_read.rs +++ b/clippy_lints/src/collection_is_never_read.rs @@ -3,7 +3,7 @@ use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; use clippy_utils::visitors::for_each_expr_with_closures; use clippy_utils::{get_enclosing_block, path_to_local_id}; use core::ops::ControlFlow; -use rustc_hir::{Block, ExprKind, HirId, LangItem, Local, Node, PatKind}; +use rustc_hir::{Block, ExprKind, HirId, LangItem, LetStmt, Node, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; @@ -58,7 +58,7 @@ static COLLECTIONS: [Symbol; 9] = [ ]; impl<'tcx> LateLintPass<'tcx> for CollectionIsNeverRead { - fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) { + fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) { // Look for local variables whose type is a container. Search surrounding bock for read access. if match_acceptable_type(cx, local, &COLLECTIONS) && let PatKind::Binding(_, local_id, _, _) = local.pat.kind @@ -70,7 +70,7 @@ impl<'tcx> LateLintPass<'tcx> for CollectionIsNeverRead { } } -fn match_acceptable_type(cx: &LateContext<'_>, local: &Local<'_>, collections: &[rustc_span::Symbol]) -> bool { +fn match_acceptable_type(cx: &LateContext<'_>, local: &LetStmt<'_>, collections: &[rustc_span::Symbol]) -> bool { let ty = cx.typeck_results().pat_ty(local.pat); collections.iter().any(|&sym| is_type_diagnostic_item(cx, ty, sym)) // String type is a lang item but not a diagnostic item for now so we need a separate check diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs index 0ea53c3928027..619e933b4fff4 100644 --- a/clippy_lints/src/let_underscore.rs +++ b/clippy_lints/src/let_underscore.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::{implements_trait, is_must_use_ty, match_type}; use clippy_utils::{is_from_proc_macro, is_must_use_func_call, paths}; -use rustc_hir::{Local, LocalSource, PatKind}; +use rustc_hir::{LetStmt, LocalSource, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{GenericArgKind, IsSuggestable}; @@ -138,7 +138,7 @@ const SYNC_GUARD_PATHS: [&[&str]; 3] = [ ]; impl<'tcx> LateLintPass<'tcx> for LetUnderscore { - fn check_local(&mut self, cx: &LateContext<'tcx>, local: &Local<'tcx>) { + fn check_local(&mut self, cx: &LateContext<'tcx>, local: &LetStmt<'tcx>) { if matches!(local.source, LocalSource::Normal) && !in_external_macro(cx.tcx.sess, local.span) && let PatKind::Wild = local.pat.kind diff --git a/clippy_lints/src/let_with_type_underscore.rs b/clippy_lints/src/let_with_type_underscore.rs index 5f3f9b43f4580..593b29154b426 100644 --- a/clippy_lints/src/let_with_type_underscore.rs +++ b/clippy_lints/src/let_with_type_underscore.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::snippet; -use rustc_hir::{Local, TyKind}; +use rustc_hir::{LetStmt, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; @@ -26,7 +26,7 @@ declare_clippy_lint! { declare_lint_pass!(UnderscoreTyped => [LET_WITH_TYPE_UNDERSCORE]); impl LateLintPass<'_> for UnderscoreTyped { - fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) { + fn check_local(&mut self, cx: &LateContext<'_>, local: &LetStmt<'_>) { if !in_external_macro(cx.tcx.sess, local.span) && let Some(ty) = local.ty // Ensure that it has a type defined && let TyKind::Infer = &ty.kind // that type is '_' diff --git a/clippy_lints/src/loops/utils.rs b/clippy_lints/src/loops/utils.rs index 8bca33754e818..7b45cc95431c2 100644 --- a/clippy_lints/src/loops/utils.rs +++ b/clippy_lints/src/loops/utils.rs @@ -3,7 +3,7 @@ use clippy_utils::{get_parent_expr, is_integer_const, path_to_local, path_to_loc use rustc_ast::ast::{LitIntType, LitKind}; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, walk_local, Visitor}; -use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, HirId, HirIdMap, Local, Mutability, PatKind}; +use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, HirId, HirIdMap, LetStmt, Mutability, PatKind}; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, Ty}; @@ -141,7 +141,7 @@ impl<'a, 'tcx> InitializeVisitor<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; - fn visit_local(&mut self, l: &'tcx Local<'_>) { + fn visit_local(&mut self, l: &'tcx LetStmt<'_>) { // Look for declarations of the variable if l.pat.hir_id == self.var_id && let PatKind::Binding(.., ident, _) = l.pat.kind diff --git a/clippy_lints/src/loops/while_let_loop.rs b/clippy_lints/src/loops/while_let_loop.rs index 93774b8976824..bd04827a1f0ea 100644 --- a/clippy_lints/src/loops/while_let_loop.rs +++ b/clippy_lints/src/loops/while_let_loop.rs @@ -5,13 +5,13 @@ use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::needs_ordered_drop; use clippy_utils::visitors::any_temporaries_need_ordered_drop; use rustc_errors::Applicability; -use rustc_hir::{Block, Expr, ExprKind, Local, MatchSource, Pat, StmtKind}; +use rustc_hir::{Block, Expr, ExprKind, LetStmt, MatchSource, Pat, StmtKind}; use rustc_lint::LateContext; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_block: &'tcx Block<'_>) { let (init, has_trailing_exprs) = match (loop_block.stmts, loop_block.expr) { ([stmt, stmts @ ..], expr) => { - if let StmtKind::Let(&Local { + if let StmtKind::Let(&LetStmt { init: Some(e), els: None, .. diff --git a/clippy_lints/src/loops/while_let_on_iterator.rs b/clippy_lints/src/loops/while_let_on_iterator.rs index d070ee7498561..194dd4752f91b 100644 --- a/clippy_lints/src/loops/while_let_on_iterator.rs +++ b/clippy_lints/src/loops/while_let_on_iterator.rs @@ -6,7 +6,7 @@ use clippy_utils::{get_enclosing_loop_or_multi_call_closure, higher, is_refutabl use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::intravisit::{walk_expr, Visitor}; -use rustc_hir::{Closure, Expr, ExprKind, HirId, LangItem, Local, Mutability, PatKind, UnOp}; +use rustc_hir::{Closure, Expr, ExprKind, HirId, LangItem, LetStmt, Mutability, PatKind, UnOp}; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_middle::ty::adjustment::Adjust; @@ -286,7 +286,7 @@ fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: & self.cx.tcx.hir() } - fn visit_local(&mut self, l: &'tcx Local<'_>) { + fn visit_local(&mut self, l: &'tcx LetStmt<'_>) { if !self.after_loop { l.pat.each_binding_or_first(&mut |_, id, _, _| { if id == self.local_id { diff --git a/clippy_lints/src/manual_hash_one.rs b/clippy_lints/src/manual_hash_one.rs index 5cbab0ec977c1..f8f33cfc82e99 100644 --- a/clippy_lints/src/manual_hash_one.rs +++ b/clippy_lints/src/manual_hash_one.rs @@ -4,7 +4,7 @@ use clippy_utils::source::snippet_opt; use clippy_utils::visitors::{is_local_used, local_used_once}; use clippy_utils::{is_trait_method, path_to_local_id}; use rustc_errors::Applicability; -use rustc_hir::{BindingAnnotation, ExprKind, Local, Node, PatKind, StmtKind}; +use rustc_hir::{BindingAnnotation, ExprKind, LetStmt, Node, PatKind, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; use rustc_span::sym; @@ -60,7 +60,7 @@ impl ManualHashOne { impl_lint_pass!(ManualHashOne => [MANUAL_HASH_ONE]); impl LateLintPass<'_> for ManualHashOne { - fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) { + fn check_local(&mut self, cx: &LateContext<'_>, local: &LetStmt<'_>) { // `let mut hasher = seg.build_hasher();` if let PatKind::Binding(BindingAnnotation::MUT, hasher, _, None) = local.pat.kind && let Some(init) = local.init diff --git a/clippy_lints/src/matches/infallible_destructuring_match.rs b/clippy_lints/src/matches/infallible_destructuring_match.rs index c8a48246e6766..0f242e0b9e12b 100644 --- a/clippy_lints/src/matches/infallible_destructuring_match.rs +++ b/clippy_lints/src/matches/infallible_destructuring_match.rs @@ -2,12 +2,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::{path_to_local_id, peel_blocks, strip_pat_refs}; use rustc_errors::Applicability; -use rustc_hir::{ByRef, ExprKind, Local, MatchSource, PatKind, QPath}; +use rustc_hir::{ByRef, ExprKind, LetStmt, MatchSource, PatKind, QPath}; use rustc_lint::LateContext; use super::INFALLIBLE_DESTRUCTURING_MATCH; -pub(crate) fn check(cx: &LateContext<'_>, local: &Local<'_>) -> bool { +pub(crate) fn check(cx: &LateContext<'_>, local: &LetStmt<'_>) -> bool { if !local.span.from_expansion() && let Some(expr) = local.init && let ExprKind::Match(target, arms, MatchSource::Normal) = expr.kind diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs index 50494f4819f44..580d4a6429631 100644 --- a/clippy_lints/src/matches/mod.rs +++ b/clippy_lints/src/matches/mod.rs @@ -27,7 +27,7 @@ mod wild_in_or_pats; use clippy_config::msrvs::{self, Msrv}; use clippy_utils::source::{snippet_opt, walk_span_to_context}; use clippy_utils::{higher, in_constant, is_direct_expn_of, is_span_match, tokenize_with_text}; -use rustc_hir::{Arm, Expr, ExprKind, Local, MatchSource, Pat}; +use rustc_hir::{Arm, Expr, ExprKind, LetStmt, MatchSource, Pat}; use rustc_lexer::TokenKind; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; @@ -1124,7 +1124,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches { } } - fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'_>) { + fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'_>) { self.infallible_destructuring_match_linted |= local.els.is_none() && infallible_destructuring_match::check(cx, local); } diff --git a/clippy_lints/src/methods/needless_collect.rs b/clippy_lints/src/methods/needless_collect.rs index 78540353005d3..378644c53c068 100644 --- a/clippy_lints/src/methods/needless_collect.rs +++ b/clippy_lints/src/methods/needless_collect.rs @@ -11,7 +11,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, MultiSpan}; use rustc_hir::intravisit::{walk_block, walk_expr, Visitor}; use rustc_hir::{ - BindingAnnotation, Block, Expr, ExprKind, HirId, HirIdSet, Local, Mutability, Node, PatKind, Stmt, StmtKind, + BindingAnnotation, Block, Expr, ExprKind, HirId, HirIdSet, LetStmt, Mutability, Node, PatKind, Stmt, StmtKind, }; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; @@ -424,7 +424,7 @@ fn get_expr_and_hir_id_from_stmt<'v>(stmt: &'v Stmt<'v>) -> Option<(&'v Expr<'v> match stmt.kind { StmtKind::Expr(expr) | StmtKind::Semi(expr) => Some((expr, None)), StmtKind::Item(..) => None, - StmtKind::Let(Local { init, pat, .. }) => { + StmtKind::Let(LetStmt { init, pat, .. }) => { if let PatKind::Binding(_, hir_id, ..) = pat.kind { init.map(|init_expr| (init_expr, Some(hir_id))) } else { diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs index 55cd1a38ec96c..94e263cf3d1df 100644 --- a/clippy_lints/src/methods/str_splitn.rs +++ b/clippy_lints/src/methods/str_splitn.rs @@ -8,7 +8,7 @@ use clippy_utils::{is_diag_item_method, match_def_path, path_to_local_id, paths} use core::ops::ControlFlow; use rustc_errors::Applicability; use rustc_hir::{ - BindingAnnotation, Expr, ExprKind, HirId, LangItem, Local, MatchSource, Node, Pat, PatKind, QPath, Stmt, StmtKind, + BindingAnnotation, Expr, ExprKind, HirId, LangItem, LetStmt, MatchSource, Node, Pat, PatKind, QPath, Stmt, StmtKind, }; use rustc_lint::LateContext; use rustc_middle::ty; @@ -198,7 +198,7 @@ fn indirect_usage<'tcx>( binding: HirId, ctxt: SyntaxContext, ) -> Option> { - if let StmtKind::Let(&Local { + if let StmtKind::Let(&LetStmt { pat: Pat { kind: PatKind::Binding(BindingAnnotation::NONE, _, ident, None), .. diff --git a/clippy_lints/src/mixed_read_write_in_expression.rs b/clippy_lints/src/mixed_read_write_in_expression.rs index 12c7c18afde6c..656fb907fcda0 100644 --- a/clippy_lints/src/mixed_read_write_in_expression.rs +++ b/clippy_lints/src/mixed_read_write_in_expression.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_note}; use clippy_utils::{get_parent_expr, path_to_local, path_to_local_id}; use rustc_hir::intravisit::{walk_expr, Visitor}; -use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, Local, Node, Stmt, StmtKind}; +use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, LetStmt, Node, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::declare_lint_pass; @@ -98,7 +98,7 @@ impl<'tcx> LateLintPass<'tcx> for EvalOrderDependence { fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { match stmt.kind { StmtKind::Let(local) => { - if let Local { init: Some(e), .. } = local { + if let LetStmt { init: Some(e), .. } = local { DivergenceVisitor { cx }.visit_expr(e); } }, diff --git a/clippy_lints/src/mut_key.rs b/clippy_lints/src/mut_key.rs index c32025fcbb6ae..79f0a398d55dd 100644 --- a/clippy_lints/src/mut_key.rs +++ b/clippy_lints/src/mut_key.rs @@ -121,7 +121,7 @@ impl<'tcx> LateLintPass<'tcx> for MutableKeyType { } } - fn check_local(&mut self, cx: &LateContext<'_>, local: &hir::Local<'_>) { + fn check_local(&mut self, cx: &LateContext<'_>, local: &hir::LetStmt<'_>) { if let hir::PatKind::Wild = local.pat.kind { return; } diff --git a/clippy_lints/src/needless_late_init.rs b/clippy_lints/src/needless_late_init.rs index 4cda4b171e31b..810799acb2e28 100644 --- a/clippy_lints/src/needless_late_init.rs +++ b/clippy_lints/src/needless_late_init.rs @@ -6,7 +6,7 @@ use clippy_utils::visitors::{for_each_expr, for_each_expr_with_closures, is_loca use core::ops::ControlFlow; use rustc_errors::{Applicability, MultiSpan}; use rustc_hir::{ - BindingAnnotation, Block, Expr, ExprKind, HirId, Local, LocalSource, MatchSource, Node, Pat, PatKind, Stmt, + BindingAnnotation, Block, Expr, ExprKind, HirId, LetStmt, LocalSource, MatchSource, Node, Pat, PatKind, Stmt, StmtKind, }; use rustc_lint::{LateContext, LateLintPass}; @@ -237,7 +237,7 @@ fn first_usage<'tcx>( }) } -fn local_snippet_without_semicolon(cx: &LateContext<'_>, local: &Local<'_>) -> Option { +fn local_snippet_without_semicolon(cx: &LateContext<'_>, local: &LetStmt<'_>) -> Option { let span = local.span.with_hi(match local.ty { // let : ; // ~~~~~~~~~~~~~~~ @@ -252,7 +252,7 @@ fn local_snippet_without_semicolon(cx: &LateContext<'_>, local: &Local<'_>) -> O fn check<'tcx>( cx: &LateContext<'tcx>, - local: &'tcx Local<'tcx>, + local: &'tcx LetStmt<'tcx>, local_stmt: &'tcx Stmt<'tcx>, block: &'tcx Block<'tcx>, binding_id: HirId, @@ -363,9 +363,9 @@ fn check<'tcx>( } impl<'tcx> LateLintPass<'tcx> for NeedlessLateInit { - fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) { + fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) { let mut parents = cx.tcx.hir().parent_iter(local.hir_id); - if let Local { + if let LetStmt { init: None, pat: &Pat { diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index 831c291ed7cc5..f1db571e1137a 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -14,7 +14,7 @@ use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::LangItem::{self, OptionNone, OptionSome, ResultErr, ResultOk}; use rustc_hir::{ - BindingAnnotation, Block, ByRef, Expr, ExprKind, Local, Node, PatKind, PathSegment, QPath, Stmt, StmtKind, + BindingAnnotation, Block, ByRef, Expr, ExprKind, LetStmt, Node, PatKind, PathSegment, QPath, Stmt, StmtKind, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty; @@ -109,7 +109,7 @@ fn find_let_else_ret_expression<'hir>(block: &'hir Block<'hir>) -> Option<&'hir } fn check_let_some_else_return_none(cx: &LateContext<'_>, stmt: &Stmt<'_>) { - if let StmtKind::Let(Local { + if let StmtKind::Let(LetStmt { pat, init: Some(init_expr), els: Some(els), diff --git a/clippy_lints/src/read_zero_byte_vec.rs b/clippy_lints/src/read_zero_byte_vec.rs index 0ebdb031d5a18..7f4735c6a889b 100644 --- a/clippy_lints/src/read_zero_byte_vec.rs +++ b/clippy_lints/src/read_zero_byte_vec.rs @@ -3,7 +3,7 @@ use clippy_utils::get_enclosing_block; use clippy_utils::higher::{get_vec_init_kind, VecInitKind}; use clippy_utils::source::snippet; -use hir::{Expr, ExprKind, HirId, Local, PatKind, PathSegment, QPath, StmtKind}; +use hir::{Expr, ExprKind, HirId, LetStmt, PatKind, PathSegment, QPath, StmtKind}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def::Res; @@ -57,7 +57,7 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec { } if let StmtKind::Let(local) = stmt.kind - && let Local { + && let LetStmt { pat, init: Some(init), .. } = local && let PatKind::Binding(_, id, ident, _) = pat.kind diff --git a/clippy_lints/src/redundant_locals.rs b/clippy_lints/src/redundant_locals.rs index 6528a7b369f74..0f579f779dfd5 100644 --- a/clippy_lints/src/redundant_locals.rs +++ b/clippy_lints/src/redundant_locals.rs @@ -3,7 +3,7 @@ use clippy_utils::is_from_proc_macro; use clippy_utils::ty::needs_ordered_drop; use rustc_ast::Mutability; use rustc_hir::def::Res; -use rustc_hir::{BindingAnnotation, ByRef, ExprKind, HirId, Local, Node, Pat, PatKind, QPath}; +use rustc_hir::{BindingAnnotation, ByRef, ExprKind, HirId, LetStmt, Node, Pat, PatKind, QPath}; use rustc_hir_typeck::expr_use_visitor::PlaceBase; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; @@ -47,7 +47,7 @@ declare_clippy_lint! { declare_lint_pass!(RedundantLocals => [REDUNDANT_LOCALS]); impl<'tcx> LateLintPass<'tcx> for RedundantLocals { - fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) { + fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) { if !local.span.is_desugaring(DesugaringKind::Async) // the pattern is a single by-value binding && let PatKind::Binding(BindingAnnotation(ByRef::No, mutability), _, ident, None) = local.pat.kind diff --git a/clippy_lints/src/redundant_type_annotations.rs b/clippy_lints/src/redundant_type_annotations.rs index 079e6500e3cf4..96f6f0ec36fce 100644 --- a/clippy_lints/src/redundant_type_annotations.rs +++ b/clippy_lints/src/redundant_type_annotations.rs @@ -131,7 +131,7 @@ fn extract_primty(ty_kind: &hir::TyKind<'_>) -> Option { } impl LateLintPass<'_> for RedundantTypeAnnotations { - fn check_local<'tcx>(&mut self, cx: &LateContext<'tcx>, local: &'tcx rustc_hir::Local<'tcx>) { + fn check_local<'tcx>(&mut self, cx: &LateContext<'tcx>, local: &'tcx rustc_hir::LetStmt<'tcx>) { if !is_lint_allowed(cx, REDUNDANT_TYPE_ANNOTATIONS, local.hir_id) // type annotation part && !local.span.from_expansion() diff --git a/clippy_lints/src/reserve_after_initialization.rs b/clippy_lints/src/reserve_after_initialization.rs index ca7a0c7c87bb9..c227b5b22f4dd 100644 --- a/clippy_lints/src/reserve_after_initialization.rs +++ b/clippy_lints/src/reserve_after_initialization.rs @@ -4,7 +4,7 @@ use clippy_utils::source::snippet; use clippy_utils::{is_from_proc_macro, path_to_local_id}; use rustc_errors::Applicability; use rustc_hir::def::Res; -use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Local, PatKind, QPath, Stmt, StmtKind}; +use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, LetStmt, PatKind, QPath, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; @@ -69,7 +69,7 @@ impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization { self.searcher = None; } - fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) { + fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) { if let Some(init_expr) = local.init && let PatKind::Binding(BindingAnnotation::MUT, id, _, None) = local.pat.kind && !in_external_macro(cx.sess(), local.span) diff --git a/clippy_lints/src/types/mod.rs b/clippy_lints/src/types/mod.rs index 2ad15ac8312d9..0802cb2b7c75d 100644 --- a/clippy_lints/src/types/mod.rs +++ b/clippy_lints/src/types/mod.rs @@ -12,7 +12,7 @@ mod vec_box; use rustc_hir as hir; use rustc_hir::intravisit::FnKind; use rustc_hir::{ - Body, FnDecl, FnRetTy, GenericArg, ImplItem, ImplItemKind, Item, ItemKind, Local, MutTy, QPath, TraitItem, + Body, FnDecl, FnRetTy, GenericArg, ImplItem, ImplItemKind, Item, ItemKind, LetStmt, MutTy, QPath, TraitItem, TraitItemKind, TyKind, }; use rustc_lint::{LateContext, LateLintPass}; @@ -425,7 +425,7 @@ impl<'tcx> LateLintPass<'tcx> for Types { } } - fn check_local(&mut self, cx: &LateContext<'tcx>, local: &Local<'tcx>) { + fn check_local(&mut self, cx: &LateContext<'tcx>, local: &LetStmt<'tcx>) { if let Some(ty) = local.ty { self.check_ty( cx, diff --git a/clippy_lints/src/undocumented_unsafe_blocks.rs b/clippy_lints/src/undocumented_unsafe_blocks.rs index 0efa65b28e230..fe3888d09c980 100644 --- a/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -158,7 +158,7 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks { } fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &hir::Stmt<'tcx>) { - let (hir::StmtKind::Let(&hir::Local { init: Some(expr), .. }) + let (hir::StmtKind::Let(&hir::LetStmt { init: Some(expr), .. }) | hir::StmtKind::Expr(expr) | hir::StmtKind::Semi(expr)) = stmt.kind else { @@ -342,7 +342,7 @@ fn block_parents_have_safety_comment( ) -> bool { let (span, hir_id) = match cx.tcx.parent_hir_node(id) { Node::Expr(expr) => match cx.tcx.parent_hir_node(expr.hir_id) { - Node::Local(hir::Local { span, hir_id, .. }) => (*span, *hir_id), + Node::Local(hir::LetStmt { span, hir_id, .. }) => (*span, *hir_id), Node::Item(hir::Item { kind: hir::ItemKind::Const(..) | ItemKind::Static(..), span, @@ -358,12 +358,12 @@ fn block_parents_have_safety_comment( }, Node::Stmt(hir::Stmt { kind: - hir::StmtKind::Let(hir::Local { span, hir_id, .. }) + hir::StmtKind::Let(hir::LetStmt { span, hir_id, .. }) | hir::StmtKind::Expr(hir::Expr { span, hir_id, .. }) | hir::StmtKind::Semi(hir::Expr { span, hir_id, .. }), .. }) - | Node::Local(hir::Local { span, hir_id, .. }) => (*span, *hir_id), + | Node::Local(hir::LetStmt { span, hir_id, .. }) => (*span, *hir_id), Node::Item(hir::Item { kind: hir::ItemKind::Const(..) | ItemKind::Static(..), span, diff --git a/clippy_lints/src/unit_types/let_unit_value.rs b/clippy_lints/src/unit_types/let_unit_value.rs index 9406d16076957..c11acab98c015 100644 --- a/clippy_lints/src/unit_types/let_unit_value.rs +++ b/clippy_lints/src/unit_types/let_unit_value.rs @@ -4,14 +4,14 @@ use clippy_utils::visitors::{for_each_local_assignment, for_each_value_source}; use core::ops::ControlFlow; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{Expr, ExprKind, HirId, HirIdSet, Local, MatchSource, Node, PatKind, QPath, TyKind}; +use rustc_hir::{Expr, ExprKind, HirId, HirIdSet, LetStmt, MatchSource, Node, PatKind, QPath, TyKind}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::{in_external_macro, is_from_async_await}; use rustc_middle::ty; use super::LET_UNIT_VALUE; -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>) { +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx LetStmt<'_>) { // skip `let () = { ... }` if let PatKind::Tuple(fields, ..) = local.pat.kind && fields.is_empty() diff --git a/clippy_lints/src/unit_types/mod.rs b/clippy_lints/src/unit_types/mod.rs index 0abd48e6423bb..e016bd3434b10 100644 --- a/clippy_lints/src/unit_types/mod.rs +++ b/clippy_lints/src/unit_types/mod.rs @@ -3,7 +3,7 @@ mod unit_arg; mod unit_cmp; mod utils; -use rustc_hir::{Expr, Local}; +use rustc_hir::{Expr, LetStmt}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -99,7 +99,7 @@ declare_clippy_lint! { declare_lint_pass!(UnitTypes => [LET_UNIT_VALUE, UNIT_CMP, UNIT_ARG]); impl<'tcx> LateLintPass<'tcx> for UnitTypes { - fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) { + fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) { let_unit_value::check(cx, local); } diff --git a/clippy_lints/src/unused_peekable.rs b/clippy_lints/src/unused_peekable.rs index 3f4ab3e31cfe7..e152a0e83438d 100644 --- a/clippy_lints/src/unused_peekable.rs +++ b/clippy_lints/src/unused_peekable.rs @@ -3,7 +3,7 @@ use clippy_utils::ty::{is_type_diagnostic_item, peel_mid_ty_refs_is_mutable}; use clippy_utils::{fn_def_id, is_trait_method, path_to_local_id, peel_ref_operators}; use rustc_ast::Mutability; use rustc_hir::intravisit::{walk_expr, Visitor}; -use rustc_hir::{Block, Expr, ExprKind, HirId, Local, Node, PatKind, PathSegment, StmtKind}; +use rustc_hir::{Block, Expr, ExprKind, HirId, LetStmt, Node, PatKind, PathSegment, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_session::declare_lint_pass; @@ -190,7 +190,7 @@ impl<'tcx> Visitor<'tcx> for PeekableVisitor<'_, 'tcx> { }, } }, - Node::Local(Local { init: Some(init), .. }) => { + Node::Local(LetStmt { init: Some(init), .. }) => { if arg_is_mut_peekable(self.cx, init) { self.found_peek_call = true; } diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index 7cfcf3fe946e5..fba96b630a01f 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -9,7 +9,7 @@ use clippy_utils::ty::is_copy; use clippy_utils::visitors::for_each_local_use_after_expr; use clippy_utils::{get_parent_expr, higher, is_trait_method}; use rustc_errors::Applicability; -use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, Local, Mutability, Node, Pat, PatKind}; +use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, LetStmt, Mutability, Node, Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_middle::ty::layout::LayoutOf; @@ -63,7 +63,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec { match cx.tcx.parent_hir_node(expr.hir_id) { // search for `let foo = vec![_]` expressions where all uses of `foo` // adjust to slices or call a method that exist on slices (e.g. len) - Node::Local(Local { + Node::Local(LetStmt { ty: None, pat: Pat { @@ -93,7 +93,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec { } }, // if the local pattern has a specified type, do not lint. - Node::Local(Local { ty: Some(_), .. }) if higher::VecArgs::hir(cx, expr).is_some() => { + Node::Local(LetStmt { ty: Some(_), .. }) if higher::VecArgs::hir(cx, expr).is_some() => { self.span_to_lint_map.insert(callsite, None); }, // search for `for _ in vec![...]` diff --git a/clippy_lints/src/vec_init_then_push.rs b/clippy_lints/src/vec_init_then_push.rs index ac3b2bdaf650e..b58a4fb84746b 100644 --- a/clippy_lints/src/vec_init_then_push.rs +++ b/clippy_lints/src/vec_init_then_push.rs @@ -7,7 +7,7 @@ use core::ops::ControlFlow; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::{ - BindingAnnotation, Block, Expr, ExprKind, HirId, Local, Mutability, PatKind, QPath, Stmt, StmtKind, UnOp, + BindingAnnotation, Block, Expr, ExprKind, HirId, LetStmt, Mutability, PatKind, QPath, Stmt, StmtKind, UnOp, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; @@ -157,7 +157,7 @@ impl<'tcx> LateLintPass<'tcx> for VecInitThenPush { self.searcher = None; } - fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) { + fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) { if let Some(init_expr) = local.init && let PatKind::Binding(BindingAnnotation::MUT, id, name, None) = local.pat.kind && !in_external_macro(cx.sess(), local.span) diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 11b56ed47de8e..0709d56c23189 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -99,7 +99,7 @@ use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk}; use rustc_hir::{ self as hir, def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Closure, Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, Item, - ItemKind, LangItem, Local, MatchSource, Mutability, Node, OwnerId, Param, Pat, PatKind, Path, PathSegment, PrimTy, + ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp, }; use rustc_lexer::{tokenize, TokenKind}; @@ -1462,7 +1462,7 @@ pub fn is_else_clause(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool { pub fn is_inside_let_else(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool { let mut child_id = expr.hir_id; for (parent_id, node) in tcx.hir().parent_iter(child_id) { - if let Node::Local(Local { + if let Node::Local(LetStmt { init: Some(init), els: Some(els), .. @@ -1482,7 +1482,7 @@ pub fn is_inside_let_else(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool { pub fn is_else_clause_in_let_else(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool { let mut child_id = expr.hir_id; for (parent_id, node) in tcx.hir().parent_iter(child_id) { - if let Node::Local(Local { els: Some(els), .. }) = node + if let Node::Local(LetStmt { els: Some(els), .. }) = node && els.hir_id == child_id { return true; @@ -2158,7 +2158,7 @@ pub fn is_expr_used_or_unified(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool { Node::Stmt(Stmt { kind: StmtKind::Expr(_) | StmtKind::Semi(_) - | StmtKind::Let(Local { + | StmtKind::Let(LetStmt { pat: Pat { kind: PatKind::Wild, .. @@ -2639,7 +2639,7 @@ pub struct ExprUseCtxt<'tcx> { /// The node which consumes a value. pub enum ExprUseNode<'tcx> { /// Assignment to, or initializer for, a local - Local(&'tcx Local<'tcx>), + Local(&'tcx LetStmt<'tcx>), /// Initializer for a const or static item. ConstStatic(OwnerId), /// Implicit or explicit return from a function. @@ -2671,7 +2671,7 @@ impl<'tcx> ExprUseNode<'tcx> { /// Gets the needed type as it's defined without any type inference. pub fn defined_ty(&self, cx: &LateContext<'tcx>) -> Option> { match *self { - Self::Local(Local { ty: Some(ty), .. }) => Some(DefinedTy::Hir(ty)), + Self::Local(LetStmt { ty: Some(ty), .. }) => Some(DefinedTy::Hir(ty)), Self::ConstStatic(id) => Some(DefinedTy::Mir( cx.param_env .and(Binder::dummy(cx.tcx.type_of(id).instantiate_identity())), @@ -3158,7 +3158,7 @@ pub fn is_never_expr<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> Option< } } - fn visit_local(&mut self, l: &'tcx Local<'_>) { + fn visit_local(&mut self, l: &'tcx LetStmt<'_>) { if let Some(e) = l.init { self.visit_expr(e); } From 43a61e9aca89e9d872e00222e92318d5043ca87c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 22 Mar 2024 18:06:20 +0100 Subject: [PATCH 16/24] Rename `hir::Node::Local` into `hir::Node::LetStmt` --- clippy_lints/src/assigning_clones.rs | 2 +- clippy_lints/src/box_default.rs | 2 +- clippy_lints/src/casts/ref_as_ptr.rs | 2 +- clippy_lints/src/casts/unnecessary_cast.rs | 4 ++-- clippy_lints/src/ignored_unit_patterns.rs | 2 +- clippy_lints/src/loops/same_item_push.rs | 2 +- clippy_lints/src/manual_rem_euclid.rs | 2 +- .../src/matches/match_single_binding.rs | 2 +- clippy_lints/src/matches/needless_match.rs | 2 +- clippy_lints/src/methods/clone_on_copy.rs | 2 +- .../iter_on_single_or_empty_collections.rs | 2 +- clippy_lints/src/methods/needless_collect.rs | 2 +- .../src/methods/readonly_write_lock.rs | 2 +- clippy_lints/src/methods/str_splitn.rs | 2 +- clippy_lints/src/methods/unnecessary_fold.rs | 2 +- clippy_lints/src/ptr.rs | 2 +- clippy_lints/src/shadow.rs | 2 +- clippy_lints/src/tuple_array_conversions.rs | 4 ++-- clippy_lints/src/undocumented_unsafe_blocks.rs | 6 +++--- clippy_lints/src/unit_types/let_unit_value.rs | 2 +- clippy_lints/src/unused_peekable.rs | 2 +- .../utils/internal_lints/metadata_collector.rs | 2 +- .../internal_lints/unnecessary_def_path.rs | 2 +- clippy_lints/src/vec.rs | 4 ++-- clippy_lints/src/zero_repeat_side_effects.rs | 2 +- clippy_utils/src/lib.rs | 18 +++++++++--------- clippy_utils/src/ty/type_certainty/mod.rs | 2 +- 27 files changed, 40 insertions(+), 40 deletions(-) diff --git a/clippy_lints/src/assigning_clones.rs b/clippy_lints/src/assigning_clones.rs index 88d9f762a87b3..8e27b3ccefdc3 100644 --- a/clippy_lints/src/assigning_clones.rs +++ b/clippy_lints/src/assigning_clones.rs @@ -163,7 +163,7 @@ fn is_ok_to_suggest<'tcx>(cx: &LateContext<'tcx>, lhs: &Expr<'tcx>, call: &CallC // TODO: This check currently bails if the local variable has no initializer. // That is overly conservative - the lint should fire even if there was no initializer, // but the variable has been initialized before `lhs` was evaluated. - if let Some(Node::Local(local)) = cx.tcx.hir().parent_id_iter(local).next().map(|p| cx.tcx.hir_node(p)) + if let Some(Node::LetStmt(local)) = cx.tcx.hir().parent_id_iter(local).next().map(|p| cx.tcx.hir_node(p)) && local.init.is_none() { return false; diff --git a/clippy_lints/src/box_default.rs b/clippy_lints/src/box_default.rs index a950de4bd2235..8683cb86e8ac8 100644 --- a/clippy_lints/src/box_default.rs +++ b/clippy_lints/src/box_default.rs @@ -139,7 +139,7 @@ impl<'tcx> Visitor<'tcx> for InferVisitor { fn given_type(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { match cx.tcx.parent_hir_node(expr.hir_id) { - Node::Local(LetStmt { ty: Some(ty), .. }) => { + Node::LetStmt(LetStmt { ty: Some(ty), .. }) => { let mut v = InferVisitor::default(); v.visit_ty(ty); !v.0 diff --git a/clippy_lints/src/casts/ref_as_ptr.rs b/clippy_lints/src/casts/ref_as_ptr.rs index 9d5a486336d5f..0d7eae182c49a 100644 --- a/clippy_lints/src/casts/ref_as_ptr.rs +++ b/clippy_lints/src/casts/ref_as_ptr.rs @@ -24,7 +24,7 @@ pub(super) fn check<'tcx>( && let ty::RawPtr(TypeAndMut { mutbl: to_mutbl, .. }) = cast_to.kind() && let Some(use_cx) = expr_use_ctxt(cx, expr) // TODO: only block the lint if `cast_expr` is a temporary - && !matches!(use_cx.node, ExprUseNode::Local(_) | ExprUseNode::ConstStatic(_)) + && !matches!(use_cx.node, ExprUseNode::LetStmt(_) | ExprUseNode::ConstStatic(_)) { let core_or_std = if is_no_std_crate(cx) { "core" } else { "std" }; let fn_name = match to_mutbl { diff --git a/clippy_lints/src/casts/unnecessary_cast.rs b/clippy_lints/src/casts/unnecessary_cast.rs index 08341ff32f358..148d52cb5ddca 100644 --- a/clippy_lints/src/casts/unnecessary_cast.rs +++ b/clippy_lints/src/casts/unnecessary_cast.rs @@ -66,7 +66,7 @@ pub(super) fn check<'tcx>( && let QPath::Resolved(None, Path { res, .. }) = qpath && let Res::Local(hir_id) = res && let parent = cx.tcx.parent_hir_node(*hir_id) - && let Node::Local(local) = parent + && let Node::LetStmt(local) = parent { if let Some(ty) = local.ty && let TyKind::Path(qpath) = ty.kind @@ -275,7 +275,7 @@ fn is_cast_from_ty_alias<'tcx>(cx: &LateContext<'tcx>, expr: impl Visitable<'tcx } // Local usage } else if let Res::Local(hir_id) = res - && let Node::Local(l) = cx.tcx.parent_hir_node(hir_id) + && let Node::LetStmt(l) = cx.tcx.parent_hir_node(hir_id) { if let Some(e) = l.init && is_cast_from_ty_alias(cx, e, cast_from) diff --git a/clippy_lints/src/ignored_unit_patterns.rs b/clippy_lints/src/ignored_unit_patterns.rs index 80a537b9f9413..a32201d80793c 100644 --- a/clippy_lints/src/ignored_unit_patterns.rs +++ b/clippy_lints/src/ignored_unit_patterns.rs @@ -46,7 +46,7 @@ impl<'tcx> LateLintPass<'tcx> for IgnoredUnitPatterns { // Ignore function parameters return; }, - Node::Local(local) if local.ty.is_some() => { + Node::LetStmt(local) if local.ty.is_some() => { // Ignore let bindings with explicit type return; }, diff --git a/clippy_lints/src/loops/same_item_push.rs b/clippy_lints/src/loops/same_item_push.rs index 0f35514b8ad66..670a78d58c3c6 100644 --- a/clippy_lints/src/loops/same_item_push.rs +++ b/clippy_lints/src/loops/same_item_push.rs @@ -62,7 +62,7 @@ pub(super) fn check<'tcx>( if let Node::Pat(pat) = node && let PatKind::Binding(bind_ann, ..) = pat.kind && !matches!(bind_ann, BindingAnnotation(_, Mutability::Mut)) - && let Node::Local(parent_let_expr) = cx.tcx.parent_hir_node(hir_id) + && let Node::LetStmt(parent_let_expr) = cx.tcx.parent_hir_node(hir_id) && let Some(init) = parent_let_expr.init { match init.kind { diff --git a/clippy_lints/src/manual_rem_euclid.rs b/clippy_lints/src/manual_rem_euclid.rs index 0bde62bd55490..ab9bca170cf77 100644 --- a/clippy_lints/src/manual_rem_euclid.rs +++ b/clippy_lints/src/manual_rem_euclid.rs @@ -81,7 +81,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid { // Apply only to params or locals with annotated types match cx.tcx.parent_hir_node(hir_id) { Node::Param(..) => (), - Node::Local(local) => { + Node::LetStmt(local) => { let Some(ty) = local.ty else { return }; if matches!(ty.kind, TyKind::Infer) { return; diff --git a/clippy_lints/src/matches/match_single_binding.rs b/clippy_lints/src/matches/match_single_binding.rs index 61977045fd460..864923b27739d 100644 --- a/clippy_lints/src/matches/match_single_binding.rs +++ b/clippy_lints/src/matches/match_single_binding.rs @@ -148,7 +148,7 @@ 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 { if let Node::Expr(parent_arm_expr) = cx.tcx.parent_hir_node(ex.hir_id) { return match cx.tcx.parent_hir_node(parent_arm_expr.hir_id) { - Node::Local(parent_let_expr) => Some(AssignmentExpr::Local { + Node::LetStmt(parent_let_expr) => Some(AssignmentExpr::Local { span: parent_let_expr.span, pat_span: parent_let_expr.pat.span(), }), diff --git a/clippy_lints/src/matches/needless_match.rs b/clippy_lints/src/matches/needless_match.rs index 3d3f29e5fc6c0..cee77f62b61e6 100644 --- a/clippy_lints/src/matches/needless_match.rs +++ b/clippy_lints/src/matches/needless_match.rs @@ -125,7 +125,7 @@ fn strip_return<'hir>(expr: &'hir Expr<'hir>) -> &'hir Expr<'hir> { fn expr_ty_matches_p_ty(cx: &LateContext<'_>, expr: &Expr<'_>, p_expr: &Expr<'_>) -> bool { match cx.tcx.parent_hir_node(p_expr.hir_id) { // Compare match_expr ty with local in `let local = match match_expr {..}` - Node::Local(local) => { + Node::LetStmt(local) => { let results = cx.typeck_results(); return same_type_and_consts(results.node_type(local.hir_id), results.expr_ty(expr)); }, diff --git a/clippy_lints/src/methods/clone_on_copy.rs b/clippy_lints/src/methods/clone_on_copy.rs index fb5c0c544a95b..d4a5de3d1dea8 100644 --- a/clippy_lints/src/methods/clone_on_copy.rs +++ b/clippy_lints/src/methods/clone_on_copy.rs @@ -69,7 +69,7 @@ pub(super) fn check( _ => false, }, // local binding capturing a reference - Node::Local(l) if matches!(l.pat.kind, PatKind::Binding(BindingAnnotation(ByRef::Yes, _), ..)) => { + Node::LetStmt(l) if matches!(l.pat.kind, PatKind::Binding(BindingAnnotation(ByRef::Yes, _), ..)) => { return; }, _ => false, diff --git a/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs b/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs index 4c7c56e7174a0..19b7e97339deb 100644 --- a/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs +++ b/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs @@ -50,7 +50,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: &str, re | ExprKind::Break(_, _) => true, _ => false, }, - Some((Node::Stmt(_) | Node::Local(_), _)) => false, + Some((Node::Stmt(_) | Node::LetStmt(_), _)) => false, _ => true, }; diff --git a/clippy_lints/src/methods/needless_collect.rs b/clippy_lints/src/methods/needless_collect.rs index 378644c53c068..9e2fd92255e1f 100644 --- a/clippy_lints/src/methods/needless_collect.rs +++ b/clippy_lints/src/methods/needless_collect.rs @@ -85,7 +85,7 @@ pub(super) fn check<'tcx>( ); } }, - Node::Local(l) => { + Node::LetStmt(l) => { if let PatKind::Binding(BindingAnnotation::NONE | BindingAnnotation::MUT, id, _, None) = l.pat.kind && let ty = cx.typeck_results().expr_ty(collect_expr) && [sym::Vec, sym::VecDeque, sym::BinaryHeap, sym::LinkedList] diff --git a/clippy_lints/src/methods/readonly_write_lock.rs b/clippy_lints/src/methods/readonly_write_lock.rs index 6c6846c4b476c..9b0180d936991 100644 --- a/clippy_lints/src/methods/readonly_write_lock.rs +++ b/clippy_lints/src/methods/readonly_write_lock.rs @@ -24,7 +24,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, receiver && let Node::Expr(unwrap_call_expr) = cx.tcx.parent_hir_node(expr.hir_id) && is_unwrap_call(cx, unwrap_call_expr) && let parent = cx.tcx.parent_hir_node(unwrap_call_expr.hir_id) - && let Node::Local(local) = parent + && let Node::LetStmt(local) = parent && let Some(mir) = enclosing_mir(cx.tcx, expr.hir_id) && let Some((local, _)) = mir .local_decls diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs index 94e263cf3d1df..946cdb49d2744 100644 --- a/clippy_lints/src/methods/str_splitn.rs +++ b/clippy_lints/src/methods/str_splitn.rs @@ -128,7 +128,7 @@ fn check_manual_split_once_indirect( ) -> Option<()> { let ctxt = expr.span.ctxt(); let mut parents = cx.tcx.hir().parent_iter(expr.hir_id); - if let (_, Node::Local(local)) = parents.next()? + if let (_, Node::LetStmt(local)) = parents.next()? && let PatKind::Binding(BindingAnnotation::MUT, iter_binding_id, iter_ident, None) = local.pat.kind && let (iter_stmt_id, Node::Stmt(_)) = parents.next()? && let (_, Node::Block(enclosing_block)) = parents.next()? diff --git a/clippy_lints/src/methods/unnecessary_fold.rs b/clippy_lints/src/methods/unnecessary_fold.rs index 988f3e86fcf08..ccc8d17970ece 100644 --- a/clippy_lints/src/methods/unnecessary_fold.rs +++ b/clippy_lints/src/methods/unnecessary_fold.rs @@ -20,7 +20,7 @@ fn needs_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { // some common cases where turbofish isn't needed: // - assigned to a local variable with a type annotation - if let hir::Node::Local(local) = parent + if let hir::Node::LetStmt(local) = parent && local.ty.is_some() { return false; diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 2587b3881bbfa..896c99a710461 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -604,7 +604,7 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args: match get_expr_use_or_unification_node(self.cx.tcx, e) { Some((Node::Stmt(_), _)) => (), - Some((Node::Local(l), _)) => { + Some((Node::LetStmt(l), _)) => { // Only trace simple bindings. e.g `let x = y;` if let PatKind::Binding(BindingAnnotation::NONE, id, _, None) = l.pat.kind { self.bindings.insert(id, args_idx); diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index df7bd4c8d1d39..d98b37bda355e 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -241,7 +241,7 @@ fn find_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Expr<' ExprKind::Match(e, _, _) | ExprKind::Let(&LetExpr { init: e, .. }) => Some(e), _ => None, }, - Node::Local(local) => local.init, + Node::LetStmt(local) => local.init, _ => None, }; return init; diff --git a/clippy_lints/src/tuple_array_conversions.rs b/clippy_lints/src/tuple_array_conversions.rs index 0d84a9ab395ed..564b065d0ba27 100644 --- a/clippy_lints/src/tuple_array_conversions.rs +++ b/clippy_lints/src/tuple_array_conversions.rs @@ -159,7 +159,7 @@ fn all_bindings_are_for_conv<'tcx>( .iter() .map(|node| match node { Node::Pat(pat) => kind.eq(&pat.kind).then_some(pat.hir_id), - Node::Local(l) => Some(l.hir_id), + Node::LetStmt(l) => Some(l.hir_id), _ => None, }) .all_equal() @@ -170,7 +170,7 @@ fn all_bindings_are_for_conv<'tcx>( && local_parents.first().is_some_and(|node| { let Some(ty) = match node { Node::Pat(pat) => Some(pat.hir_id), - Node::Local(l) => Some(l.hir_id), + Node::LetStmt(l) => Some(l.hir_id), _ => None, } .map(|hir_id| cx.typeck_results().node_type(hir_id)) else { diff --git a/clippy_lints/src/undocumented_unsafe_blocks.rs b/clippy_lints/src/undocumented_unsafe_blocks.rs index fe3888d09c980..5fe4b74b3a7a6 100644 --- a/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -342,7 +342,7 @@ fn block_parents_have_safety_comment( ) -> bool { let (span, hir_id) = match cx.tcx.parent_hir_node(id) { Node::Expr(expr) => match cx.tcx.parent_hir_node(expr.hir_id) { - Node::Local(hir::LetStmt { span, hir_id, .. }) => (*span, *hir_id), + Node::LetStmt(hir::LetStmt { span, hir_id, .. }) => (*span, *hir_id), Node::Item(hir::Item { kind: hir::ItemKind::Const(..) | ItemKind::Static(..), span, @@ -363,7 +363,7 @@ fn block_parents_have_safety_comment( | hir::StmtKind::Semi(hir::Expr { span, hir_id, .. }), .. }) - | Node::Local(hir::LetStmt { span, hir_id, .. }) => (*span, *hir_id), + | Node::LetStmt(hir::LetStmt { span, hir_id, .. }) => (*span, *hir_id), Node::Item(hir::Item { kind: hir::ItemKind::Const(..) | ItemKind::Static(..), span, @@ -603,7 +603,7 @@ fn get_body_search_span(cx: &LateContext<'_>) -> Option { for (_, node) in map.parent_iter(body.hir_id) { match node { Node::Expr(e) => span = e.span, - Node::Block(_) | Node::Arm(_) | Node::Stmt(_) | Node::Local(_) => (), + Node::Block(_) | Node::Arm(_) | Node::Stmt(_) | Node::LetStmt(_) => (), Node::Item(hir::Item { kind: hir::ItemKind::Const(..) | ItemKind::Static(..), .. diff --git a/clippy_lints/src/unit_types/let_unit_value.rs b/clippy_lints/src/unit_types/let_unit_value.rs index c11acab98c015..ffb909d790734 100644 --- a/clippy_lints/src/unit_types/let_unit_value.rs +++ b/clippy_lints/src/unit_types/let_unit_value.rs @@ -102,7 +102,7 @@ fn expr_needs_inferred_result<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) - return false; } while let Some(id) = locals_to_check.pop() { - if let Node::Local(l) = cx.tcx.parent_hir_node(id) { + if let Node::LetStmt(l) = cx.tcx.parent_hir_node(id) { if !l.ty.map_or(true, |ty| matches!(ty.kind, TyKind::Infer)) { return false; } diff --git a/clippy_lints/src/unused_peekable.rs b/clippy_lints/src/unused_peekable.rs index e152a0e83438d..e6f799335d7dc 100644 --- a/clippy_lints/src/unused_peekable.rs +++ b/clippy_lints/src/unused_peekable.rs @@ -190,7 +190,7 @@ impl<'tcx> Visitor<'tcx> for PeekableVisitor<'_, 'tcx> { }, } }, - Node::Local(LetStmt { init: Some(init), .. }) => { + Node::LetStmt(LetStmt { init: Some(init), .. }) => { if arg_is_mut_peekable(self.cx, init) { self.found_peek_call = true; } diff --git a/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/clippy_lints/src/utils/internal_lints/metadata_collector.rs index 1ebe1d6a2c4b6..c56c8ddc7a928 100644 --- a/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ b/clippy_lints/src/utils/internal_lints/metadata_collector.rs @@ -1006,7 +1006,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>> { match cx.tcx.parent_hir_node(hir_id) { - hir::Node::Local(local) => Some(local), + hir::Node::LetStmt(local) => Some(local), 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 f4e277fd0c4cd..304a137937402 100644 --- a/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs +++ b/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs @@ -217,7 +217,7 @@ fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option match cx.qpath_res(qpath, expr.hir_id) { Res::Local(hir_id) => { - if let Node::Local(Local { init: Some(init), .. }) = cx.tcx.parent_hir_node(hir_id) { + if let Node::LetStmt(Local { init: Some(init), .. }) = cx.tcx.parent_hir_node(hir_id) { path_to_matched_type(cx, init) } else { None diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index fba96b630a01f..27ead55bf39cc 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -63,7 +63,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec { match cx.tcx.parent_hir_node(expr.hir_id) { // search for `let foo = vec![_]` expressions where all uses of `foo` // adjust to slices or call a method that exist on slices (e.g. len) - Node::Local(LetStmt { + Node::LetStmt(LetStmt { ty: None, pat: Pat { @@ -93,7 +93,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec { } }, // if the local pattern has a specified type, do not lint. - Node::Local(LetStmt { ty: Some(_), .. }) if higher::VecArgs::hir(cx, expr).is_some() => { + Node::LetStmt(LetStmt { ty: Some(_), .. }) if higher::VecArgs::hir(cx, expr).is_some() => { self.span_to_lint_map.insert(callsite, None); }, // search for `for _ in vec![...]` diff --git a/clippy_lints/src/zero_repeat_side_effects.rs b/clippy_lints/src/zero_repeat_side_effects.rs index 852d04cd21b2f..143fecdd237d8 100644 --- a/clippy_lints/src/zero_repeat_side_effects.rs +++ b/clippy_lints/src/zero_repeat_side_effects.rs @@ -78,7 +78,7 @@ fn inner_check(cx: &LateContext<'_>, expr: &'_ rustc_hir::Expr<'_>, inner_expr: let parent_hir_node = cx.tcx.parent_hir_node(expr.hir_id); let return_type = cx.typeck_results().expr_ty(expr); - if let Node::Local(l) = parent_hir_node { + if let Node::LetStmt(l) = parent_hir_node { array_span_lint( cx, l.span, diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 0709d56c23189..d7886e723e86a 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -184,7 +184,7 @@ pub fn expr_or_init<'a, 'b, 'tcx: 'b>(cx: &LateContext<'tcx>, mut expr: &'a Expr pub fn find_binding_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Expr<'tcx>> { if let Node::Pat(pat) = cx.tcx.hir_node(hir_id) && matches!(pat.kind, PatKind::Binding(BindingAnnotation::NONE, ..)) - && let Node::Local(local) = cx.tcx.parent_hir_node(hir_id) + && let Node::LetStmt(local) = cx.tcx.parent_hir_node(hir_id) { return local.init; } @@ -1079,7 +1079,7 @@ pub fn capture_local_usage(cx: &LateContext<'_>, e: &Expr<'_>) -> CaptureKind { }, _ => break, }, - Node::Local(l) => match pat_capture_kind(cx, l.pat) { + Node::LetStmt(l) => match pat_capture_kind(cx, l.pat) { CaptureKind::Value => break, capture @ CaptureKind::Ref(_) => return capture, }, @@ -1357,7 +1357,7 @@ pub fn get_enclosing_loop_or_multi_call_closure<'tcx>( ExprKind::Closure { .. } | ExprKind::Loop(..) => return Some(e), _ => (), }, - Node::Stmt(_) | Node::Block(_) | Node::Local(_) | Node::Arm(_) => (), + Node::Stmt(_) | Node::Block(_) | Node::LetStmt(_) | Node::Arm(_) => (), _ => break, } } @@ -1462,7 +1462,7 @@ pub fn is_else_clause(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool { pub fn is_inside_let_else(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool { let mut child_id = expr.hir_id; for (parent_id, node) in tcx.hir().parent_iter(child_id) { - if let Node::Local(LetStmt { + if let Node::LetStmt(LetStmt { init: Some(init), els: Some(els), .. @@ -1482,7 +1482,7 @@ pub fn is_inside_let_else(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool { pub fn is_else_clause_in_let_else(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool { let mut child_id = expr.hir_id; for (parent_id, node) in tcx.hir().parent_iter(child_id) { - if let Node::Local(LetStmt { els: Some(els), .. }) = node + if let Node::LetStmt(LetStmt { els: Some(els), .. }) = node && els.hir_id == child_id { return true; @@ -2639,7 +2639,7 @@ pub struct ExprUseCtxt<'tcx> { /// The node which consumes a value. pub enum ExprUseNode<'tcx> { /// Assignment to, or initializer for, a local - Local(&'tcx LetStmt<'tcx>), + LetStmt(&'tcx LetStmt<'tcx>), /// Initializer for a const or static item. ConstStatic(OwnerId), /// Implicit or explicit return from a function. @@ -2671,7 +2671,7 @@ impl<'tcx> ExprUseNode<'tcx> { /// Gets the needed type as it's defined without any type inference. pub fn defined_ty(&self, cx: &LateContext<'tcx>) -> Option> { match *self { - Self::Local(LetStmt { ty: Some(ty), .. }) => Some(DefinedTy::Hir(ty)), + Self::LetStmt(LetStmt { ty: Some(ty), .. }) => Some(DefinedTy::Hir(ty)), Self::ConstStatic(id) => Some(DefinedTy::Mir( cx.param_env .and(Binder::dummy(cx.tcx.type_of(id).instantiate_identity())), @@ -2731,7 +2731,7 @@ impl<'tcx> ExprUseNode<'tcx> { let sig = cx.tcx.fn_sig(id).skip_binder(); Some(DefinedTy::Mir(cx.tcx.param_env(id).and(sig.input(i)))) }, - Self::Local(_) | Self::FieldAccess(..) | Self::Callee | Self::Expr | Self::Other => None, + Self::LetStmt(_) | Self::FieldAccess(..) | Self::Callee | Self::Expr | Self::Other => None, } } } @@ -2770,7 +2770,7 @@ pub fn expr_use_ctxt<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> Optio .continue_value() .map(|(use_node, child_id)| { let node = match use_node { - Node::Local(l) => ExprUseNode::Local(l), + Node::LetStmt(l) => ExprUseNode::LetStmt(l), Node::ExprField(field) => ExprUseNode::Field(field), Node::Item(&Item { diff --git a/clippy_utils/src/ty/type_certainty/mod.rs b/clippy_utils/src/ty/type_certainty/mod.rs index 7913926928f2a..762830ffd78d9 100644 --- a/clippy_utils/src/ty/type_certainty/mod.rs +++ b/clippy_utils/src/ty/type_certainty/mod.rs @@ -242,7 +242,7 @@ fn path_segment_certainty( Node::Param(..) => Certainty::Certain(None), // A local's type is certain if its type annotation is certain or it has an initializer whose // type is certain. - Node::Local(local) => { + Node::LetStmt(local) => { let lhs = local.ty.map_or(Certainty::Uncertain, |ty| type_certainty(cx, ty)); let rhs = local .init From 4d623015e0c993aea542834b44fc4dd18b62483e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 Mar 2024 12:21:20 +0100 Subject: [PATCH 17/24] rename MIR int2ptr casts to match library name --- clippy_utils/src/qualify_min_const_fn.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index dadb0d662ce8f..0c4260037f23c 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -112,7 +112,7 @@ fn check_rvalue<'tcx>( Rvalue::Repeat(operand, _) | Rvalue::Use(operand) | Rvalue::Cast( - CastKind::PointerFromExposedAddress + CastKind::PointerWithExposedProvenance | CastKind::IntToInt | CastKind::FloatToInt | CastKind::IntToFloat From 5919b26d33aac5da7e78468c4412814869b0b12f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 17 Mar 2024 10:12:25 +0100 Subject: [PATCH 18/24] move assert_unsafe_preconditions to its own file These macros and functions are not intrinsics, after all. --- clippy_utils/src/qualify_min_const_fn.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index dadb0d662ce8f..cabebf89becc8 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -174,7 +174,7 @@ fn check_rvalue<'tcx>( )) } }, - Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(_) | NullOp::UbCheck(_), _) + Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(_) | NullOp::UbChecks, _) | Rvalue::ShallowInitBox(_, _) => Ok(()), Rvalue::UnaryOp(_, operand) => { let ty = operand.ty(body, tcx); From 733c7af87f44a2e71540d3ff12c66f1a0a1a6b16 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Sun, 24 Mar 2024 14:57:57 +0000 Subject: [PATCH 19/24] Rename `{enter,exit}_lint_attrs` to `check_attributes{,_post}` --- clippy_config/src/msrvs.rs | 4 ++-- clippy_lints/src/cognitive_complexity.rs | 4 ++-- clippy_lints/src/missing_doc.rs | 4 ++-- clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs | 2 +- clippy_utils/src/lib.rs | 8 ++++---- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/clippy_config/src/msrvs.rs b/clippy_config/src/msrvs.rs index bf4da5f14fe0a..149c4776dc9c9 100644 --- a/clippy_config/src/msrvs.rs +++ b/clippy_config/src/msrvs.rs @@ -143,13 +143,13 @@ impl Msrv { None } - pub fn enter_lint_attrs(&mut self, sess: &Session, attrs: &[Attribute]) { + pub fn check_attributes(&mut self, sess: &Session, attrs: &[Attribute]) { if let Some(version) = Self::parse_attr(sess, attrs) { self.stack.push(version); } } - pub fn exit_lint_attrs(&mut self, sess: &Session, attrs: &[Attribute]) { + pub fn check_attributes_post(&mut self, sess: &Session, attrs: &[Attribute]) { if Self::parse_attr(sess, attrs).is_some() { self.stack.pop(); } diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs index 60f436dc5d2be..7dac3c5d9dabc 100644 --- a/clippy_lints/src/cognitive_complexity.rs +++ b/clippy_lints/src/cognitive_complexity.rs @@ -158,10 +158,10 @@ impl<'tcx> LateLintPass<'tcx> for CognitiveComplexity { } } - fn enter_lint_attrs(&mut self, cx: &LateContext<'tcx>, attrs: &'tcx [Attribute]) { + fn check_attributes(&mut self, cx: &LateContext<'tcx>, attrs: &'tcx [Attribute]) { self.limit.push_attrs(cx.sess(), attrs, "cognitive_complexity"); } - fn exit_lint_attrs(&mut self, cx: &LateContext<'tcx>, attrs: &'tcx [Attribute]) { + fn check_attributes_post(&mut self, cx: &LateContext<'tcx>, attrs: &'tcx [Attribute]) { self.limit.pop_attrs(cx.sess(), attrs, "cognitive_complexity"); } } diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index 6878fb3349d4a..2773427e72d5a 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -162,12 +162,12 @@ impl MissingDoc { impl_lint_pass!(MissingDoc => [MISSING_DOCS_IN_PRIVATE_ITEMS]); impl<'tcx> LateLintPass<'tcx> for MissingDoc { - fn enter_lint_attrs(&mut self, _: &LateContext<'tcx>, attrs: &'tcx [ast::Attribute]) { + fn check_attributes(&mut self, _: &LateContext<'tcx>, attrs: &'tcx [ast::Attribute]) { let doc_hidden = self.doc_hidden() || is_doc_hidden(attrs); self.doc_hidden_stack.push(doc_hidden); } - fn exit_lint_attrs(&mut self, _: &LateContext<'tcx>, _: &'tcx [ast::Attribute]) { + fn check_attributes_post(&mut self, _: &LateContext<'tcx>, _: &'tcx [ast::Attribute]) { self.doc_hidden_stack.pop().expect("empty doc_hidden_stack"); } diff --git a/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs b/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs index 6d5240db83249..8d208fbb7e954 100644 --- a/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs +++ b/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs @@ -42,7 +42,7 @@ impl LateLintPass<'_> for MsrvAttrImpl { .filter(|t| matches!(t.unpack(), GenericArgKind::Type(_))) .any(|t| match_type(cx, t.expect_ty(), &paths::MSRV)) }) - && !items.iter().any(|item| item.ident.name == sym!(enter_lint_attrs)) + && !items.iter().any(|item| item.ident.name == sym!(check_attributes)) { let context = if is_late_pass { "LateContext" } else { "EarlyContext" }; let lint_pass = if is_late_pass { "LateLintPass" } else { "EarlyLintPass" }; diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 3b1b99caebe23..8251bdf78fc7d 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -131,14 +131,14 @@ use rustc_middle::hir::nested_filter; #[macro_export] macro_rules! extract_msrv_attr { ($context:ident) => { - fn enter_lint_attrs(&mut self, cx: &rustc_lint::$context<'_>, attrs: &[rustc_ast::ast::Attribute]) { + fn check_attributes(&mut self, cx: &rustc_lint::$context<'_>, attrs: &[rustc_ast::ast::Attribute]) { let sess = rustc_lint::LintContext::sess(cx); - self.msrv.enter_lint_attrs(sess, attrs); + self.msrv.check_attributes(sess, attrs); } - fn exit_lint_attrs(&mut self, cx: &rustc_lint::$context<'_>, attrs: &[rustc_ast::ast::Attribute]) { + fn check_attributes_post(&mut self, cx: &rustc_lint::$context<'_>, attrs: &[rustc_ast::ast::Attribute]) { let sess = rustc_lint::LintContext::sess(cx); - self.msrv.exit_lint_attrs(sess, attrs); + self.msrv.check_attributes_post(sess, attrs); } }; } From 57627d254d29110fa82c982fedd839d293d0d418 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 26 Mar 2024 05:48:13 -0400 Subject: [PATCH 20/24] Change `f16` and `f128` clippy stubs to be nonpanicking It turns out there is a bit of a circular dependency - I cannot add anything to `core` because Clippy fails, and I can't actually add correct Clippy implementations without new implementations from `core`. Change some of the Clippy stubs from `unimplemented!` to success values and leave a FIXME in their place to mitigate this. Fixes --- clippy_lints/src/float_literal.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/float_literal.rs b/clippy_lints/src/float_literal.rs index 07fbb1cb5c9f8..981a76d683d2e 100644 --- a/clippy_lints/src/float_literal.rs +++ b/clippy_lints/src/float_literal.rs @@ -83,7 +83,10 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral { LitFloatType::Unsuffixed => None, }; let (is_whole, is_inf, mut float_str) = match fty { - FloatTy::F16 => unimplemented!("f16_f128"), + FloatTy::F16 => { + // FIXME(f16_f128): do a check like the others when parsing is available + return; + }, FloatTy::F32 => { let value = sym_str.parse::().unwrap(); @@ -94,7 +97,10 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral { (value.fract() == 0.0, value.is_infinite(), formatter.format(value)) }, - FloatTy::F128 => unimplemented!("f16_f128"), + FloatTy::F128 => { + // FIXME(f16_f128): do a check like the others when parsing is available + return; + }, }; if is_inf { @@ -139,10 +145,11 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral { #[must_use] fn max_digits(fty: FloatTy) -> u32 { match fty { - FloatTy::F16 => unimplemented!("f16_f128"), + // FIXME(f16_f128): replace the magic numbers once `{f16,f128}::DIGITS` are available + FloatTy::F16 => 3, FloatTy::F32 => f32::DIGITS, FloatTy::F64 => f64::DIGITS, - FloatTy::F128 => unimplemented!("f16_f128"), + FloatTy::F128 => 33, } } From a6a1f782d6347b691376c1ef1e1c3b4727142806 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 26 Mar 2024 14:11:51 -0400 Subject: [PATCH 21/24] Inherited -> TypeckRootCtxt --- clippy_lints/src/methods/unnecessary_to_owned.rs | 6 +++--- clippy_lints/src/transmute/utils.rs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index bc5dd10cad0a8..e58d477642795 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -12,7 +12,7 @@ use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::{BorrowKind, Expr, ExprKind, ItemKind, LangItem, Node}; -use rustc_hir_typeck::{FnCtxt, Inherited}; +use rustc_hir_typeck::{FnCtxt, TypeckRootCtxt}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; use rustc_middle::mir::Mutability; @@ -438,8 +438,8 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< Node::Item(item) => { if let ItemKind::Fn(_, _, body_id) = &item.kind && let output_ty = return_ty(cx, item.owner_id) - && let inherited = Inherited::new(cx.tcx, item.owner_id.def_id) - && let fn_ctxt = FnCtxt::new(&inherited, cx.param_env, item.owner_id.def_id) + && let root_ctxt = TypeckRootCtxt::new(cx.tcx, item.owner_id.def_id) + && let fn_ctxt = FnCtxt::new(&root_ctxt, cx.param_env, item.owner_id.def_id) && fn_ctxt.can_coerce(ty, output_ty) { if has_lifetime(output_ty) && has_lifetime(ty) { diff --git a/clippy_lints/src/transmute/utils.rs b/clippy_lints/src/transmute/utils.rs index 7a7bb9f9c94c3..15f1890aa39ea 100644 --- a/clippy_lints/src/transmute/utils.rs +++ b/clippy_lints/src/transmute/utils.rs @@ -1,6 +1,6 @@ use rustc_hir as hir; use rustc_hir::Expr; -use rustc_hir_typeck::{cast, FnCtxt, Inherited}; +use rustc_hir_typeck::{cast, FnCtxt, TypeckRootCtxt}; use rustc_lint::LateContext; use rustc_middle::ty::cast::CastKind; use rustc_middle::ty::Ty; @@ -34,8 +34,8 @@ pub(super) fn check_cast<'tcx>( let hir_id = e.hir_id; let local_def_id = hir_id.owner.def_id; - let inherited = Inherited::new(cx.tcx, local_def_id); - let fn_ctxt = FnCtxt::new(&inherited, cx.param_env, local_def_id); + let root_ctxt = TypeckRootCtxt::new(cx.tcx, local_def_id); + let fn_ctxt = FnCtxt::new(&root_ctxt, cx.param_env, local_def_id); if let Ok(check) = cast::CastCheck::new( &fn_ctxt, From 11b28d44bd428cdb4c939e51b064426c4b73a293 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Sat, 23 Mar 2024 21:04:45 -0400 Subject: [PATCH 22/24] Implement `mut ref`/`mut ref mut` --- clippy_lints/src/functions/misnamed_getters.rs | 4 ++-- clippy_lints/src/index_refutable_slice.rs | 4 ++-- clippy_lints/src/iter_without_into_iter.rs | 4 ++-- clippy_lints/src/len_zero.rs | 8 ++++---- .../src/matches/infallible_destructuring_match.rs | 4 ++-- clippy_lints/src/matches/match_as_ref.rs | 2 +- clippy_lints/src/matches/needless_match.rs | 2 +- clippy_lints/src/matches/redundant_guards.rs | 2 +- clippy_lints/src/methods/clone_on_copy.rs | 2 +- clippy_lints/src/methods/iter_kv_map.rs | 5 ++--- clippy_lints/src/misc.rs | 4 ++-- clippy_lints/src/question_mark.rs | 10 +++++++--- clippy_lints/src/utils/author.rs | 2 ++ clippy_utils/src/lib.rs | 10 +++++----- 14 files changed, 34 insertions(+), 29 deletions(-) diff --git a/clippy_lints/src/functions/misnamed_getters.rs b/clippy_lints/src/functions/misnamed_getters.rs index bf96c0d62b05a..8ac17e17688d3 100644 --- a/clippy_lints/src/functions/misnamed_getters.rs +++ b/clippy_lints/src/functions/misnamed_getters.rs @@ -24,13 +24,13 @@ pub fn check_fn(cx: &LateContext<'_>, kind: FnKind<'_>, decl: &FnDecl<'_>, body: let name = ident.name.as_str(); let name = match decl.implicit_self { - ImplicitSelfKind::MutRef => { + ImplicitSelfKind::RefMut => { let Some(name) = name.strip_suffix("_mut") else { return; }; name }, - ImplicitSelfKind::Imm | ImplicitSelfKind::Mut | ImplicitSelfKind::ImmRef => name, + ImplicitSelfKind::Imm | ImplicitSelfKind::Mut | ImplicitSelfKind::RefImm => name, ImplicitSelfKind::None => return, }; diff --git a/clippy_lints/src/index_refutable_slice.rs b/clippy_lints/src/index_refutable_slice.rs index 5b5eb355f86cd..4d1f89b1d9d92 100644 --- a/clippy_lints/src/index_refutable_slice.rs +++ b/clippy_lints/src/index_refutable_slice.rs @@ -97,7 +97,7 @@ fn find_slice_values(cx: &LateContext<'_>, pat: &hir::Pat<'_>) -> FxIndexMap, pat: &hir::Pat<'_>) -> FxIndexMap, item: &rustc_hir::ImplItem<'_>) { let item_did = item.owner_id.to_def_id(); let (borrow_prefix, expected_implicit_self) = match item.ident.name { - sym::iter => ("&", ImplicitSelfKind::ImmRef), - sym::iter_mut => ("&mut ", ImplicitSelfKind::MutRef), + sym::iter => ("&", ImplicitSelfKind::RefImm), + sym::iter_mut => ("&mut ", ImplicitSelfKind::RefMut), _ => return, }; diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 27d85cde5320a..cae9ada5a33cf 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -384,8 +384,8 @@ impl LenOutput { fn expected_sig(self, self_kind: ImplicitSelfKind) -> String { let self_ref = match self_kind { - ImplicitSelfKind::ImmRef => "&", - ImplicitSelfKind::MutRef => "&mut ", + ImplicitSelfKind::RefImm => "&", + ImplicitSelfKind::RefMut => "&mut ", _ => "", }; match self { @@ -411,8 +411,8 @@ fn check_is_empty_sig<'tcx>( [arg, res] if len_output.matches_is_empty_output(cx, *res) => { matches!( (arg.kind(), self_kind), - (ty::Ref(_, _, Mutability::Not), ImplicitSelfKind::ImmRef) - | (ty::Ref(_, _, Mutability::Mut), ImplicitSelfKind::MutRef) + (ty::Ref(_, _, Mutability::Not), ImplicitSelfKind::RefImm) + | (ty::Ref(_, _, Mutability::Mut), ImplicitSelfKind::RefMut) ) || (!arg.is_ref() && matches!(self_kind, ImplicitSelfKind::Imm | ImplicitSelfKind::Mut)) }, _ => false, diff --git a/clippy_lints/src/matches/infallible_destructuring_match.rs b/clippy_lints/src/matches/infallible_destructuring_match.rs index 0f242e0b9e12b..93d7683d2af81 100644 --- a/clippy_lints/src/matches/infallible_destructuring_match.rs +++ b/clippy_lints/src/matches/infallible_destructuring_match.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::{path_to_local_id, peel_blocks, strip_pat_refs}; use rustc_errors::Applicability; -use rustc_hir::{ByRef, ExprKind, LetStmt, MatchSource, PatKind, QPath}; +use rustc_hir::{ExprKind, LetStmt, MatchSource, PatKind, QPath}; use rustc_lint::LateContext; use super::INFALLIBLE_DESTRUCTURING_MATCH; @@ -30,7 +30,7 @@ pub(crate) fn check(cx: &LateContext<'_>, local: &LetStmt<'_>) -> bool { format!( "let {}({}{}) = {};", snippet_with_applicability(cx, variant_name.span, "..", &mut applicability), - if binding.0 == ByRef::Yes { "ref " } else { "" }, + binding.prefix_str(), snippet_with_applicability(cx, local.pat.span, "..", &mut applicability), snippet_with_applicability(cx, target.span, "..", &mut applicability), ), diff --git a/clippy_lints/src/matches/match_as_ref.rs b/clippy_lints/src/matches/match_as_ref.rs index 3f737da92c055..6b484ff2749b2 100644 --- a/clippy_lints/src/matches/match_as_ref.rs +++ b/clippy_lints/src/matches/match_as_ref.rs @@ -67,7 +67,7 @@ fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool { fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option { if let PatKind::TupleStruct(ref qpath, [first_pat, ..], _) = arm.pat.kind && is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), LangItem::OptionSome) - && let PatKind::Binding(BindingAnnotation(ByRef::Yes, mutabl), .., ident, _) = first_pat.kind + && let PatKind::Binding(BindingAnnotation(ByRef::Yes(mutabl), _), .., ident, _) = first_pat.kind && let ExprKind::Call(e, [arg]) = peel_blocks(arm.body).kind && is_res_lang_ctor(cx, path_res(cx, e), LangItem::OptionSome) && let ExprKind::Path(QPath::Resolved(_, path2)) = arg.kind diff --git a/clippy_lints/src/matches/needless_match.rs b/clippy_lints/src/matches/needless_match.rs index cee77f62b61e6..fe83e784c3c9c 100644 --- a/clippy_lints/src/matches/needless_match.rs +++ b/clippy_lints/src/matches/needless_match.rs @@ -178,7 +178,7 @@ fn pat_same_as_expr(pat: &Pat<'_>, expr: &Expr<'_>) -> bool { }, )), ) => { - return !matches!(annot, BindingAnnotation(ByRef::Yes, _)) && pat_ident.name == first_seg.ident.name; + return !matches!(annot, BindingAnnotation(ByRef::Yes(_), _)) && pat_ident.name == first_seg.ident.name; }, // Example: `Custom::TypeA => Custom::TypeB`, or `None => None` (PatKind::Path(QPath::Resolved(_, p_path)), ExprKind::Path(QPath::Resolved(_, e_path))) => { diff --git a/clippy_lints/src/matches/redundant_guards.rs b/clippy_lints/src/matches/redundant_guards.rs index 6bae51b45b8fa..50cbccc396839 100644 --- a/clippy_lints/src/matches/redundant_guards.rs +++ b/clippy_lints/src/matches/redundant_guards.rs @@ -182,7 +182,7 @@ fn get_pat_binding<'tcx>( if let PatKind::Binding(bind_annot, hir_id, ident, _) = pat.kind && hir_id == local { - if matches!(bind_annot.0, rustc_ast::ByRef::Yes) { + if matches!(bind_annot.0, rustc_ast::ByRef::Yes(_)) { let _ = byref_ident.insert(ident); } // the second call of `replace()` returns a `Some(span)`, meaning a multi-binding pattern diff --git a/clippy_lints/src/methods/clone_on_copy.rs b/clippy_lints/src/methods/clone_on_copy.rs index d4a5de3d1dea8..3e099004c4794 100644 --- a/clippy_lints/src/methods/clone_on_copy.rs +++ b/clippy_lints/src/methods/clone_on_copy.rs @@ -69,7 +69,7 @@ pub(super) fn check( _ => false, }, // local binding capturing a reference - Node::LetStmt(l) if matches!(l.pat.kind, PatKind::Binding(BindingAnnotation(ByRef::Yes, _), ..)) => { + Node::LetStmt(l) if matches!(l.pat.kind, PatKind::Binding(BindingAnnotation(ByRef::Yes(_), _), ..)) => { return; }, _ => false, diff --git a/clippy_lints/src/methods/iter_kv_map.rs b/clippy_lints/src/methods/iter_kv_map.rs index 6394f35f8604f..1431a5db2d96a 100644 --- a/clippy_lints/src/methods/iter_kv_map.rs +++ b/clippy_lints/src/methods/iter_kv_map.rs @@ -60,8 +60,6 @@ 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, @@ -69,7 +67,8 @@ pub(super) fn check<'tcx>( &format!("iterating on a map's {replacement_kind}s"), "try", format!( - "{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{ref_annotation}{mut_annotation}{bound_ident}| {})", + "{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{}{bound_ident}| {})", + annotation.prefix_str(), snippet_with_applicability(cx, body_expr.span, "/* body */", &mut applicability) ), applicability, diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index ea6e662b4be36..11fecb7d72e2b 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -129,7 +129,7 @@ impl<'tcx> LateLintPass<'tcx> for LintPass { if !is_lint_allowed(cx, REF_PATTERNS, arg.pat.hir_id) { return; } - if let PatKind::Binding(BindingAnnotation(ByRef::Yes, _), ..) = arg.pat.kind { + if let PatKind::Binding(BindingAnnotation(ByRef::Yes(_), _), ..) = arg.pat.kind { span_lint( cx, TOPLEVEL_REF_ARG, @@ -144,7 +144,7 @@ impl<'tcx> LateLintPass<'tcx> for LintPass { fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { if !in_external_macro(cx.tcx.sess, stmt.span) && let StmtKind::Let(local) = stmt.kind - && let PatKind::Binding(BindingAnnotation(ByRef::Yes, mutabl), .., name, None) = local.pat.kind + && let PatKind::Binding(BindingAnnotation(ByRef::Yes(mutabl), _), .., name, None) = local.pat.kind && let Some(init) = local.init // Do not emit if clippy::ref_patterns is not allowed to avoid having two lints for the same issue. && is_lint_allowed(cx, REF_PATTERNS, local.pat.hir_id) diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index f1db571e1137a..b57220e6cf0af 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -14,7 +14,7 @@ use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::LangItem::{self, OptionNone, OptionSome, ResultErr, ResultOk}; use rustc_hir::{ - BindingAnnotation, Block, ByRef, Expr, ExprKind, LetStmt, Node, PatKind, PathSegment, QPath, Stmt, StmtKind, + BindingAnnotation, Block, ByRef, Expr, ExprKind, LetStmt, Mutability, Node, PatKind, PathSegment, QPath, Stmt, StmtKind, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty; @@ -283,9 +283,13 @@ fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: let mut applicability = Applicability::MachineApplicable; let receiver_str = snippet_with_applicability(cx, let_expr.span, "..", &mut applicability); let requires_semi = matches!(cx.tcx.parent_hir_node(expr.hir_id), Node::Stmt(_)); + let method_call_str = match by_ref { + ByRef::Yes(Mutability::Mut) => ".as_mut()", + ByRef::Yes(Mutability::Not) => ".as_ref()", + ByRef::No => "", + }; let sugg = format!( - "{receiver_str}{}?{}", - if by_ref == ByRef::Yes { ".as_ref()" } else { "" }, + "{receiver_str}{method_call_str}?{}", if requires_semi { ";" } else { "" } ); span_lint_and_sugg( diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index 5319915b2eac1..e45beb4910beb 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -649,6 +649,8 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { BindingAnnotation::REF => "REF", BindingAnnotation::MUT => "MUT", BindingAnnotation::REF_MUT => "REF_MUT", + BindingAnnotation::MUT_REF => "MUT_REF", + BindingAnnotation::MUT_REF_MUT => "MUT_REF_MUT", }; kind!("Binding(BindingAnnotation::{ann}, _, {name}, {sub})"); self.ident(name); diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 8251bdf78fc7d..95bab5801d1c7 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -97,7 +97,7 @@ use rustc_hir::hir_id::{HirIdMap, HirIdSet}; use rustc_hir::intravisit::{walk_expr, FnKind, Visitor}; use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk}; use rustc_hir::{ - self as hir, def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Closure, Destination, Expr, + self as hir, def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, ByRef, Closure, Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp, @@ -107,7 +107,6 @@ use rustc_lint::{LateContext, Level, Lint, LintContext}; use rustc_middle::hir::place::PlaceBase; use rustc_middle::mir::Const; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; -use rustc_middle::ty::binding::BindingMode; use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::{ @@ -1006,11 +1005,12 @@ pub fn capture_local_usage(cx: &LateContext<'_>, e: &Expr<'_>) -> CaptureKind { .typeck_results() .extract_binding_mode(cx.sess(), id, span) .unwrap() + .0 { - BindingMode::BindByValue(_) if !is_copy(cx, cx.typeck_results().node_type(id)) => { + ByRef::No if !is_copy(cx, cx.typeck_results().node_type(id)) => { capture = CaptureKind::Value; }, - BindingMode::BindByReference(Mutability::Mut) if capture != CaptureKind::Value => { + ByRef::Yes(Mutability::Mut) if capture != CaptureKind::Value => { capture = CaptureKind::Ref(Mutability::Mut); }, _ => (), @@ -2035,7 +2035,7 @@ fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool { .typeck_results() .pat_binding_modes() .get(pat.hir_id) - .is_some_and(|mode| matches!(mode, BindingMode::BindByReference(_))) + .is_some_and(|mode| matches!(mode.0, ByRef::Yes(_))) { // If a tuple `(x, y)` is of type `&(i32, i32)`, then due to match ergonomics, // the inner patterns become references. Don't consider this the identity function From 53e31dc45cecb671c664dd13685cfa9dc832b336 Mon Sep 17 00:00:00 2001 From: joboet Date: Wed, 3 Apr 2024 15:17:00 +0200 Subject: [PATCH 23/24] rename `expose_addr` to `expose_provenance` --- clippy_utils/src/qualify_min_const_fn.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index 12b0800599700..325c9bee05782 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -149,7 +149,7 @@ fn check_rvalue<'tcx>( Err((span, "unsizing casts are not allowed in const fn".into())) } }, - Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => { + Rvalue::Cast(CastKind::PointerExposeProvenance, _, _) => { Err((span, "casting pointers to ints is unstable in const fn".into())) }, Rvalue::Cast(CastKind::DynStar, _, _) => { From bb023e90d8dfbdee714aa33cfa44b91753a99a03 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 4 Apr 2024 19:48:53 +0200 Subject: [PATCH 24/24] Bump nightly version -> 2024-04-04 --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index a63e66f3214c9..b2fe5c8bee7a5 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2024-03-21" +channel = "nightly-2024-04-04" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]