diff --git a/clippy_lints/src/double_parens.rs b/clippy_lints/src/double_parens.rs index b51bb7951..4dd8f01ee 100644 --- a/clippy_lints/src/double_parens.rs +++ b/clippy_lints/src/double_parens.rs @@ -40,35 +40,29 @@ declare_lint_pass!(DoubleParens => [DOUBLE_PARENS]); impl EarlyLintPass for DoubleParens { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { - if expr.span.from_expansion() { - return; - } - - let msg: &str = "consider removing unnecessary double parentheses"; - - match expr.kind { - ExprKind::Paren(ref in_paren) => match in_paren.kind { - ExprKind::Paren(_) | ExprKind::Tup(_) => { - span_lint(cx, DOUBLE_PARENS, expr.span, msg); - }, - _ => {}, + let span = match &expr.kind { + ExprKind::Paren(in_paren) if matches!(in_paren.kind, ExprKind::Paren(_) | ExprKind::Tup(_)) => expr.span, + ExprKind::Call(_, params) + if let [param] = &**params + && let ExprKind::Paren(_) = param.kind => + { + param.span }, - ExprKind::Call(_, ref params) => { - if params.len() == 1 { - let param = ¶ms[0]; - if let ExprKind::Paren(_) = param.kind { - span_lint(cx, DOUBLE_PARENS, param.span, msg); - } - } + ExprKind::MethodCall(call) + if let [arg] = &*call.args + && let ExprKind::Paren(_) = arg.kind => + { + arg.span }, - ExprKind::MethodCall(ref call) => { - if let [ref arg] = call.args[..] { - if let ExprKind::Paren(_) = arg.kind { - span_lint(cx, DOUBLE_PARENS, arg.span, msg); - } - } - }, - _ => {}, + _ => return, + }; + if !expr.span.from_expansion() { + span_lint( + cx, + DOUBLE_PARENS, + span, + "consider removing unnecessary double parentheses", + ); } } } diff --git a/clippy_lints/src/endian_bytes.rs b/clippy_lints/src/endian_bytes.rs index 99328e3e6..5bba9c562 100644 --- a/clippy_lints/src/endian_bytes.rs +++ b/clippy_lints/src/endian_bytes.rs @@ -109,32 +109,27 @@ impl LintKind { impl LateLintPass<'_> for EndianBytes { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { - if in_external_macro(cx.sess(), expr.span) { - return; - } - - if let ExprKind::MethodCall(method_name, receiver, args, ..) = expr.kind - && args.is_empty() - && let ty = cx.typeck_results().expr_ty(receiver) - && ty.is_primitive_ty() - && maybe_lint_endian_bytes(cx, expr, Prefix::To, method_name.ident.name, ty) - { - return; - } - - if let ExprKind::Call(function, ..) = expr.kind - && let ExprKind::Path(qpath) = function.kind - && let Some(def_id) = cx.qpath_res(&qpath, function.hir_id).opt_def_id() - && let Some(function_name) = cx.get_def_path(def_id).last() - && let ty = cx.typeck_results().expr_ty(expr) + let (prefix, name, ty_expr) = match expr.kind { + ExprKind::MethodCall(method_name, receiver, [], ..) => (Prefix::To, method_name.ident.name, receiver), + ExprKind::Call(function, ..) + if let ExprKind::Path(qpath) = function.kind + && let Some(def_id) = cx.qpath_res(&qpath, function.hir_id).opt_def_id() + && let Some(function_name) = cx.get_def_path(def_id).last() => + { + (Prefix::From, *function_name, expr) + }, + _ => return, + }; + if !in_external_macro(cx.sess(), expr.span) + && let ty = cx.typeck_results().expr_ty(ty_expr) && ty.is_primitive_ty() { - maybe_lint_endian_bytes(cx, expr, Prefix::From, *function_name, ty); + maybe_lint_endian_bytes(cx, expr, prefix, name, ty); } } } -fn maybe_lint_endian_bytes(cx: &LateContext<'_>, expr: &Expr<'_>, prefix: Prefix, name: Symbol, ty: Ty<'_>) -> bool { +fn maybe_lint_endian_bytes(cx: &LateContext<'_>, expr: &Expr<'_>, prefix: Prefix, name: Symbol, ty: Ty<'_>) { let ne = LintKind::Host.as_name(prefix); let le = LintKind::Little.as_name(prefix); let be = LintKind::Big.as_name(prefix); @@ -143,7 +138,7 @@ fn maybe_lint_endian_bytes(cx: &LateContext<'_>, expr: &Expr<'_>, prefix: Prefix name if name == ne => ((&LintKind::Host), [(&LintKind::Little), (&LintKind::Big)]), name if name == le => ((&LintKind::Little), [(&LintKind::Host), (&LintKind::Big)]), name if name == be => ((&LintKind::Big), [(&LintKind::Host), (&LintKind::Little)]), - _ => return false, + _ => return, }; let mut help = None; @@ -208,6 +203,4 @@ fn maybe_lint_endian_bytes(cx: &LateContext<'_>, expr: &Expr<'_>, prefix: Prefix } }, ); - - true } diff --git a/clippy_lints/src/excessive_bools.rs b/clippy_lints/src/excessive_bools.rs index 8b5c5e017..8f469efb1 100644 --- a/clippy_lints/src/excessive_bools.rs +++ b/clippy_lints/src/excessive_bools.rs @@ -88,12 +88,6 @@ pub struct ExcessiveBools { max_fn_params_bools: u64, } -#[derive(Eq, PartialEq, Debug, Copy, Clone)] -enum Kind { - Struct, - Fn, -} - impl ExcessiveBools { pub fn new(conf: &'static Conf) -> Self { Self { @@ -101,55 +95,50 @@ impl ExcessiveBools { max_fn_params_bools: conf.max_fn_params_bools, } } - - fn too_many_bools<'tcx>(&self, tys: impl Iterator>, kind: Kind) -> bool { - if let Ok(bools) = tys.filter(|ty| is_bool(ty)).count().try_into() { - (if Kind::Fn == kind { - self.max_fn_params_bools - } else { - self.max_struct_bools - }) < bools - } else { - false - } - } - - fn check_fn_sig(&self, cx: &LateContext<'_>, fn_decl: &FnDecl<'_>, span: Span) { - if !span.from_expansion() && self.too_many_bools(fn_decl.inputs.iter(), Kind::Fn) { - span_lint_and_help( - cx, - FN_PARAMS_EXCESSIVE_BOOLS, - span, - format!("more than {} bools in function parameters", self.max_fn_params_bools), - None, - "consider refactoring bools into two-variant enums", - ); - } - } } impl_lint_pass!(ExcessiveBools => [STRUCT_EXCESSIVE_BOOLS, FN_PARAMS_EXCESSIVE_BOOLS]); +fn has_n_bools<'tcx>(iter: impl Iterator>, mut count: u64) -> bool { + iter.filter(|ty| is_bool(ty)).any(|_| { + let (x, overflow) = count.overflowing_sub(1); + count = x; + overflow + }) +} + +fn check_fn_decl(cx: &LateContext<'_>, decl: &FnDecl<'_>, sp: Span, max: u64) { + if has_n_bools(decl.inputs.iter(), max) && !sp.from_expansion() { + span_lint_and_help( + cx, + FN_PARAMS_EXCESSIVE_BOOLS, + sp, + format!("more than {max} bools in function parameters"), + None, + "consider refactoring bools into two-variant enums", + ); + } +} + impl<'tcx> LateLintPass<'tcx> for ExcessiveBools { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { - if item.span.from_expansion() { - return; - } - if let ItemKind::Struct(variant_data, _) = &item.kind { - if has_repr_attr(cx, item.hir_id()) { - return; - } - - if self.too_many_bools(variant_data.fields().iter().map(|field| field.ty), Kind::Struct) { - span_lint_and_help( - cx, - STRUCT_EXCESSIVE_BOOLS, - item.span, - format!("more than {} bools in a struct", self.max_struct_bools), - None, - "consider using a state machine or refactoring bools into two-variant enums", - ); - } + if let ItemKind::Struct(variant_data, _) = &item.kind + && variant_data.fields().len() as u64 > self.max_struct_bools + && has_n_bools( + variant_data.fields().iter().map(|field| field.ty), + self.max_struct_bools, + ) + && !has_repr_attr(cx, item.hir_id()) + && !item.span.from_expansion() + { + span_lint_and_help( + cx, + STRUCT_EXCESSIVE_BOOLS, + item.span, + format!("more than {} bools in a struct", self.max_struct_bools), + None, + "consider using a state machine or refactoring bools into two-variant enums", + ); } } @@ -157,8 +146,9 @@ impl<'tcx> LateLintPass<'tcx> for ExcessiveBools { // functions with a body are already checked by `check_fn` if let TraitItemKind::Fn(fn_sig, TraitFn::Required(_)) = &trait_item.kind && fn_sig.header.abi == Abi::Rust + && fn_sig.decl.inputs.len() as u64 > self.max_fn_params_bools { - self.check_fn_sig(cx, fn_sig.decl, fn_sig.span); + check_fn_decl(cx, fn_sig.decl, fn_sig.span, self.max_fn_params_bools); } } @@ -171,12 +161,13 @@ impl<'tcx> LateLintPass<'tcx> for ExcessiveBools { span: Span, def_id: LocalDefId, ) { - let hir_id = cx.tcx.local_def_id_to_hir_id(def_id); if let Some(fn_header) = fn_kind.header() && fn_header.abi == Abi::Rust - && get_parent_as_impl(cx.tcx, hir_id).map_or(true, |impl_item| impl_item.of_trait.is_none()) + && fn_decl.inputs.len() as u64 > self.max_fn_params_bools + && get_parent_as_impl(cx.tcx, cx.tcx.local_def_id_to_hir_id(def_id)) + .map_or(true, |impl_item| impl_item.of_trait.is_none()) { - self.check_fn_sig(cx, fn_decl, span); + check_fn_decl(cx, fn_decl, span, self.max_fn_params_bools); } } } diff --git a/clippy_lints/src/extra_unused_type_parameters.rs b/clippy_lints/src/extra_unused_type_parameters.rs index 52b30b91c..bfe4e253a 100644 --- a/clippy_lints/src/extra_unused_type_parameters.rs +++ b/clippy_lints/src/extra_unused_type_parameters.rs @@ -51,21 +51,6 @@ impl ExtraUnusedTypeParameters { avoid_breaking_exported_api: conf.avoid_breaking_exported_api, } } - - /// Don't lint external macros or functions with empty bodies. Also, don't lint exported items - /// if the `avoid_breaking_exported_api` config option is set. - fn is_empty_exported_or_macro( - &self, - cx: &LateContext<'_>, - span: Span, - def_id: LocalDefId, - body_id: BodyId, - ) -> bool { - let body = cx.tcx.hir().body(body_id).value; - let fn_empty = matches!(&body.kind, ExprKind::Block(blk, None) if blk.stmts.is_empty() && blk.expr.is_none()); - let is_exported = cx.effective_visibilities.is_exported(def_id); - in_external_macro(cx.sess(), span) || fn_empty || (is_exported && self.avoid_breaking_exported_api) - } } impl_lint_pass!(ExtraUnusedTypeParameters => [EXTRA_UNUSED_TYPE_PARAMETERS]); @@ -267,10 +252,17 @@ impl<'cx, 'tcx> Visitor<'tcx> for TypeWalker<'cx, 'tcx> { } } +fn is_empty_body(cx: &LateContext<'_>, body: BodyId) -> bool { + matches!(cx.tcx.hir().body(body).value.kind, ExprKind::Block(b, _) if b.stmts.is_empty() && b.expr.is_none()) +} + impl<'tcx> LateLintPass<'tcx> for ExtraUnusedTypeParameters { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { if let ItemKind::Fn(_, generics, body_id) = item.kind - && !self.is_empty_exported_or_macro(cx, item.span, item.owner_id.def_id, body_id) + && !generics.params.is_empty() + && !is_empty_body(cx, body_id) + && (!self.avoid_breaking_exported_api || !cx.effective_visibilities.is_exported(item.owner_id.def_id)) + && !in_external_macro(cx.sess(), item.span) && !is_from_proc_macro(cx, item) { let mut walker = TypeWalker::new(cx, generics); @@ -282,8 +274,12 @@ impl<'tcx> LateLintPass<'tcx> for ExtraUnusedTypeParameters { fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'tcx>) { // Only lint on inherent methods, not trait methods. if let ImplItemKind::Fn(.., body_id) = item.kind + && !item.generics.params.is_empty() && trait_ref_of_method(cx, item.owner_id.def_id).is_none() - && !self.is_empty_exported_or_macro(cx, item.span, item.owner_id.def_id, body_id) + && !is_empty_body(cx, body_id) + && (!self.avoid_breaking_exported_api || !cx.effective_visibilities.is_exported(item.owner_id.def_id)) + && !in_external_macro(cx.sess(), item.span) + && !is_from_proc_macro(cx, item) { let mut walker = TypeWalker::new(cx, item.generics); walk_impl_item(&mut walker, item); diff --git a/clippy_lints/src/future_not_send.rs b/clippy_lints/src/future_not_send.rs index 1fd8faf3e..2643de3b1 100644 --- a/clippy_lints/src/future_not_send.rs +++ b/clippy_lints/src/future_not_send.rs @@ -66,15 +66,11 @@ 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_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() { - if Some(trait_pred.skip_binder().trait_ref.def_id) == cx.tcx.lang_items().future_trait() { - is_future = true; - break; - } - } - } + let is_future = preds.iter_instantiated_copied(cx.tcx, args).any(|(p, _)| { + p.as_trait_clause().is_some_and(|trait_pred| { + Some(trait_pred.skip_binder().trait_ref.def_id) == cx.tcx.lang_items().future_trait() + }) + }); if is_future { let send_trait = cx.tcx.get_diagnostic_item(sym::Send).unwrap(); let span = decl.output.span(); diff --git a/clippy_lints/src/if_let_mutex.rs b/clippy_lints/src/if_let_mutex.rs index a55836a97..b38cc7b36 100644 --- a/clippy_lints/src/if_let_mutex.rs +++ b/clippy_lints/src/if_let_mutex.rs @@ -1,8 +1,9 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{higher, SpanlessEq}; +use core::ops::ControlFlow; use rustc_errors::Diag; -use rustc_hir::intravisit::{self as visit, Visitor}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -44,8 +45,6 @@ declare_lint_pass!(IfLetMutex => [IF_LET_MUTEX]); impl<'tcx> LateLintPass<'tcx> for IfLetMutex { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - let mut arm_visit = ArmVisitor { found_mutex: None, cx }; - let mut op_visit = OppVisitor { found_mutex: None, cx }; if let Some(higher::IfLet { let_expr, if_then, @@ -53,12 +52,20 @@ impl<'tcx> LateLintPass<'tcx> for IfLetMutex { .. }) = higher::IfLet::hir(cx, expr) { - op_visit.visit_expr(let_expr); - if let Some(op_mutex) = op_visit.found_mutex { - arm_visit.visit_expr(if_then); - arm_visit.visit_expr(if_else); + let is_mutex_lock = |e: &'tcx Expr<'tcx>| { + if let Some(mutex) = is_mutex_lock_call(cx, e) { + ControlFlow::Break(mutex) + } else { + ControlFlow::Continue(()) + } + }; - if let Some(arm_mutex) = arm_visit.found_mutex_if_same_as(op_mutex) { + let op_mutex = for_each_expr_without_closures(let_expr, is_mutex_lock); + if let Some(op_mutex) = op_mutex { + let arm_mutex = for_each_expr_without_closures((if_then, if_else), is_mutex_lock); + if let Some(arm_mutex) = arm_mutex + && SpanlessEq::new(cx).eq_expr(op_mutex, arm_mutex) + { let diag = |diag: &mut Diag<'_, ()>| { diag.span_label( op_mutex.span, @@ -83,48 +90,6 @@ impl<'tcx> LateLintPass<'tcx> for IfLetMutex { } } -/// Checks if `Mutex::lock` is called in the `if let` expr. -pub struct OppVisitor<'a, 'tcx> { - found_mutex: Option<&'tcx Expr<'tcx>>, - cx: &'a LateContext<'tcx>, -} - -impl<'tcx> Visitor<'tcx> for OppVisitor<'_, 'tcx> { - fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { - if let Some(mutex) = is_mutex_lock_call(self.cx, expr) { - self.found_mutex = Some(mutex); - return; - } - visit::walk_expr(self, expr); - } -} - -/// Checks if `Mutex::lock` is called in any of the branches. -pub struct ArmVisitor<'a, 'tcx> { - found_mutex: Option<&'tcx Expr<'tcx>>, - cx: &'a LateContext<'tcx>, -} - -impl<'tcx> Visitor<'tcx> for ArmVisitor<'_, 'tcx> { - fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { - if let Some(mutex) = is_mutex_lock_call(self.cx, expr) { - self.found_mutex = Some(mutex); - return; - } - visit::walk_expr(self, expr); - } -} - -impl<'tcx, 'l> ArmVisitor<'tcx, 'l> { - fn found_mutex_if_same_as(&self, op_mutex: &Expr<'_>) -> Option<&Expr<'_>> { - self.found_mutex.and_then(|arm_mutex| { - SpanlessEq::new(self.cx) - .eq_expr(op_mutex, arm_mutex) - .then_some(arm_mutex) - }) - } -} - fn is_mutex_lock_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind && path.ident.as_str() == "lock" diff --git a/clippy_lints/src/if_not_else.rs b/clippy_lints/src/if_not_else.rs index 4dc1ff837..2f6daeeb9 100644 --- a/clippy_lints/src/if_not_else.rs +++ b/clippy_lints/src/if_not_else.rs @@ -56,44 +56,33 @@ fn is_zero_const(expr: &Expr<'_>, cx: &LateContext<'_>) -> bool { } impl LateLintPass<'_> for IfNotElse { - fn check_expr(&mut self, cx: &LateContext<'_>, item: &Expr<'_>) { - // While loops will be desugared to ExprKind::If. This will cause the lint to fire. - // To fix this, return early if this span comes from a macro or desugaring. - if item.span.from_expansion() { - return; - } - if let ExprKind::If(cond, _, Some(els)) = item.kind { - if let ExprKind::Block(..) = els.kind { - // Disable firing the lint in "else if" expressions. - if is_else_clause(cx.tcx, item) { - return; - } + fn check_expr(&mut self, cx: &LateContext<'_>, e: &Expr<'_>) { + if let ExprKind::If(cond, _, Some(els)) = e.kind + && let ExprKind::DropTemps(cond) = cond.kind + && let ExprKind::Block(..) = els.kind + { + let (msg, help) = match cond.kind { + ExprKind::Unary(UnOp::Not, _) => ( + "unnecessary boolean `not` operation", + "remove the `!` and swap the blocks of the `if`/`else`", + ), + // Don't lint on `… != 0`, as these are likely to be bit tests. + // For example, `if foo & 0x0F00 != 0 { … } else { … }` is already in the "proper" order. + ExprKind::Binary(op, _, rhs) if op.node == BinOpKind::Ne && !is_zero_const(rhs, cx) => ( + "unnecessary `!=` operation", + "change to `==` and swap the blocks of the `if`/`else`", + ), + _ => return, + }; - match cond.peel_drop_temps().kind { - ExprKind::Unary(UnOp::Not, _) => { - span_lint_and_help( - cx, - IF_NOT_ELSE, - item.span, - "unnecessary boolean `not` operation", - None, - "remove the `!` and swap the blocks of the `if`/`else`", - ); - }, - ExprKind::Binary(ref kind, _, lhs) if kind.node == BinOpKind::Ne && !is_zero_const(lhs, cx) => { - // Disable firing the lint on `… != 0`, as these are likely to be bit tests. - // For example, `if foo & 0x0F00 != 0 { … } else { … }` already is in the "proper" order. - span_lint_and_help( - cx, - IF_NOT_ELSE, - item.span, - "unnecessary `!=` operation", - None, - "change to `==` and swap the blocks of the `if`/`else`", - ); - }, - _ => (), - } + // `from_expansion` will also catch `while` loops which appear in the HIR as: + // ```rust + // loop { + // if cond { ... } else { break; } + // } + // ``` + if !e.span.from_expansion() && !is_else_clause(cx.tcx, e) { + span_lint_and_help(cx, IF_NOT_ELSE, e.span, msg, None, help); } } } diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs index 18df3887d..39ea16b05 100644 --- a/clippy_lints/src/if_then_some_else_none.rs +++ b/clippy_lints/src/if_then_some_else_none.rs @@ -63,26 +63,6 @@ impl_lint_pass!(IfThenSomeElseNone => [IF_THEN_SOME_ELSE_NONE]); impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if !self.msrv.meets(msrvs::BOOL_THEN) { - return; - } - - if in_external_macro(cx.sess(), expr.span) { - return; - } - - // We only care about the top-most `if` in the chain - if is_else_clause(cx.tcx, expr) { - return; - } - - // `bool::then()` and `bool::then_some()` are not const - if in_constant(cx, expr.hir_id) { - return; - } - - let ctxt = expr.span.ctxt(); - if let Some(higher::If { cond, then, @@ -91,9 +71,14 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { && let ExprKind::Block(then_block, _) = then.kind && let Some(then_expr) = then_block.expr && let ExprKind::Call(then_call, [then_arg]) = then_expr.kind + && let ctxt = expr.span.ctxt() && then_expr.span.ctxt() == ctxt && is_res_lang_ctor(cx, path_res(cx, then_call), OptionSome) && is_res_lang_ctor(cx, path_res(cx, peel_blocks(els)), OptionNone) + && !is_else_clause(cx.tcx, expr) + && !in_constant(cx, expr.hir_id) + && !in_external_macro(cx.sess(), expr.span) + && self.msrv.meets(msrvs::BOOL_THEN) && !contains_return(then_block.stmts) { let mut app = Applicability::Unspecified; diff --git a/clippy_lints/src/ignored_unit_patterns.rs b/clippy_lints/src/ignored_unit_patterns.rs index a32201d80..54b8adbc8 100644 --- a/clippy_lints/src/ignored_unit_patterns.rs +++ b/clippy_lints/src/ignored_unit_patterns.rs @@ -37,22 +37,21 @@ declare_lint_pass!(IgnoredUnitPatterns => [IGNORED_UNIT_PATTERNS]); impl<'tcx> LateLintPass<'tcx> for IgnoredUnitPatterns { fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx hir::Pat<'tcx>) { - if pat.span.from_expansion() { - return; - } - - match cx.tcx.parent_hir_node(pat.hir_id) { - Node::Param(param) if matches!(cx.tcx.parent_hir_node(param.hir_id), Node::Item(_)) => { - // Ignore function parameters - return; - }, - Node::LetStmt(local) if local.ty.is_some() => { - // Ignore let bindings with explicit type - return; - }, - _ => {}, - } - if matches!(pat.kind, PatKind::Wild) && cx.typeck_results().pat_ty(pat).peel_refs().is_unit() { + if matches!(pat.kind, PatKind::Wild) + && !pat.span.from_expansion() + && cx.typeck_results().pat_ty(pat).peel_refs().is_unit() + { + match cx.tcx.parent_hir_node(pat.hir_id) { + Node::Param(param) if matches!(cx.tcx.parent_hir_node(param.hir_id), Node::Item(_)) => { + // Ignore function parameters + return; + }, + Node::LetStmt(local) if local.ty.is_some() => { + // Ignore let bindings with explicit type + return; + }, + _ => {}, + } span_lint_and_sugg( cx, IGNORED_UNIT_PATTERNS, diff --git a/clippy_lints/src/inconsistent_struct_constructor.rs b/clippy_lints/src/inconsistent_struct_constructor.rs index 1075975f0..5b0aadf35 100644 --- a/clippy_lints/src/inconsistent_struct_constructor.rs +++ b/clippy_lints/src/inconsistent_struct_constructor.rs @@ -65,13 +65,13 @@ declare_lint_pass!(InconsistentStructConstructor => [INCONSISTENT_STRUCT_CONSTRU impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { - if !expr.span.from_expansion() - && let ExprKind::Struct(qpath, fields, base) = expr.kind + if let ExprKind::Struct(qpath, fields, base) = expr.kind + && fields.iter().all(|f| f.is_shorthand) + && !expr.span.from_expansion() && let ty = cx.typeck_results().expr_ty(expr) && let Some(adt_def) = ty.ty_adt_def() && adt_def.is_struct() && let Some(variant) = adt_def.variants().iter().next() - && fields.iter().all(|f| f.is_shorthand) { let mut def_order_map = FxHashMap::default(); for (idx, field) in variant.fields.iter().enumerate() { diff --git a/clippy_lints/src/index_refutable_slice.rs b/clippy_lints/src/index_refutable_slice.rs index 1cd6d9837..526b4e1fb 100644 --- a/clippy_lints/src/index_refutable_slice.rs +++ b/clippy_lints/src/index_refutable_slice.rs @@ -71,8 +71,8 @@ impl_lint_pass!(IndexRefutableSlice => [INDEX_REFUTABLE_SLICE]); impl<'tcx> LateLintPass<'tcx> for IndexRefutableSlice { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { - if (!expr.span.from_expansion() || is_expn_of(expr.span, "if_chain").is_some()) - && let Some(IfLet { let_pat, if_then, .. }) = IfLet::hir(cx, expr) + if let Some(IfLet { let_pat, if_then, .. }) = IfLet::hir(cx, expr) + && (!expr.span.from_expansion() || is_expn_of(expr.span, "if_chain").is_some()) && !is_lint_allowed(cx, INDEX_REFUTABLE_SLICE, expr.hir_id) && self.msrv.meets(msrvs::SLICE_PATTERNS) && let found_slices = find_slice_values(cx, let_pat) diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs index 0d104e08e..6729c7c8d 100644 --- a/clippy_lints/src/indexing_slicing.rs +++ b/clippy_lints/src/indexing_slicing.rs @@ -102,13 +102,8 @@ impl IndexingSlicing { impl<'tcx> LateLintPass<'tcx> for IndexingSlicing { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if (self.suppress_restriction_lint_in_const && cx.tcx.hir().is_inside_const_context(expr.hir_id)) - || is_from_proc_macro(cx, expr) - { - return; - } - if let ExprKind::Index(array, index, _) = &expr.kind + && (!self.suppress_restriction_lint_in_const || !cx.tcx.hir().is_inside_const_context(expr.hir_id)) && let expr_ty = cx.typeck_results().expr_ty(array) && let mut deref = deref_chain(cx, expr_ty) && deref.any(|l| { @@ -116,6 +111,7 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing { || l.peel_refs().is_array() || ty_has_applicable_get_function(cx, l.peel_refs(), expr_ty, expr) }) + && !is_from_proc_macro(cx, expr) { let note = "the suggestion might not be applicable in constant blocks"; let ty = cx.typeck_results().expr_ty(array).peel_refs(); diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs index 9ad027358..fa7e7f6b7 100644 --- a/clippy_lints/src/infinite_iter.rs +++ b/clippy_lints/src/infinite_iter.rs @@ -226,13 +226,14 @@ const INFINITE_COLLECTORS: &[Symbol] = &[ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { match expr.kind { ExprKind::MethodCall(method, receiver, args, _) => { + let method_str = method.ident.name.as_str(); for &(name, len) in &COMPLETING_METHODS { - if method.ident.name.as_str() == name && args.len() == len { + if method_str == name && args.len() == len { return is_infinite(cx, receiver); } } for &(name, len) in &POSSIBLY_COMPLETING_METHODS { - if method.ident.name.as_str() == name && args.len() == len { + if method_str == name && args.len() == len { return MaybeInfinite.and(is_infinite(cx, receiver)); } }