mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-10 07:04:18 +00:00
Auto merge of #13065 - Jarcho:misc_small2, r=xFrednet
Misc refactorings part 2 A couple of theses are a bit more involved. No behaviour changes included in this set. changelog: none
This commit is contained in:
commit
637d39fab8
13 changed files with 170 additions and 265 deletions
|
@ -40,35 +40,29 @@ declare_lint_pass!(DoubleParens => [DOUBLE_PARENS]);
|
||||||
|
|
||||||
impl EarlyLintPass for DoubleParens {
|
impl EarlyLintPass for DoubleParens {
|
||||||
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
|
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
|
||||||
if expr.span.from_expansion() {
|
let span = match &expr.kind {
|
||||||
return;
|
ExprKind::Paren(in_paren) if matches!(in_paren.kind, ExprKind::Paren(_) | ExprKind::Tup(_)) => expr.span,
|
||||||
}
|
ExprKind::Call(_, params)
|
||||||
|
if let [param] = &**params
|
||||||
let msg: &str = "consider removing unnecessary double parentheses";
|
&& let ExprKind::Paren(_) = param.kind =>
|
||||||
|
{
|
||||||
match expr.kind {
|
param.span
|
||||||
ExprKind::Paren(ref in_paren) => match in_paren.kind {
|
|
||||||
ExprKind::Paren(_) | ExprKind::Tup(_) => {
|
|
||||||
span_lint(cx, DOUBLE_PARENS, expr.span, msg);
|
|
||||||
},
|
|
||||||
_ => {},
|
|
||||||
},
|
},
|
||||||
ExprKind::Call(_, ref params) => {
|
ExprKind::MethodCall(call)
|
||||||
if params.len() == 1 {
|
if let [arg] = &*call.args
|
||||||
let param = ¶ms[0];
|
&& let ExprKind::Paren(_) = arg.kind =>
|
||||||
if let ExprKind::Paren(_) = param.kind {
|
{
|
||||||
span_lint(cx, DOUBLE_PARENS, param.span, msg);
|
arg.span
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
ExprKind::MethodCall(ref call) => {
|
_ => return,
|
||||||
if let [ref arg] = call.args[..] {
|
};
|
||||||
if let ExprKind::Paren(_) = arg.kind {
|
if !expr.span.from_expansion() {
|
||||||
span_lint(cx, DOUBLE_PARENS, arg.span, msg);
|
span_lint(
|
||||||
}
|
cx,
|
||||||
}
|
DOUBLE_PARENS,
|
||||||
},
|
span,
|
||||||
_ => {},
|
"consider removing unnecessary double parentheses",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,32 +109,27 @@ impl LintKind {
|
||||||
|
|
||||||
impl LateLintPass<'_> for EndianBytes {
|
impl LateLintPass<'_> for EndianBytes {
|
||||||
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
|
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||||
if in_external_macro(cx.sess(), expr.span) {
|
let (prefix, name, ty_expr) = match expr.kind {
|
||||||
return;
|
ExprKind::MethodCall(method_name, receiver, [], ..) => (Prefix::To, method_name.ident.name, receiver),
|
||||||
}
|
ExprKind::Call(function, ..)
|
||||||
|
if let ExprKind::Path(qpath) = function.kind
|
||||||
if let ExprKind::MethodCall(method_name, receiver, args, ..) = expr.kind
|
&& let Some(def_id) = cx.qpath_res(&qpath, function.hir_id).opt_def_id()
|
||||||
&& args.is_empty()
|
&& let Some(function_name) = cx.get_def_path(def_id).last() =>
|
||||||
&& let ty = cx.typeck_results().expr_ty(receiver)
|
{
|
||||||
&& ty.is_primitive_ty()
|
(Prefix::From, *function_name, expr)
|
||||||
&& maybe_lint_endian_bytes(cx, expr, Prefix::To, method_name.ident.name, ty)
|
},
|
||||||
{
|
_ => return,
|
||||||
return;
|
};
|
||||||
}
|
if !in_external_macro(cx.sess(), expr.span)
|
||||||
|
&& let ty = cx.typeck_results().expr_ty(ty_expr)
|
||||||
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)
|
|
||||||
&& ty.is_primitive_ty()
|
&& 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 ne = LintKind::Host.as_name(prefix);
|
||||||
let le = LintKind::Little.as_name(prefix);
|
let le = LintKind::Little.as_name(prefix);
|
||||||
let be = LintKind::Big.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 == ne => ((&LintKind::Host), [(&LintKind::Little), (&LintKind::Big)]),
|
||||||
name if name == le => ((&LintKind::Little), [(&LintKind::Host), (&LintKind::Big)]),
|
name if name == le => ((&LintKind::Little), [(&LintKind::Host), (&LintKind::Big)]),
|
||||||
name if name == be => ((&LintKind::Big), [(&LintKind::Host), (&LintKind::Little)]),
|
name if name == be => ((&LintKind::Big), [(&LintKind::Host), (&LintKind::Little)]),
|
||||||
_ => return false,
|
_ => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut help = None;
|
let mut help = None;
|
||||||
|
@ -208,6 +203,4 @@ fn maybe_lint_endian_bytes(cx: &LateContext<'_>, expr: &Expr<'_>, prefix: Prefix
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,12 +88,6 @@ pub struct ExcessiveBools {
|
||||||
max_fn_params_bools: u64,
|
max_fn_params_bools: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
|
|
||||||
enum Kind {
|
|
||||||
Struct,
|
|
||||||
Fn,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ExcessiveBools {
|
impl ExcessiveBools {
|
||||||
pub fn new(conf: &'static Conf) -> Self {
|
pub fn new(conf: &'static Conf) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -101,55 +95,50 @@ impl ExcessiveBools {
|
||||||
max_fn_params_bools: conf.max_fn_params_bools,
|
max_fn_params_bools: conf.max_fn_params_bools,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn too_many_bools<'tcx>(&self, tys: impl Iterator<Item = &'tcx Ty<'tcx>>, 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]);
|
impl_lint_pass!(ExcessiveBools => [STRUCT_EXCESSIVE_BOOLS, FN_PARAMS_EXCESSIVE_BOOLS]);
|
||||||
|
|
||||||
|
fn has_n_bools<'tcx>(iter: impl Iterator<Item = &'tcx Ty<'tcx>>, 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 {
|
impl<'tcx> LateLintPass<'tcx> for ExcessiveBools {
|
||||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
|
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
|
||||||
if item.span.from_expansion() {
|
if let ItemKind::Struct(variant_data, _) = &item.kind
|
||||||
return;
|
&& variant_data.fields().len() as u64 > self.max_struct_bools
|
||||||
}
|
&& has_n_bools(
|
||||||
if let ItemKind::Struct(variant_data, _) = &item.kind {
|
variant_data.fields().iter().map(|field| field.ty),
|
||||||
if has_repr_attr(cx, item.hir_id()) {
|
self.max_struct_bools,
|
||||||
return;
|
)
|
||||||
}
|
&& !has_repr_attr(cx, item.hir_id())
|
||||||
|
&& !item.span.from_expansion()
|
||||||
if self.too_many_bools(variant_data.fields().iter().map(|field| field.ty), Kind::Struct) {
|
{
|
||||||
span_lint_and_help(
|
span_lint_and_help(
|
||||||
cx,
|
cx,
|
||||||
STRUCT_EXCESSIVE_BOOLS,
|
STRUCT_EXCESSIVE_BOOLS,
|
||||||
item.span,
|
item.span,
|
||||||
format!("more than {} bools in a struct", self.max_struct_bools),
|
format!("more than {} bools in a struct", self.max_struct_bools),
|
||||||
None,
|
None,
|
||||||
"consider using a state machine or refactoring bools into two-variant enums",
|
"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`
|
// functions with a body are already checked by `check_fn`
|
||||||
if let TraitItemKind::Fn(fn_sig, TraitFn::Required(_)) = &trait_item.kind
|
if let TraitItemKind::Fn(fn_sig, TraitFn::Required(_)) = &trait_item.kind
|
||||||
&& fn_sig.header.abi == Abi::Rust
|
&& 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,
|
span: Span,
|
||||||
def_id: LocalDefId,
|
def_id: LocalDefId,
|
||||||
) {
|
) {
|
||||||
let hir_id = cx.tcx.local_def_id_to_hir_id(def_id);
|
|
||||||
if let Some(fn_header) = fn_kind.header()
|
if let Some(fn_header) = fn_kind.header()
|
||||||
&& fn_header.abi == Abi::Rust
|
&& 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,21 +51,6 @@ impl ExtraUnusedTypeParameters {
|
||||||
avoid_breaking_exported_api: conf.avoid_breaking_exported_api,
|
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]);
|
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 {
|
impl<'tcx> LateLintPass<'tcx> for ExtraUnusedTypeParameters {
|
||||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
|
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
|
||||||
if let ItemKind::Fn(_, generics, body_id) = item.kind
|
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)
|
&& !is_from_proc_macro(cx, item)
|
||||||
{
|
{
|
||||||
let mut walker = TypeWalker::new(cx, generics);
|
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>) {
|
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'tcx>) {
|
||||||
// Only lint on inherent methods, not trait methods.
|
// Only lint on inherent methods, not trait methods.
|
||||||
if let ImplItemKind::Fn(.., body_id) = item.kind
|
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()
|
&& 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);
|
let mut walker = TypeWalker::new(cx, item.generics);
|
||||||
walk_impl_item(&mut walker, item);
|
walk_impl_item(&mut walker, item);
|
||||||
|
|
|
@ -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());
|
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() {
|
if let ty::Alias(ty::Opaque, AliasTy { def_id, args, .. }) = *ret_ty.kind() {
|
||||||
let preds = cx.tcx.explicit_item_super_predicates(def_id);
|
let preds = cx.tcx.explicit_item_super_predicates(def_id);
|
||||||
let mut is_future = false;
|
let is_future = preds.iter_instantiated_copied(cx.tcx, args).any(|(p, _)| {
|
||||||
for (p, _span) in preds.iter_instantiated_copied(cx.tcx, args) {
|
p.as_trait_clause().is_some_and(|trait_pred| {
|
||||||
if let Some(trait_pred) = p.as_trait_clause() {
|
Some(trait_pred.skip_binder().trait_ref.def_id) == cx.tcx.lang_items().future_trait()
|
||||||
if Some(trait_pred.skip_binder().trait_ref.def_id) == cx.tcx.lang_items().future_trait() {
|
})
|
||||||
is_future = true;
|
});
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if is_future {
|
if is_future {
|
||||||
let send_trait = cx.tcx.get_diagnostic_item(sym::Send).unwrap();
|
let send_trait = cx.tcx.get_diagnostic_item(sym::Send).unwrap();
|
||||||
let span = decl.output.span();
|
let span = decl.output.span();
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
use clippy_utils::diagnostics::span_lint_and_then;
|
use clippy_utils::diagnostics::span_lint_and_then;
|
||||||
use clippy_utils::ty::is_type_diagnostic_item;
|
use clippy_utils::ty::is_type_diagnostic_item;
|
||||||
|
use clippy_utils::visitors::for_each_expr_without_closures;
|
||||||
use clippy_utils::{higher, SpanlessEq};
|
use clippy_utils::{higher, SpanlessEq};
|
||||||
|
use core::ops::ControlFlow;
|
||||||
use rustc_errors::Diag;
|
use rustc_errors::Diag;
|
||||||
use rustc_hir::intravisit::{self as visit, Visitor};
|
|
||||||
use rustc_hir::{Expr, ExprKind};
|
use rustc_hir::{Expr, ExprKind};
|
||||||
use rustc_lint::{LateContext, LateLintPass};
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
use rustc_session::declare_lint_pass;
|
use rustc_session::declare_lint_pass;
|
||||||
|
@ -44,8 +45,6 @@ declare_lint_pass!(IfLetMutex => [IF_LET_MUTEX]);
|
||||||
|
|
||||||
impl<'tcx> LateLintPass<'tcx> for IfLetMutex {
|
impl<'tcx> LateLintPass<'tcx> for IfLetMutex {
|
||||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
|
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 {
|
if let Some(higher::IfLet {
|
||||||
let_expr,
|
let_expr,
|
||||||
if_then,
|
if_then,
|
||||||
|
@ -53,12 +52,20 @@ impl<'tcx> LateLintPass<'tcx> for IfLetMutex {
|
||||||
..
|
..
|
||||||
}) = higher::IfLet::hir(cx, expr)
|
}) = higher::IfLet::hir(cx, expr)
|
||||||
{
|
{
|
||||||
op_visit.visit_expr(let_expr);
|
let is_mutex_lock = |e: &'tcx Expr<'tcx>| {
|
||||||
if let Some(op_mutex) = op_visit.found_mutex {
|
if let Some(mutex) = is_mutex_lock_call(cx, e) {
|
||||||
arm_visit.visit_expr(if_then);
|
ControlFlow::Break(mutex)
|
||||||
arm_visit.visit_expr(if_else);
|
} 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<'_, ()>| {
|
let diag = |diag: &mut Diag<'_, ()>| {
|
||||||
diag.span_label(
|
diag.span_label(
|
||||||
op_mutex.span,
|
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>> {
|
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
|
if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind
|
||||||
&& path.ident.as_str() == "lock"
|
&& path.ident.as_str() == "lock"
|
||||||
|
|
|
@ -56,44 +56,33 @@ fn is_zero_const(expr: &Expr<'_>, cx: &LateContext<'_>) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LateLintPass<'_> for IfNotElse {
|
impl LateLintPass<'_> for IfNotElse {
|
||||||
fn check_expr(&mut self, cx: &LateContext<'_>, item: &Expr<'_>) {
|
fn check_expr(&mut self, cx: &LateContext<'_>, e: &Expr<'_>) {
|
||||||
// While loops will be desugared to ExprKind::If. This will cause the lint to fire.
|
if let ExprKind::If(cond, _, Some(els)) = e.kind
|
||||||
// To fix this, return early if this span comes from a macro or desugaring.
|
&& let ExprKind::DropTemps(cond) = cond.kind
|
||||||
if item.span.from_expansion() {
|
&& let ExprKind::Block(..) = els.kind
|
||||||
return;
|
{
|
||||||
}
|
let (msg, help) = match cond.kind {
|
||||||
if let ExprKind::If(cond, _, Some(els)) = item.kind {
|
ExprKind::Unary(UnOp::Not, _) => (
|
||||||
if let ExprKind::Block(..) = els.kind {
|
"unnecessary boolean `not` operation",
|
||||||
// Disable firing the lint in "else if" expressions.
|
"remove the `!` and swap the blocks of the `if`/`else`",
|
||||||
if is_else_clause(cx.tcx, item) {
|
),
|
||||||
return;
|
// 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 {
|
// `from_expansion` will also catch `while` loops which appear in the HIR as:
|
||||||
ExprKind::Unary(UnOp::Not, _) => {
|
// ```rust
|
||||||
span_lint_and_help(
|
// loop {
|
||||||
cx,
|
// if cond { ... } else { break; }
|
||||||
IF_NOT_ELSE,
|
// }
|
||||||
item.span,
|
// ```
|
||||||
"unnecessary boolean `not` operation",
|
if !e.span.from_expansion() && !is_else_clause(cx.tcx, e) {
|
||||||
None,
|
span_lint_and_help(cx, IF_NOT_ELSE, e.span, msg, None, help);
|
||||||
"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`",
|
|
||||||
);
|
|
||||||
},
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,26 +63,6 @@ impl_lint_pass!(IfThenSomeElseNone => [IF_THEN_SOME_ELSE_NONE]);
|
||||||
|
|
||||||
impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone {
|
impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone {
|
||||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
|
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 {
|
if let Some(higher::If {
|
||||||
cond,
|
cond,
|
||||||
then,
|
then,
|
||||||
|
@ -91,9 +71,14 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone {
|
||||||
&& let ExprKind::Block(then_block, _) = then.kind
|
&& let ExprKind::Block(then_block, _) = then.kind
|
||||||
&& let Some(then_expr) = then_block.expr
|
&& let Some(then_expr) = then_block.expr
|
||||||
&& let ExprKind::Call(then_call, [then_arg]) = then_expr.kind
|
&& let ExprKind::Call(then_call, [then_arg]) = then_expr.kind
|
||||||
|
&& let ctxt = expr.span.ctxt()
|
||||||
&& then_expr.span.ctxt() == 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, then_call), OptionSome)
|
||||||
&& is_res_lang_ctor(cx, path_res(cx, peel_blocks(els)), OptionNone)
|
&& 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)
|
&& !contains_return(then_block.stmts)
|
||||||
{
|
{
|
||||||
let mut app = Applicability::Unspecified;
|
let mut app = Applicability::Unspecified;
|
||||||
|
|
|
@ -37,22 +37,21 @@ declare_lint_pass!(IgnoredUnitPatterns => [IGNORED_UNIT_PATTERNS]);
|
||||||
|
|
||||||
impl<'tcx> LateLintPass<'tcx> for IgnoredUnitPatterns {
|
impl<'tcx> LateLintPass<'tcx> for IgnoredUnitPatterns {
|
||||||
fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx hir::Pat<'tcx>) {
|
fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx hir::Pat<'tcx>) {
|
||||||
if pat.span.from_expansion() {
|
if matches!(pat.kind, PatKind::Wild)
|
||||||
return;
|
&& !pat.span.from_expansion()
|
||||||
}
|
&& cx.typeck_results().pat_ty(pat).peel_refs().is_unit()
|
||||||
|
{
|
||||||
match cx.tcx.parent_hir_node(pat.hir_id) {
|
match cx.tcx.parent_hir_node(pat.hir_id) {
|
||||||
Node::Param(param) if matches!(cx.tcx.parent_hir_node(param.hir_id), Node::Item(_)) => {
|
Node::Param(param) if matches!(cx.tcx.parent_hir_node(param.hir_id), Node::Item(_)) => {
|
||||||
// Ignore function parameters
|
// Ignore function parameters
|
||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
Node::LetStmt(local) if local.ty.is_some() => {
|
Node::LetStmt(local) if local.ty.is_some() => {
|
||||||
// Ignore let bindings with explicit type
|
// Ignore let bindings with explicit type
|
||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
if matches!(pat.kind, PatKind::Wild) && cx.typeck_results().pat_ty(pat).peel_refs().is_unit() {
|
|
||||||
span_lint_and_sugg(
|
span_lint_and_sugg(
|
||||||
cx,
|
cx,
|
||||||
IGNORED_UNIT_PATTERNS,
|
IGNORED_UNIT_PATTERNS,
|
||||||
|
|
|
@ -65,13 +65,13 @@ declare_lint_pass!(InconsistentStructConstructor => [INCONSISTENT_STRUCT_CONSTRU
|
||||||
|
|
||||||
impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor {
|
impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor {
|
||||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
|
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
|
||||||
if !expr.span.from_expansion()
|
if let ExprKind::Struct(qpath, fields, base) = expr.kind
|
||||||
&& 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 ty = cx.typeck_results().expr_ty(expr)
|
||||||
&& let Some(adt_def) = ty.ty_adt_def()
|
&& let Some(adt_def) = ty.ty_adt_def()
|
||||||
&& adt_def.is_struct()
|
&& adt_def.is_struct()
|
||||||
&& let Some(variant) = adt_def.variants().iter().next()
|
&& let Some(variant) = adt_def.variants().iter().next()
|
||||||
&& fields.iter().all(|f| f.is_shorthand)
|
|
||||||
{
|
{
|
||||||
let mut def_order_map = FxHashMap::default();
|
let mut def_order_map = FxHashMap::default();
|
||||||
for (idx, field) in variant.fields.iter().enumerate() {
|
for (idx, field) in variant.fields.iter().enumerate() {
|
||||||
|
|
|
@ -71,8 +71,8 @@ impl_lint_pass!(IndexRefutableSlice => [INDEX_REFUTABLE_SLICE]);
|
||||||
|
|
||||||
impl<'tcx> LateLintPass<'tcx> for IndexRefutableSlice {
|
impl<'tcx> LateLintPass<'tcx> for IndexRefutableSlice {
|
||||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
|
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())
|
if let Some(IfLet { let_pat, if_then, .. }) = IfLet::hir(cx, expr)
|
||||||
&& 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)
|
&& !is_lint_allowed(cx, INDEX_REFUTABLE_SLICE, expr.hir_id)
|
||||||
&& self.msrv.meets(msrvs::SLICE_PATTERNS)
|
&& self.msrv.meets(msrvs::SLICE_PATTERNS)
|
||||||
&& let found_slices = find_slice_values(cx, let_pat)
|
&& let found_slices = find_slice_values(cx, let_pat)
|
||||||
|
|
|
@ -102,13 +102,8 @@ impl IndexingSlicing {
|
||||||
|
|
||||||
impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
|
impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
|
||||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
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
|
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 expr_ty = cx.typeck_results().expr_ty(array)
|
||||||
&& let mut deref = deref_chain(cx, expr_ty)
|
&& let mut deref = deref_chain(cx, expr_ty)
|
||||||
&& deref.any(|l| {
|
&& deref.any(|l| {
|
||||||
|
@ -116,6 +111,7 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
|
||||||
|| l.peel_refs().is_array()
|
|| l.peel_refs().is_array()
|
||||||
|| ty_has_applicable_get_function(cx, l.peel_refs(), expr_ty, expr)
|
|| 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 note = "the suggestion might not be applicable in constant blocks";
|
||||||
let ty = cx.typeck_results().expr_ty(array).peel_refs();
|
let ty = cx.typeck_results().expr_ty(array).peel_refs();
|
||||||
|
|
|
@ -226,13 +226,14 @@ const INFINITE_COLLECTORS: &[Symbol] = &[
|
||||||
fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
|
fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
|
||||||
match expr.kind {
|
match expr.kind {
|
||||||
ExprKind::MethodCall(method, receiver, args, _) => {
|
ExprKind::MethodCall(method, receiver, args, _) => {
|
||||||
|
let method_str = method.ident.name.as_str();
|
||||||
for &(name, len) in &COMPLETING_METHODS {
|
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);
|
return is_infinite(cx, receiver);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for &(name, len) in &POSSIBLY_COMPLETING_METHODS {
|
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));
|
return MaybeInfinite.and(is_infinite(cx, receiver));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue