mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-26 08:44:35 +00:00
Clean up after if chain removal
This commit is contained in:
parent
9681b4afe0
commit
13b4bb12ad
@ -14,7 +14,6 @@ cargo_metadata = "0.15.3"
|
||||
clippy_config = { path = "../clippy_config" }
|
||||
clippy_utils = { path = "../clippy_utils" }
|
||||
declare_clippy_lint = { path = "../declare_clippy_lint" }
|
||||
if_chain = "1.0"
|
||||
itertools = "0.10.1"
|
||||
quine-mc_cluskey = "0.2"
|
||||
regex-syntax = "0.7"
|
||||
|
@ -5,7 +5,6 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sug
|
||||
use clippy_utils::is_from_proc_macro;
|
||||
use clippy_utils::macros::{is_panic, macro_backtrace};
|
||||
use clippy_utils::source::{first_line_of_span, is_present_in_source, snippet_opt, without_block_comments};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::token::{Token, TokenKind};
|
||||
use rustc_ast::tokenstream::TokenTree;
|
||||
use rustc_ast::{
|
||||
|
@ -4,7 +4,6 @@ use clippy_utils::ty::implements_trait;
|
||||
use clippy_utils::visitors::{for_each_expr, Descend};
|
||||
use clippy_utils::{get_parent_expr, higher};
|
||||
use core::ops::ControlFlow;
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BlockCheckMode, Expr, ExprKind};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
|
@ -2,7 +2,6 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
|
||||
use clippy_utils::eq_expr_value;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::LitKind;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
|
||||
|
@ -54,25 +54,25 @@ impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef {
|
||||
&& !addrof_target.span.from_expansion()
|
||||
&& let ExprKind::Unary(UnOp::Deref, deref_target) = addrof_target.kind
|
||||
&& !deref_target.span.from_expansion()
|
||||
&& !matches!(deref_target.kind, ExprKind::Unary(UnOp::Deref, ..) )
|
||||
&& !matches!(deref_target.kind, ExprKind::Unary(UnOp::Deref, ..))
|
||||
&& let ref_ty = cx.typeck_results().expr_ty(deref_target)
|
||||
&& let ty::Ref(_, inner_ty, Mutability::Not) = ref_ty.kind()
|
||||
&& !is_from_proc_macro(cx, e)
|
||||
{
|
||||
|
||||
if let Some(parent_expr) = get_parent_expr(cx, e){
|
||||
if matches!(parent_expr.kind, ExprKind::Unary(UnOp::Deref, ..)) &&
|
||||
!is_lint_allowed(cx, DEREF_ADDROF, parent_expr.hir_id) {
|
||||
if let Some(parent_expr) = get_parent_expr(cx, e) {
|
||||
if matches!(parent_expr.kind, ExprKind::Unary(UnOp::Deref, ..))
|
||||
&& !is_lint_allowed(cx, DEREF_ADDROF, parent_expr.hir_id)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// modification to `&mut &*x` is different from `&mut x`
|
||||
if matches!(deref_target.kind, ExprKind::Path(..)
|
||||
| ExprKind::Field(..)
|
||||
| ExprKind::Index(..)
|
||||
| ExprKind::Unary(UnOp::Deref, ..))
|
||||
&& matches!(parent_expr.kind, ExprKind::AddrOf(_, Mutability::Mut, _)) {
|
||||
return;
|
||||
if matches!(
|
||||
deref_target.kind,
|
||||
ExprKind::Path(..) | ExprKind::Field(..) | ExprKind::Index(..) | ExprKind::Unary(UnOp::Deref, ..)
|
||||
) && matches!(parent_expr.kind, ExprKind::AddrOf(_, Mutability::Mut, _))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -86,12 +86,12 @@ impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef {
|
||||
e.span,
|
||||
"if you would like to reborrow, try removing `&*`",
|
||||
snippet_opt(cx, deref_target.span).unwrap(),
|
||||
Applicability::MachineApplicable
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
|
||||
// has deref trait -> give 2 help
|
||||
// doesn't have deref trait -> give 1 help
|
||||
if let Some(deref_trait_id) = cx.tcx.lang_items().deref_trait(){
|
||||
if let Some(deref_trait_id) = cx.tcx.lang_items().deref_trait() {
|
||||
if !implements_trait(cx, *inner_ty, deref_trait_id, &[]) {
|
||||
return;
|
||||
}
|
||||
@ -100,16 +100,11 @@ impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef {
|
||||
diag.span_suggestion(
|
||||
e.span,
|
||||
"if you would like to deref, try using `&**`",
|
||||
format!(
|
||||
"&**{}",
|
||||
&snippet_opt(cx, deref_target.span).unwrap(),
|
||||
),
|
||||
Applicability::MaybeIncorrect
|
||||
format!("&**{}", &snippet_opt(cx, deref_target.span).unwrap()),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
use cargo_metadata::{DependencyKind, Metadata, Node, Package, PackageId};
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use if_chain::if_chain;
|
||||
use itertools::Itertools;
|
||||
use rustc_hir::def_id::LOCAL_CRATE;
|
||||
use rustc_lint::LateContext;
|
||||
@ -16,9 +15,13 @@ pub(super) fn check(cx: &LateContext<'_>, metadata: &Metadata) {
|
||||
packages.sort_by(|a, b| a.name.cmp(&b.name));
|
||||
|
||||
if let Some(resolve) = &metadata.resolve
|
||||
&& let Some(local_id) = packages
|
||||
.iter()
|
||||
.find_map(|p| if p.name == local_name.as_str() { Some(&p.id) } else { None })
|
||||
&& let Some(local_id) = packages.iter().find_map(|p| {
|
||||
if p.name == local_name.as_str() {
|
||||
Some(&p.id)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
{
|
||||
for (name, group) in &packages.iter().group_by(|p| p.name.clone()) {
|
||||
let group: Vec<&Package> = group.collect();
|
||||
|
@ -1,6 +1,5 @@
|
||||
use cargo_metadata::Metadata;
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use if_chain::if_chain;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::source_map::DUMMY_SP;
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
use clippy_utils::consts::{constant, Constant};
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::{method_chain_args, sext};
|
||||
use if_chain::if_chain;
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
|
@ -1,7 +1,6 @@
|
||||
use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::source;
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::Mutability;
|
||||
use rustc_hir::{Expr, ExprKind, Node};
|
||||
use rustc_lint::LateContext;
|
||||
|
@ -1,7 +1,6 @@
|
||||
use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
@ -37,7 +36,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
|
||||
{
|
||||
let func = match rpk {
|
||||
RawPartsKind::Immutable => "from_raw_parts",
|
||||
RawPartsKind::Mutable => "from_raw_parts_mut"
|
||||
RawPartsKind::Mutable => "from_raw_parts_mut",
|
||||
};
|
||||
let span = expr.span;
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
@ -50,7 +49,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
|
||||
&format!("casting the result of `{func}` to {cast_to}"),
|
||||
"replace with",
|
||||
format!("core::ptr::slice_{func}({ptr}, {len})"),
|
||||
applicability
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::LitKind;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
@ -34,6 +33,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, Mutability};
|
||||
use rustc_lint::LateContext;
|
||||
@ -18,10 +17,18 @@ 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()
|
||||
&& matches!((from_mutbl, to_mutbl),
|
||||
(Mutability::Not, Mutability::Mut) | (Mutability::Mut, Mutability::Not))
|
||||
&& 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()
|
||||
&& matches!(
|
||||
(from_mutbl, to_mutbl),
|
||||
(Mutability::Not, Mutability::Mut) | (Mutability::Mut, Mutability::Not)
|
||||
)
|
||||
&& from_ty == to_ty
|
||||
{
|
||||
let sugg = Sugg::hir(cx, cast_expr, "_");
|
||||
|
@ -3,7 +3,6 @@ use clippy_utils::numeric_literal::NumericLiteral;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::visitors::{for_each_expr, Visitable};
|
||||
use clippy_utils::{get_parent_expr, get_parent_node, is_hir_ty_cfg_dependant, is_ty_alias, path_to_local};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::{LitFloatType, LitIntType, LitKind};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
@ -52,7 +51,9 @@ pub(super) fn check<'tcx>(
|
||||
cx,
|
||||
UNNECESSARY_CAST,
|
||||
expr.span,
|
||||
&format!("casting raw pointers to the same type and constness is unnecessary (`{cast_from}` -> `{cast_to}`)"),
|
||||
&format!(
|
||||
"casting raw pointers to the same type and constness is unnecessary (`{cast_from}` -> `{cast_to}`)"
|
||||
),
|
||||
"try",
|
||||
cast_str.clone(),
|
||||
Applicability::MaybeIncorrect,
|
||||
@ -87,8 +88,8 @@ pub(super) fn check<'tcx>(
|
||||
if let ExprKind::Cast(_, cast_to) = expr.kind
|
||||
&& let TyKind::Path(QPath::Resolved(_, path)) = &cast_to.kind
|
||||
&& let Res::PrimTy(_) = path.res
|
||||
{}
|
||||
else {
|
||||
{
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -108,10 +109,13 @@ pub(super) fn check<'tcx>(
|
||||
&& let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node)
|
||||
&& let from_nbits = 128 - n.leading_zeros()
|
||||
&& let to_nbits = fp_ty_mantissa_nbits(cast_to)
|
||||
&& from_nbits != 0 && to_nbits != 0 && from_nbits <= to_nbits && num_lit.is_decimal()
|
||||
&& from_nbits != 0
|
||||
&& to_nbits != 0
|
||||
&& from_nbits <= to_nbits
|
||||
&& num_lit.is_decimal()
|
||||
{
|
||||
lint_unnecessary_cast(cx, expr, num_lit.integer, cast_from, cast_to);
|
||||
return true
|
||||
return true;
|
||||
}
|
||||
|
||||
match lit.node {
|
||||
|
@ -4,7 +4,6 @@ use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::{in_constant, is_integer_literal, SpanlessEq};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind, QPath, TyKind};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
@ -58,7 +57,6 @@ impl<'tcx> LateLintPass<'tcx> for CheckedConversions {
|
||||
let result = if !in_constant(cx, item.hir_id)
|
||||
&& !in_external_macro(cx.sess(), item.span)
|
||||
&& let ExprKind::Binary(op, left, right) = &item.kind
|
||||
|
||||
{
|
||||
match op.node {
|
||||
BinOpKind::Ge | BinOpKind::Le => single_check(item),
|
||||
@ -192,12 +190,11 @@ impl ConversionType {
|
||||
/// Check for `expr <= (to_type::MAX as from_type)`
|
||||
fn check_upper_bound<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<Conversion<'tcx>> {
|
||||
if let ExprKind::Binary(ref op, left, right) = &expr.kind
|
||||
&& let Some((candidate, check)) = normalize_le_ge(op, left, right)
|
||||
&& let Some((from, to)) = get_types_from_cast(check, INTS, "max_value", "MAX")
|
||||
|
||||
{
|
||||
Conversion::try_new(candidate, from, to)
|
||||
} else {
|
||||
&& let Some((candidate, check)) = normalize_le_ge(op, left, right)
|
||||
&& let Some((from, to)) = get_types_from_cast(check, INTS, "max_value", "MAX")
|
||||
{
|
||||
Conversion::try_new(candidate, from, to)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
@ -243,7 +240,6 @@ fn get_types_from_cast<'a>(
|
||||
// to_type::max_value(), from_type
|
||||
&& let TyKind::Path(ref from_type_path) = &from_type.kind
|
||||
&& let Some(from_sym) = int_ty_to_sym(from_type_path)
|
||||
|
||||
{
|
||||
Some((limit, from_sym))
|
||||
} else {
|
||||
@ -257,7 +253,6 @@ fn get_types_from_cast<'a>(
|
||||
// `from_type::from`
|
||||
&& let ExprKind::Path(ref path) = &from_func.kind
|
||||
&& let Some(from_sym) = get_implementing_type(path, INTS, "from")
|
||||
|
||||
{
|
||||
Some((limit, from_sym))
|
||||
} else {
|
||||
|
@ -15,7 +15,6 @@
|
||||
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
|
||||
use clippy_utils::source::{snippet, snippet_block, snippet_block_with_applicability};
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass};
|
||||
@ -131,7 +130,11 @@ fn check_collapsible_maybe_if_let(cx: &EarlyContext<'_>, then_span: Span, else_:
|
||||
// Prevent "elseif"
|
||||
// Check that the "else" is followed by whitespace
|
||||
let up_to_else = then_span.between(block.span);
|
||||
let requires_space = if let Some(c) = snippet(cx, up_to_else, "..").chars().last() { !c.is_whitespace() } else { false };
|
||||
let requires_space = if let Some(c) = snippet(cx, up_to_else, "..").chars().last() {
|
||||
!c.is_whitespace()
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
span_lint_and_sugg(
|
||||
@ -160,21 +163,27 @@ fn check_collapsible_no_if_let(cx: &EarlyContext<'_>, expr: &ast::Expr, check: &
|
||||
&& let ctxt = expr.span.ctxt()
|
||||
&& inner.span.ctxt() == ctxt
|
||||
{
|
||||
span_lint_and_then(cx, COLLAPSIBLE_IF, expr.span, "this `if` statement can be collapsed", |diag| {
|
||||
let mut app = Applicability::MachineApplicable;
|
||||
let lhs = Sugg::ast(cx, check, "..", ctxt, &mut app);
|
||||
let rhs = Sugg::ast(cx, check_inner, "..", ctxt, &mut app);
|
||||
diag.span_suggestion(
|
||||
expr.span,
|
||||
"collapse nested if block",
|
||||
format!(
|
||||
"if {} {}",
|
||||
lhs.and(&rhs),
|
||||
snippet_block(cx, content.span, "..", Some(expr.span)),
|
||||
),
|
||||
app, // snippet
|
||||
);
|
||||
});
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
COLLAPSIBLE_IF,
|
||||
expr.span,
|
||||
"this `if` statement can be collapsed",
|
||||
|diag| {
|
||||
let mut app = Applicability::MachineApplicable;
|
||||
let lhs = Sugg::ast(cx, check, "..", ctxt, &mut app);
|
||||
let rhs = Sugg::ast(cx, check_inner, "..", ctxt, &mut app);
|
||||
diag.span_suggestion(
|
||||
expr.span,
|
||||
"collapse nested if block",
|
||||
format!(
|
||||
"if {} {}",
|
||||
lhs.and(&rhs),
|
||||
snippet_block(cx, content.span, "..", Some(expr.span)),
|
||||
),
|
||||
app, // snippet
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,8 +5,6 @@ use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::sym;
|
||||
|
||||
use if_chain::if_chain;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for types that implement `Copy` as well as
|
||||
@ -39,9 +37,9 @@ declare_lint_pass!(CopyIterator => [COPY_ITERATOR]);
|
||||
impl<'tcx> LateLintPass<'tcx> for CopyIterator {
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
|
||||
if let ItemKind::Impl(Impl {
|
||||
of_trait: Some(ref trait_ref),
|
||||
..
|
||||
}) = item.kind
|
||||
of_trait: Some(ref trait_ref),
|
||||
..
|
||||
}) = item.kind
|
||||
&& let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
|
||||
&& is_copy(cx, ty)
|
||||
&& let Some(trait_id) = trait_ref.trait_def_id()
|
||||
|
@ -104,9 +104,19 @@ fn contains_unhygienic_crate_reference(tts: &TokenStream) -> Option<Span> {
|
||||
}
|
||||
|
||||
fn is_crate_keyword(tt: &TokenTree) -> Option<Span> {
|
||||
if let TokenTree::Token(Token { kind: TokenKind::Ident(symbol, _), span }, _) = tt
|
||||
if let TokenTree::Token(
|
||||
Token {
|
||||
kind: TokenKind::Ident(symbol, _),
|
||||
span,
|
||||
},
|
||||
_,
|
||||
) = tt
|
||||
&& symbol.as_str() == "crate"
|
||||
{ Some(*span) } else { None }
|
||||
{
|
||||
Some(*span)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn is_token(tt: &TokenTree, kind: &TokenKind) -> bool {
|
||||
|
@ -1,6 +1,5 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet;
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
@ -46,7 +45,7 @@ impl LateLintPass<'_> for CreateDir {
|
||||
"consider calling `std::fs::create_dir_all` instead",
|
||||
format!("create_dir_all({})", snippet(cx, arg.span, "..")),
|
||||
Applicability::MaybeIncorrect,
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,8 +10,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
||||
#[cfg(feature = "internal")]
|
||||
crate::utils::internal_lints::compiler_lint_functions::COMPILER_LINT_FUNCTIONS_INFO,
|
||||
#[cfg(feature = "internal")]
|
||||
crate::utils::internal_lints::if_chain_style::IF_CHAIN_STYLE_INFO,
|
||||
#[cfg(feature = "internal")]
|
||||
crate::utils::internal_lints::interning_defined_symbol::INTERNING_DEFINED_SYMBOL_INFO,
|
||||
#[cfg(feature = "internal")]
|
||||
crate::utils::internal_lints::interning_defined_symbol::UNNECESSARY_SYMBOL_STR_INFO,
|
||||
|
@ -2,7 +2,6 @@ use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg};
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
use clippy_utils::ty::{has_drop, is_copy};
|
||||
use clippy_utils::{any_parent_is_automatically_derived, contains_name, get_parent_expr, is_from_proc_macro};
|
||||
use if_chain::if_chain;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::Res;
|
||||
|
@ -79,7 +79,7 @@ impl LateLintPass<'_> for DefaultConstructedUnitStructs {
|
||||
"remove this call to `default`",
|
||||
String::new(),
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
use clippy_utils::diagnostics::span_lint_hir_and_then;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::{get_parent_node, numeric_literal};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::{LitFloatType, LitIntType, LitKind};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::intravisit::{walk_expr, walk_stmt, Visitor};
|
||||
@ -83,38 +82,40 @@ impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> {
|
||||
/// Check whether a passed literal has potential to cause fallback or not.
|
||||
fn check_lit(&self, lit: &Lit, lit_ty: Ty<'tcx>, emit_hir_id: HirId) {
|
||||
if !in_external_macro(self.cx.sess(), lit.span)
|
||||
&& matches!(self.ty_bounds.last(), Some(ExplicitTyBound(false)))
|
||||
&& matches!(lit.node,
|
||||
LitKind::Int(_, LitIntType::Unsuffixed) | LitKind::Float(_, LitFloatType::Unsuffixed))
|
||||
{
|
||||
let (suffix, is_float) = match lit_ty.kind() {
|
||||
ty::Int(IntTy::I32) => ("i32", false),
|
||||
ty::Float(FloatTy::F64) => ("f64", true),
|
||||
// Default numeric fallback never results in other types.
|
||||
_ => return,
|
||||
};
|
||||
&& matches!(self.ty_bounds.last(), Some(ExplicitTyBound(false)))
|
||||
&& matches!(
|
||||
lit.node,
|
||||
LitKind::Int(_, LitIntType::Unsuffixed) | LitKind::Float(_, LitFloatType::Unsuffixed)
|
||||
)
|
||||
{
|
||||
let (suffix, is_float) = match lit_ty.kind() {
|
||||
ty::Int(IntTy::I32) => ("i32", false),
|
||||
ty::Float(FloatTy::F64) => ("f64", true),
|
||||
// Default numeric fallback never results in other types.
|
||||
_ => return,
|
||||
};
|
||||
|
||||
let src = if let Some(src) = snippet_opt(self.cx, lit.span) {
|
||||
src
|
||||
} else {
|
||||
match lit.node {
|
||||
LitKind::Int(src, _) => format!("{src}"),
|
||||
LitKind::Float(src, _) => format!("{src}"),
|
||||
_ => return,
|
||||
}
|
||||
};
|
||||
let sugg = numeric_literal::format(&src, Some(suffix), is_float);
|
||||
span_lint_hir_and_then(
|
||||
self.cx,
|
||||
DEFAULT_NUMERIC_FALLBACK,
|
||||
emit_hir_id,
|
||||
lit.span,
|
||||
"default numeric fallback might occur",
|
||||
|diag| {
|
||||
diag.span_suggestion(lit.span, "consider adding suffix", sugg, Applicability::MaybeIncorrect);
|
||||
}
|
||||
);
|
||||
}
|
||||
let src = if let Some(src) = snippet_opt(self.cx, lit.span) {
|
||||
src
|
||||
} else {
|
||||
match lit.node {
|
||||
LitKind::Int(src, _) => format!("{src}"),
|
||||
LitKind::Float(src, _) => format!("{src}"),
|
||||
_ => return,
|
||||
}
|
||||
};
|
||||
let sugg = numeric_literal::format(&src, Some(suffix), is_float);
|
||||
span_lint_hir_and_then(
|
||||
self.cx,
|
||||
DEFAULT_NUMERIC_FALLBACK,
|
||||
emit_hir_id,
|
||||
lit.span,
|
||||
"default numeric fallback might occur",
|
||||
|diag| {
|
||||
diag.span_suggestion(lit.span, "consider adding suffix", sugg, Applicability::MaybeIncorrect);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -155,14 +156,13 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
|
||||
|
||||
// Push field type then visit each field expr.
|
||||
for field in *fields {
|
||||
let bound =
|
||||
fields_def
|
||||
.iter()
|
||||
.find_map(|f_def| {
|
||||
if f_def.ident(self.cx.tcx) == field.ident
|
||||
{ Some(self.cx.tcx.type_of(f_def.did).instantiate_identity()) }
|
||||
else { None }
|
||||
});
|
||||
let bound = fields_def.iter().find_map(|f_def| {
|
||||
if f_def.ident(self.cx.tcx) == field.ident {
|
||||
Some(self.cx.tcx.type_of(f_def.did).instantiate_identity())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
self.ty_bounds.push(bound.into());
|
||||
self.visit_expr(field.expr);
|
||||
self.ty_bounds.pop();
|
||||
|
@ -154,55 +154,42 @@ fn check_enum<'tcx>(cx: &LateContext<'tcx>, item: &'tcx Item<'_>, func_expr: &Ex
|
||||
&& let Some(variant_def) = adt_def.variants().iter().find(|v| v.def_id == variant_id)
|
||||
&& variant_def.fields.is_empty()
|
||||
&& !variant_def.is_field_list_non_exhaustive()
|
||||
|
||||
{
|
||||
let enum_span = cx.tcx.def_span(adt_def.did());
|
||||
let indent_enum = indent_of(cx, enum_span).unwrap_or(0);
|
||||
let variant_span = cx.tcx.def_span(variant_def.def_id);
|
||||
let indent_variant = indent_of(cx, variant_span).unwrap_or(0);
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
DERIVABLE_IMPLS,
|
||||
item.span,
|
||||
"this `impl` can be derived",
|
||||
|diag| {
|
||||
diag.span_suggestion_hidden(
|
||||
item.span,
|
||||
"remove the manual implementation...",
|
||||
String::new(),
|
||||
Applicability::MachineApplicable
|
||||
);
|
||||
diag.span_suggestion(
|
||||
enum_span.shrink_to_lo(),
|
||||
"...and instead derive it...",
|
||||
format!(
|
||||
"#[derive(Default)]\n{indent}",
|
||||
indent = " ".repeat(indent_enum),
|
||||
),
|
||||
Applicability::MachineApplicable
|
||||
);
|
||||
diag.span_suggestion(
|
||||
variant_span.shrink_to_lo(),
|
||||
"...and mark the default variant",
|
||||
format!(
|
||||
"#[default]\n{indent}",
|
||||
indent = " ".repeat(indent_variant),
|
||||
),
|
||||
Applicability::MachineApplicable
|
||||
);
|
||||
}
|
||||
);
|
||||
span_lint_and_then(cx, DERIVABLE_IMPLS, item.span, "this `impl` can be derived", |diag| {
|
||||
diag.span_suggestion_hidden(
|
||||
item.span,
|
||||
"remove the manual implementation...",
|
||||
String::new(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
diag.span_suggestion(
|
||||
enum_span.shrink_to_lo(),
|
||||
"...and instead derive it...",
|
||||
format!("#[derive(Default)]\n{indent}", indent = " ".repeat(indent_enum),),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
diag.span_suggestion(
|
||||
variant_span.shrink_to_lo(),
|
||||
"...and mark the default variant",
|
||||
format!("#[default]\n{indent}", indent = " ".repeat(indent_variant),),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for DerivableImpls {
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
|
||||
if let ItemKind::Impl(Impl {
|
||||
of_trait: Some(ref trait_ref),
|
||||
items: [child],
|
||||
self_ty,
|
||||
..
|
||||
}) = item.kind
|
||||
of_trait: Some(ref trait_ref),
|
||||
items: [child],
|
||||
self_ty,
|
||||
..
|
||||
}) = item.kind
|
||||
&& !cx.tcx.has_attr(item.owner_id, sym::automatically_derived)
|
||||
&& !item.span.from_expansion()
|
||||
&& let Some(def_id) = trait_ref.trait_def_id()
|
||||
@ -215,7 +202,6 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls {
|
||||
&& let attrs = cx.tcx.hir().attrs(item.hir_id())
|
||||
&& !attrs.iter().any(|attr| attr.doc_str().is_some())
|
||||
&& cx.tcx.hir().attrs(impl_item_hir).is_empty()
|
||||
|
||||
{
|
||||
if adt_def.is_struct() {
|
||||
check_struct(cx, item, self_ty, func_expr, adt_def, args, cx.tcx.typeck_body(*b));
|
||||
|
@ -1,7 +1,6 @@
|
||||
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then};
|
||||
use clippy_utils::ty::{implements_trait, implements_trait_with_env, is_copy};
|
||||
use clippy_utils::{is_lint_allowed, match_def_path, paths};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, Visitor};
|
||||
@ -258,12 +257,9 @@ fn check_hash_peq<'tcx>(
|
||||
|diag| {
|
||||
if let Some(local_def_id) = impl_id.as_local() {
|
||||
let hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_def_id);
|
||||
diag.span_note(
|
||||
cx.tcx.hir().span(hir_id),
|
||||
"`PartialEq` implemented here"
|
||||
);
|
||||
diag.span_note(cx.tcx.hir().span(hir_id), "`PartialEq` implemented here");
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
});
|
||||
@ -302,21 +298,12 @@ fn check_ord_partial_ord<'tcx>(
|
||||
"you are deriving `Ord` but have implemented `PartialOrd` explicitly"
|
||||
};
|
||||
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
DERIVE_ORD_XOR_PARTIAL_ORD,
|
||||
span,
|
||||
mess,
|
||||
|diag| {
|
||||
if let Some(local_def_id) = impl_id.as_local() {
|
||||
let hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_def_id);
|
||||
diag.span_note(
|
||||
cx.tcx.hir().span(hir_id),
|
||||
"`PartialOrd` implemented here"
|
||||
);
|
||||
}
|
||||
span_lint_and_then(cx, DERIVE_ORD_XOR_PARTIAL_ORD, span, mess, |diag| {
|
||||
if let Some(local_def_id) = impl_id.as_local() {
|
||||
let hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_def_id);
|
||||
diag.span_note(cx.tcx.hir().span(hir_id), "`PartialOrd` implemented here");
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -397,7 +384,9 @@ fn check_unsafe_derive_deserialize<'tcx>(
|
||||
&& let Some(local_def_id) = def.did().as_local()
|
||||
&& let adt_hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_def_id)
|
||||
&& !is_lint_allowed(cx, UNSAFE_DERIVE_DESERIALIZE, adt_hir_id)
|
||||
&& cx.tcx.inherent_impls(def.did())
|
||||
&& cx
|
||||
.tcx
|
||||
.inherent_impls(def.did())
|
||||
.iter()
|
||||
.map(|imp_did| cx.tcx.hir().expect_item(imp_did.expect_local()))
|
||||
.any(|imp| has_unsafe(cx, imp))
|
||||
@ -408,7 +397,7 @@ fn check_unsafe_derive_deserialize<'tcx>(
|
||||
item.span,
|
||||
"you are deriving `serde::Deserialize` on a type that has methods using `unsafe`",
|
||||
None,
|
||||
"consider implementing `serde::Deserialize` manually. See https://serde.rs/impl-deserialize.html"
|
||||
"consider implementing `serde::Deserialize` manually. See https://serde.rs/impl-deserialize.html",
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -477,7 +466,7 @@ fn check_partial_eq_without_eq<'tcx>(cx: &LateContext<'tcx>, span: Span, trait_r
|
||||
"consider deriving `Eq` as well",
|
||||
"PartialEq, Eq".to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,6 @@ use clippy_utils::macros::{is_panic, root_macro_call_first_node};
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
|
||||
use clippy_utils::{is_entrypoint_fn, method_chain_args, return_ty};
|
||||
use if_chain::if_chain;
|
||||
use pulldown_cmark::Event::{
|
||||
Code, End, FootnoteReference, HardBreak, Html, Rule, SoftBreak, Start, TaskListMarker, Text,
|
||||
};
|
||||
@ -428,23 +427,21 @@ fn lint_for_missing_headers(
|
||||
span,
|
||||
"docs for function returning `Result` missing `# Errors` section",
|
||||
);
|
||||
} else {
|
||||
if let Some(body_id) = body_id
|
||||
&& let Some(future) = cx.tcx.lang_items().future_trait()
|
||||
&& let typeck = cx.tcx.typeck_body(body_id)
|
||||
&& let body = cx.tcx.hir().body(body_id)
|
||||
&& let ret_ty = typeck.expr_ty(body.value)
|
||||
&& implements_trait(cx, ret_ty, future, &[])
|
||||
&& let ty::Coroutine(_, subs, _) = ret_ty.kind()
|
||||
&& is_type_diagnostic_item(cx, subs.as_coroutine().return_ty(), sym::Result)
|
||||
{
|
||||
span_lint(
|
||||
cx,
|
||||
MISSING_ERRORS_DOC,
|
||||
span,
|
||||
"docs for function returning `Result` missing `# Errors` section",
|
||||
);
|
||||
}
|
||||
} else if let Some(body_id) = body_id
|
||||
&& let Some(future) = cx.tcx.lang_items().future_trait()
|
||||
&& let typeck = cx.tcx.typeck_body(body_id)
|
||||
&& let body = cx.tcx.hir().body(body_id)
|
||||
&& let ret_ty = typeck.expr_ty(body.value)
|
||||
&& implements_trait(cx, ret_ty, future, &[])
|
||||
&& let ty::Coroutine(_, subs, _) = ret_ty.kind()
|
||||
&& is_type_diagnostic_item(cx, subs.as_coroutine().return_ty(), sym::Result)
|
||||
{
|
||||
span_lint(
|
||||
cx,
|
||||
MISSING_ERRORS_DOC,
|
||||
span,
|
||||
"docs for function returning `Result` missing `# Errors` section",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::peel_blocks;
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Body, ExprKind, Impl, ImplItemKind, Item, ItemKind, Node};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
@ -37,10 +36,10 @@ declare_lint_pass!(EmptyDrop => [EMPTY_DROP]);
|
||||
impl LateLintPass<'_> for EmptyDrop {
|
||||
fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
|
||||
if let ItemKind::Impl(Impl {
|
||||
of_trait: Some(ref trait_ref),
|
||||
items: [child],
|
||||
..
|
||||
}) = item.kind
|
||||
of_trait: Some(ref trait_ref),
|
||||
items: [child],
|
||||
..
|
||||
}) = item.kind
|
||||
&& trait_ref.trait_def_id() == cx.tcx.lang_items().drop_trait()
|
||||
&& let impl_item_hir = child.id.hir_id()
|
||||
&& let Some(Node::ImplItem(impl_item)) = cx.tcx.hir().find(impl_item_hir)
|
||||
@ -48,7 +47,8 @@ impl LateLintPass<'_> for EmptyDrop {
|
||||
&& let Body { value: func_expr, .. } = cx.tcx.hir().body(*b)
|
||||
&& let func_expr = peel_blocks(func_expr)
|
||||
&& let ExprKind::Block(block, _) = func_expr.kind
|
||||
&& block.stmts.is_empty() && block.expr.is_none()
|
||||
&& block.stmts.is_empty()
|
||||
&& block.expr.is_none()
|
||||
{
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
@ -57,7 +57,7 @@ impl LateLintPass<'_> for EmptyDrop {
|
||||
"empty drop implementation",
|
||||
"try removing this impl",
|
||||
String::new(),
|
||||
Applicability::MaybeIncorrect
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::source::indent_of;
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Item, ItemKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
@ -77,9 +76,7 @@ impl LateLintPass<'_> for ExhaustiveItems {
|
||||
&& !attrs.iter().any(|a| a.has_name(sym::non_exhaustive))
|
||||
{
|
||||
let (lint, msg) = if let ItemKind::Struct(ref v, ..) = item.kind {
|
||||
if v.fields().iter().any(|f| {
|
||||
!cx.tcx.visibility(f.def_id).is_public()
|
||||
}) {
|
||||
if v.fields().iter().any(|f| !cx.tcx.visibility(f.def_id).is_public()) {
|
||||
// skip structs with private fields
|
||||
return;
|
||||
}
|
||||
@ -89,20 +86,15 @@ impl LateLintPass<'_> for ExhaustiveItems {
|
||||
};
|
||||
let suggestion_span = item.span.shrink_to_lo();
|
||||
let indent = " ".repeat(indent_of(cx, item.span).unwrap_or(0));
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
lint,
|
||||
item.span,
|
||||
msg,
|
||||
|diag| {
|
||||
let sugg = format!("#[non_exhaustive]\n{indent}");
|
||||
diag.span_suggestion(suggestion_span,
|
||||
"try adding #[non_exhaustive]",
|
||||
sugg,
|
||||
Applicability::MaybeIncorrect);
|
||||
}
|
||||
);
|
||||
|
||||
span_lint_and_then(cx, lint, item.span, msg, |diag| {
|
||||
let sugg = format!("#[non_exhaustive]\n{indent}");
|
||||
diag.span_suggestion(
|
||||
suggestion_span,
|
||||
"try adding #[non_exhaustive]",
|
||||
sugg,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::is_entrypoint_fn;
|
||||
use if_chain::if_chain;
|
||||
use rustc_hir::{Expr, ExprKind, Item, ItemKind, Node};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
|
@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::macros::{find_format_args, format_args_inputs_span};
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::{is_expn_of, path_def_id};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::{BindingAnnotation, Block, BlockCheckMode, Expr, ExprKind, Node, PatKind, QPath, Stmt, StmtKind};
|
||||
|
@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::macros::{is_panic, root_macro_call_first_node};
|
||||
use clippy_utils::method_chain_args;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use if_chain::if_chain;
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty;
|
||||
@ -55,7 +54,9 @@ impl<'tcx> LateLintPass<'tcx> for FallibleImplFrom {
|
||||
// check for `impl From<???> for ..`
|
||||
if let hir::ItemKind::Impl(impl_) = &item.kind
|
||||
&& let Some(impl_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id)
|
||||
&& cx.tcx.is_diagnostic_item(sym::From, impl_trait_ref.skip_binder().def_id)
|
||||
&& cx
|
||||
.tcx
|
||||
.is_diagnostic_item(sym::From, impl_trait_ref.skip_binder().def_id)
|
||||
{
|
||||
lint_impl_body(cx, item.span, impl_.items);
|
||||
}
|
||||
@ -97,8 +98,7 @@ fn lint_impl_body(cx: &LateContext<'_>, impl_span: Span, impl_items: &[hir::Impl
|
||||
|
||||
for impl_item in impl_items {
|
||||
if impl_item.ident.name == sym::from
|
||||
&& let ImplItemKind::Fn(_, body_id) =
|
||||
cx.tcx.hir().impl_item(impl_item.id).kind
|
||||
&& let ImplItemKind::Fn(_, body_id) = cx.tcx.hir().impl_item(impl_item.id).kind
|
||||
{
|
||||
// check the body for `begin_panic` or `unwrap`
|
||||
let body = cx.tcx.hir().body(body_id);
|
||||
@ -119,9 +119,11 @@ fn lint_impl_body(cx: &LateContext<'_>, impl_span: Span, impl_items: &[hir::Impl
|
||||
move |diag| {
|
||||
diag.help(
|
||||
"`From` is intended for infallible conversions only. \
|
||||
Use `TryFrom` if there's a possibility for the conversion to fail");
|
||||
Use `TryFrom` if there's a possibility for the conversion to fail",
|
||||
);
|
||||
diag.span_note(fpu.result, "potential failure(s)");
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::numeric_literal;
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::{self, LitFloatType, LitKind};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
@ -79,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral {
|
||||
let type_suffix = match lit_float_ty {
|
||||
LitFloatType::Suffixed(ast::FloatTy::F32) => Some("f32"),
|
||||
LitFloatType::Suffixed(ast::FloatTy::F64) => Some("f64"),
|
||||
LitFloatType::Unsuffixed => None
|
||||
LitFloatType::Unsuffixed => None,
|
||||
};
|
||||
let (is_whole, is_inf, mut float_str) = match fty {
|
||||
FloatTy::F32 => {
|
||||
@ -90,7 +89,6 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral {
|
||||
FloatTy::F64 => {
|
||||
let value = sym_str.parse::<f64>().unwrap();
|
||||
|
||||
|
||||
(value.fract() == 0.0, value.is_infinite(), formatter.format(value))
|
||||
},
|
||||
};
|
||||
|
@ -4,7 +4,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::{
|
||||
eq_expr_value, get_parent_expr, higher, in_constant, is_no_std_crate, numeric_literal, peel_blocks, sugg,
|
||||
};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, UnOp};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
@ -143,17 +142,14 @@ fn prepare_receiver_sugg<'a>(cx: &LateContext<'_>, mut expr: &'a Expr<'a>) -> Su
|
||||
"{suggestion}{}{}",
|
||||
// Check for float literals without numbers following the decimal
|
||||
// separator such as `2.` and adds a trailing zero
|
||||
if sym.as_str().ends_with('.') {
|
||||
"0"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
if sym.as_str().ends_with('.') { "0" } else { "" },
|
||||
float_ty.name_str()
|
||||
).into();
|
||||
)
|
||||
.into();
|
||||
|
||||
suggestion = match suggestion {
|
||||
Sugg::MaybeParen(_) => Sugg::MaybeParen(op),
|
||||
_ => Sugg::NonParen(op)
|
||||
_ => Sugg::NonParen(op),
|
||||
};
|
||||
}
|
||||
|
||||
@ -357,31 +353,59 @@ fn detect_hypot(cx: &LateContext<'_>, receiver: &Expr<'_>) -> Option<String> {
|
||||
) = receiver.kind
|
||||
{
|
||||
// check if expression of the form x * x + y * y
|
||||
if let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, lmul_lhs, lmul_rhs) = add_lhs.kind
|
||||
&& let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, rmul_lhs, rmul_rhs) = add_rhs.kind
|
||||
if let ExprKind::Binary(
|
||||
Spanned {
|
||||
node: BinOpKind::Mul, ..
|
||||
},
|
||||
lmul_lhs,
|
||||
lmul_rhs,
|
||||
) = add_lhs.kind
|
||||
&& let ExprKind::Binary(
|
||||
Spanned {
|
||||
node: BinOpKind::Mul, ..
|
||||
},
|
||||
rmul_lhs,
|
||||
rmul_rhs,
|
||||
) = add_rhs.kind
|
||||
&& eq_expr_value(cx, lmul_lhs, lmul_rhs)
|
||||
&& eq_expr_value(cx, rmul_lhs, rmul_rhs)
|
||||
{
|
||||
return Some(format!("{}.hypot({})", Sugg::hir(cx, lmul_lhs, "..").maybe_par(), Sugg::hir(cx, rmul_lhs, "..")));
|
||||
return Some(format!(
|
||||
"{}.hypot({})",
|
||||
Sugg::hir(cx, lmul_lhs, "..").maybe_par(),
|
||||
Sugg::hir(cx, rmul_lhs, "..")
|
||||
));
|
||||
}
|
||||
|
||||
// check if expression of the form x.powi(2) + y.powi(2)
|
||||
if let ExprKind::MethodCall(
|
||||
PathSegment { ident: lmethod_name, .. },
|
||||
largs_0, [largs_1, ..],
|
||||
_
|
||||
) = &add_lhs.kind
|
||||
PathSegment {
|
||||
ident: lmethod_name, ..
|
||||
},
|
||||
largs_0,
|
||||
[largs_1, ..],
|
||||
_,
|
||||
) = &add_lhs.kind
|
||||
&& let ExprKind::MethodCall(
|
||||
PathSegment { ident: rmethod_name, .. },
|
||||
rargs_0, [rargs_1, ..],
|
||||
_
|
||||
PathSegment {
|
||||
ident: rmethod_name, ..
|
||||
},
|
||||
rargs_0,
|
||||
[rargs_1, ..],
|
||||
_,
|
||||
) = &add_rhs.kind
|
||||
&& lmethod_name.as_str() == "powi" && rmethod_name.as_str() == "powi"
|
||||
&& lmethod_name.as_str() == "powi"
|
||||
&& rmethod_name.as_str() == "powi"
|
||||
&& let Some(lvalue) = constant(cx, cx.typeck_results(), largs_1)
|
||||
&& let Some(rvalue) = constant(cx, cx.typeck_results(), rargs_1)
|
||||
&& Int(2) == lvalue && Int(2) == rvalue
|
||||
&& Int(2) == lvalue
|
||||
&& Int(2) == rvalue
|
||||
{
|
||||
return Some(format!("{}.hypot({})", Sugg::hir(cx, largs_0, "..").maybe_par(), Sugg::hir(cx, rargs_0, "..")));
|
||||
return Some(format!(
|
||||
"{}.hypot({})",
|
||||
Sugg::hir(cx, largs_0, "..").maybe_par(),
|
||||
Sugg::hir(cx, rargs_0, "..")
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@ -405,7 +429,13 @@ fn check_hypot(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) {
|
||||
// TODO: Lint expressions of the form `x.exp() - y` where y > 1
|
||||
// and suggest usage of `x.exp_m1() - (y - 1)` instead
|
||||
fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
if let ExprKind::Binary(Spanned { node: BinOpKind::Sub, .. }, lhs, rhs) = expr.kind
|
||||
if let ExprKind::Binary(
|
||||
Spanned {
|
||||
node: BinOpKind::Sub, ..
|
||||
},
|
||||
lhs,
|
||||
rhs,
|
||||
) = expr.kind
|
||||
&& cx.typeck_results().expr_ty(lhs).is_floating_point()
|
||||
&& let Some(value) = constant(cx, cx.typeck_results(), rhs)
|
||||
&& (F32(1.0) == value || F64(1.0) == value)
|
||||
@ -419,17 +449,20 @@ fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
expr.span,
|
||||
"(e.pow(x) - 1) can be computed more accurately",
|
||||
"consider using",
|
||||
format!(
|
||||
"{}.exp_m1()",
|
||||
Sugg::hir(cx, self_arg, "..").maybe_par()
|
||||
),
|
||||
format!("{}.exp_m1()", Sugg::hir(cx, self_arg, "..").maybe_par()),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn is_float_mul_expr<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(&'a Expr<'a>, &'a Expr<'a>)> {
|
||||
if let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, lhs, rhs) = &expr.kind
|
||||
if let ExprKind::Binary(
|
||||
Spanned {
|
||||
node: BinOpKind::Mul, ..
|
||||
},
|
||||
lhs,
|
||||
rhs,
|
||||
) = &expr.kind
|
||||
&& cx.typeck_results().expr_ty(lhs).is_floating_point()
|
||||
&& cx.typeck_results().expr_ty(rhs).is_floating_point()
|
||||
{
|
||||
@ -543,7 +576,11 @@ fn are_negated<'a>(cx: &LateContext<'_>, expr1: &'a Expr<'a>, expr2: &'a Expr<'a
|
||||
}
|
||||
|
||||
fn check_custom_abs(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
if let Some(higher::If { cond, then, r#else: Some(r#else) }) = higher::If::hir(expr)
|
||||
if let Some(higher::If {
|
||||
cond,
|
||||
then,
|
||||
r#else: Some(r#else),
|
||||
}) = higher::If::hir(expr)
|
||||
&& let if_body_expr = peel_blocks(then)
|
||||
&& let else_body_expr = peel_blocks(r#else)
|
||||
&& let Some((if_expr_positive, body)) = are_negated(cx, if_body_expr, else_body_expr)
|
||||
@ -584,15 +621,27 @@ fn check_custom_abs(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
}
|
||||
|
||||
fn are_same_base_logs(cx: &LateContext<'_>, expr_a: &Expr<'_>, expr_b: &Expr<'_>) -> bool {
|
||||
if let ExprKind::MethodCall(PathSegment { ident: method_name_a, .. }, _, args_a, _) = expr_a.kind
|
||||
&& let ExprKind::MethodCall(PathSegment { ident: method_name_b, .. }, _, args_b, _) = expr_b.kind
|
||||
if let ExprKind::MethodCall(
|
||||
PathSegment {
|
||||
ident: method_name_a, ..
|
||||
},
|
||||
_,
|
||||
args_a,
|
||||
_,
|
||||
) = expr_a.kind
|
||||
&& let ExprKind::MethodCall(
|
||||
PathSegment {
|
||||
ident: method_name_b, ..
|
||||
},
|
||||
_,
|
||||
args_b,
|
||||
_,
|
||||
) = expr_b.kind
|
||||
{
|
||||
return method_name_a.as_str() == method_name_b.as_str() &&
|
||||
args_a.len() == args_b.len() &&
|
||||
(
|
||||
["ln", "log2", "log10"].contains(&method_name_a.as_str()) ||
|
||||
method_name_a.as_str() == "log" && args_a.len() == 1 && eq_expr_value(cx, &args_a[0], &args_b[0])
|
||||
);
|
||||
return method_name_a.as_str() == method_name_b.as_str()
|
||||
&& args_a.len() == args_b.len()
|
||||
&& (["ln", "log2", "log10"].contains(&method_name_a.as_str())
|
||||
|| method_name_a.as_str() == "log" && args_a.len() == 1 && eq_expr_value(cx, &args_a[0], &args_b[0]));
|
||||
}
|
||||
|
||||
false
|
||||
@ -601,12 +650,12 @@ fn are_same_base_logs(cx: &LateContext<'_>, expr_a: &Expr<'_>, expr_b: &Expr<'_>
|
||||
fn check_log_division(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
// check if expression of the form x.logN() / y.logN()
|
||||
if let ExprKind::Binary(
|
||||
Spanned {
|
||||
node: BinOpKind::Div, ..
|
||||
},
|
||||
lhs,
|
||||
rhs,
|
||||
) = &expr.kind
|
||||
Spanned {
|
||||
node: BinOpKind::Div, ..
|
||||
},
|
||||
lhs,
|
||||
rhs,
|
||||
) = &expr.kind
|
||||
&& are_same_base_logs(cx, lhs, rhs)
|
||||
&& let ExprKind::MethodCall(_, largs_self, ..) = &lhs.kind
|
||||
&& let ExprKind::MethodCall(_, rargs_self, ..) = &rhs.kind
|
||||
@ -617,7 +666,11 @@ fn check_log_division(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
expr.span,
|
||||
"log base can be expressed more clearly",
|
||||
"consider using",
|
||||
format!("{}.log({})", Sugg::hir(cx, largs_self, "..").maybe_par(), Sugg::hir(cx, rargs_self, ".."),),
|
||||
format!(
|
||||
"{}.log({})",
|
||||
Sugg::hir(cx, largs_self, "..").maybe_par(),
|
||||
Sugg::hir(cx, rargs_self, ".."),
|
||||
),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
@ -625,12 +678,12 @@ fn check_log_division(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
|
||||
fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
if let ExprKind::Binary(
|
||||
Spanned {
|
||||
node: BinOpKind::Div, ..
|
||||
},
|
||||
div_lhs,
|
||||
div_rhs,
|
||||
) = &expr.kind
|
||||
Spanned {
|
||||
node: BinOpKind::Div, ..
|
||||
},
|
||||
div_lhs,
|
||||
div_rhs,
|
||||
) = &expr.kind
|
||||
&& let ExprKind::Binary(
|
||||
Spanned {
|
||||
node: BinOpKind::Mul, ..
|
||||
@ -642,8 +695,8 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
&& let Some(lvalue) = constant(cx, cx.typeck_results(), mul_rhs)
|
||||
{
|
||||
// TODO: also check for constant values near PI/180 or 180/PI
|
||||
if (F32(f32_consts::PI) == rvalue || F64(f64_consts::PI) == rvalue) &&
|
||||
(F32(180_f32) == lvalue || F64(180_f64) == lvalue)
|
||||
if (F32(f32_consts::PI) == rvalue || F64(f64_consts::PI) == rvalue)
|
||||
&& (F32(180_f32) == lvalue || F64(180_f64) == lvalue)
|
||||
{
|
||||
let mut proposal = format!("{}.to_degrees()", Sugg::hir(cx, mul_lhs, "..").maybe_par());
|
||||
if let ExprKind::Lit(literal) = mul_lhs.kind
|
||||
@ -665,9 +718,8 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
proposal,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else if
|
||||
(F32(180_f32) == rvalue || F64(180_f64) == rvalue) &&
|
||||
(F32(f32_consts::PI) == lvalue || F64(f64_consts::PI) == lvalue)
|
||||
} else if (F32(180_f32) == rvalue || F64(180_f64) == rvalue)
|
||||
&& (F32(f32_consts::PI) == lvalue || F64(f64_consts::PI) == lvalue)
|
||||
{
|
||||
let mut proposal = format!("{}.to_radians()", Sugg::hir(cx, mul_lhs, "..").maybe_par());
|
||||
if let ExprKind::Lit(literal) = mul_lhs.kind
|
||||
|
@ -8,7 +8,6 @@ use clippy_utils::macros::{
|
||||
};
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::ty::{implements_trait, is_type_lang_item};
|
||||
use if_chain::if_chain;
|
||||
use itertools::Itertools;
|
||||
use rustc_ast::{
|
||||
FormatArgPosition, FormatArgPositionKind, FormatArgsPiece, FormatArgumentKind, FormatCount, FormatOptions,
|
||||
@ -422,9 +421,7 @@ fn check_to_string_in_format_args(cx: &LateContext<'_>, name: Symbol, value: &Ex
|
||||
cx,
|
||||
TO_STRING_IN_FORMAT_ARGS,
|
||||
to_string_span.with_lo(receiver.span.hi()),
|
||||
&format!(
|
||||
"`to_string` applied to a type that implements `Display` in `{name}!` args"
|
||||
),
|
||||
&format!("`to_string` applied to a type that implements `Display` in `{name}!` args"),
|
||||
"remove this",
|
||||
String::new(),
|
||||
Applicability::MachineApplicable,
|
||||
@ -434,9 +431,7 @@ fn check_to_string_in_format_args(cx: &LateContext<'_>, name: Symbol, value: &Ex
|
||||
cx,
|
||||
TO_STRING_IN_FORMAT_ARGS,
|
||||
value.span,
|
||||
&format!(
|
||||
"`to_string` applied to a type that implements `Display` in `{name}!` args"
|
||||
),
|
||||
&format!("`to_string` applied to a type that implements `Display` in `{name}!` args"),
|
||||
"use this",
|
||||
format!(
|
||||
"{}{:*>n_needed_derefs$}{receiver_snippet}",
|
||||
|
@ -1,7 +1,6 @@
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
|
||||
use clippy_utils::macros::{find_format_arg_expr, find_format_args, is_format_macro, root_macro_call_first_node};
|
||||
use clippy_utils::{get_parent_as_impl, is_diag_trait_item, path_to_local, peel_ref_operators};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::{FormatArgsPiece, FormatTrait};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind, Impl, ImplItem, ImplItemKind, QPath};
|
||||
@ -243,20 +242,22 @@ fn check_print_in_format_impl(cx: &LateContext<'_>, expr: &Expr<'_>, impl_trait:
|
||||
fn is_format_trait_impl(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) -> Option<FormatTraitNames> {
|
||||
if impl_item.ident.name == sym::fmt
|
||||
&& let ImplItemKind::Fn(_, body_id) = impl_item.kind
|
||||
&& let Some(Impl { of_trait: Some(trait_ref),..}) = get_parent_as_impl(cx.tcx, impl_item.hir_id())
|
||||
&& let Some(Impl {
|
||||
of_trait: Some(trait_ref),
|
||||
..
|
||||
}) = get_parent_as_impl(cx.tcx, impl_item.hir_id())
|
||||
&& let Some(did) = trait_ref.trait_def_id()
|
||||
&& let Some(name) = cx.tcx.get_diagnostic_name(did)
|
||||
&& matches!(name, sym::Debug | sym::Display)
|
||||
{
|
||||
let body = cx.tcx.hir().body(body_id);
|
||||
let formatter_name = body.params.get(1)
|
||||
let formatter_name = body
|
||||
.params
|
||||
.get(1)
|
||||
.and_then(|param| param.pat.simple_ident())
|
||||
.map(|ident| ident.name);
|
||||
|
||||
Some(FormatTraitNames {
|
||||
name,
|
||||
formatter_name,
|
||||
})
|
||||
Some(FormatTraitNames { name, formatter_name })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note};
|
||||
use clippy_utils::is_span_if;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::{BinOpKind, Block, Expr, ExprKind, StmtKind, UnOp};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
@ -193,9 +192,7 @@ fn check_unop(cx: &EarlyContext<'_>, expr: &Expr) {
|
||||
`{binop_str}{unop_str}` is a single operator"
|
||||
),
|
||||
None,
|
||||
&format!(
|
||||
"put a space between `{binop_str}` and `{unop_str}` and remove the space after `{unop_str}`"
|
||||
),
|
||||
&format!("put a space between `{binop_str}` and `{unop_str}` and remove the space after `{unop_str}`"),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -219,7 +216,6 @@ fn check_else(cx: &EarlyContext<'_>, expr: &Expr) {
|
||||
&& let Some(else_snippet) = snippet_opt(cx, else_span)
|
||||
&& let Some((pre_else, post_else)) = else_snippet.split_once("else")
|
||||
&& let Some((_, post_else_post_eol)) = post_else.split_once('\n')
|
||||
|
||||
{
|
||||
// Allow allman style braces `} \n else \n {`
|
||||
if is_block(else_)
|
||||
@ -234,7 +230,7 @@ fn check_else(cx: &EarlyContext<'_>, expr: &Expr) {
|
||||
// Don't warn if the only thing inside post_else_post_eol is a comment block.
|
||||
let trimmed_post_else_post_eol = post_else_post_eol.trim();
|
||||
if trimmed_post_else_post_eol.starts_with("/*") && trimmed_post_else_post_eol.ends_with("*/") {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
let else_desc = if is_if(else_) { "if" } else { "{..}" };
|
||||
@ -267,7 +263,8 @@ fn check_array(cx: &EarlyContext<'_>, expr: &Expr) {
|
||||
if let ExprKind::Array(ref array) = expr.kind {
|
||||
for element in array {
|
||||
if let ExprKind::Binary(ref op, ref lhs, _) = element.kind
|
||||
&& has_unary_equivalent(op.node) && lhs.span.eq_ctxt(op.span)
|
||||
&& has_unary_equivalent(op.node)
|
||||
&& lhs.span.eq_ctxt(op.span)
|
||||
&& let space_span = lhs.span.between(op.span)
|
||||
&& let Some(space_snippet) = snippet_opt(cx, space_span)
|
||||
&& let lint_span = lhs.span.with_lo(lhs.span.hi())
|
||||
@ -313,9 +310,7 @@ fn check_missing_else(cx: &EarlyContext<'_>, first: &Expr, second: &Expr) {
|
||||
else_span,
|
||||
&format!("this looks like {looks_like} but the `else` is missing"),
|
||||
None,
|
||||
&format!(
|
||||
"to remove this lint, add the missing `else` or add a new line before {next_thing}",
|
||||
),
|
||||
&format!("to remove this lint, add the missing `else` or add a new line before {next_thing}",),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::is_integer_literal;
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{def, Expr, ExprKind, LangItem, PrimTy, QPath, TyKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
@ -61,25 +60,16 @@ impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 {
|
||||
|
||||
// check if the second argument is a primitive `10`
|
||||
&& is_integer_literal(radix, 10)
|
||||
|
||||
{
|
||||
let expr = if let ExprKind::AddrOf(_, _, expr) = &src.kind {
|
||||
let ty = cx.typeck_results().expr_ty(expr);
|
||||
if is_ty_stringish(cx, ty) {
|
||||
expr
|
||||
} else {
|
||||
&src
|
||||
}
|
||||
if is_ty_stringish(cx, ty) { expr } else { &src }
|
||||
} else {
|
||||
&src
|
||||
};
|
||||
|
||||
let sugg = Sugg::hir_with_applicability(
|
||||
cx,
|
||||
expr,
|
||||
"<string>",
|
||||
&mut Applicability::MachineApplicable
|
||||
).maybe_par();
|
||||
let sugg =
|
||||
Sugg::hir_with_applicability(cx, expr, "<string>", &mut Applicability::MachineApplicable).maybe_par();
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
@ -88,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 {
|
||||
"this call to `from_str_radix` can be replaced with a call to `str::parse`",
|
||||
"try",
|
||||
format!("{sugg}.parse::<{}>()", prim_ty.name_str()),
|
||||
Applicability::MaybeIncorrect
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ pub fn check_fn(cx: &LateContext<'_>, kind: FnKind<'_>, decl: &FnDecl<'_>, body:
|
||||
// Body must be &(mut) <self_data>.name
|
||||
// self_data is not necessarily self, to also lint sub-getters, etc…
|
||||
|
||||
let block_expr = if let ExprKind::Block(block,_) = body.value.kind
|
||||
let block_expr = if let ExprKind::Block(block, _) = body.value.kind
|
||||
&& block.stmts.is_empty()
|
||||
&& let Some(block_expr) = block.expr
|
||||
{
|
||||
|
@ -87,11 +87,12 @@ fn check_result_unit_err(cx: &LateContext<'_>, err_ty: Ty<'_>, fn_header_span: S
|
||||
|
||||
fn check_result_large_err<'tcx>(cx: &LateContext<'tcx>, err_ty: Ty<'tcx>, hir_ty_span: Span, large_err_threshold: u64) {
|
||||
if let Adt(adt, subst) = err_ty.kind()
|
||||
&& let Some(local_def_id) = err_ty.ty_adt_def().expect("already checked this is adt").did().as_local()
|
||||
&& let Some(hir::Node::Item(item)) = cx
|
||||
.tcx
|
||||
.hir()
|
||||
.find_by_def_id(local_def_id)
|
||||
&& let Some(local_def_id) = err_ty
|
||||
.ty_adt_def()
|
||||
.expect("already checked this is adt")
|
||||
.did()
|
||||
.as_local()
|
||||
&& let Some(hir::Node::Item(item)) = cx.tcx.hir().find_by_def_id(local_def_id)
|
||||
&& let hir::ItemKind::Enum(ref def, _) = item.kind
|
||||
{
|
||||
let variants_size = AdtVariantInfo::new(cx, *adt, subst);
|
||||
@ -114,17 +115,19 @@ fn check_result_large_err<'tcx>(cx: &LateContext<'tcx>, err_ty: Ty<'tcx>, hir_ty
|
||||
let variant_def = &def.variants[variant.ind];
|
||||
diag.span_label(
|
||||
variant_def.span,
|
||||
format!("the variant `{}` contains at least {} bytes", variant_def.ident, variant.size),
|
||||
format!(
|
||||
"the variant `{}` contains at least {} bytes",
|
||||
variant_def.ident, variant.size
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
diag.help(format!("try reducing the size of `{err_ty}`, for example by boxing large elements or replacing it with `Box<{err_ty}>`"));
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
let ty_size = approx_ty_size(cx, err_ty);
|
||||
if ty_size >= large_err_threshold {
|
||||
span_lint_and_then(
|
||||
|
@ -1,7 +1,6 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::{higher, SpanlessEq};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Diagnostic;
|
||||
use rustc_hir::intravisit::{self as visit, Visitor};
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
|
@ -13,8 +13,6 @@ use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::source_map::Span;
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
use if_chain::if_chain;
|
||||
|
||||
use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
|
||||
use clippy_utils::source::{snippet, snippet_opt};
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
@ -348,8 +346,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'a, 'b, 't
|
||||
|
||||
if self.cx.tcx.is_diagnostic_item(sym::HashMap, ty_did) {
|
||||
if method.ident.name == sym::new {
|
||||
self.suggestions
|
||||
.insert(e.span, "HashMap::default()".to_string());
|
||||
self.suggestions.insert(e.span, "HashMap::default()".to_string());
|
||||
} else if method.ident.name == sym!(with_capacity) {
|
||||
self.suggestions.insert(
|
||||
e.span,
|
||||
@ -361,8 +358,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'a, 'b, 't
|
||||
}
|
||||
} else if self.cx.tcx.is_diagnostic_item(sym::HashSet, ty_did) {
|
||||
if method.ident.name == sym::new {
|
||||
self.suggestions
|
||||
.insert(e.span, "HashSet::default()".to_string());
|
||||
self.suggestions.insert(e.span, "HashSet::default()".to_string());
|
||||
} else if method.ident.name == sym!(with_capacity) {
|
||||
self.suggestions.insert(
|
||||
e.span,
|
||||
|
@ -2,7 +2,6 @@ use clippy_utils::consts::{constant, Constant};
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::get_parent_expr;
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::{LitIntType, LitKind};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BinOpKind, Block, Expr, ExprKind, Stmt, StmtKind};
|
||||
@ -47,10 +46,20 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingAdd {
|
||||
&& let ExprKind::Block(block, None) = then.kind
|
||||
&& let Block {
|
||||
stmts:
|
||||
[Stmt
|
||||
{ kind: StmtKind::Expr(ex) | StmtKind::Semi(ex), .. }],
|
||||
expr: None, ..} |
|
||||
Block { stmts: [], expr: Some(ex), ..} = block
|
||||
[
|
||||
Stmt {
|
||||
kind: StmtKind::Expr(ex) | StmtKind::Semi(ex),
|
||||
..
|
||||
},
|
||||
],
|
||||
expr: None,
|
||||
..
|
||||
}
|
||||
| Block {
|
||||
stmts: [],
|
||||
expr: Some(ex),
|
||||
..
|
||||
} = block
|
||||
&& let ExprKind::AssignOp(op1, target, value) = ex.kind
|
||||
&& let ty = cx.typeck_results().expr_ty(target)
|
||||
&& Some(c) == get_int_max(ty)
|
||||
@ -73,7 +82,15 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingAdd {
|
||||
} else {
|
||||
format!("{code} = {code}.saturating_add(1);")
|
||||
};
|
||||
span_lint_and_sugg(cx, IMPLICIT_SATURATING_ADD, expr.span, "manual saturating add detected", "use instead", sugg, app);
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
IMPLICIT_SATURATING_ADD,
|
||||
expr.span,
|
||||
"manual saturating add detected",
|
||||
"use instead",
|
||||
sugg,
|
||||
app,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::{higher, is_integer_literal, peel_blocks_with_stmt, SpanlessEq};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::LitKind;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BinOpKind, Expr, ExprKind, QPath};
|
||||
@ -59,7 +58,6 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub {
|
||||
|
||||
// Extracting out the variable name
|
||||
&& let ExprKind::Path(QPath::Resolved(_, ares_path)) = target.kind
|
||||
|
||||
{
|
||||
// Handle symmetric conditions in the if statement
|
||||
let (cond_var, cond_num_val) = if SpanlessEq::new(cx).eq_expr(cond_left, target) {
|
||||
@ -102,7 +100,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub {
|
||||
&& let None = cx.tcx.impl_trait_ref(impl_id) // An inherent impl
|
||||
&& cx.tcx.type_of(impl_id).instantiate_identity().is_integral()
|
||||
{
|
||||
print_lint_and_sugg(cx, var_name, expr)
|
||||
print_lint_and_sugg(cx, var_name, expr);
|
||||
}
|
||||
},
|
||||
ExprKind::Call(func, []) => {
|
||||
@ -113,7 +111,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub {
|
||||
&& let None = cx.tcx.impl_trait_ref(impl_id) // An inherent impl
|
||||
&& cx.tcx.type_of(impl_id).instantiate_identity().is_integral()
|
||||
{
|
||||
print_lint_and_sugg(cx, var_name, expr)
|
||||
print_lint_and_sugg(cx, var_name, expr);
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
@ -131,9 +129,7 @@ fn subtracts_one<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<&'a Exp
|
||||
ExprKind::Assign(target, value, _) => {
|
||||
if let ExprKind::Binary(ref op1, left1, right1) = value.kind
|
||||
&& BinOpKind::Sub == op1.node
|
||||
|
||||
&& SpanlessEq::new(cx).eq_expr(left1, target)
|
||||
|
||||
&& is_integer_literal(right1, 1)
|
||||
{
|
||||
Some(target)
|
||||
|
@ -1,6 +1,5 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet;
|
||||
use if_chain::if_chain;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{self as hir, ExprKind};
|
||||
@ -94,14 +93,15 @@ impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor {
|
||||
fields_snippet.push_str(&last_ident.to_string());
|
||||
|
||||
let base_snippet = if let Some(base) = base {
|
||||
format!(", ..{}", snippet(cx, base.span, ".."))
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
format!(", ..{}", snippet(cx, base.span, ".."))
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
|
||||
let sugg = format!("{} {{ {fields_snippet}{base_snippet} }}",
|
||||
let sugg = format!(
|
||||
"{} {{ {fields_snippet}{base_snippet} }}",
|
||||
snippet(cx, qpath.span(), ".."),
|
||||
);
|
||||
);
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
@ -111,7 +111,7 @@ impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor {
|
||||
"try",
|
||||
sugg,
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,6 @@ use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::higher::IfLet;
|
||||
use clippy_utils::ty::is_copy;
|
||||
use clippy_utils::{is_expn_of, is_lint_allowed, path_to_local};
|
||||
use if_chain::if_chain;
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
@ -71,10 +70,9 @@ 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)
|
||||
&& let Some(IfLet { let_pat, if_then, .. }) = IfLet::hir(cx, expr)
|
||||
&& !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)
|
||||
&& !found_slices.is_empty()
|
||||
&& let filtered_slices = filter_lintable_slices(cx, found_slices, self.max_suggested_slice, if_then)
|
||||
|
@ -90,22 +90,16 @@ impl LateLintPass<'_> for InstantSubtraction {
|
||||
) = expr.kind
|
||||
{
|
||||
if is_instant_now_call(cx, lhs)
|
||||
|
||||
&& is_an_instant(cx, rhs)
|
||||
&& let Some(sugg) = Sugg::hir_opt(cx, rhs)
|
||||
|
||||
{
|
||||
print_manual_instant_elapsed_sugg(cx, expr, sugg)
|
||||
} else {
|
||||
if !expr.span.from_expansion()
|
||||
&& self.msrv.meets(msrvs::TRY_FROM)
|
||||
|
||||
&& is_an_instant(cx, lhs)
|
||||
&& is_a_duration(cx, rhs)
|
||||
|
||||
{
|
||||
print_unchecked_duration_subtraction_sugg(cx, lhs, rhs, expr)
|
||||
}
|
||||
print_manual_instant_elapsed_sugg(cx, expr, sugg);
|
||||
} else if !expr.span.from_expansion()
|
||||
&& self.msrv.meets(msrvs::TRY_FROM)
|
||||
&& is_an_instant(cx, lhs)
|
||||
&& is_a_duration(cx, rhs)
|
||||
{
|
||||
print_unchecked_duration_subtraction_sugg(cx, lhs, rhs, expr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Item, ItemKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
@ -59,7 +58,6 @@ impl<'tcx> LateLintPass<'tcx> for LargeConstArrays {
|
||||
&& let Ok(element_count) = element_count.try_to_target_usize(cx.tcx)
|
||||
&& let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes())
|
||||
&& self.maximum_allowed_size < u128::from(element_count) * u128::from(element_size)
|
||||
|
||||
{
|
||||
let hi_pos = item.ident.span.lo() - BytePos::from_usize(1);
|
||||
let sugg_span = Span::new(
|
||||
@ -80,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeConstArrays {
|
||||
"static",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ impl LateLintPass<'_> for LargeIncludeFile {
|
||||
if let Some(macro_call) = root_macro_call_first_node(cx, expr)
|
||||
&& !is_lint_allowed(cx, LARGE_INCLUDE_FILE, expr.hir_id)
|
||||
&& (cx.tcx.is_diagnostic_item(sym::include_bytes_macro, macro_call.def_id)
|
||||
|| cx.tcx.is_diagnostic_item(sym::include_str_macro, macro_call.def_id))
|
||||
|| cx.tcx.is_diagnostic_item(sym::include_str_macro, macro_call.def_id))
|
||||
&& let ExprKind::Lit(lit) = &expr.kind
|
||||
{
|
||||
let len = match &lit.node {
|
||||
|
@ -2,7 +2,6 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_the
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::{get_item_name, get_parent_as_impl, is_lint_allowed, peel_ref_operators};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::LitKind;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::Res;
|
||||
@ -144,10 +143,8 @@ impl<'tcx> LateLintPass<'tcx> for LenZero {
|
||||
&& let Some(local_id) = ty_id.as_local()
|
||||
&& let ty_hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_id)
|
||||
&& !is_lint_allowed(cx, LEN_WITHOUT_IS_EMPTY, ty_hir_id)
|
||||
&& let Some(output) = parse_len_output(
|
||||
cx,
|
||||
cx.tcx.fn_sig(item.owner_id).instantiate_identity().skip_binder()
|
||||
)
|
||||
&& let Some(output) =
|
||||
parse_len_output(cx, cx.tcx.fn_sig(item.owner_id).instantiate_identity().skip_binder())
|
||||
{
|
||||
let (name, kind) = match cx.tcx.hir().find(ty_hir_id) {
|
||||
Some(Node::ForeignItem(x)) => (x.ident.name, "extern type"),
|
||||
@ -156,10 +153,10 @@ impl<'tcx> LateLintPass<'tcx> for LenZero {
|
||||
ItemKind::Enum(..) => (x.ident.name, "enum"),
|
||||
ItemKind::Union(..) => (x.ident.name, "union"),
|
||||
_ => (x.ident.name, "type"),
|
||||
}
|
||||
},
|
||||
_ => return,
|
||||
};
|
||||
check_for_is_empty(cx, sig.span, sig.decl.implicit_self, output, ty_id, name, kind)
|
||||
check_for_is_empty(cx, sig.span, sig.decl.implicit_self, output, ty_id, name, kind);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::path_to_local_id;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::visitors::is_local_used;
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::{BindingAnnotation, Mutability};
|
||||
@ -65,7 +64,14 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq {
|
||||
&& let hir::StmtKind::Local(local) = stmt.kind
|
||||
&& let hir::PatKind::Binding(mode, canonical_id, ident, None) = local.pat.kind
|
||||
&& let hir::StmtKind::Expr(if_) = expr.kind
|
||||
&& let hir::ExprKind::If(hir::Expr { kind: hir::ExprKind::DropTemps(cond), ..}, then, else_) = if_.kind
|
||||
&& let hir::ExprKind::If(
|
||||
hir::Expr {
|
||||
kind: hir::ExprKind::DropTemps(cond),
|
||||
..
|
||||
},
|
||||
then,
|
||||
else_,
|
||||
) = if_.kind
|
||||
&& !is_local_used(cx, *cond, canonical_id)
|
||||
&& let hir::ExprKind::Block(then, _) = then.kind
|
||||
&& let Some(value) = check_assign(cx, canonical_id, then)
|
||||
@ -73,11 +79,13 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq {
|
||||
{
|
||||
let span = stmt.span.to(if_.span);
|
||||
|
||||
let has_interior_mutability = !cx.typeck_results().node_type(canonical_id).is_freeze(
|
||||
cx.tcx,
|
||||
cx.param_env,
|
||||
);
|
||||
if has_interior_mutability { return; }
|
||||
let has_interior_mutability = !cx
|
||||
.typeck_results()
|
||||
.node_type(canonical_id)
|
||||
.is_freeze(cx.tcx, cx.param_env);
|
||||
if has_interior_mutability {
|
||||
return;
|
||||
}
|
||||
|
||||
let (default_multi_stmts, default) = if let Some(else_) = else_ {
|
||||
if let hir::ExprKind::Block(else_, _) = else_.kind {
|
||||
@ -114,21 +122,23 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq {
|
||||
value=snippet(cx, value.span, "<value>"),
|
||||
default=snippet(cx, default.span, "<default>"),
|
||||
);
|
||||
span_lint_and_then(cx,
|
||||
USELESS_LET_IF_SEQ,
|
||||
span,
|
||||
"`if _ { .. } else { .. }` is an expression",
|
||||
|diag| {
|
||||
diag.span_suggestion(
|
||||
span,
|
||||
"it is more idiomatic to write",
|
||||
sug,
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
if !mutability.is_empty() {
|
||||
diag.note("you might not need `mut` at all");
|
||||
}
|
||||
});
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
USELESS_LET_IF_SEQ,
|
||||
span,
|
||||
"`if _ { .. } else { .. }` is an expression",
|
||||
|diag| {
|
||||
diag.span_suggestion(
|
||||
span,
|
||||
"it is more idiomatic to write",
|
||||
sug,
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
if !mutability.is_empty() {
|
||||
diag.note("you might not need `mut` at all");
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -145,7 +155,12 @@ fn check_assign<'tcx>(
|
||||
&& let hir::ExprKind::Assign(var, value, _) = expr.kind
|
||||
&& path_to_local_id(var, decl)
|
||||
{
|
||||
if block.stmts.iter().take(block.stmts.len()-1).any(|stmt| is_local_used(cx, stmt, decl)) {
|
||||
if block
|
||||
.stmts
|
||||
.iter()
|
||||
.take(block.stmts.len() - 1)
|
||||
.any(|stmt| is_local_used(cx, stmt, decl))
|
||||
{
|
||||
None
|
||||
} else {
|
||||
Some(value)
|
||||
|
@ -44,8 +44,8 @@ impl LateLintPass<'_> for UnderscoreTyped {
|
||||
local.span,
|
||||
"variable declared with type underscore",
|
||||
Some(ty.span.with_lo(local.pat.span.hi())),
|
||||
"remove the explicit type `_` declaration"
|
||||
)
|
||||
"remove the explicit type `_` declaration",
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -521,7 +521,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
store.register_late_pass(|_| {
|
||||
Box::new(utils::internal_lints::compiler_lint_functions::CompilerLintFunctions::new())
|
||||
});
|
||||
store.register_late_pass(|_| Box::new(utils::internal_lints::if_chain_style::IfChainStyle));
|
||||
store.register_late_pass(|_| Box::new(utils::internal_lints::invalid_paths::InvalidPaths));
|
||||
store.register_late_pass(|_| {
|
||||
Box::<utils::internal_lints::interning_defined_symbol::InterningDefinedSymbol>::default()
|
||||
|
@ -313,7 +313,6 @@ fn explicit_self_type<'tcx>(cx: &LateContext<'tcx>, func: &FnDecl<'tcx>, ident:
|
||||
if let Some(ident) = ident
|
||||
&& ident.name == kw::SelfLower
|
||||
&& !func.implicit_self.has_implicit_self()
|
||||
|
||||
&& let Some(self_ty) = func.inputs.first()
|
||||
{
|
||||
let mut visitor = RefVisitor::new(cx);
|
||||
|
@ -4,7 +4,6 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::numeric_literal::{NumericLiteral, Radix};
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::{Expr, ExprKind, LitKind};
|
||||
use rustc_ast::token;
|
||||
use rustc_errors::Applicability;
|
||||
@ -268,18 +267,17 @@ impl LiteralDigitGrouping {
|
||||
}
|
||||
|
||||
let result = (|| {
|
||||
|
||||
let integral_group_size = Self::get_group_size(num_lit.integer.split('_'), num_lit.radix, true)?;
|
||||
if let Some(fraction) = num_lit.fraction {
|
||||
let fractional_group_size = Self::get_group_size(
|
||||
fraction.rsplit('_'),
|
||||
num_lit.radix,
|
||||
self.lint_fraction_readability)?;
|
||||
let fractional_group_size =
|
||||
Self::get_group_size(fraction.rsplit('_'), num_lit.radix, self.lint_fraction_readability)?;
|
||||
|
||||
let consistent = Self::parts_consistent(integral_group_size,
|
||||
fractional_group_size,
|
||||
num_lit.integer.len(),
|
||||
fraction.len());
|
||||
let consistent = Self::parts_consistent(
|
||||
integral_group_size,
|
||||
fractional_group_size,
|
||||
num_lit.integer.len(),
|
||||
fraction.len(),
|
||||
);
|
||||
if !consistent {
|
||||
return Err(WarningType::InconsistentDigitGrouping);
|
||||
};
|
||||
@ -288,18 +286,13 @@ impl LiteralDigitGrouping {
|
||||
Ok(())
|
||||
})();
|
||||
|
||||
|
||||
if let Err(warning_type) = result {
|
||||
let should_warn = match warning_type {
|
||||
| WarningType::UnreadableLiteral
|
||||
WarningType::UnreadableLiteral
|
||||
| WarningType::InconsistentDigitGrouping
|
||||
| WarningType::UnusualByteGroupings
|
||||
| WarningType::LargeDigitGroups => {
|
||||
!span.from_expansion()
|
||||
}
|
||||
WarningType::DecimalRepresentation | WarningType::MistypedLiteralSuffix => {
|
||||
true
|
||||
}
|
||||
| WarningType::LargeDigitGroups => !span.from_expansion(),
|
||||
WarningType::DecimalRepresentation | WarningType::MistypedLiteralSuffix => true,
|
||||
};
|
||||
if should_warn {
|
||||
warning_type.display(num_lit.format(), cx, span);
|
||||
|
@ -2,7 +2,6 @@ use super::{make_iterator_snippet, IncrementVisitor, InitializeVisitor, EXPLICIT
|
||||
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::{get_enclosing_block, is_integer_const};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::intravisit::{walk_block, walk_expr};
|
||||
use rustc_hir::{Expr, Pat};
|
||||
@ -53,7 +52,7 @@ pub(super) fn check<'tcx>(
|
||||
applicability,
|
||||
);
|
||||
return;
|
||||
}
|
||||
},
|
||||
Some(ty::Int(int_ty)) => int_ty.name_str(),
|
||||
Some(ty::Uint(uint_ty)) => uint_ty.name_str(),
|
||||
_ => return,
|
||||
|
@ -4,7 +4,6 @@ use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use clippy_utils::{higher, is_res_lang_ctor, path_res, peel_blocks_with_stmt};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
@ -23,7 +22,11 @@ pub(super) fn check<'tcx>(
|
||||
let inner_expr = peel_blocks_with_stmt(body);
|
||||
// Check for the specific case that the result is returned and optimize suggestion for that (more
|
||||
// cases can be added later)
|
||||
if let Some(higher::If { cond, then, r#else: None, }) = higher::If::hir(inner_expr)
|
||||
if let Some(higher::If {
|
||||
cond,
|
||||
then,
|
||||
r#else: None,
|
||||
}) = higher::If::hir(inner_expr)
|
||||
&& let Some(binding_id) = get_binding(pat)
|
||||
&& let ExprKind::Block(block, _) = then.kind
|
||||
&& let [stmt] = block.stmts
|
||||
@ -51,7 +54,12 @@ pub(super) fn check<'tcx>(
|
||||
);
|
||||
}
|
||||
let ty = cx.typeck_results().expr_ty(inner_ret);
|
||||
if cx.tcx.lang_items().copy_trait().map_or(false, |id| implements_trait(cx, ty, id, &[])) {
|
||||
if cx
|
||||
.tcx
|
||||
.lang_items()
|
||||
.copy_trait()
|
||||
.map_or(false, |id| implements_trait(cx, ty, id, &[]))
|
||||
{
|
||||
snippet.push_str(
|
||||
&format!(
|
||||
".find(|{}{}| {})",
|
||||
@ -84,12 +92,7 @@ pub(super) fn check<'tcx>(
|
||||
if applicability == Applicability::MaybeIncorrect {
|
||||
diag.note("you may need to dereference some variables");
|
||||
}
|
||||
diag.span_suggestion(
|
||||
lint_span,
|
||||
"replace with an iterator",
|
||||
snippet,
|
||||
applicability,
|
||||
);
|
||||
diag.span_suggestion(lint_span, "replace with an iterator", snippet, applicability);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ use super::MANUAL_FLATTEN;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::visitors::is_local_used;
|
||||
use clippy_utils::{higher, path_to_local_id, peel_blocks_with_stmt};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::{Expr, Pat, PatKind};
|
||||
@ -38,7 +37,8 @@ pub(super) fn check<'tcx>(
|
||||
{
|
||||
let if_let_type = if some_ctor { "Some" } else { "Ok" };
|
||||
// Prepare the error message
|
||||
let msg = format!("unnecessary `if let` since only the `{if_let_type}` variant of the iterator element is used");
|
||||
let msg =
|
||||
format!("unnecessary `if let` since only the `{if_let_type}` variant of the iterator element is used");
|
||||
|
||||
// Prepare the help message
|
||||
let mut applicability = Applicability::MaybeIncorrect;
|
||||
@ -46,39 +46,25 @@ pub(super) fn check<'tcx>(
|
||||
let copied = match cx.typeck_results().expr_ty(let_expr).kind() {
|
||||
ty::Ref(_, inner, _) => match inner.kind() {
|
||||
ty::Ref(..) => ".copied()",
|
||||
_ => ""
|
||||
}
|
||||
_ => ""
|
||||
_ => "",
|
||||
},
|
||||
_ => "",
|
||||
};
|
||||
|
||||
let sugg = format!("{arg_snippet}{copied}.flatten()");
|
||||
|
||||
// If suggestion is not a one-liner, it won't be shown inline within the error message. In that case,
|
||||
// it will be shown in the extra `help` message at the end, which is why the first `help_msg` needs
|
||||
// to refer to the correct relative position of the suggestion.
|
||||
// If suggestion is not a one-liner, it won't be shown inline within the error message. In that
|
||||
// case, it will be shown in the extra `help` message at the end, which is why the first
|
||||
// `help_msg` needs to refer to the correct relative position of the suggestion.
|
||||
let help_msg = if sugg.contains('\n') {
|
||||
"remove the `if let` statement in the for loop and then..."
|
||||
} else {
|
||||
"...and remove the `if let` statement in the for loop"
|
||||
};
|
||||
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
MANUAL_FLATTEN,
|
||||
span,
|
||||
&msg,
|
||||
|diag| {
|
||||
diag.span_suggestion(
|
||||
arg.span,
|
||||
"try",
|
||||
sugg,
|
||||
applicability,
|
||||
);
|
||||
diag.span_help(
|
||||
inner_expr.span,
|
||||
help_msg,
|
||||
);
|
||||
}
|
||||
);
|
||||
span_lint_and_then(cx, MANUAL_FLATTEN, span, &msg, |diag| {
|
||||
diag.span_suggestion(arg.span, "try", sugg, applicability);
|
||||
diag.span_help(inner_expr.span, help_msg);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,6 @@ use clippy_utils::source::snippet;
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::ty::is_copy;
|
||||
use clippy_utils::{get_enclosing_block, higher, path_to_local, sugg};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::intravisit::walk_block;
|
||||
@ -69,8 +68,19 @@ pub(super) fn check<'tcx>(
|
||||
// Source and destination must be different
|
||||
&& path_to_local(base_left) != path_to_local(base_right)
|
||||
{
|
||||
Some((ty, IndexExpr { base: base_left, idx: start_left, idx_offset: offset_left },
|
||||
IndexExpr { base: base_right, idx: start_right, idx_offset: offset_right }))
|
||||
Some((
|
||||
ty,
|
||||
IndexExpr {
|
||||
base: base_left,
|
||||
idx: start_left,
|
||||
idx_offset: offset_left,
|
||||
},
|
||||
IndexExpr {
|
||||
base: base_right,
|
||||
idx: start_right,
|
||||
idx_offset: offset_right,
|
||||
},
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -127,9 +137,7 @@ fn build_manual_memcpy_suggestion<'tcx>(
|
||||
}
|
||||
} else {
|
||||
match limits {
|
||||
ast::RangeLimits::Closed => {
|
||||
sugg + &sugg::ONE.into()
|
||||
},
|
||||
ast::RangeLimits::Closed => sugg + &sugg::ONE.into(),
|
||||
ast::RangeLimits::HalfOpen => sugg,
|
||||
}
|
||||
}
|
||||
@ -329,7 +337,11 @@ fn get_slice_like_element_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Opti
|
||||
fn fetch_cloned_expr<'tcx>(expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
|
||||
if let ExprKind::MethodCall(method, arg, [], _) = expr.kind
|
||||
&& method.ident.name == sym::clone
|
||||
{ arg } else { expr }
|
||||
{
|
||||
arg
|
||||
} else {
|
||||
expr
|
||||
}
|
||||
}
|
||||
|
||||
fn get_details_from_idx<'tcx>(
|
||||
|
@ -31,7 +31,12 @@ fn unpack_cond<'tcx>(cond: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
|
||||
}
|
||||
|
||||
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, body: &'tcx Expr<'_>) {
|
||||
if let ExprKind::Block(Block { stmts: [], expr: None, ..}, _) = body.kind
|
||||
if let ExprKind::Block(
|
||||
Block {
|
||||
stmts: [], expr: None, ..
|
||||
},
|
||||
_,
|
||||
) = body.kind
|
||||
&& let ExprKind::MethodCall(method, callee, ..) = unpack_cond(cond).kind
|
||||
&& [sym::load, sym::compare_exchange, sym::compare_exchange_weak].contains(&method.ident.name)
|
||||
&& let ty::Adt(def, _args) = cx.typeck_results().expr_ty(callee).kind()
|
||||
@ -47,8 +52,9 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, body: &'
|
||||
"{ core::hint::spin_loop() }"
|
||||
} else {
|
||||
"{ std::hint::spin_loop() }"
|
||||
}).into(),
|
||||
Applicability::MachineApplicable
|
||||
})
|
||||
.into(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
use super::MUT_RANGE_BOUND;
|
||||
use clippy_utils::diagnostics::span_lint_and_note;
|
||||
use clippy_utils::{get_enclosing_block, higher, path_to_local};
|
||||
use if_chain::if_chain;
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_hir::{BindingAnnotation, Expr, ExprKind, HirId, Node, PatKind};
|
||||
use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
|
||||
@ -13,10 +12,10 @@ use rustc_span::source_map::Span;
|
||||
|
||||
pub(super) fn check(cx: &LateContext<'_>, arg: &Expr<'_>, body: &Expr<'_>) {
|
||||
if let Some(higher::Range {
|
||||
start: Some(start),
|
||||
end: Some(end),
|
||||
..
|
||||
}) = higher::Range::hir(arg)
|
||||
start: Some(start),
|
||||
end: Some(end),
|
||||
..
|
||||
}) = higher::Range::hir(arg)
|
||||
&& let (mut_id_start, mut_id_end) = (check_for_mutability(cx, start), check_for_mutability(cx, end))
|
||||
&& (mut_id_start.is_some() || mut_id_end.is_some())
|
||||
{
|
||||
|
@ -4,7 +4,6 @@ use clippy_utils::source::snippet;
|
||||
use clippy_utils::ty::has_iter_method;
|
||||
use clippy_utils::visitors::is_local_used;
|
||||
use clippy_utils::{contains_name, higher, is_integer_const, sugg, SpanlessEq};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
|
@ -3,7 +3,6 @@ use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::path_to_local;
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
|
||||
use if_chain::if_chain;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
@ -76,7 +75,7 @@ pub(super) fn check<'tcx>(
|
||||
if let Res::Def(DefKind::Const, ..) = cx.qpath_res(path, init.hir_id) {
|
||||
emit_lint(cx, vec, pushed_item, ctxt);
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
@ -182,8 +181,8 @@ fn get_vec_push<'tcx>(
|
||||
// Check that the method being called is push() on a Vec
|
||||
&& is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym::Vec)
|
||||
&& path.ident.name.as_str() == "push"
|
||||
{
|
||||
return Some((self_expr, pushed_item, semi_stmt.span.ctxt()))
|
||||
}
|
||||
{
|
||||
return Some((self_expr, pushed_item, semi_stmt.span.ctxt()));
|
||||
}
|
||||
None
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ use super::SINGLE_ELEMENT_LOOP;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::{indent_of, snippet_with_applicability};
|
||||
use clippy_utils::visitors::contains_break_or_continue;
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::util::parser::PREC_PREFIX;
|
||||
use rustc_ast::Mutability;
|
||||
use rustc_errors::Applicability;
|
||||
@ -79,10 +78,12 @@ pub(super) fn check<'tcx>(
|
||||
let indent = " ".repeat(indent_of(cx, block.stmts[0].span).unwrap_or(0));
|
||||
|
||||
// Reference iterator from `&(mut) []` or `[].iter(_mut)()`.
|
||||
if !prefix.is_empty() && (
|
||||
// Precedence of internal expression is less than or equal to precedence of `&expr`.
|
||||
arg_expression.precedence().order() <= PREC_PREFIX || is_range_literal(arg_expression)
|
||||
) {
|
||||
if !prefix.is_empty()
|
||||
&& (
|
||||
// Precedence of internal expression is less than or equal to precedence of `&expr`.
|
||||
arg_expression.precedence().order() <= PREC_PREFIX || is_range_literal(arg_expression)
|
||||
)
|
||||
{
|
||||
arg_snip = format!("({arg_snip})").into();
|
||||
}
|
||||
|
||||
@ -94,6 +95,6 @@ pub(super) fn check<'tcx>(
|
||||
"try",
|
||||
format!("{{\n{indent}let {pat_snip} = {prefix}{arg_snip};{block_str}}}"),
|
||||
applicability,
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
use clippy_utils::ty::{has_iter_method, implements_trait};
|
||||
use clippy_utils::{get_parent_expr, is_integer_const, path_to_local, path_to_local_id, sugg};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::{LitIntType, LitKind};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::intravisit::{walk_expr, walk_local, walk_pat, walk_stmt, Visitor};
|
||||
@ -156,7 +155,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> {
|
||||
ty,
|
||||
name: ident.name,
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
walk_local(self, l);
|
||||
|
@ -2,7 +2,6 @@ use super::WHILE_IMMUTABLE_CONDITION;
|
||||
use clippy_utils::consts::constant;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::usage::mutated_variables;
|
||||
use if_chain::if_chain;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::DefIdMap;
|
||||
use rustc_hir::intravisit::{walk_expr, Visitor};
|
||||
|
@ -3,7 +3,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::visitors::is_res_used;
|
||||
use clippy_utils::{get_enclosing_loop_or_multi_call_closure, higher, is_refutable, is_res_lang_ctor, is_trait_method};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::intravisit::{walk_expr, Visitor};
|
||||
@ -15,7 +14,7 @@ use rustc_span::symbol::sym;
|
||||
use rustc_span::Symbol;
|
||||
|
||||
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
let (scrutinee_expr, iter_expr_struct, iter_expr, some_pat, loop_expr) = if let Some(higher::WhileLet { if_then, let_pat, let_expr }) = higher::WhileLet::hir(expr)
|
||||
if let Some(higher::WhileLet { if_then, let_pat, let_expr }) = higher::WhileLet::hir(expr)
|
||||
// check for `Some(..)` pattern
|
||||
&& let PatKind::TupleStruct(ref pat_path, some_pat, _) = let_pat.kind
|
||||
&& is_res_lang_ctor(cx, cx.qpath_res(pat_path, let_pat.hir_id), LangItem::OptionSome)
|
||||
@ -27,45 +26,41 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
// get the loop containing the match expression
|
||||
&& !uses_iter(cx, &iter_expr_struct, if_then)
|
||||
{
|
||||
(let_expr, iter_expr_struct, iter_expr, some_pat, expr)
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let loop_var = if let Some(some_pat) = some_pat.first() {
|
||||
if is_refutable(cx, some_pat) {
|
||||
// Refutable patterns don't work with for loops.
|
||||
return;
|
||||
}
|
||||
snippet_with_applicability(cx, some_pat.span, "..", &mut applicability)
|
||||
} else {
|
||||
"_".into()
|
||||
};
|
||||
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let loop_var = if let Some(some_pat) = some_pat.first() {
|
||||
if is_refutable(cx, some_pat) {
|
||||
// Refutable patterns don't work with for loops.
|
||||
return;
|
||||
}
|
||||
snippet_with_applicability(cx, some_pat.span, "..", &mut applicability)
|
||||
} else {
|
||||
"_".into()
|
||||
};
|
||||
// If the iterator is a field or the iterator is accessed after the loop is complete it needs to be
|
||||
// borrowed mutably. TODO: If the struct can be partially moved from and the struct isn't used
|
||||
// afterwards a mutable borrow of a field isn't necessary.
|
||||
let by_ref = if cx.typeck_results().expr_ty(iter_expr).ref_mutability() == Some(Mutability::Mut)
|
||||
|| !iter_expr_struct.can_move
|
||||
|| !iter_expr_struct.fields.is_empty()
|
||||
|| needs_mutable_borrow(cx, &iter_expr_struct, expr)
|
||||
{
|
||||
".by_ref()"
|
||||
} else {
|
||||
""
|
||||
};
|
||||
|
||||
// If the iterator is a field or the iterator is accessed after the loop is complete it needs to be
|
||||
// borrowed mutably. TODO: If the struct can be partially moved from and the struct isn't used
|
||||
// afterwards a mutable borrow of a field isn't necessary.
|
||||
let by_ref = if cx.typeck_results().expr_ty(iter_expr).ref_mutability() == Some(Mutability::Mut)
|
||||
|| !iter_expr_struct.can_move
|
||||
|| !iter_expr_struct.fields.is_empty()
|
||||
|| needs_mutable_borrow(cx, &iter_expr_struct, loop_expr)
|
||||
{
|
||||
".by_ref()"
|
||||
} else {
|
||||
""
|
||||
};
|
||||
|
||||
let iterator = snippet_with_applicability(cx, iter_expr.span, "_", &mut applicability);
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
WHILE_LET_ON_ITERATOR,
|
||||
expr.span.with_hi(scrutinee_expr.span.hi()),
|
||||
"this loop could be written as a `for` loop",
|
||||
"try",
|
||||
format!("for {loop_var} in {iterator}{by_ref}"),
|
||||
applicability,
|
||||
);
|
||||
let iterator = snippet_with_applicability(cx, iter_expr.span, "_", &mut applicability);
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
WHILE_LET_ON_ITERATOR,
|
||||
expr.span.with_hi(let_expr.span.hi()),
|
||||
"this loop could be written as a `for` loop",
|
||||
"try",
|
||||
format!("for {loop_var} in {iterator}{by_ref}"),
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -1,7 +1,6 @@
|
||||
use clippy_utils::diagnostics::span_lint_hir_and_then;
|
||||
use clippy_utils::source::snippet;
|
||||
use hir::def::{DefKind, Res};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_errors::Applicability;
|
||||
@ -108,10 +107,8 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports {
|
||||
self.imports.push((def_path, span, hir_id));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if item.span.from_expansion() {
|
||||
self.push_unique_macro_pat_ty(cx, item.span);
|
||||
}
|
||||
} else if item.span.from_expansion() {
|
||||
self.push_unique_macro_pat_ty(cx, item.span);
|
||||
}
|
||||
}
|
||||
fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) {
|
||||
|
@ -1,7 +1,6 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::{is_entrypoint_fn, is_no_std_crate};
|
||||
use if_chain::if_chain;
|
||||
use rustc_hir::{Expr, ExprKind, QPath};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
@ -54,8 +53,8 @@ impl LateLintPass<'_> for MainRecursion {
|
||||
func.span,
|
||||
&format!("recursing into entrypoint `{}`", snippet(cx, func.span, "main")),
|
||||
None,
|
||||
"consider using another function for this recursion"
|
||||
)
|
||||
"consider using another function for this recursion",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::source::{position_before_rarrow, snippet_block, snippet_opt};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::intravisit::FnKind;
|
||||
use rustc_hir::{
|
||||
@ -85,7 +84,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn {
|
||||
header_span,
|
||||
help,
|
||||
format!("{header_snip}{ret_snip}"),
|
||||
Applicability::MachineApplicable
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
|
||||
let body_snip = snippet_block(cx, closure_body.value.span, "..", Some(block.span));
|
||||
@ -93,7 +92,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn {
|
||||
block.span,
|
||||
"move the body of the async block to the enclosing function",
|
||||
body_snip,
|
||||
Applicability::MachineApplicable
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
},
|
||||
|
@ -98,16 +98,18 @@ fn get_one_size_of_ty<'tcx>(
|
||||
fn get_size_of_ty<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<(&'tcx rustc_hir::Ty<'tcx>, Ty<'tcx>)> {
|
||||
if let ExprKind::Call(count_func, _func_args) = expr.kind
|
||||
&& let ExprKind::Path(ref count_func_qpath) = count_func.kind
|
||||
|
||||
&& let QPath::Resolved(_, count_func_path) = count_func_qpath
|
||||
&& let Some(segment_zero) = count_func_path.segments.first()
|
||||
&& let Some(args) = segment_zero.args
|
||||
&& let Some(GenericArg::Type(real_ty)) = args.args.first()
|
||||
|
||||
&& let Some(def_id) = cx.qpath_res(count_func_qpath, count_func.hir_id).opt_def_id()
|
||||
&& cx.tcx.is_diagnostic_item(sym::mem_size_of, def_id)
|
||||
{
|
||||
cx.typeck_results().node_args(count_func.hir_id).types().next().map(|resolved_ty| (*real_ty, resolved_ty))
|
||||
cx.typeck_results()
|
||||
.node_args(count_func.hir_id)
|
||||
.types()
|
||||
.next()
|
||||
.map(|resolved_ty| (*real_ty, resolved_ty))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -4,7 +4,6 @@ use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::usage::mutated_variables;
|
||||
use clippy_utils::{eq_expr_value, higher, match_def_path, paths};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::LitKind;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::intravisit::{walk_expr, Visitor};
|
||||
@ -97,25 +96,35 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip {
|
||||
|
||||
let strippings = find_stripping(cx, strip_kind, target_res, pattern, then);
|
||||
if !strippings.is_empty() {
|
||||
|
||||
let kind_word = match strip_kind {
|
||||
StripKind::Prefix => "prefix",
|
||||
StripKind::Suffix => "suffix",
|
||||
};
|
||||
|
||||
let test_span = expr.span.until(then.span);
|
||||
span_lint_and_then(cx, MANUAL_STRIP, strippings[0], &format!("stripping a {kind_word} manually"), |diag| {
|
||||
diag.span_note(test_span, format!("the {kind_word} was tested here"));
|
||||
multispan_sugg(
|
||||
diag,
|
||||
&format!("try using the `strip_{kind_word}` method"),
|
||||
vec![(test_span,
|
||||
format!("if let Some(<stripped>) = {}.strip_{kind_word}({}) ",
|
||||
snippet(cx, target_arg.span, ".."),
|
||||
snippet(cx, pattern.span, "..")))]
|
||||
.into_iter().chain(strippings.into_iter().map(|span| (span, "<stripped>".into()))),
|
||||
);
|
||||
});
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
MANUAL_STRIP,
|
||||
strippings[0],
|
||||
&format!("stripping a {kind_word} manually"),
|
||||
|diag| {
|
||||
diag.span_note(test_span, format!("the {kind_word} was tested here"));
|
||||
multispan_sugg(
|
||||
diag,
|
||||
&format!("try using the `strip_{kind_word}` method"),
|
||||
vec![(
|
||||
test_span,
|
||||
format!(
|
||||
"if let Some(<stripped>) = {}.strip_{kind_word}({}) ",
|
||||
snippet(cx, target_arg.span, ".."),
|
||||
snippet(cx, pattern.span, "..")
|
||||
),
|
||||
)]
|
||||
.into_iter()
|
||||
.chain(strippings.into_iter().map(|span| (span, "<stripped>".into()))),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -210,7 +219,13 @@ fn find_stripping<'tcx>(
|
||||
}
|
||||
},
|
||||
(StripKind::Suffix, None, Some(end)) => {
|
||||
if let ExprKind::Binary(Spanned { node: BinOpKind::Sub, .. }, left, right) = end.kind
|
||||
if let ExprKind::Binary(
|
||||
Spanned {
|
||||
node: BinOpKind::Sub, ..
|
||||
},
|
||||
left,
|
||||
right,
|
||||
) = end.kind
|
||||
&& let Some(left_arg) = len_arg(self.cx, left)
|
||||
&& let ExprKind::Path(left_path) = &left_arg.kind
|
||||
&& self.cx.qpath_res(left_path, left_arg.hir_id) == self.target
|
||||
@ -220,7 +235,7 @@ fn find_stripping<'tcx>(
|
||||
return;
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_context};
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::{iter_input_pats, method_chain_args};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
|
@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::{higher, is_res_lang_ctor};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind, LangItem, PatKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
|
@ -5,7 +5,6 @@ use clippy_utils::visitors::is_local_used;
|
||||
use clippy_utils::{
|
||||
is_res_lang_ctor, is_unit_expr, path_to_local, peel_blocks_with_stmt, peel_ref_operators, SpanlessEq,
|
||||
};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::MultiSpan;
|
||||
use rustc_hir::LangItem::OptionNone;
|
||||
use rustc_hir::{Arm, Expr, Guard, HirId, Let, Pat, PatKind};
|
||||
@ -84,7 +83,11 @@ fn check_arm<'tcx>(
|
||||
{
|
||||
let msg = format!(
|
||||
"this `{}` can be collapsed into the outer `{}`",
|
||||
if matches!(inner, IfLetOrMatch::Match(..)) { "match" } else { "if let" },
|
||||
if matches!(inner, IfLetOrMatch::Match(..)) {
|
||||
"match"
|
||||
} else {
|
||||
"if let"
|
||||
},
|
||||
if outer_is_match { "match" } else { "if let" },
|
||||
);
|
||||
// collapsing patterns need an explicit field name in struct pattern matching
|
||||
@ -94,18 +97,15 @@ fn check_arm<'tcx>(
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
COLLAPSIBLE_MATCH,
|
||||
inner_expr.span,
|
||||
&msg,
|
||||
|diag| {
|
||||
let mut help_span = MultiSpan::from_spans(vec![binding_span, inner_then_pat.span]);
|
||||
help_span.push_span_label(binding_span, "replace this binding");
|
||||
help_span.push_span_label(inner_then_pat.span, format!("with this pattern{replace_msg}"));
|
||||
diag.span_help(help_span, "the outer pattern can be modified to include the inner pattern");
|
||||
},
|
||||
);
|
||||
span_lint_and_then(cx, COLLAPSIBLE_MATCH, inner_expr.span, &msg, |diag| {
|
||||
let mut help_span = MultiSpan::from_spans(vec![binding_span, inner_then_pat.span]);
|
||||
help_span.push_span_label(binding_span, "replace this binding");
|
||||
help_span.push_span_label(inner_then_pat.span, format!("with this pattern{replace_msg}"));
|
||||
diag.span_help(
|
||||
help_span,
|
||||
"the outer pattern can be modified to include the inner pattern",
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,14 +11,13 @@ pub(crate) fn check(cx: &LateContext<'_>, local: &Local<'_>) -> bool {
|
||||
if !local.span.from_expansion()
|
||||
&& let Some(expr) = local.init
|
||||
&& let ExprKind::Match(target, arms, MatchSource::Normal) = expr.kind
|
||||
&& arms.len() == 1 && arms[0].guard.is_none()
|
||||
&& let PatKind::TupleStruct(
|
||||
QPath::Resolved(None, variant_name), args, _) = arms[0].pat.kind
|
||||
&& arms.len() == 1
|
||||
&& arms[0].guard.is_none()
|
||||
&& let PatKind::TupleStruct(QPath::Resolved(None, variant_name), args, _) = arms[0].pat.kind
|
||||
&& args.len() == 1
|
||||
&& let PatKind::Binding(binding, arg, ..) = strip_pat_refs(&args[0]).kind
|
||||
&& let body = peel_blocks(arms[0].body)
|
||||
&& path_to_local_id(body, arg)
|
||||
|
||||
{
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
span_lint_and_sugg(
|
||||
|
@ -23,16 +23,18 @@ fn get_cond_expr<'tcx>(
|
||||
) -> Option<SomeExpr<'tcx>> {
|
||||
if let Some(block_expr) = peels_blocks_incl_unsafe_opt(expr)
|
||||
&& let ExprKind::If(cond, then_expr, Some(else_expr)) = block_expr.kind
|
||||
&& let PatKind::Binding(_,target, ..) = pat.kind
|
||||
&& let PatKind::Binding(_, target, ..) = pat.kind
|
||||
&& (is_some_expr(cx, target, ctxt, then_expr) && is_none_expr(cx, else_expr)
|
||||
|| is_none_expr(cx, then_expr) && is_some_expr(cx, target, ctxt, else_expr)) // check that one expr resolves to `Some(x)`, the other to `None`
|
||||
|| is_none_expr(cx, then_expr) && is_some_expr(cx, target, ctxt, else_expr))
|
||||
// check that one expr resolves to `Some(x)`, the other to `None`
|
||||
{
|
||||
return Some(SomeExpr {
|
||||
expr: peels_blocks_incl_unsafe(cond.peel_drop_temps()),
|
||||
needs_unsafe_block: contains_unsafe_block(cx, expr),
|
||||
needs_negated: is_none_expr(cx, then_expr) // if the `then_expr` resolves to `None`, need to negate the cond
|
||||
})
|
||||
};
|
||||
expr: peels_blocks_incl_unsafe(cond.peel_drop_temps()),
|
||||
needs_unsafe_block: contains_unsafe_block(cx, expr),
|
||||
needs_negated: is_none_expr(cx, then_expr), /* if the `then_expr` resolves to `None`, need to negate the
|
||||
* cond */
|
||||
});
|
||||
};
|
||||
None
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,6 @@ use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt};
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::usage::contains_return_break_continue_macro;
|
||||
use clippy_utils::{is_res_lang_ctor, path_to_local_id, sugg};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::LangItem::{OptionNone, ResultErr};
|
||||
@ -17,30 +16,27 @@ use super::MANUAL_UNWRAP_OR;
|
||||
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, scrutinee: &'tcx Expr<'_>, arms: &'tcx [Arm<'_>]) {
|
||||
let ty = cx.typeck_results().expr_ty(scrutinee);
|
||||
if let Some(ty_name) = if is_type_diagnostic_item(cx, ty, sym::Option) {
|
||||
Some("Option")
|
||||
} else if is_type_diagnostic_item(cx, ty, sym::Result) {
|
||||
Some("Result")
|
||||
} else {
|
||||
None
|
||||
}
|
||||
&& let Some(or_arm) = applicable_or_arm(cx, arms)
|
||||
Some("Option")
|
||||
} else if is_type_diagnostic_item(cx, ty, sym::Result) {
|
||||
Some("Result")
|
||||
} else {
|
||||
None
|
||||
} && let Some(or_arm) = applicable_or_arm(cx, arms)
|
||||
&& let Some(or_body_snippet) = snippet_opt(cx, or_arm.body.span)
|
||||
&& let Some(indent) = indent_of(cx, expr.span)
|
||||
&& constant_simple(cx, cx.typeck_results(), or_arm.body).is_some()
|
||||
{
|
||||
let reindented_or_body =
|
||||
reindent_multiline(or_body_snippet.into(), true, Some(indent));
|
||||
let reindented_or_body = reindent_multiline(or_body_snippet.into(), true, Some(indent));
|
||||
|
||||
let mut app = Applicability::MachineApplicable;
|
||||
let suggestion = sugg::Sugg::hir_with_context(cx, scrutinee, expr.span.ctxt(), "..", &mut app).maybe_par();
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
MANUAL_UNWRAP_OR, expr.span,
|
||||
MANUAL_UNWRAP_OR,
|
||||
expr.span,
|
||||
&format!("this pattern reimplements `{ty_name}::unwrap_or`"),
|
||||
"replace with",
|
||||
format!(
|
||||
"{suggestion}.unwrap_or({reindented_or_body})",
|
||||
),
|
||||
format!("{suggestion}.unwrap_or({reindented_or_body})",),
|
||||
app,
|
||||
);
|
||||
}
|
||||
@ -49,14 +45,13 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, scrutinee:
|
||||
fn applicable_or_arm<'a>(cx: &LateContext<'_>, arms: &'a [Arm<'a>]) -> Option<&'a Arm<'a>> {
|
||||
if arms.len() == 2
|
||||
&& arms.iter().all(|arm| arm.guard.is_none())
|
||||
&& let Some((idx, or_arm)) = arms.iter().enumerate().find(|(_, arm)| {
|
||||
match arm.pat.kind {
|
||||
PatKind::Path(ref qpath) => is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), OptionNone),
|
||||
PatKind::TupleStruct(ref qpath, [pat], _) =>
|
||||
matches!(pat.kind, PatKind::Wild)
|
||||
&& is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), ResultErr),
|
||||
_ => false,
|
||||
}
|
||||
&& let Some((idx, or_arm)) = arms.iter().enumerate().find(|(_, arm)| match arm.pat.kind {
|
||||
PatKind::Path(ref qpath) => is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), OptionNone),
|
||||
PatKind::TupleStruct(ref qpath, [pat], _) => {
|
||||
matches!(pat.kind, PatKind::Wild)
|
||||
&& is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), ResultErr)
|
||||
},
|
||||
_ => false,
|
||||
})
|
||||
&& let unwrap_arm = &arms[1 - idx]
|
||||
&& let PatKind::TupleStruct(ref qpath, [unwrap_pat], _) = unwrap_arm.pat.kind
|
||||
|
@ -71,9 +71,10 @@ fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option<Mutability> {
|
||||
&& 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
|
||||
&& path2.segments.len() == 1 && ident.name == path2.segments[0].ident.name
|
||||
&& path2.segments.len() == 1
|
||||
&& ident.name == path2.segments[0].ident.name
|
||||
{
|
||||
return Some(mutabl)
|
||||
return Some(mutabl);
|
||||
}
|
||||
None
|
||||
}
|
||||
|
@ -87,10 +87,7 @@ where
|
||||
&& b0 != b1
|
||||
&& (first_guard.is_none() || iter.len() == 0)
|
||||
&& first_attrs.is_empty()
|
||||
&& iter
|
||||
.all(|arm| {
|
||||
find_bool_lit(&arm.2.kind).map_or(false, |b| b == b0) && arm.3.is_none() && arm.0.is_empty()
|
||||
})
|
||||
&& iter.all(|arm| find_bool_lit(&arm.2.kind).map_or(false, |b| b == b0) && arm.3.is_none() && arm.0.is_empty())
|
||||
{
|
||||
if let Some(last_pat) = last_pat_opt {
|
||||
if !is_wild(last_pat) {
|
||||
@ -119,7 +116,10 @@ where
|
||||
.join(" | ")
|
||||
};
|
||||
let pat_and_guard = if let Some(Guard::If(g)) = first_guard {
|
||||
format!("{pat} if {}", snippet_with_applicability(cx, g.span, "..", &mut applicability))
|
||||
format!(
|
||||
"{pat} if {}",
|
||||
snippet_with_applicability(cx, g.span, "..", &mut applicability)
|
||||
)
|
||||
} else {
|
||||
pat
|
||||
};
|
||||
@ -135,7 +135,10 @@ where
|
||||
cx,
|
||||
MATCH_LIKE_MATCHES_MACRO,
|
||||
expr.span,
|
||||
&format!("{} expression looks like `matches!` macro", if is_if_let { "if let .. else" } else { "match" }),
|
||||
&format!(
|
||||
"{} expression looks like `matches!` macro",
|
||||
if is_if_let { "if let .. else" } else { "match" }
|
||||
),
|
||||
"try",
|
||||
format!(
|
||||
"{}matches!({}, {pat_and_guard})",
|
||||
|
@ -1,7 +1,6 @@
|
||||
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 if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind, LangItem};
|
||||
use rustc_lint::LateContext;
|
||||
@ -12,7 +11,6 @@ use super::MATCH_ON_VEC_ITEMS;
|
||||
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, scrutinee: &'tcx Expr<'_>) {
|
||||
if let Some(idx_expr) = is_vec_indexing(cx, scrutinee)
|
||||
&& let ExprKind::Index(vec, idx, _) = idx_expr.kind
|
||||
|
||||
{
|
||||
// FIXME: could be improved to suggest surrounding every pattern with Some(_),
|
||||
// but only when `or_patterns` are stabilized.
|
||||
@ -22,12 +20,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, scrutinee: &'tcx Expr<'_>) {
|
||||
scrutinee.span,
|
||||
"indexing into a vector may panic",
|
||||
"try",
|
||||
format!(
|
||||
"{}.get({})",
|
||||
snippet(cx, vec.span, ".."),
|
||||
snippet(cx, idx.span, "..")
|
||||
),
|
||||
Applicability::MaybeIncorrect
|
||||
format!("{}.get({})", snippet(cx, vec.span, ".."), snippet(cx, idx.span, "..")),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -36,7 +30,6 @@ fn is_vec_indexing<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Opti
|
||||
if let ExprKind::Index(array, index, _) = expr.kind
|
||||
&& is_vector(cx, array)
|
||||
&& !is_full_range(cx, index)
|
||||
|
||||
{
|
||||
return Some(expr);
|
||||
}
|
||||
|
@ -23,10 +23,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, scrutinee: &'tcx Expr<'_>, arm
|
||||
if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty(scrutinee).kind()
|
||||
&& let ty::Str = ty.kind()
|
||||
{
|
||||
let mut visitor = MatchExprVisitor {
|
||||
cx,
|
||||
case_method: None,
|
||||
};
|
||||
let mut visitor = MatchExprVisitor { cx, case_method: None };
|
||||
|
||||
visitor.visit_expr(scrutinee);
|
||||
|
||||
@ -87,9 +84,9 @@ fn verify_case<'a>(case_method: &'a CaseMethod, arms: &'a [Arm<'_>]) -> Option<(
|
||||
|
||||
for arm in arms {
|
||||
if let PatKind::Lit(Expr {
|
||||
kind: ExprKind::Lit(lit),
|
||||
..
|
||||
}) = arm.pat.kind
|
||||
kind: ExprKind::Lit(lit),
|
||||
..
|
||||
}) = arm.pat.kind
|
||||
&& let LitKind::Str(symbol, _) = lit.node
|
||||
&& let input = symbol.as_str()
|
||||
&& !case_check(input)
|
||||
|
@ -39,7 +39,8 @@ pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm<'
|
||||
&& is_panic(cx, macro_call.def_id)
|
||||
{
|
||||
// `Err(_)` or `Err(_e)` arm with `panic!` found
|
||||
span_lint_and_note(cx,
|
||||
span_lint_and_note(
|
||||
cx,
|
||||
MATCH_WILD_ERR_ARM,
|
||||
arm.pat.span,
|
||||
&format!("`Err({ident_bind_name})` matches all errors"),
|
||||
|
@ -5,7 +5,6 @@ use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::ty::{is_type_diagnostic_item, needs_ordered_drop};
|
||||
use clippy_utils::visitors::{any_temporaries_need_ordered_drop, for_each_expr};
|
||||
use clippy_utils::{higher, is_expn_of, is_trait_method};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::LitKind;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
|
@ -14,7 +14,6 @@ pub(crate) fn check(cx: &LateContext<'_>, pat: &Pat<'_>) {
|
||||
&& (def.is_struct() || def.is_union())
|
||||
&& fields.len() == def.non_enum_variant().fields.len()
|
||||
&& !def.non_enum_variant().is_field_list_non_exhaustive()
|
||||
|
||||
{
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
|
@ -93,14 +93,18 @@ fn report_single_pattern(
|
||||
&& let (ty, ty_ref_count) = peel_mid_ty_refs(cx.typeck_results().expr_ty(ex))
|
||||
&& let Some(spe_trait_id) = cx.tcx.lang_items().structural_peq_trait()
|
||||
&& let Some(pe_trait_id) = cx.tcx.lang_items().eq_trait()
|
||||
&& (ty.is_integral() || ty.is_char() || ty.is_str()
|
||||
|| (implements_trait(cx, ty, spe_trait_id, &[])
|
||||
&& implements_trait(cx, ty, pe_trait_id, &[ty.into()])))
|
||||
&& (ty.is_integral()
|
||||
|| ty.is_char()
|
||||
|| ty.is_str()
|
||||
|| (implements_trait(cx, ty, spe_trait_id, &[]) && implements_trait(cx, ty, pe_trait_id, &[ty.into()])))
|
||||
{
|
||||
// scrutinee derives PartialEq and the pattern is a constant.
|
||||
let pat_ref_count = match pat.kind {
|
||||
// string literals are already a reference.
|
||||
PatKind::Lit(Expr { kind: ExprKind::Lit(lit), .. }) if lit.node.is_str() => pat_ref_count + 1,
|
||||
PatKind::Lit(Expr {
|
||||
kind: ExprKind::Lit(lit),
|
||||
..
|
||||
}) if lit.node.is_str() => pat_ref_count + 1,
|
||||
_ => pat_ref_count,
|
||||
};
|
||||
// References are only implicitly added to the pattern, so no overflow here.
|
||||
|
@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::{get_parent_expr, is_res_lang_ctor, path_res};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::LangItem::ResultErr;
|
||||
use rustc_hir::{Expr, ExprKind, LangItem, MatchSource, QPath};
|
||||
@ -104,7 +103,6 @@ fn poll_result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<
|
||||
if let ty::Adt(def, subst) = ty.kind()
|
||||
&& cx.tcx.lang_items().get(LangItem::Poll) == Some(def.did())
|
||||
&& let ready_ty = subst.type_at(0)
|
||||
|
||||
&& let ty::Adt(ready_def, ready_subst) = ready_ty.kind()
|
||||
&& cx.tcx.is_diagnostic_item(sym::Result, ready_def.did())
|
||||
{
|
||||
@ -119,11 +117,9 @@ fn poll_option_result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) ->
|
||||
if let ty::Adt(def, subst) = ty.kind()
|
||||
&& cx.tcx.lang_items().get(LangItem::Poll) == Some(def.did())
|
||||
&& let ready_ty = subst.type_at(0)
|
||||
|
||||
&& let ty::Adt(ready_def, ready_subst) = ready_ty.kind()
|
||||
&& cx.tcx.is_diagnostic_item(sym::Option, ready_def.did())
|
||||
&& let some_ty = ready_subst.type_at(0)
|
||||
|
||||
&& let ty::Adt(some_def, some_subst) = some_ty.kind()
|
||||
&& cx.tcx.is_diagnostic_item(sym::Result, some_def.did())
|
||||
{
|
||||
|
@ -4,7 +4,6 @@ use clippy_utils::source::{snippet, snippet_with_applicability};
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::ty::is_non_aggregate_primitive_type;
|
||||
use clippy_utils::{is_default_equivalent, is_res_lang_ctor, path_res, peel_ref_operators};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::LangItem::OptionNone;
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
@ -163,8 +162,9 @@ fn check_replace_with_uninit(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<'
|
||||
),
|
||||
applicability,
|
||||
);
|
||||
} else if cx.tcx.is_diagnostic_item(sym::mem_zeroed, repl_def_id) &&
|
||||
!cx.typeck_results().expr_ty(src).is_primitive() {
|
||||
} else if cx.tcx.is_diagnostic_item(sym::mem_zeroed, repl_def_id)
|
||||
&& !cx.typeck_results().expr_ty(src).is_primitive()
|
||||
{
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
MEM_REPLACE_WITH_UNINIT,
|
||||
|
@ -3,7 +3,6 @@ use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and
|
||||
use clippy_utils::peel_blocks;
|
||||
use clippy_utils::source::{snippet, snippet_with_context};
|
||||
use clippy_utils::visitors::find_all_ret_expressions;
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
|
||||
@ -81,16 +80,11 @@ pub(crate) trait BindInsteadOfMap {
|
||||
|
||||
let closure_args_snip = snippet(cx, closure_args_span, "..");
|
||||
let option_snip = snippet(cx, recv.span, "..");
|
||||
let note = format!("{option_snip}.{}({closure_args_snip} {some_inner_snip})", Self::GOOD_METHOD_NAME);
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
BIND_INSTEAD_OF_MAP,
|
||||
expr.span,
|
||||
&msg,
|
||||
"try",
|
||||
note,
|
||||
app,
|
||||
let note = format!(
|
||||
"{option_snip}.{}({closure_args_snip} {some_inner_snip})",
|
||||
Self::GOOD_METHOD_NAME
|
||||
);
|
||||
span_lint_and_sugg(cx, BIND_INSTEAD_OF_MAP, expr.span, &msg, "try", note, app);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
@ -115,7 +109,11 @@ pub(crate) trait BindInsteadOfMap {
|
||||
let (span, msg) = if can_sugg
|
||||
&& let hir::ExprKind::MethodCall(segment, ..) = expr.kind
|
||||
&& let Some(msg) = Self::lint_msg(cx)
|
||||
{ (segment.ident.span, msg) } else { return false; };
|
||||
{
|
||||
(segment.ident.span, msg)
|
||||
} else {
|
||||
return false;
|
||||
};
|
||||
span_lint_and_then(cx, BIND_INSTEAD_OF_MAP, expr.span, &msg, |diag| {
|
||||
multispan_sugg_with_applicability(
|
||||
diag,
|
||||
@ -136,7 +134,10 @@ pub(crate) trait BindInsteadOfMap {
|
||||
if let Some(adt) = cx.typeck_results().expr_ty(recv).ty_adt_def()
|
||||
&& let Some(vid) = cx.tcx.lang_items().get(Self::VARIANT_LANG_ITEM)
|
||||
&& adt.did() == cx.tcx.parent(vid)
|
||||
{} else { return false; }
|
||||
{
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
match arg.kind {
|
||||
hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }) => {
|
||||
|
@ -3,7 +3,6 @@ use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::visitors::is_local_used;
|
||||
use clippy_utils::{path_to_local_id, peel_blocks, peel_ref_operators, strip_pat_refs};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BinOpKind, Closure, Expr, ExprKind, PatKind};
|
||||
use rustc_lint::LateContext;
|
||||
@ -24,9 +23,7 @@ pub(super) fn check<'tcx>(
|
||||
&& let PatKind::Binding(_, arg_id, _, _) = strip_pat_refs(param.pat).kind
|
||||
&& let ExprKind::Binary(ref op, l, r) = body.value.kind
|
||||
&& op.node == BinOpKind::Eq
|
||||
&& is_type_diagnostic_item(cx,
|
||||
cx.typeck_results().expr_ty(filter_recv).peel_refs(),
|
||||
sym::SliceIter)
|
||||
&& is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(filter_recv).peel_refs(), sym::SliceIter)
|
||||
&& let operand_is_arg = (|expr| {
|
||||
let expr = peel_ref_operators(cx, peel_blocks(expr));
|
||||
path_to_local_id(expr, arg_id)
|
||||
@ -41,8 +38,7 @@ pub(super) fn check<'tcx>(
|
||||
&& ty::Uint(UintTy::U8) == *cx.typeck_results().expr_ty(needle).peel_refs().kind()
|
||||
&& !is_local_used(cx, needle, arg_id)
|
||||
{
|
||||
let haystack = if let ExprKind::MethodCall(path, receiver, [], _) =
|
||||
filter_recv.kind {
|
||||
let haystack = if let ExprKind::MethodCall(path, receiver, [], _) = filter_recv.kind {
|
||||
let p = path.ident.name;
|
||||
if p == sym::iter || p == sym::iter_mut {
|
||||
receiver
|
||||
@ -59,9 +55,11 @@ pub(super) fn check<'tcx>(
|
||||
expr.span,
|
||||
"you appear to be counting bytes the naive way",
|
||||
"consider using the bytecount crate",
|
||||
format!("bytecount::count({}, {})",
|
||||
snippet_with_applicability(cx, haystack.span, "..", &mut applicability),
|
||||
snippet_with_applicability(cx, needle.span, "..", &mut applicability)),
|
||||
format!(
|
||||
"bytecount::count({}, {})",
|
||||
snippet_with_applicability(cx, haystack.span, "..", &mut applicability),
|
||||
snippet_with_applicability(cx, needle.span, "..", &mut applicability)
|
||||
),
|
||||
applicability,
|
||||
);
|
||||
};
|
||||
|
@ -1,7 +1,6 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::ty::is_type_lang_item;
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::LateContext;
|
||||
@ -27,8 +26,11 @@ pub(super) fn check<'tcx>(
|
||||
expr.span,
|
||||
"using long and hard to read `.bytes().count()`",
|
||||
"consider calling `.len()` instead",
|
||||
format!("{}.len()", snippet_with_applicability(cx, bytes_recv.span, "..", &mut applicability)),
|
||||
applicability
|
||||
format!(
|
||||
"{}.len()",
|
||||
snippet_with_applicability(cx, bytes_recv.span, "..", &mut applicability)
|
||||
),
|
||||
applicability,
|
||||
);
|
||||
};
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt};
|
||||
use clippy_utils::ty::is_type_lang_item;
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::LitKind;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind, LangItem};
|
||||
@ -30,7 +29,10 @@ pub(super) fn check<'tcx>(
|
||||
if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
|
||||
&& let Some(impl_id) = cx.tcx.impl_of_method(method_id)
|
||||
&& cx.tcx.type_of(impl_id).instantiate_identity().is_str()
|
||||
&& let ExprKind::Lit(Spanned { node: LitKind::Str(ext_literal, ..), ..}) = arg.kind
|
||||
&& let ExprKind::Lit(Spanned {
|
||||
node: LitKind::Str(ext_literal, ..),
|
||||
..
|
||||
}) = arg.kind
|
||||
&& (2..=6).contains(&ext_literal.as_str().len())
|
||||
&& let ext_str = ext_literal.as_str()
|
||||
&& ext_str.starts_with('.')
|
||||
@ -47,7 +49,6 @@ pub(super) fn check<'tcx>(
|
||||
|diag| {
|
||||
diag.help("consider using a case-insensitive comparison instead");
|
||||
if let Some(mut recv_source) = snippet_opt(cx, recv.span) {
|
||||
|
||||
if !cx.typeck_results().expr_ty(recv).is_ref() {
|
||||
recv_source = format!("&{recv_source}");
|
||||
}
|
||||
@ -57,9 +58,12 @@ pub(super) fn check<'tcx>(
|
||||
"std::path::Path::new({})
|
||||
.extension()
|
||||
.map_or(false, |ext| ext.eq_ignore_ascii_case(\"{}\"))",
|
||||
recv_source, ext_str.strip_prefix('.').unwrap()).into(),
|
||||
recv_source,
|
||||
ext_str.strip_prefix('.').unwrap()
|
||||
)
|
||||
.into(),
|
||||
true,
|
||||
Some(indent_of(cx, call_span).unwrap_or(0) + 4)
|
||||
Some(indent_of(cx, call_span).unwrap_or(0) + 4),
|
||||
);
|
||||
|
||||
diag.span_suggestion(
|
||||
@ -69,7 +73,7 @@ pub(super) fn check<'tcx>(
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::{method_chain_args, path_def_id};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::{LateContext, Lint};
|
||||
@ -33,10 +32,12 @@ pub(super) fn check(
|
||||
info.expr.span,
|
||||
&format!("you should use the `{suggest}` method"),
|
||||
"like this",
|
||||
format!("{}{}.{suggest}({})",
|
||||
if info.eq { "" } else { "!" },
|
||||
snippet_with_applicability(cx, args[0].0.span, "..", &mut applicability),
|
||||
snippet_with_applicability(cx, arg_char.span, "..", &mut applicability)),
|
||||
format!(
|
||||
"{}{}.{suggest}({})",
|
||||
if info.eq { "" } else { "!" },
|
||||
snippet_with_applicability(cx, args[0].0.span, "..", &mut applicability),
|
||||
snippet_with_applicability(cx, arg_char.span, "..", &mut applicability)
|
||||
),
|
||||
applicability,
|
||||
);
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::method_chain_args;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
@ -26,10 +25,12 @@ pub(super) fn check(
|
||||
info.expr.span,
|
||||
&format!("you should use the `{suggest}` method"),
|
||||
"like this",
|
||||
format!("{}{}.{suggest}('{}')",
|
||||
if info.eq { "" } else { "!" },
|
||||
snippet_with_applicability(cx, args[0].0.span, "..", &mut applicability),
|
||||
c.escape_default()),
|
||||
format!(
|
||||
"{}{}.{suggest}('{}')",
|
||||
if info.eq { "" } else { "!" },
|
||||
snippet_with_applicability(cx, args[0].0.span, "..", &mut applicability),
|
||||
c.escape_default()
|
||||
),
|
||||
applicability,
|
||||
);
|
||||
|
||||
|
@ -27,7 +27,6 @@ pub(super) fn check(
|
||||
&& let Some(data_type) = get_data_type(cx, result_type)
|
||||
// Tests if the T type in a `Result<T, E>` implements debug
|
||||
&& has_debug_impl(cx, data_type)
|
||||
|
||||
{
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
@ -36,8 +35,8 @@ pub(super) fn check(
|
||||
"called `.err().expect()` on a `Result` value",
|
||||
"try",
|
||||
"expect_err".to_string(),
|
||||
Applicability::MachineApplicable
|
||||
);
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind, LangItem};
|
||||
use rustc_lint::LateContext;
|
||||
|
@ -1,7 +1,6 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::get_parent_expr;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use if_chain::if_chain;
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::source_map::Span;
|
||||
|
@ -4,7 +4,6 @@ use clippy_utils::source::{indent_of, reindent_multiline, snippet};
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::{higher, is_trait_method, path_to_local_id, peel_blocks, SpanlessEq};
|
||||
use hir::{Body, HirId, MatchSource, Pat};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::Res;
|
||||
@ -33,7 +32,7 @@ fn is_method(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol) ->
|
||||
&& let hir::ExprKind::Path(path) = &receiver.kind
|
||||
&& let Res::Local(ref local) = cx.qpath_res(path, receiver.hir_id)
|
||||
{
|
||||
return arg_id == *local
|
||||
return arg_id == *local;
|
||||
}
|
||||
false
|
||||
},
|
||||
@ -324,7 +323,6 @@ pub(super) fn check(
|
||||
|
||||
&& let Some(check_result) =
|
||||
offending_expr.check_map_call(cx, map_body, map_param_id, filter_param_id, is_filter_param_ref)
|
||||
|
||||
{
|
||||
let span = filter_span.with_hi(expr.span.hi());
|
||||
let (filter_name, lint) = if is_find {
|
||||
@ -335,18 +333,23 @@ pub(super) fn check(
|
||||
let msg = format!("`{filter_name}(..).map(..)` can be simplified as `{filter_name}_map(..)`");
|
||||
|
||||
let (sugg, note_and_span, applicability) = match check_result {
|
||||
CheckResult::Method { map_arg, method, side_effect_expr_span } => {
|
||||
CheckResult::Method {
|
||||
map_arg,
|
||||
method,
|
||||
side_effect_expr_span,
|
||||
} => {
|
||||
let (to_opt, deref) = match method {
|
||||
CalledMethod::ResultIsOk => (".ok()", String::new()),
|
||||
CalledMethod::OptionIsSome => {
|
||||
let derefs = cx.typeck_results()
|
||||
let derefs = cx
|
||||
.typeck_results()
|
||||
.expr_adjustments(map_arg)
|
||||
.iter()
|
||||
.filter(|adj| matches!(adj.kind, Adjust::Deref(_)))
|
||||
.count();
|
||||
|
||||
("", "*".repeat(derefs))
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
let sugg = format!(
|
||||
@ -363,15 +366,24 @@ pub(super) fn check(
|
||||
};
|
||||
|
||||
(sugg, note_and_span, applicability)
|
||||
}
|
||||
CheckResult::PatternMatching { variant_span, variant_ident } => {
|
||||
},
|
||||
CheckResult::PatternMatching {
|
||||
variant_span,
|
||||
variant_ident,
|
||||
} => {
|
||||
let pat = snippet(cx, variant_span, "<pattern>");
|
||||
|
||||
(format!("{filter_name}_map(|{map_param_ident}| match {map_param_ident} {{ \
|
||||
(
|
||||
format!(
|
||||
"{filter_name}_map(|{map_param_ident}| match {map_param_ident} {{ \
|
||||
{pat} => Some({variant_ident}), \
|
||||
_ => None \
|
||||
}})"), None, Applicability::MachineApplicable)
|
||||
}
|
||||
}})"
|
||||
),
|
||||
None,
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
},
|
||||
};
|
||||
span_lint_and_then(cx, lint, span, &msg, |diag| {
|
||||
diag.span_suggestion(span, "try", sugg, applicability);
|
||||
|
@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use clippy_utils::{is_path_diagnostic_item, sugg};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::LateContext;
|
||||
@ -16,7 +15,6 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Exp
|
||||
&& let ty = cx.typeck_results().expr_ty(expr)
|
||||
&& let arg_ty = cx.typeck_results().expr_ty(&args[0])
|
||||
&& let Some(iter_id) = cx.tcx.get_diagnostic_item(sym::Iterator)
|
||||
|
||||
&& implements_trait(cx, arg_ty, iter_id, &[])
|
||||
{
|
||||
// `expr` implements `FromIterator` trait
|
||||
@ -44,7 +42,6 @@ fn extract_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ty: Ty<'_>) ->
|
||||
if let Some(snippet) = snippet_opt(cx, call_site)
|
||||
&& let snippet_split = snippet.split("::").collect::<Vec<_>>()
|
||||
&& let Some((_, elements)) = snippet_split.split_last()
|
||||
|
||||
{
|
||||
if let [type_specifier, _] = snippet_split.as_slice()
|
||||
&& let Some(type_specifier) = strip_angle_brackets(type_specifier)
|
||||
@ -55,9 +52,16 @@ fn extract_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ty: Ty<'_>) ->
|
||||
// is there a type specifier? (i.e.: like `<u32>` in `collections::BTreeSet::<u32>::`)
|
||||
if let Some(type_specifier) = snippet_split.iter().find(|e| strip_angle_brackets(e).is_some()) {
|
||||
// remove the type specifier from the path elements
|
||||
let without_ts = elements.iter().filter_map(|e| {
|
||||
if e == type_specifier { None } else { Some((*e).to_string()) }
|
||||
}).collect::<Vec<_>>();
|
||||
let without_ts = elements
|
||||
.iter()
|
||||
.filter_map(|e| {
|
||||
if e == type_specifier {
|
||||
None
|
||||
} else {
|
||||
Some((*e).to_string())
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
// join and add the type specifier at the end (i.e.: `collections::BTreeSet<u32>`)
|
||||
format!("{}{type_specifier}", without_ts.join("::"))
|
||||
} else {
|
||||
|
@ -1,7 +1,6 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::LitKind;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
@ -20,7 +19,10 @@ pub(super) fn check<'tcx>(
|
||||
if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
|
||||
&& let Some(impl_id) = cx.tcx.impl_of_method(method_id)
|
||||
&& let identity = cx.tcx.type_of(impl_id).instantiate_identity()
|
||||
&& let hir::ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = arg.kind
|
||||
&& let hir::ExprKind::Lit(Spanned {
|
||||
node: LitKind::Int(0, _),
|
||||
..
|
||||
}) = arg.kind
|
||||
{
|
||||
if identity.is_slice() {
|
||||
let mut app = Applicability::MachineApplicable;
|
||||
@ -34,18 +36,18 @@ pub(super) fn check<'tcx>(
|
||||
format!("{slice_name}.first()"),
|
||||
app,
|
||||
);
|
||||
} else if is_type_diagnostic_item(cx, identity, sym::VecDeque){
|
||||
let mut app = Applicability::MachineApplicable;
|
||||
let slice_name = snippet_with_applicability(cx, recv.span, "..", &mut app);
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
GET_FIRST,
|
||||
expr.span,
|
||||
&format!("accessing first element with `{slice_name}.get(0)`"),
|
||||
"try",
|
||||
format!("{slice_name}.front()"),
|
||||
app,
|
||||
);
|
||||
} else if is_type_diagnostic_item(cx, identity, sym::VecDeque) {
|
||||
let mut app = Applicability::MachineApplicable;
|
||||
let slice_name = snippet_with_applicability(cx, recv.span, "..", &mut app);
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
GET_FIRST,
|
||||
expr.span,
|
||||
&format!("accessing first element with `{slice_name}.get(0)`"),
|
||||
"try",
|
||||
format!("{slice_name}.front()"),
|
||||
app,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
use clippy_utils::ty::{implements_trait, peel_mid_ty_refs};
|
||||
use clippy_utils::{is_diag_item_method, is_diag_trait_item};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::LateContext;
|
||||
|
@ -1,7 +1,6 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::ty::{is_type_lang_item, walk_ptrs_ty_depth};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::LateContext;
|
||||
@ -18,7 +17,8 @@ pub fn check(
|
||||
receiver: &hir::Expr<'_>,
|
||||
args: &[hir::Expr<'_>],
|
||||
) {
|
||||
if args.is_empty() && method_name == sym::to_string
|
||||
if args.is_empty()
|
||||
&& method_name == sym::to_string
|
||||
&& let Some(to_string_meth_did) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
|
||||
&& cx.tcx.is_diagnostic_item(sym::to_string_method, to_string_meth_did)
|
||||
&& let Some(args) = cx.typeck_results().node_args_opt(expr.hir_id)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user