Auto merge of #13069 - Jarcho:misc_small4, r=Manishearth
Misc refactorings part 4 And even more rearrangements to check the HIR tree before other checks. changelog: none
This commit is contained in:
commit
8fa406b03f
@ -121,11 +121,9 @@
|
|||||||
|
|
||||||
impl<'tcx> LateLintPass<'tcx> for LenZero {
|
impl<'tcx> LateLintPass<'tcx> for LenZero {
|
||||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
|
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
|
||||||
if item.span.from_expansion() {
|
if let ItemKind::Trait(_, _, _, _, trait_items) = item.kind
|
||||||
return;
|
&& !item.span.from_expansion()
|
||||||
}
|
{
|
||||||
|
|
||||||
if let ItemKind::Trait(_, _, _, _, trait_items) = item.kind {
|
|
||||||
check_trait_items(cx, item, trait_items);
|
check_trait_items(cx, item, trait_items);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -162,17 +160,14 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>)
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||||
if expr.span.from_expansion() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let ExprKind::Let(lt) = expr.kind
|
if let ExprKind::Let(lt) = expr.kind
|
||||||
&& has_is_empty(cx, lt.init)
|
|
||||||
&& match lt.pat.kind {
|
&& match lt.pat.kind {
|
||||||
PatKind::Slice([], None, []) => true,
|
PatKind::Slice([], None, []) => true,
|
||||||
PatKind::Lit(lit) if is_empty_string(lit) => true,
|
PatKind::Lit(lit) if is_empty_string(lit) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
|
&& !expr.span.from_expansion()
|
||||||
|
&& has_is_empty(cx, lt.init)
|
||||||
{
|
{
|
||||||
let mut applicability = Applicability::MachineApplicable;
|
let mut applicability = Applicability::MachineApplicable;
|
||||||
|
|
||||||
@ -190,7 +185,9 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let ExprKind::Binary(Spanned { node: cmp, .. }, left, right) = expr.kind {
|
if let ExprKind::Binary(Spanned { node: cmp, .. }, left, right) = expr.kind
|
||||||
|
&& !expr.span.from_expansion()
|
||||||
|
{
|
||||||
// expr.span might contains parenthesis, see issue #10529
|
// expr.span might contains parenthesis, see issue #10529
|
||||||
let actual_span = span_without_enclosing_paren(cx, expr.span);
|
let actual_span = span_without_enclosing_paren(cx, expr.span);
|
||||||
match cmp {
|
match cmp {
|
||||||
|
@ -58,12 +58,10 @@
|
|||||||
|
|
||||||
impl<'tcx> LateLintPass<'tcx> for LetIfSeq {
|
impl<'tcx> LateLintPass<'tcx> for LetIfSeq {
|
||||||
fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) {
|
fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) {
|
||||||
let mut it = block.stmts.iter().peekable();
|
for [stmt, next] in block.stmts.array_windows::<2>() {
|
||||||
while let Some(stmt) = it.next() {
|
if let hir::StmtKind::Let(local) = stmt.kind
|
||||||
if let Some(expr) = it.peek()
|
|
||||||
&& let hir::StmtKind::Let(local) = stmt.kind
|
|
||||||
&& let hir::PatKind::Binding(mode, canonical_id, ident, None) = local.pat.kind
|
&& let hir::PatKind::Binding(mode, canonical_id, ident, None) = local.pat.kind
|
||||||
&& let hir::StmtKind::Expr(if_) = expr.kind
|
&& let hir::StmtKind::Expr(if_) = next.kind
|
||||||
&& let hir::ExprKind::If(
|
&& let hir::ExprKind::If(
|
||||||
hir::Expr {
|
hir::Expr {
|
||||||
kind: hir::ExprKind::DropTemps(cond),
|
kind: hir::ExprKind::DropTemps(cond),
|
||||||
|
@ -139,9 +139,9 @@
|
|||||||
impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
|
impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
|
||||||
fn check_local(&mut self, cx: &LateContext<'tcx>, local: &LetStmt<'tcx>) {
|
fn check_local(&mut self, cx: &LateContext<'tcx>, local: &LetStmt<'tcx>) {
|
||||||
if matches!(local.source, LocalSource::Normal)
|
if matches!(local.source, LocalSource::Normal)
|
||||||
&& !in_external_macro(cx.tcx.sess, local.span)
|
|
||||||
&& let PatKind::Wild = local.pat.kind
|
&& let PatKind::Wild = local.pat.kind
|
||||||
&& let Some(init) = local.init
|
&& let Some(init) = local.init
|
||||||
|
&& !in_external_macro(cx.tcx.sess, local.span)
|
||||||
{
|
{
|
||||||
let init_ty = cx.typeck_results().expr_ty(init);
|
let init_ty = cx.typeck_results().expr_ty(init);
|
||||||
let contains_sync_guard = init_ty.walk().any(|inner| match inner.unpack() {
|
let contains_sync_guard = init_ty.walk().any(|inner| match inner.unpack() {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use clippy_utils::diagnostics::span_lint_and_help;
|
use clippy_utils::diagnostics::span_lint_and_help;
|
||||||
use clippy_utils::source::snippet;
|
use clippy_utils::is_from_proc_macro;
|
||||||
use rustc_hir::{LetStmt, TyKind};
|
use rustc_hir::{LetStmt, TyKind};
|
||||||
use rustc_lint::{LateContext, LateLintPass};
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
use rustc_middle::lint::in_external_macro;
|
use rustc_middle::lint::in_external_macro;
|
||||||
@ -25,19 +25,14 @@
|
|||||||
}
|
}
|
||||||
declare_lint_pass!(UnderscoreTyped => [LET_WITH_TYPE_UNDERSCORE]);
|
declare_lint_pass!(UnderscoreTyped => [LET_WITH_TYPE_UNDERSCORE]);
|
||||||
|
|
||||||
impl LateLintPass<'_> for UnderscoreTyped {
|
impl<'tcx> LateLintPass<'tcx> for UnderscoreTyped {
|
||||||
fn check_local(&mut self, cx: &LateContext<'_>, local: &LetStmt<'_>) {
|
fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'_>) {
|
||||||
if !in_external_macro(cx.tcx.sess, local.span)
|
if let Some(ty) = local.ty // Ensure that it has a type defined
|
||||||
&& let Some(ty) = local.ty // Ensure that it has a type defined
|
|
||||||
&& let TyKind::Infer = &ty.kind // that type is '_'
|
&& let TyKind::Infer = &ty.kind // that type is '_'
|
||||||
&& local.span.eq_ctxt(ty.span)
|
&& local.span.eq_ctxt(ty.span)
|
||||||
|
&& !in_external_macro(cx.tcx.sess, local.span)
|
||||||
|
&& !is_from_proc_macro(cx, ty)
|
||||||
{
|
{
|
||||||
// NOTE: Using `is_from_proc_macro` on `init` will require that it's initialized,
|
|
||||||
// this doesn't. Alternatively, `WithSearchPat` can be implemented for `Ty`
|
|
||||||
if snippet(cx, ty.span, "_").trim() != "_" {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
span_lint_and_help(
|
span_lint_and_help(
|
||||||
cx,
|
cx,
|
||||||
LET_WITH_TYPE_UNDERSCORE,
|
LET_WITH_TYPE_UNDERSCORE,
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#![feature(if_let_guard)]
|
#![feature(if_let_guard)]
|
||||||
#![feature(is_sorted)]
|
#![feature(is_sorted)]
|
||||||
#![feature(iter_intersperse)]
|
#![feature(iter_intersperse)]
|
||||||
|
#![feature(iter_partition_in_place)]
|
||||||
#![feature(let_chains)]
|
#![feature(let_chains)]
|
||||||
#![feature(never_type)]
|
#![feature(never_type)]
|
||||||
#![feature(rustc_private)]
|
#![feature(rustc_private)]
|
||||||
|
@ -233,11 +233,9 @@ pub struct LiteralDigitGrouping {
|
|||||||
|
|
||||||
impl EarlyLintPass for LiteralDigitGrouping {
|
impl EarlyLintPass for LiteralDigitGrouping {
|
||||||
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
|
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
|
||||||
if in_external_macro(cx.sess(), expr.span) {
|
if let ExprKind::Lit(lit) = expr.kind
|
||||||
return;
|
&& !in_external_macro(cx.sess(), expr.span)
|
||||||
}
|
{
|
||||||
|
|
||||||
if let ExprKind::Lit(lit) = expr.kind {
|
|
||||||
self.check_lit(cx, lit, expr.span);
|
self.check_lit(cx, lit, expr.span);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -448,11 +446,9 @@ pub struct DecimalLiteralRepresentation {
|
|||||||
|
|
||||||
impl EarlyLintPass for DecimalLiteralRepresentation {
|
impl EarlyLintPass for DecimalLiteralRepresentation {
|
||||||
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
|
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
|
||||||
if in_external_macro(cx.sess(), expr.span) {
|
if let ExprKind::Lit(lit) = expr.kind
|
||||||
return;
|
&& !in_external_macro(cx.sess(), expr.span)
|
||||||
}
|
{
|
||||||
|
|
||||||
if let ExprKind::Lit(lit) = expr.kind {
|
|
||||||
self.check_lit(cx, lit, expr.span);
|
self.check_lit(cx, lit, expr.span);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,13 +50,10 @@ pub fn new(msrv: Msrv) -> Self {
|
|||||||
|
|
||||||
impl<'tcx> LateLintPass<'tcx> for ManualBits {
|
impl<'tcx> LateLintPass<'tcx> for ManualBits {
|
||||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||||
if !self.msrv.meets(msrvs::MANUAL_BITS) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let ExprKind::Binary(bin_op, left_expr, right_expr) = expr.kind
|
if let ExprKind::Binary(bin_op, left_expr, right_expr) = expr.kind
|
||||||
&& let BinOpKind::Mul = &bin_op.node
|
&& let BinOpKind::Mul = &bin_op.node
|
||||||
&& !in_external_macro(cx.sess(), expr.span)
|
&& !in_external_macro(cx.sess(), expr.span)
|
||||||
|
&& self.msrv.meets(msrvs::MANUAL_BITS)
|
||||||
&& let ctxt = expr.span.ctxt()
|
&& let ctxt = expr.span.ctxt()
|
||||||
&& left_expr.span.ctxt() == ctxt
|
&& left_expr.span.ctxt() == ctxt
|
||||||
&& right_expr.span.ctxt() == ctxt
|
&& right_expr.span.ctxt() == ctxt
|
||||||
|
@ -82,29 +82,26 @@ pub fn msg(self) -> &'static str {
|
|||||||
|
|
||||||
impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods {
|
impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods {
|
||||||
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 !in_external_macro(cx.sess(), expr.span)
|
if let ExprKind::Binary(kind, lhs, rhs) = expr.kind
|
||||||
&& (
|
|
||||||
matches!(cx.tcx.constness(cx.tcx.hir().enclosing_body_owner(expr.hir_id)), Constness::NotConst)
|
|
||||||
|| cx.tcx.features().declared(sym!(const_float_classify))
|
|
||||||
) && let ExprKind::Binary(kind, lhs, rhs) = expr.kind
|
|
||||||
&& let ExprKind::Binary(lhs_kind, lhs_lhs, lhs_rhs) = lhs.kind
|
&& let ExprKind::Binary(lhs_kind, lhs_lhs, lhs_rhs) = lhs.kind
|
||||||
&& let ExprKind::Binary(rhs_kind, rhs_lhs, rhs_rhs) = rhs.kind
|
&& let ExprKind::Binary(rhs_kind, rhs_lhs, rhs_rhs) = rhs.kind
|
||||||
// Checking all possible scenarios using a function would be a hopeless task, as we have
|
// Checking all possible scenarios using a function would be a hopeless task, as we have
|
||||||
// 16 possible alignments of constants/operands. For now, let's use `partition`.
|
// 16 possible alignments of constants/operands. For now, let's use `partition`.
|
||||||
&& let (operands, constants) = [lhs_lhs, lhs_rhs, rhs_lhs, rhs_rhs]
|
&& let mut exprs = [lhs_lhs, lhs_rhs, rhs_lhs, rhs_rhs]
|
||||||
.into_iter()
|
&& exprs.iter_mut().partition_in_place(|i| path_to_local(i).is_some()) == 2
|
||||||
.partition::<Vec<&Expr<'_>>, _>(|i| path_to_local(i).is_some())
|
&& !in_external_macro(cx.sess(), expr.span)
|
||||||
&& let [first, second] = &*operands
|
&& (
|
||||||
&& let Some([const_1, const_2]) = constants
|
matches!(cx.tcx.constness(cx.tcx.hir().enclosing_body_owner(expr.hir_id)), Constness::NotConst)
|
||||||
.into_iter()
|
|| cx.tcx.features().declared(sym!(const_float_classify))
|
||||||
.map(|i| constant(cx, cx.typeck_results(), i))
|
)
|
||||||
.collect::<Option<Vec<_>>>()
|
&& let [first, second, const_1, const_2] = exprs
|
||||||
.as_deref()
|
&& let Some(const_1) = constant(cx, cx.typeck_results(), const_1)
|
||||||
|
&& let Some(const_2) = constant(cx, cx.typeck_results(), const_2)
|
||||||
&& path_to_local(first).is_some_and(|f| path_to_local(second).is_some_and(|s| f == s))
|
&& path_to_local(first).is_some_and(|f| path_to_local(second).is_some_and(|s| f == s))
|
||||||
// The actual infinity check, we also allow `NEG_INFINITY` before` INFINITY` just in
|
// The actual infinity check, we also allow `NEG_INFINITY` before` INFINITY` just in
|
||||||
// case somebody does that for some reason
|
// case somebody does that for some reason
|
||||||
&& (is_infinity(const_1) && is_neg_infinity(const_2)
|
&& (is_infinity(&const_1) && is_neg_infinity(&const_2)
|
||||||
|| is_neg_infinity(const_1) && is_infinity(const_2))
|
|| is_neg_infinity(&const_1) && is_infinity(&const_2))
|
||||||
&& let Some(local_snippet) = snippet_opt(cx, first.span)
|
&& let Some(local_snippet) = snippet_opt(cx, first.span)
|
||||||
{
|
{
|
||||||
let variant = match (kind.node, lhs_kind.node, rhs_kind.node) {
|
let variant = match (kind.node, lhs_kind.node, rhs_kind.node) {
|
||||||
|
@ -49,16 +49,14 @@
|
|||||||
|
|
||||||
impl<'tcx> QuestionMark {
|
impl<'tcx> QuestionMark {
|
||||||
pub(crate) fn check_manual_let_else(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) {
|
pub(crate) fn check_manual_let_else(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) {
|
||||||
if !self.msrv.meets(msrvs::LET_ELSE) || in_external_macro(cx.sess(), stmt.span) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let StmtKind::Let(local) = stmt.kind
|
if let StmtKind::Let(local) = stmt.kind
|
||||||
&& let Some(init) = local.init
|
&& let Some(init) = local.init
|
||||||
&& local.els.is_none()
|
&& local.els.is_none()
|
||||||
&& local.ty.is_none()
|
&& local.ty.is_none()
|
||||||
&& init.span.eq_ctxt(stmt.span)
|
&& init.span.eq_ctxt(stmt.span)
|
||||||
&& let Some(if_let_or_match) = IfLetOrMatch::parse(cx, init)
|
&& let Some(if_let_or_match) = IfLetOrMatch::parse(cx, init)
|
||||||
|
&& self.msrv.meets(msrvs::LET_ELSE)
|
||||||
|
&& !in_external_macro(cx.sess(), stmt.span)
|
||||||
{
|
{
|
||||||
match if_let_or_match {
|
match if_let_or_match {
|
||||||
IfLetOrMatch::IfLet(if_let_expr, let_pat, if_then, if_else, ..) => {
|
IfLetOrMatch::IfLet(if_let_expr, let_pat, if_then, if_else, ..) => {
|
||||||
|
@ -47,13 +47,13 @@ pub fn new(msrv: Msrv) -> Self {
|
|||||||
|
|
||||||
impl LateLintPass<'_> for ManualMainSeparatorStr {
|
impl LateLintPass<'_> for ManualMainSeparatorStr {
|
||||||
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
|
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||||
if self.msrv.meets(msrvs::PATH_MAIN_SEPARATOR_STR)
|
let (target, _) = peel_hir_expr_refs(expr);
|
||||||
&& let (target, _) = peel_hir_expr_refs(expr)
|
if let ExprKind::MethodCall(path, receiver, &[], _) = target.kind
|
||||||
&& is_trait_method(cx, target, sym::ToString)
|
|
||||||
&& let ExprKind::MethodCall(path, receiver, &[], _) = target.kind
|
|
||||||
&& path.ident.name == sym::to_string
|
&& path.ident.name == sym::to_string
|
||||||
&& let ExprKind::Path(QPath::Resolved(None, path)) = receiver.kind
|
&& let ExprKind::Path(QPath::Resolved(None, path)) = receiver.kind
|
||||||
&& let Res::Def(DefKind::Const, receiver_def_id) = path.res
|
&& let Res::Def(DefKind::Const, receiver_def_id) = path.res
|
||||||
|
&& is_trait_method(cx, target, sym::ToString)
|
||||||
|
&& self.msrv.meets(msrvs::PATH_MAIN_SEPARATOR_STR)
|
||||||
&& match_def_path(cx, receiver_def_id, &paths::PATH_MAIN_SEPARATOR)
|
&& match_def_path(cx, receiver_def_id, &paths::PATH_MAIN_SEPARATOR)
|
||||||
&& let ty::Ref(_, ty, Mutability::Not) = cx.typeck_results().expr_ty_adjusted(expr).kind()
|
&& let ty::Ref(_, ty, Mutability::Not) = cx.typeck_results().expr_ty_adjusted(expr).kind()
|
||||||
&& ty.is_str()
|
&& ty.is_str()
|
||||||
|
@ -97,19 +97,15 @@ pub fn new(msrv: Msrv) -> Self {
|
|||||||
|
|
||||||
impl EarlyLintPass for ManualNonExhaustiveStruct {
|
impl EarlyLintPass for ManualNonExhaustiveStruct {
|
||||||
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
|
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
|
||||||
if !self.msrv.meets(msrvs::NON_EXHAUSTIVE) {
|
if let ast::ItemKind::Struct(variant_data, _) = &item.kind
|
||||||
return;
|
&& let (fields, delimiter) = match variant_data {
|
||||||
}
|
|
||||||
|
|
||||||
if let ast::ItemKind::Struct(variant_data, _) = &item.kind {
|
|
||||||
let (fields, delimiter) = match variant_data {
|
|
||||||
ast::VariantData::Struct { fields, .. } => (&**fields, '{'),
|
ast::VariantData::Struct { fields, .. } => (&**fields, '{'),
|
||||||
ast::VariantData::Tuple(fields, _) => (&**fields, '('),
|
ast::VariantData::Tuple(fields, _) => (&**fields, '('),
|
||||||
ast::VariantData::Unit(_) => return,
|
ast::VariantData::Unit(_) => return,
|
||||||
};
|
|
||||||
if fields.len() <= 1 {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
&& fields.len() > 1
|
||||||
|
&& self.msrv.meets(msrvs::NON_EXHAUSTIVE)
|
||||||
|
{
|
||||||
let mut iter = fields.iter().filter_map(|f| match f.vis.kind {
|
let mut iter = fields.iter().filter_map(|f| match f.vis.kind {
|
||||||
VisibilityKind::Public => None,
|
VisibilityKind::Public => None,
|
||||||
VisibilityKind::Inherited => Some(Ok(f)),
|
VisibilityKind::Inherited => Some(Ok(f)),
|
||||||
|
@ -76,14 +76,11 @@ fn min(self, other: Self) -> Self {
|
|||||||
|
|
||||||
impl LateLintPass<'_> for ManualRangePatterns {
|
impl LateLintPass<'_> for ManualRangePatterns {
|
||||||
fn check_pat(&mut self, cx: &LateContext<'_>, pat: &'_ rustc_hir::Pat<'_>) {
|
fn check_pat(&mut self, cx: &LateContext<'_>, pat: &'_ rustc_hir::Pat<'_>) {
|
||||||
if in_external_macro(cx.sess(), pat.span) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// a pattern like 1 | 2 seems fine, lint if there are at least 3 alternatives
|
// a pattern like 1 | 2 seems fine, lint if there are at least 3 alternatives
|
||||||
// or at least one range
|
// or at least one range
|
||||||
if let PatKind::Or(pats) = pat.kind
|
if let PatKind::Or(pats) = pat.kind
|
||||||
&& (pats.len() >= 3 || pats.iter().any(|p| matches!(p.kind, PatKind::Range(..))))
|
&& (pats.len() >= 3 || pats.iter().any(|p| matches!(p.kind, PatKind::Range(..))))
|
||||||
|
&& !in_external_macro(cx.sess(), pat.span)
|
||||||
{
|
{
|
||||||
let mut min = Num::dummy(i128::MAX);
|
let mut min = Num::dummy(i128::MAX);
|
||||||
let mut max = Num::dummy(i128::MIN);
|
let mut max = Num::dummy(i128::MIN);
|
||||||
|
@ -48,35 +48,30 @@ pub fn new(msrv: Msrv) -> Self {
|
|||||||
|
|
||||||
impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid {
|
impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid {
|
||||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||||
if !self.msrv.meets(msrvs::REM_EUCLID) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if in_constant(cx, expr.hir_id) && !self.msrv.meets(msrvs::REM_EUCLID_CONST) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if in_external_macro(cx.sess(), expr.span) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// (x % c + c) % c
|
// (x % c + c) % c
|
||||||
if let ExprKind::Binary(op1, expr1, right) = expr.kind
|
if let ExprKind::Binary(rem_op, rem_lhs, rem_rhs) = expr.kind
|
||||||
&& op1.node == BinOpKind::Rem
|
&& rem_op.node == BinOpKind::Rem
|
||||||
|
&& let ExprKind::Binary(add_op, add_lhs, add_rhs) = rem_lhs.kind
|
||||||
|
&& add_op.node == BinOpKind::Add
|
||||||
&& let ctxt = expr.span.ctxt()
|
&& let ctxt = expr.span.ctxt()
|
||||||
&& expr1.span.ctxt() == ctxt
|
&& rem_lhs.span.ctxt() == ctxt
|
||||||
&& let Some(const1) = check_for_unsigned_int_constant(cx, right)
|
&& rem_rhs.span.ctxt() == ctxt
|
||||||
&& let ExprKind::Binary(op2, left, right) = expr1.kind
|
&& add_lhs.span.ctxt() == ctxt
|
||||||
&& op2.node == BinOpKind::Add
|
&& add_rhs.span.ctxt() == ctxt
|
||||||
&& let Some((const2, expr2)) = check_for_either_unsigned_int_constant(cx, left, right)
|
&& !in_external_macro(cx.sess(), expr.span)
|
||||||
&& expr2.span.ctxt() == ctxt
|
&& self.msrv.meets(msrvs::REM_EUCLID)
|
||||||
&& let ExprKind::Binary(op3, expr3, right) = expr2.kind
|
&& (self.msrv.meets(msrvs::REM_EUCLID_CONST) || !in_constant(cx, expr.hir_id))
|
||||||
&& op3.node == BinOpKind::Rem
|
&& let Some(const1) = check_for_unsigned_int_constant(cx, rem_rhs)
|
||||||
&& let Some(const3) = check_for_unsigned_int_constant(cx, right)
|
&& let Some((const2, add_other)) = check_for_either_unsigned_int_constant(cx, add_lhs, add_rhs)
|
||||||
|
&& let ExprKind::Binary(rem2_op, rem2_lhs, rem2_rhs) = add_other.kind
|
||||||
|
&& rem2_op.node == BinOpKind::Rem
|
||||||
|
&& const1 == const2
|
||||||
|
&& let Some(hir_id) = path_to_local(rem2_lhs)
|
||||||
|
&& let Some(const3) = check_for_unsigned_int_constant(cx, rem2_rhs)
|
||||||
// Also ensures the const is nonzero since zero can't be a divisor
|
// Also ensures the const is nonzero since zero can't be a divisor
|
||||||
&& const1 == const2 && const2 == const3
|
&& const2 == const3
|
||||||
&& let Some(hir_id) = path_to_local(expr3)
|
&& rem2_lhs.span.ctxt() == ctxt
|
||||||
&& let Node::Pat(_) = cx.tcx.hir_node(hir_id)
|
&& rem2_rhs.span.ctxt() == ctxt
|
||||||
{
|
{
|
||||||
// Apply only to params or locals with annotated types
|
// Apply only to params or locals with annotated types
|
||||||
match cx.tcx.parent_hir_node(hir_id) {
|
match cx.tcx.parent_hir_node(hir_id) {
|
||||||
@ -91,7 +86,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mut app = Applicability::MachineApplicable;
|
let mut app = Applicability::MachineApplicable;
|
||||||
let rem_of = snippet_with_context(cx, expr3.span, ctxt, "_", &mut app).0;
|
let rem_of = snippet_with_context(cx, rem2_lhs.span, ctxt, "_", &mut app).0;
|
||||||
span_lint_and_sugg(
|
span_lint_and_sugg(
|
||||||
cx,
|
cx,
|
||||||
MANUAL_REM_EUCLID,
|
MANUAL_REM_EUCLID,
|
||||||
|
@ -70,9 +70,8 @@ pub fn new(msrv: Msrv) -> Self {
|
|||||||
impl<'tcx> LateLintPass<'tcx> for ManualRetain {
|
impl<'tcx> LateLintPass<'tcx> for ManualRetain {
|
||||||
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 let Assign(left_expr, collect_expr, _) = &expr.kind
|
if let Assign(left_expr, collect_expr, _) = &expr.kind
|
||||||
&& let hir::ExprKind::MethodCall(seg, ..) = &collect_expr.kind
|
&& let hir::ExprKind::MethodCall(seg, target_expr, [], _) = &collect_expr.kind
|
||||||
&& seg.args.is_none()
|
&& 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)
|
&& 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)
|
&& cx.tcx.is_diagnostic_item(sym::iterator_collect_fn, collect_def_id)
|
||||||
{
|
{
|
||||||
|
@ -40,11 +40,11 @@
|
|||||||
|
|
||||||
impl<'tcx> LateLintPass<'tcx> for ManualSliceSizeCalculation {
|
impl<'tcx> LateLintPass<'tcx> for ManualSliceSizeCalculation {
|
||||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
|
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
|
||||||
// Does not apply inside const because size_of_val is not cost in stable.
|
if let ExprKind::Binary(ref op, left, right) = expr.kind
|
||||||
if !in_constant(cx, expr.hir_id)
|
|
||||||
&& let ExprKind::Binary(ref op, left, right) = expr.kind
|
|
||||||
&& BinOpKind::Mul == op.node
|
&& BinOpKind::Mul == op.node
|
||||||
&& !expr.span.from_expansion()
|
&& !expr.span.from_expansion()
|
||||||
|
// Does not apply inside const because size_of_val is not cost in stable.
|
||||||
|
&& !in_constant(cx, expr.hir_id)
|
||||||
&& let Some(receiver) = simplify(cx, left, right)
|
&& let Some(receiver) = simplify(cx, left, right)
|
||||||
{
|
{
|
||||||
let ctxt = expr.span.ctxt();
|
let ctxt = expr.span.ctxt();
|
||||||
|
@ -66,14 +66,11 @@ enum StripKind {
|
|||||||
|
|
||||||
impl<'tcx> LateLintPass<'tcx> for ManualStrip {
|
impl<'tcx> LateLintPass<'tcx> for ManualStrip {
|
||||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||||
if !self.msrv.meets(msrvs::STR_STRIP_PREFIX) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(higher::If { cond, then, .. }) = higher::If::hir(expr)
|
if let Some(higher::If { cond, then, .. }) = higher::If::hir(expr)
|
||||||
&& let ExprKind::MethodCall(_, target_arg, [pattern], _) = cond.kind
|
&& let ExprKind::MethodCall(_, target_arg, [pattern], _) = cond.kind
|
||||||
&& let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(cond.hir_id)
|
|
||||||
&& let ExprKind::Path(target_path) = &target_arg.kind
|
&& let ExprKind::Path(target_path) = &target_arg.kind
|
||||||
|
&& self.msrv.meets(msrvs::STR_STRIP_PREFIX)
|
||||||
|
&& let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(cond.hir_id)
|
||||||
{
|
{
|
||||||
let strip_kind = if match_def_path(cx, method_def_id, &paths::STR_STARTS_WITH) {
|
let strip_kind = if match_def_path(cx, method_def_id, &paths::STR_STARTS_WITH) {
|
||||||
StripKind::Prefix
|
StripKind::Prefix
|
||||||
|
@ -172,11 +172,10 @@ fn handle<'tcx>(cx: &LateContext<'tcx>, if_let_or_match: IfLetOrMatch<'tcx>, exp
|
|||||||
|
|
||||||
impl<'tcx> LateLintPass<'tcx> for ManualUnwrapOrDefault {
|
impl<'tcx> LateLintPass<'tcx> for ManualUnwrapOrDefault {
|
||||||
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 expr.span.from_expansion() || in_constant(cx, expr.hir_id) {
|
if let Some(if_let_or_match) = IfLetOrMatch::parse(cx, expr)
|
||||||
return;
|
&& !expr.span.from_expansion()
|
||||||
}
|
&& !in_constant(cx, expr.hir_id)
|
||||||
// Call handle only if the expression is `if let` or `match`
|
{
|
||||||
if let Some(if_let_or_match) = IfLetOrMatch::parse(cx, expr) {
|
|
||||||
handle(cx, if_let_or_match, expr);
|
handle(cx, if_let_or_match, expr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -253,14 +253,11 @@ fn lint_map_unit_fn(
|
|||||||
|
|
||||||
impl<'tcx> LateLintPass<'tcx> for MapUnit {
|
impl<'tcx> LateLintPass<'tcx> for MapUnit {
|
||||||
fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &hir::Stmt<'_>) {
|
fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &hir::Stmt<'_>) {
|
||||||
if stmt.span.from_expansion() {
|
if let hir::StmtKind::Semi(expr) = stmt.kind
|
||||||
return;
|
&& !stmt.span.from_expansion()
|
||||||
}
|
&& let Some(arglists) = method_chain_args(expr, &["map"])
|
||||||
|
{
|
||||||
if let hir::StmtKind::Semi(expr) = stmt.kind {
|
|
||||||
if let Some(arglists) = method_chain_args(expr, &["map"]) {
|
|
||||||
lint_map_unit_fn(cx, stmt, expr, arglists[0]);
|
lint_map_unit_fn(cx, stmt, expr, arglists[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
use rustc_lint::{LateContext, LateLintPass};
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
use rustc_session::declare_lint_pass;
|
use rustc_session::declare_lint_pass;
|
||||||
use rustc_span::sym;
|
use rustc_span::sym;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering::{Equal, Greater, Less};
|
||||||
|
|
||||||
declare_clippy_lint! {
|
declare_clippy_lint! {
|
||||||
/// ### What it does
|
/// ### What it does
|
||||||
@ -36,26 +36,21 @@
|
|||||||
|
|
||||||
impl<'tcx> LateLintPass<'tcx> for MinMaxPass {
|
impl<'tcx> LateLintPass<'tcx> for MinMaxPass {
|
||||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||||
if let Some((outer_max, outer_c, oe)) = min_max(cx, expr) {
|
if let Some((outer_max, outer_c, oe)) = min_max(cx, expr)
|
||||||
if let Some((inner_max, inner_c, ie)) = min_max(cx, oe) {
|
&& let Some((inner_max, inner_c, ie)) = min_max(cx, oe)
|
||||||
if outer_max == inner_max {
|
&& outer_max != inner_max
|
||||||
return;
|
&& let Some(ord) = Constant::partial_cmp(cx.tcx, cx.typeck_results().expr_ty(ie), &outer_c, &inner_c)
|
||||||
}
|
&& matches!(
|
||||||
match (
|
(outer_max, ord),
|
||||||
outer_max,
|
(MinMax::Max, Equal | Greater) | (MinMax::Min, Equal | Less)
|
||||||
Constant::partial_cmp(cx.tcx, cx.typeck_results().expr_ty(ie), &outer_c, &inner_c),
|
)
|
||||||
) {
|
{
|
||||||
(_, None) | (MinMax::Max, Some(Ordering::Less)) | (MinMax::Min, Some(Ordering::Greater)) => (),
|
|
||||||
_ => {
|
|
||||||
span_lint(
|
span_lint(
|
||||||
cx,
|
cx,
|
||||||
MIN_MAX,
|
MIN_MAX,
|
||||||
expr.span,
|
expr.span,
|
||||||
"this `min`/`max` combination leads to constant result",
|
"this `min`/`max` combination leads to constant result",
|
||||||
);
|
);
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user