Merge remote-tracking branch 'upstream/master' into rustup
This commit is contained in:
commit
415fdb2d1a
522 changed files with 5251 additions and 2556 deletions
|
|
@ -1,5 +1,6 @@
|
|||
use ast::{AttrStyle, Attribute};
|
||||
use clippy_utils::{diagnostics::span_lint_and_sugg, is_from_proc_macro};
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::is_from_proc_macro;
|
||||
use rustc_ast as ast;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
|
|
|
|||
|
|
@ -1,12 +1,11 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::last_path_segment;
|
||||
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
|
||||
use if_chain::if_chain;
|
||||
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_lint::LateLintPass;
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::print::with_forced_trimmed_paths;
|
||||
use rustc_middle::ty::GenericArgKind;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
|
|
@ -15,8 +14,8 @@ declare_clippy_lint! {
|
|||
/// This lint warns when you use `Arc` with a type that does not implement `Send` or `Sync`.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// Wrapping a type in Arc doesn't add thread safety to the underlying data, so data races
|
||||
/// could occur when touching the underlying data.
|
||||
/// `Arc<T>` is only `Send`/`Sync` when `T` is [both `Send` and `Sync`](https://doc.rust-lang.org/std/sync/struct.Arc.html#impl-Send-for-Arc%3CT%3E),
|
||||
/// either `T` should be made `Send + Sync` or an `Rc` should be used instead of an `Arc`
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
|
|
@ -24,16 +23,17 @@ declare_clippy_lint! {
|
|||
/// # use std::sync::Arc;
|
||||
///
|
||||
/// fn main() {
|
||||
/// // This is safe, as `i32` implements `Send` and `Sync`.
|
||||
/// // This is fine, as `i32` implements `Send` and `Sync`.
|
||||
/// let a = Arc::new(42);
|
||||
///
|
||||
/// // This is not safe, as `RefCell` does not implement `Sync`.
|
||||
/// // `RefCell` is `!Sync`, so either the `Arc` should be replaced with an `Rc`
|
||||
/// // or the `RefCell` replaced with something like a `RwLock`
|
||||
/// let b = Arc::new(RefCell::new(42));
|
||||
/// }
|
||||
/// ```
|
||||
#[clippy::version = "1.72.0"]
|
||||
pub ARC_WITH_NON_SEND_SYNC,
|
||||
correctness,
|
||||
suspicious,
|
||||
"using `Arc` with a type that does not implement `Send` or `Sync`"
|
||||
}
|
||||
declare_lint_pass!(ArcWithNonSendSync => [ARC_WITH_NON_SEND_SYNC]);
|
||||
|
|
@ -41,32 +41,38 @@ declare_lint_pass!(ArcWithNonSendSync => [ARC_WITH_NON_SEND_SYNC]);
|
|||
impl LateLintPass<'_> for ArcWithNonSendSync {
|
||||
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
let ty = cx.typeck_results().expr_ty(expr);
|
||||
if_chain! {
|
||||
if is_type_diagnostic_item(cx, ty, sym::Arc);
|
||||
if let ExprKind::Call(func, [arg]) = expr.kind;
|
||||
if let ExprKind::Path(func_path) = func.kind;
|
||||
if last_path_segment(&func_path).ident.name == sym::new;
|
||||
if let arg_ty = cx.typeck_results().expr_ty(arg);
|
||||
if !matches!(arg_ty.kind(), ty::Param(_));
|
||||
if !cx.tcx
|
||||
.lang_items()
|
||||
.sync_trait()
|
||||
.map_or(false, |id| implements_trait(cx, arg_ty, id, &[])) ||
|
||||
!cx.tcx
|
||||
.get_diagnostic_item(sym::Send)
|
||||
.map_or(false, |id| implements_trait(cx, arg_ty, id, &[]));
|
||||
if is_type_diagnostic_item(cx, ty, sym::Arc)
|
||||
&& let ExprKind::Call(func, [arg]) = expr.kind
|
||||
&& let ExprKind::Path(func_path) = func.kind
|
||||
&& last_path_segment(&func_path).ident.name == sym::new
|
||||
&& let arg_ty = cx.typeck_results().expr_ty(arg)
|
||||
// make sure that the type is not and does not contain any type parameters
|
||||
&& arg_ty.walk().all(|arg| {
|
||||
!matches!(arg.unpack(), GenericArgKind::Type(ty) if matches!(ty.kind(), ty::Param(_)))
|
||||
})
|
||||
&& let Some(send) = cx.tcx.get_diagnostic_item(sym::Send)
|
||||
&& let Some(sync) = cx.tcx.lang_items().sync_trait()
|
||||
&& let [is_send, is_sync] = [send, sync].map(|id| implements_trait(cx, arg_ty, id, &[]))
|
||||
&& !(is_send && is_sync)
|
||||
{
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
ARC_WITH_NON_SEND_SYNC,
|
||||
expr.span,
|
||||
"usage of an `Arc` that is not `Send` or `Sync`",
|
||||
|diag| with_forced_trimmed_paths!({
|
||||
if !is_send {
|
||||
diag.note(format!("the trait `Send` is not implemented for `{arg_ty}`"));
|
||||
}
|
||||
if !is_sync {
|
||||
diag.note(format!("the trait `Sync` is not implemented for `{arg_ty}`"));
|
||||
}
|
||||
|
||||
then {
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
ARC_WITH_NON_SEND_SYNC,
|
||||
expr.span,
|
||||
"usage of `Arc<T>` where `T` is not `Send` or `Sync`",
|
||||
None,
|
||||
"consider using `Rc<T>` instead or wrapping `T` in a std::sync type like \
|
||||
`Mutex<T>`",
|
||||
);
|
||||
}
|
||||
diag.note(format!("required for `{ty}` to implement `Send` and `Sync`"));
|
||||
|
||||
diag.help("consider using an `Rc` instead or wrapping the inner type with a `Mutex`");
|
||||
}
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,14 +31,20 @@ declare_lint_pass!(AssertionsOnConstants => [ASSERTIONS_ON_CONSTANTS]);
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
|
||||
let Some(macro_call) = root_macro_call_first_node(cx, e) else { return };
|
||||
let Some(macro_call) = root_macro_call_first_node(cx, e) else {
|
||||
return;
|
||||
};
|
||||
let is_debug = match cx.tcx.get_diagnostic_name(macro_call.def_id) {
|
||||
Some(sym::debug_assert_macro) => true,
|
||||
Some(sym::assert_macro) => false,
|
||||
_ => return,
|
||||
};
|
||||
let Some((condition, panic_expn)) = find_assert_args(cx, e, macro_call.expn) else { return };
|
||||
let Some(Constant::Bool(val)) = constant(cx, cx.typeck_results(), condition) else { return };
|
||||
let Some((condition, panic_expn)) = find_assert_args(cx, e, macro_call.expn) else {
|
||||
return;
|
||||
};
|
||||
let Some(Constant::Bool(val)) = constant(cx, cx.typeck_results(), condition) else {
|
||||
return;
|
||||
};
|
||||
if val {
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
|
|
|
|||
|
|
@ -1,12 +1,10 @@
|
|||
//! checks for attributes
|
||||
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
|
||||
use clippy_utils::is_from_proc_macro;
|
||||
use clippy_utils::macros::{is_panic, macro_backtrace};
|
||||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::source::{first_line_of_span, is_present_in_source, snippet_opt, without_block_comments};
|
||||
use clippy_utils::{
|
||||
diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then},
|
||||
is_from_proc_macro,
|
||||
};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::{AttrKind, AttrStyle, Attribute, LitKind, MetaItemKind, MetaItemLit, NestedMetaItem};
|
||||
use rustc_errors::Applicability;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
|
||||
use clippy_utils::get_parent_expr;
|
||||
use clippy_utils::higher;
|
||||
use clippy_utils::source::snippet_block_with_applicability;
|
||||
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;
|
||||
|
|
@ -85,8 +84,7 @@ impl<'tcx> LateLintPass<'tcx> for BlocksInIfConditions {
|
|||
);
|
||||
}
|
||||
} else {
|
||||
let span =
|
||||
block.expr.as_ref().map_or_else(|| block.stmts[0].span, |e| e.span);
|
||||
let span = block.expr.as_ref().map_or_else(|| block.stmts[0].span, |e| e.span);
|
||||
if span.from_expansion() || expr.span.from_expansion() {
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ fn is_impl_not_trait_with_bool_out<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -
|
|||
)
|
||||
})
|
||||
.map_or(false, |assoc_item| {
|
||||
let proj = Ty::new_projection(cx.tcx,assoc_item.def_id, cx.tcx.mk_substs_trait(ty, []));
|
||||
let proj = Ty::new_projection(cx.tcx, assoc_item.def_id, cx.tcx.mk_substs_trait(ty, []));
|
||||
let nty = cx.tcx.normalize_erasing_regions(cx.param_env, proj);
|
||||
|
||||
nty.is_bool()
|
||||
|
|
@ -70,14 +70,18 @@ fn is_impl_not_trait_with_bool_out<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for BoolAssertComparison {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return };
|
||||
let Some(macro_call) = root_macro_call_first_node(cx, expr) else {
|
||||
return;
|
||||
};
|
||||
let macro_name = cx.tcx.item_name(macro_call.def_id);
|
||||
let eq_macro = match macro_name.as_str() {
|
||||
"assert_eq" | "debug_assert_eq" => true,
|
||||
"assert_ne" | "debug_assert_ne" => false,
|
||||
_ => return,
|
||||
};
|
||||
let Some ((a, b, _)) = find_assert_eq_args(cx, expr, macro_call.expn) else { return };
|
||||
let Some((a, b, _)) = find_assert_eq_args(cx, expr, macro_call.expn) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let a_span = a.span.source_callsite();
|
||||
let b_span = b.span.source_callsite();
|
||||
|
|
@ -126,7 +130,9 @@ impl<'tcx> LateLintPass<'tcx> for BoolAssertComparison {
|
|||
let mut suggestions = vec![(name_span, non_eq_mac.to_string()), (lit_span, String::new())];
|
||||
|
||||
if bool_value ^ eq_macro {
|
||||
let Some(sugg) = Sugg::hir_opt(cx, non_lit_expr) else { return };
|
||||
let Some(sugg) = Sugg::hir_opt(cx, non_lit_expr) else {
|
||||
return;
|
||||
};
|
||||
suggestions.push((non_lit_expr.span, (!sugg).to_string()));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,9 @@ use rustc_hir::{Block, ExprKind};
|
|||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
|
||||
use clippy_utils::{diagnostics::span_lint_and_then, in_constant, is_else_clause, is_integer_literal, sugg::Sugg};
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::{in_constant, is_else_clause, is_integer_literal};
|
||||
use rustc_errors::Applicability;
|
||||
|
||||
declare_clippy_lint! {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
use crate::reference::DEREF_ADDROF;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::is_from_proc_macro;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use clippy_utils::{get_parent_expr, is_lint_allowed};
|
||||
use clippy_utils::{get_parent_expr, is_from_proc_macro, is_lint_allowed};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{ExprKind, UnOp};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
|
|
|
|||
|
|
@ -1,12 +1,10 @@
|
|||
use clippy_utils::{
|
||||
diagnostics::span_lint_and_sugg, get_parent_node, is_default_equivalent, macros::macro_backtrace, match_path,
|
||||
path_def_id, paths, ty::expr_sig,
|
||||
};
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::macros::macro_backtrace;
|
||||
use clippy_utils::ty::expr_sig;
|
||||
use clippy_utils::{get_parent_node, is_default_equivalent, match_path, path_def_id, paths};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{
|
||||
intravisit::{walk_ty, Visitor},
|
||||
Block, Expr, ExprKind, Local, Node, QPath, TyKind,
|
||||
};
|
||||
use rustc_hir::intravisit::{walk_ty, Visitor};
|
||||
use rustc_hir::{Block, Expr, ExprKind, Local, Node, QPath, TyKind};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_middle::ty::print::with_forced_trimmed_paths;
|
||||
|
|
|
|||
|
|
@ -3,10 +3,8 @@ use clippy_utils::source::snippet_opt;
|
|||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::{
|
||||
mir::Mutability,
|
||||
ty::{self, Ty, TypeAndMut},
|
||||
};
|
||||
use rustc_middle::mir::Mutability;
|
||||
use rustc_middle::ty::{self, Ty, TypeAndMut};
|
||||
|
||||
use super::AS_PTR_CAST_MUT;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::{diagnostics::span_lint_and_then, source};
|
||||
use clippy_utils::source;
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::Mutability;
|
||||
use rustc_hir::{Expr, ExprKind, Node};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::{self, layout::LayoutOf, Ty, TypeAndMut};
|
||||
use rustc_middle::ty::layout::LayoutOf;
|
||||
use rustc_middle::ty::{self, Ty, TypeAndMut};
|
||||
|
||||
use super::CAST_SLICE_DIFFERENT_SIZES;
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@ use clippy_utils::source::snippet_with_context;
|
|||
use clippy_utils::{match_def_path, paths};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{def_id::DefId, Expr, ExprKind};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use clippy_utils::msrvs::POINTER_CAST_CONSTNESS;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::msrvs::{Msrv, POINTER_CAST_CONSTNESS};
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::{diagnostics::span_lint_and_sugg, msrvs::Msrv};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, Mutability};
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ pub(super) fn check<'tcx>(
|
|||
&format!("casting raw pointers to the same type and constness is unnecessary (`{cast_from}` -> `{cast_to}`)"),
|
||||
"try",
|
||||
cast_str.clone(),
|
||||
Applicability::MachineApplicable,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,8 +10,7 @@ use core::iter;
|
|||
use core::ops::ControlFlow;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def_id::DefIdSet;
|
||||
use rustc_hir::intravisit;
|
||||
use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, HirIdSet, Stmt, StmtKind};
|
||||
use rustc_hir::{intravisit, BinOpKind, Block, Expr, ExprKind, HirId, HirIdSet, Stmt, StmtKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::query::Key;
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree};
|
|||
use rustc_errors::Applicability;
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::{symbol::sym, Span};
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::Span;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
|
|
|
|||
|
|
@ -71,7 +71,9 @@ impl DbgMacro {
|
|||
|
||||
impl LateLintPass<'_> for DbgMacro {
|
||||
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return };
|
||||
let Some(macro_call) = root_macro_call_first_node(cx, expr) else {
|
||||
return;
|
||||
};
|
||||
if cx.tcx.is_diagnostic_item(sym::dbg_macro, macro_call.def_id) {
|
||||
// allows `dbg!` in test code if allow-dbg-in-test is set to true in clippy.toml
|
||||
if self.allow_dbg_in_tests
|
||||
|
|
|
|||
|
|
@ -206,6 +206,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
|||
crate::implicit_saturating_sub::IMPLICIT_SATURATING_SUB_INFO,
|
||||
crate::inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR_INFO,
|
||||
crate::incorrect_impls::INCORRECT_CLONE_IMPL_ON_COPY_TYPE_INFO,
|
||||
crate::incorrect_impls::INCORRECT_PARTIAL_ORD_IMPL_ON_ORD_TYPE_INFO,
|
||||
crate::index_refutable_slice::INDEX_REFUTABLE_SLICE_INFO,
|
||||
crate::indexing_slicing::INDEXING_SLICING_INFO,
|
||||
crate::indexing_slicing::OUT_OF_BOUNDS_INDEXING_INFO,
|
||||
|
|
@ -272,6 +273,8 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
|||
crate::manual_async_fn::MANUAL_ASYNC_FN_INFO,
|
||||
crate::manual_bits::MANUAL_BITS_INFO,
|
||||
crate::manual_clamp::MANUAL_CLAMP_INFO,
|
||||
crate::manual_float_methods::MANUAL_IS_FINITE_INFO,
|
||||
crate::manual_float_methods::MANUAL_IS_INFINITE_INFO,
|
||||
crate::manual_is_ascii_check::MANUAL_IS_ASCII_CHECK_INFO,
|
||||
crate::manual_let_else::MANUAL_LET_ELSE_INFO,
|
||||
crate::manual_main_separator_str::MANUAL_MAIN_SEPARATOR_STR_INFO,
|
||||
|
|
@ -388,6 +391,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
|||
crate::methods::OR_THEN_UNWRAP_INFO,
|
||||
crate::methods::PATH_BUF_PUSH_OVERWRITE_INFO,
|
||||
crate::methods::RANGE_ZIP_WITH_LEN_INFO,
|
||||
crate::methods::READ_LINE_WITHOUT_TRIM_INFO,
|
||||
crate::methods::REPEAT_ONCE_INFO,
|
||||
crate::methods::RESULT_MAP_OR_INTO_OPTION_INFO,
|
||||
crate::methods::SEARCH_IS_SOME_INFO,
|
||||
|
|
@ -403,6 +407,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
|||
crate::methods::SUSPICIOUS_MAP_INFO,
|
||||
crate::methods::SUSPICIOUS_SPLITN_INFO,
|
||||
crate::methods::SUSPICIOUS_TO_OWNED_INFO,
|
||||
crate::methods::TYPE_ID_ON_BOX_INFO,
|
||||
crate::methods::UNINIT_ASSUMED_INIT_INFO,
|
||||
crate::methods::UNIT_HASH_INFO,
|
||||
crate::methods::UNNECESSARY_FILTER_MAP_INFO,
|
||||
|
|
@ -468,6 +473,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
|||
crate::needless_if::NEEDLESS_IF_INFO,
|
||||
crate::needless_late_init::NEEDLESS_LATE_INIT_INFO,
|
||||
crate::needless_parens_on_range_literals::NEEDLESS_PARENS_ON_RANGE_LITERALS_INFO,
|
||||
crate::needless_pass_by_ref_mut::NEEDLESS_PASS_BY_REF_MUT_INFO,
|
||||
crate::needless_pass_by_value::NEEDLESS_PASS_BY_VALUE_INFO,
|
||||
crate::needless_question_mark::NEEDLESS_QUESTION_MARK_INFO,
|
||||
crate::needless_update::NEEDLESS_UPDATE_INFO,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
use clippy_utils::{diagnostics::span_lint_and_sugg, is_ty_alias, match_def_path, paths};
|
||||
use hir::{def::Res, ExprKind};
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::{is_ty_alias, match_def_path, paths};
|
||||
use hir::def::Res;
|
||||
use hir::ExprKind;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::last_path_segment;
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
use clippy_utils::{match_def_path, paths};
|
||||
use clippy_utils::{last_path_segment, match_def_path, paths};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{def, Expr, ExprKind, GenericArg, QPath, TyKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
|
|
|
|||
|
|
@ -4,15 +4,11 @@ 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},
|
||||
Body, Expr, ExprKind, HirId, ItemKind, Lit, Node, Stmt, StmtKind,
|
||||
};
|
||||
use rustc_hir::intravisit::{walk_expr, walk_stmt, Visitor};
|
||||
use rustc_hir::{Body, Expr, ExprKind, HirId, ItemKind, Lit, Node, Stmt, StmtKind};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_middle::{
|
||||
lint::in_external_macro,
|
||||
ty::{self, FloatTy, IntTy, PolyFnSig, Ty},
|
||||
};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_middle::ty::{self, FloatTy, IntTy, PolyFnSig, Ty};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use std::iter;
|
||||
|
||||
|
|
|
|||
|
|
@ -12,12 +12,11 @@ use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX};
|
|||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_data_structures::graph::iterate::{CycleDetector, TriColorDepthFirstSearch};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::intravisit::{walk_ty, Visitor};
|
||||
use rustc_hir::{
|
||||
self as hir,
|
||||
def_id::{DefId, LocalDefId},
|
||||
BindingAnnotation, Body, BodyId, BorrowKind, Closure, Expr, ExprKind, FnRetTy, GenericArg, HirId, ImplItem,
|
||||
ImplItemKind, Item, ItemKind, Local, MatchSource, Mutability, Node, Pat, PatKind, Path, QPath, TraitItem,
|
||||
self as hir, BindingAnnotation, Body, BodyId, BorrowKind, Closure, Expr, ExprKind, FnRetTy, GenericArg, HirId,
|
||||
ImplItem, ImplItemKind, Item, ItemKind, Local, MatchSource, Mutability, Node, Pat, PatKind, Path, QPath, TraitItem,
|
||||
TraitItemKind, TyKind, UnOp,
|
||||
};
|
||||
use rustc_index::bit_set::BitSet;
|
||||
|
|
@ -30,9 +29,11 @@ use rustc_middle::ty::{
|
|||
ProjectionPredicate, Ty, TyCtxt, TypeVisitableExt, TypeckResults,
|
||||
};
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::{symbol::sym, Span, Symbol};
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::{Span, Symbol};
|
||||
use rustc_trait_selection::infer::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::{query::evaluate_obligation::InferCtxtExt as _, Obligation, ObligationCause};
|
||||
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::{Obligation, ObligationCause};
|
||||
use std::collections::VecDeque;
|
||||
|
||||
declare_clippy_lint! {
|
||||
|
|
@ -77,6 +78,11 @@ declare_clippy_lint! {
|
|||
/// Suggests that the receiver of the expression borrows
|
||||
/// the expression.
|
||||
///
|
||||
/// ### Known problems
|
||||
/// The lint cannot tell when the implementation of a trait
|
||||
/// for `&T` and `T` do different things. Removing a borrow
|
||||
/// in such a case can change the semantics of the code.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// fn fun(_a: &i32) {}
|
||||
|
|
@ -589,7 +595,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
|
|||
pat.spans,
|
||||
"this pattern creates a reference to a reference",
|
||||
|diag| {
|
||||
diag.multipart_suggestion("try this", replacements, app);
|
||||
diag.multipart_suggestion("try", replacements, app);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
@ -1123,7 +1129,9 @@ fn needless_borrow_impl_arg_position<'tcx>(
|
|||
let destruct_trait_def_id = cx.tcx.lang_items().destruct_trait();
|
||||
let sized_trait_def_id = cx.tcx.lang_items().sized_trait();
|
||||
|
||||
let Some(callee_def_id) = fn_def_id(cx, parent) else { return Position::Other(precedence) };
|
||||
let Some(callee_def_id) = fn_def_id(cx, parent) else {
|
||||
return Position::Other(precedence);
|
||||
};
|
||||
let fn_sig = cx.tcx.fn_sig(callee_def_id).subst_identity().skip_binder();
|
||||
let substs_with_expr_ty = cx
|
||||
.typeck_results()
|
||||
|
|
@ -1296,8 +1304,8 @@ fn referent_used_exactly_once<'tcx>(
|
|||
possible_borrowers: &mut Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>,
|
||||
reference: &Expr<'tcx>,
|
||||
) -> bool {
|
||||
let mir = enclosing_mir(cx.tcx, reference.hir_id);
|
||||
if let Some(local) = expr_local(cx.tcx, reference)
|
||||
if let Some(mir) = enclosing_mir(cx.tcx, reference.hir_id)
|
||||
&& let Some(local) = expr_local(cx.tcx, reference)
|
||||
&& let [location] = *local_assignments(mir, local).as_slice()
|
||||
&& let Some(statement) = mir.basic_blocks[location.block].statements.get(location.statement_index)
|
||||
&& let StatementKind::Assign(box (_, Rvalue::Ref(_, _, place))) = statement.kind
|
||||
|
|
@ -1531,7 +1539,7 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
|
|||
Mutability::Not => "explicit `deref` method call",
|
||||
Mutability::Mut => "explicit `deref_mut` method call",
|
||||
},
|
||||
"try this",
|
||||
"try",
|
||||
format!("{addr_of_str}{deref_str}{expr_str}"),
|
||||
app,
|
||||
);
|
||||
|
|
@ -1593,7 +1601,7 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
|
|||
} else {
|
||||
format!("{prefix}{snip}")
|
||||
};
|
||||
diag.span_suggestion(data.span, "try this", sugg, app);
|
||||
diag.span_suggestion(data.span, "try", sugg, app);
|
||||
},
|
||||
);
|
||||
},
|
||||
|
|
@ -1620,7 +1628,7 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
|
|||
|diag| {
|
||||
let mut app = Applicability::MachineApplicable;
|
||||
let snip = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app).0;
|
||||
diag.span_suggestion(data.span, "try this", snip.into_owned(), app);
|
||||
diag.span_suggestion(data.span, "try", snip.into_owned(), app);
|
||||
},
|
||||
);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -3,10 +3,9 @@ use clippy_utils::msrvs::{self, Msrv};
|
|||
use clippy_utils::source::indent_of;
|
||||
use clippy_utils::{is_default_equivalent, peel_blocks};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
|
||||
use rustc_hir::{
|
||||
self as hir,
|
||||
def::{CtorKind, CtorOf, DefKind, Res},
|
||||
Body, Expr, ExprKind, GenericArg, Impl, ImplItemKind, Item, ItemKind, Node, PathSegment, QPath, TyKind,
|
||||
self as hir, Body, Expr, ExprKind, GenericArg, Impl, ImplItemKind, Item, ItemKind, Node, PathSegment, QPath, TyKind,
|
||||
};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::adjustment::{Adjust, PointerCoercion};
|
||||
|
|
|
|||
|
|
@ -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::paths;
|
||||
use clippy_utils::ty::{implements_trait, implements_trait_with_env, is_copy};
|
||||
use clippy_utils::{is_lint_allowed, match_def_path};
|
||||
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;
|
||||
|
|
@ -334,7 +333,9 @@ fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &h
|
|||
Some(id) if trait_ref.trait_def_id() == Some(id) => id,
|
||||
_ => return,
|
||||
};
|
||||
let Some(copy_id) = cx.tcx.lang_items().copy_trait() else { return };
|
||||
let Some(copy_id) = cx.tcx.lang_items().copy_trait() else {
|
||||
return;
|
||||
};
|
||||
let (ty_adt, ty_subs) = match *ty.kind() {
|
||||
// Unions can't derive clone.
|
||||
ty::Adt(adt, subs) if !adt.is_union() => (adt, subs),
|
||||
|
|
@ -345,9 +346,9 @@ fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &h
|
|||
if !is_copy(cx, ty) {
|
||||
if ty_subs.non_erasable_generics().next().is_some() {
|
||||
let has_copy_impl = cx.tcx.all_local_trait_impls(()).get(©_id).map_or(false, |impls| {
|
||||
impls
|
||||
.iter()
|
||||
.any(|&id| matches!(cx.tcx.type_of(id).subst_identity().kind(), ty::Adt(adt, _) if ty_adt.did() == adt.did()))
|
||||
impls.iter().any(|&id| {
|
||||
matches!(cx.tcx.type_of(id).subst_identity().kind(), ty::Adt(adt, _) if ty_adt.did() == adt.did())
|
||||
})
|
||||
});
|
||||
if !has_copy_impl {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods {
|
|||
path_def_id(cx, expr)
|
||||
};
|
||||
let Some(def_id) = uncalled_path.or_else(|| fn_def_id(cx, expr)) else {
|
||||
return
|
||||
return;
|
||||
};
|
||||
let conf = match self.disallowed.get(&def_id) {
|
||||
Some(&index) => &self.conf_disallowed[index],
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use clippy_utils::{diagnostics::span_lint, is_test_module_or_function};
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::is_test_module_or_function;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_hir::{Item, Pat, PatKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
|
|
|
|||
|
|
@ -31,9 +31,8 @@ use rustc_session::{declare_tool_lint, impl_lint_pass};
|
|||
use rustc_span::edition::Edition;
|
||||
use rustc_span::source_map::{BytePos, FilePathMapping, SourceMap, Span};
|
||||
use rustc_span::{sym, FileName, Pos};
|
||||
use std::io;
|
||||
use std::ops::Range;
|
||||
use std::thread;
|
||||
use std::{io, thread};
|
||||
use url::Url;
|
||||
|
||||
declare_clippy_lint! {
|
||||
|
|
@ -295,7 +294,9 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
|
|||
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
|
||||
let attrs = cx.tcx.hir().attrs(item.hir_id());
|
||||
let Some(headers) = check_attrs(cx, &self.valid_idents, attrs) else { return };
|
||||
let Some(headers) = check_attrs(cx, &self.valid_idents, attrs) else {
|
||||
return;
|
||||
};
|
||||
match item.kind {
|
||||
hir::ItemKind::Fn(ref sig, _, body_id) => {
|
||||
if !(is_entrypoint_fn(cx, item.owner_id.to_def_id()) || in_external_macro(cx.tcx.sess, item.span)) {
|
||||
|
|
@ -339,7 +340,9 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
|
|||
|
||||
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
|
||||
let attrs = cx.tcx.hir().attrs(item.hir_id());
|
||||
let Some(headers) = check_attrs(cx, &self.valid_idents, attrs) else { return };
|
||||
let Some(headers) = check_attrs(cx, &self.valid_idents, attrs) else {
|
||||
return;
|
||||
};
|
||||
if let hir::TraitItemKind::Fn(ref sig, ..) = item.kind {
|
||||
if !in_external_macro(cx.tcx.sess, item.span) {
|
||||
lint_for_missing_headers(cx, item.owner_id, sig, headers, None, None);
|
||||
|
|
@ -349,7 +352,9 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
|
|||
|
||||
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) {
|
||||
let attrs = cx.tcx.hir().attrs(item.hir_id());
|
||||
let Some(headers) = check_attrs(cx, &self.valid_idents, attrs) else { return };
|
||||
let Some(headers) = check_attrs(cx, &self.valid_idents, attrs) else {
|
||||
return;
|
||||
};
|
||||
if self.in_trait_impl || in_external_macro(cx.tcx.sess, item.span) {
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_note;
|
||||
use clippy_utils::get_parent_node;
|
||||
use clippy_utils::is_must_use_func_call;
|
||||
use clippy_utils::ty::{is_copy, is_must_use_ty, is_type_lang_item};
|
||||
use clippy_utils::{get_parent_node, is_must_use_func_call};
|
||||
use rustc_hir::{Arm, Expr, ExprKind, LangItem, Node};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use clippy_utils::{diagnostics::span_lint_and_sugg, peel_blocks};
|
||||
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};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use clippy_utils::{diagnostics::span_lint_and_then, source::snippet_opt};
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use rustc_ast::ast::{Item, ItemKind, VariantData};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_lexer::TokenKind;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
use crate::Lint;
|
||||
use clippy_utils::{diagnostics::span_lint_and_then, is_lint_allowed};
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::is_lint_allowed;
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_middle::{lint::in_external_macro, ty::Ty};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::Symbol;
|
||||
use std::borrow::Cow;
|
||||
|
|
|
|||
|
|
@ -1,18 +1,14 @@
|
|||
use clippy_utils::higher;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::{reindent_multiline, snippet_indent, snippet_with_applicability, snippet_with_context};
|
||||
use clippy_utils::{
|
||||
can_move_expr_to_closure_no_visit,
|
||||
diagnostics::span_lint_and_sugg,
|
||||
is_expr_final_block_expr, is_expr_used_or_unified, match_def_path, paths, peel_hir_expr_while,
|
||||
source::{reindent_multiline, snippet_indent, snippet_with_applicability, snippet_with_context},
|
||||
SpanlessEq,
|
||||
can_move_expr_to_closure_no_visit, higher, is_expr_final_block_expr, is_expr_used_or_unified, match_def_path,
|
||||
paths, peel_hir_expr_while, SpanlessEq,
|
||||
};
|
||||
use core::fmt::{self, Write};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{
|
||||
hir_id::HirIdSet,
|
||||
intravisit::{walk_expr, Visitor},
|
||||
Block, Expr, ExprKind, Guard, HirId, Let, Pat, Stmt, StmtKind, UnOp,
|
||||
};
|
||||
use rustc_hir::hir_id::HirIdSet;
|
||||
use rustc_hir::intravisit::{walk_expr, Visitor};
|
||||
use rustc_hir::{Block, Expr, ExprKind, Guard, HirId, Let, Pat, Stmt, StmtKind, UnOp};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::{Span, SyntaxContext, DUMMY_SP};
|
||||
|
|
@ -69,16 +65,21 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass {
|
|||
return;
|
||||
}
|
||||
|
||||
let Some(higher::If { cond: cond_expr, then: then_expr, r#else: else_expr }) = higher::If::hir(expr) else {
|
||||
return
|
||||
let Some(higher::If {
|
||||
cond: cond_expr,
|
||||
then: then_expr,
|
||||
r#else: else_expr,
|
||||
}) = higher::If::hir(expr)
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
let Some((map_ty, contains_expr)) = try_parse_contains(cx, cond_expr) else {
|
||||
return
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(then_search) = find_insert_calls(cx, &contains_expr, then_expr) else {
|
||||
return
|
||||
return;
|
||||
};
|
||||
|
||||
let mut app = Applicability::MachineApplicable;
|
||||
|
|
@ -186,7 +187,7 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass {
|
|||
MAP_ENTRY,
|
||||
expr.span,
|
||||
&format!("usage of `contains_key` followed by `insert` on a `{}`", map_ty.name()),
|
||||
"try this",
|
||||
"try",
|
||||
sugg,
|
||||
app,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
use clippy_utils::diagnostics::span_lint_hir;
|
||||
use rustc_hir::intravisit;
|
||||
use rustc_hir::{self, AssocItemKind, Body, FnDecl, HirId, HirIdSet, Impl, ItemKind, Node, Pat, PatKind};
|
||||
use rustc_hir::{self, intravisit, AssocItemKind, Body, FnDecl, HirId, HirIdSet, Impl, ItemKind, Node, Pat, PatKind};
|
||||
use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
use clippy_utils::{diagnostics::span_lint_and_help, source::snippet};
|
||||
use rustc_ast::{
|
||||
node_id::NodeSet,
|
||||
visit::{walk_block, walk_item, Visitor},
|
||||
Block, Crate, Inline, Item, ItemKind, ModKind, NodeId,
|
||||
};
|
||||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::source::snippet;
|
||||
use rustc_ast::node_id::NodeSet;
|
||||
use rustc_ast::visit::{walk_block, walk_item, Visitor};
|
||||
use rustc_ast::{Block, Crate, Inline, Item, ItemKind, ModKind, NodeId};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite {
|
|||
EXPLICIT_WRITE,
|
||||
expr.span,
|
||||
&format!("use of `{used}.unwrap()`"),
|
||||
"try this",
|
||||
"try",
|
||||
format!("{prefix}{sugg_mac}!({inputs_snippet})"),
|
||||
applicability,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then};
|
||||
use clippy_utils::is_from_proc_macro;
|
||||
use clippy_utils::trait_ref_of_method;
|
||||
use clippy_utils::{is_from_proc_macro, trait_ref_of_method};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::intravisit::{walk_impl_item, walk_item, walk_param_bound, walk_ty, Visitor};
|
||||
|
|
@ -12,10 +11,8 @@ use rustc_lint::{LateContext, LateLintPass, LintContext};
|
|||
use rustc_middle::hir::nested_filter;
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::{
|
||||
def_id::{DefId, LocalDefId},
|
||||
Span,
|
||||
};
|
||||
use rustc_span::def_id::{DefId, LocalDefId};
|
||||
use rustc_span::Span;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
use clippy_utils::consts::{
|
||||
constant, constant_simple, Constant,
|
||||
Constant::{Int, F32, F64},
|
||||
};
|
||||
use clippy_utils::consts::Constant::{Int, F32, F64};
|
||||
use clippy_utils::consts::{constant, constant_simple, Constant};
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::{
|
||||
diagnostics::span_lint_and_sugg, eq_expr_value, get_parent_expr, higher, in_constant, is_no_std_crate,
|
||||
numeric_literal, peel_blocks, sugg,
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -43,7 +43,9 @@ declare_lint_pass!(UselessFormat => [USELESS_FORMAT]);
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for UselessFormat {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return };
|
||||
let Some(macro_call) = root_macro_call_first_node(cx, expr) else {
|
||||
return;
|
||||
};
|
||||
if !cx.tcx.is_diagnostic_item(sym::format_macro, macro_call.def_id) {
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,10 +14,8 @@ use rustc_ast::{
|
|||
FormatArgPosition, FormatArgPositionKind, FormatArgsPiece, FormatArgumentKind, FormatCount, FormatOptions,
|
||||
FormatPlaceholder, FormatTrait,
|
||||
};
|
||||
use rustc_errors::{
|
||||
Applicability,
|
||||
SuggestionStyle::{CompletelyHidden, ShowCode},
|
||||
};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_errors::SuggestionStyle::{CompletelyHidden, ShowCode};
|
||||
use rustc_hir::{Expr, ExprKind, LangItem};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_middle::ty::adjustment::{Adjust, Adjustment};
|
||||
|
|
@ -188,7 +186,9 @@ impl FormatArgs {
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for FormatArgs {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
|
||||
let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return };
|
||||
let Some(macro_call) = root_macro_call_first_node(cx, expr) else {
|
||||
return;
|
||||
};
|
||||
if !is_format_macro(cx, macro_call.def_id) {
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ use rustc_errors::Applicability;
|
|||
use rustc_hir::{Expr, ExprKind, Impl, ImplItem, ImplItemKind, QPath};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::Span;
|
||||
use rustc_span::{sym, symbol::kw, Symbol};
|
||||
use rustc_span::symbol::kw;
|
||||
use rustc_span::{sym, Span, Symbol};
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
|
|
@ -127,7 +127,9 @@ impl<'tcx> LateLintPass<'tcx> for FormatImpl {
|
|||
}
|
||||
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
let Some(format_trait_impl) = self.format_trait_impl else { return };
|
||||
let Some(format_trait_impl) = self.format_trait_impl else {
|
||||
return;
|
||||
};
|
||||
|
||||
if format_trait_impl.name == sym::Display {
|
||||
check_to_string_in_display(cx, expr);
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@ use rustc_hir::{
|
|||
TyKind,
|
||||
};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::{hir::nested_filter::OnlyBodies, ty};
|
||||
use rustc_middle::hir::nested_filter::OnlyBodies;
|
||||
use rustc_middle::ty;
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::symbol::{kw, sym};
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
|
@ -163,10 +164,14 @@ fn convert_to_from(
|
|||
return None;
|
||||
}
|
||||
let impl_item = cx.tcx.hir().impl_item(impl_item_ref.id);
|
||||
let ImplItemKind::Fn(ref sig, body_id) = impl_item.kind else { return None };
|
||||
let ImplItemKind::Fn(ref sig, body_id) = impl_item.kind else {
|
||||
return None;
|
||||
};
|
||||
let body = cx.tcx.hir().body(body_id);
|
||||
let [input] = body.params else { return None };
|
||||
let PatKind::Binding(.., self_ident, None) = input.pat.kind else { return None };
|
||||
let PatKind::Binding(.., self_ident, None) = input.pat.kind else {
|
||||
return None;
|
||||
};
|
||||
|
||||
let from = snippet_opt(cx, self_ty.span)?;
|
||||
let into = snippet_opt(cx, target_ty.span)?;
|
||||
|
|
|
|||
|
|
@ -4,8 +4,7 @@ use clippy_utils::{match_def_path, path_def_id, paths};
|
|||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{Expr, ExprKind, QPath};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::RawPtr;
|
||||
use rustc_middle::ty::TypeAndMut;
|
||||
use rustc_middle::ty::{RawPtr, TypeAndMut};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::sym;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
use clippy_utils::{diagnostics::span_lint_and_then, is_in_test_function};
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::is_in_test_function;
|
||||
|
||||
use rustc_hir::{intravisit::FnKind, Body, HirId};
|
||||
use rustc_hir::intravisit::FnKind;
|
||||
use rustc_hir::{Body, HirId};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::Span;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::source::snippet;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{intravisit::FnKind, Body, ExprKind, FnDecl, ImplicitSelfKind, Unsafety};
|
||||
use rustc_hir::intravisit::FnKind;
|
||||
use rustc_hir::{Body, ExprKind, FnDecl, ImplicitSelfKind, Unsafety};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty;
|
||||
use rustc_span::Span;
|
||||
|
|
@ -12,8 +13,8 @@ use super::MISNAMED_GETTERS;
|
|||
|
||||
pub fn check_fn(cx: &LateContext<'_>, kind: FnKind<'_>, decl: &FnDecl<'_>, body: &Body<'_>, span: Span) {
|
||||
let FnKind::Method(ref ident, sig) = kind else {
|
||||
return;
|
||||
};
|
||||
return;
|
||||
};
|
||||
|
||||
// Takes only &(mut) self
|
||||
if decl.inputs.len() != 1 {
|
||||
|
|
@ -25,8 +26,8 @@ pub fn check_fn(cx: &LateContext<'_>, kind: FnKind<'_>, decl: &FnDecl<'_>, body:
|
|||
let name = match decl.implicit_self {
|
||||
ImplicitSelfKind::MutRef => {
|
||||
let Some(name) = name.strip_suffix("_mut") else {
|
||||
return;
|
||||
};
|
||||
return;
|
||||
};
|
||||
name
|
||||
},
|
||||
ImplicitSelfKind::Imm | ImplicitSelfKind::Mut | ImplicitSelfKind::ImmRef => name,
|
||||
|
|
@ -76,7 +77,7 @@ pub fn check_fn(cx: &LateContext<'_>, kind: FnKind<'_>, decl: &FnDecl<'_>, body:
|
|||
for adjusted_type in iter::once(typeck_results.expr_ty(self_data))
|
||||
.chain(typeck_results.expr_adjustments(self_data).iter().map(|adj| adj.target))
|
||||
{
|
||||
let ty::Adt(def,_) = adjusted_type.kind() else {
|
||||
let ty::Adt(def, _) = adjusted_type.kind() else {
|
||||
continue;
|
||||
};
|
||||
|
||||
|
|
@ -91,13 +92,15 @@ pub fn check_fn(cx: &LateContext<'_>, kind: FnKind<'_>, decl: &FnDecl<'_>, body:
|
|||
}
|
||||
|
||||
let Some(used_field) = used_field else {
|
||||
// Can happen if the field access is a tuple. We don't lint those because the getter name could not start with a number.
|
||||
// Can happen if the field access is a tuple. We don't lint those because the getter name could not
|
||||
// start with a number.
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(correct_field) = correct_field else {
|
||||
// There is no field corresponding to the getter name.
|
||||
// FIXME: This can be a false positive if the correct field is reachable through deeper autodereferences than used_field is
|
||||
// FIXME: This can be a false positive if the correct field is reachable through deeper
|
||||
// autodereferences than used_field is
|
||||
return;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,13 @@
|
|||
use hir::FnSig;
|
||||
use rustc_ast::ast::Attribute;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::def_id::DefIdSet;
|
||||
use rustc_hir::{self as hir, def::Res, QPath};
|
||||
use rustc_hir::{self as hir, QPath};
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_lint::{LateContext, LintContext};
|
||||
use rustc_middle::{
|
||||
lint::in_external_macro,
|
||||
ty::{self, Ty},
|
||||
};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_span::{sym, Span, Symbol};
|
||||
|
||||
use clippy_utils::attrs::is_proc_macro;
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ pub(super) fn check_fn(
|
|||
}
|
||||
|
||||
let Some(code_snippet) = snippet_opt(cx, body.value.span) else {
|
||||
return
|
||||
return;
|
||||
};
|
||||
let mut line_count: u64 = 0;
|
||||
let mut in_comment = false;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::higher;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::SpanlessEq;
|
||||
use clippy_utils::{higher, SpanlessEq};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Diagnostic;
|
||||
use rustc_hir::intravisit::{self as visit, Visitor};
|
||||
|
|
|
|||
|
|
@ -119,7 +119,13 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone {
|
|||
|
||||
fn stmts_contains_early_return(stmts: &[Stmt<'_>]) -> bool {
|
||||
stmts.iter().any(|stmt| {
|
||||
let Stmt { kind: StmtKind::Semi(e), .. } = stmt else { return false };
|
||||
let Stmt {
|
||||
kind: StmtKind::Semi(e),
|
||||
..
|
||||
} = stmt
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
|
||||
contains_return(e)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
use clippy_utils::{
|
||||
diagnostics::span_lint_hir_and_then,
|
||||
get_async_fn_body, is_async_fn,
|
||||
source::{snippet_with_applicability, snippet_with_context, walk_span_to_context},
|
||||
visitors::for_each_expr,
|
||||
};
|
||||
use clippy_utils::diagnostics::span_lint_hir_and_then;
|
||||
use clippy_utils::source::{snippet_with_applicability, snippet_with_context, walk_span_to_context};
|
||||
use clippy_utils::visitors::for_each_expr;
|
||||
use clippy_utils::{get_async_fn_body, is_async_fn};
|
||||
use core::ops::ControlFlow;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::intravisit::FnKind;
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
use clippy_utils::{diagnostics::span_lint_and_sugg, get_parent_node, last_path_segment, ty::implements_trait};
|
||||
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use clippy_utils::{get_parent_node, is_res_lang_ctor, last_path_segment, path_res};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{ExprKind, ImplItem, ImplItemKind, ItemKind, Node, UnOp};
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::{Expr, ExprKind, ImplItem, ImplItemKind, ItemKind, LangItem, Node, UnOp};
|
||||
use rustc_hir_analysis::hir_ty_to_ty;
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::EarlyBinder;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::{sym, symbol};
|
||||
use rustc_span::sym;
|
||||
use rustc_span::symbol::kw;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
|
|
@ -46,25 +50,80 @@ declare_clippy_lint! {
|
|||
correctness,
|
||||
"manual implementation of `Clone` on a `Copy` type"
|
||||
}
|
||||
declare_lint_pass!(IncorrectImpls => [INCORRECT_CLONE_IMPL_ON_COPY_TYPE]);
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for manual implementations of both `PartialOrd` and `Ord` when only `Ord` is
|
||||
/// necessary.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// If both `PartialOrd` and `Ord` are implemented, they must agree. This is commonly done by
|
||||
/// wrapping the result of `cmp` in `Some` for `partial_cmp`. Not doing this may silently
|
||||
/// introduce an error upon refactoring.
|
||||
///
|
||||
/// ### Limitations
|
||||
/// Will not lint if `Self` and `Rhs` do not have the same type.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// # use std::cmp::Ordering;
|
||||
/// #[derive(Eq, PartialEq)]
|
||||
/// struct A(u32);
|
||||
///
|
||||
/// impl Ord for A {
|
||||
/// fn cmp(&self, other: &Self) -> Ordering {
|
||||
/// // ...
|
||||
/// # todo!();
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// impl PartialOrd for A {
|
||||
/// fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
/// // ...
|
||||
/// # todo!();
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// # use std::cmp::Ordering;
|
||||
/// #[derive(Eq, PartialEq)]
|
||||
/// struct A(u32);
|
||||
///
|
||||
/// impl Ord for A {
|
||||
/// fn cmp(&self, other: &Self) -> Ordering {
|
||||
/// // ...
|
||||
/// # todo!();
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// impl PartialOrd for A {
|
||||
/// fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
/// Some(self.cmp(other))
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[clippy::version = "1.72.0"]
|
||||
pub INCORRECT_PARTIAL_ORD_IMPL_ON_ORD_TYPE,
|
||||
correctness,
|
||||
"manual implementation of `PartialOrd` when `Ord` is already implemented"
|
||||
}
|
||||
declare_lint_pass!(IncorrectImpls => [INCORRECT_CLONE_IMPL_ON_COPY_TYPE, INCORRECT_PARTIAL_ORD_IMPL_ON_ORD_TYPE]);
|
||||
|
||||
impl LateLintPass<'_> for IncorrectImpls {
|
||||
#[expect(clippy::needless_return)]
|
||||
#[expect(clippy::too_many_lines)]
|
||||
fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &ImplItem<'_>) {
|
||||
let node = get_parent_node(cx.tcx, impl_item.hir_id());
|
||||
let Some(Node::Item(item)) = node else {
|
||||
return;
|
||||
};
|
||||
let ItemKind::Impl(imp) = item.kind else {
|
||||
let Some(Node::Item(item)) = get_parent_node(cx.tcx, impl_item.hir_id()) else {
|
||||
return;
|
||||
};
|
||||
let Some(trait_impl) = cx.tcx.impl_trait_ref(item.owner_id).map(EarlyBinder::skip_binder) else {
|
||||
return;
|
||||
};
|
||||
let trait_impl_def_id = trait_impl.def_id;
|
||||
if cx.tcx.is_automatically_derived(item.owner_id.to_def_id()) {
|
||||
return;
|
||||
}
|
||||
let ItemKind::Impl(imp) = item.kind else {
|
||||
return;
|
||||
};
|
||||
let ImplItemKind::Fn(_, impl_item_id) = cx.tcx.hir().impl_item(impl_item.impl_item_id()).kind else {
|
||||
return;
|
||||
};
|
||||
|
|
@ -72,15 +131,12 @@ impl LateLintPass<'_> for IncorrectImpls {
|
|||
let ExprKind::Block(block, ..) = body.value.kind else {
|
||||
return;
|
||||
};
|
||||
// Above is duplicated from the `duplicate_manual_partial_ord_impl` branch.
|
||||
// Remove it while solving conflicts once that PR is merged.
|
||||
|
||||
// Actual implementation; remove this comment once aforementioned PR is merged
|
||||
if cx.tcx.is_diagnostic_item(sym::Clone, trait_impl_def_id)
|
||||
if cx.tcx.is_diagnostic_item(sym::Clone, trait_impl.def_id)
|
||||
&& let Some(copy_def_id) = cx.tcx.get_diagnostic_item(sym::Copy)
|
||||
&& implements_trait(
|
||||
cx,
|
||||
hir_ty_to_ty(cx.tcx, imp.self_ty),
|
||||
trait_impl.self_ty(),
|
||||
copy_def_id,
|
||||
&[],
|
||||
)
|
||||
|
|
@ -88,9 +144,9 @@ impl LateLintPass<'_> for IncorrectImpls {
|
|||
if impl_item.ident.name == sym::clone {
|
||||
if block.stmts.is_empty()
|
||||
&& let Some(expr) = block.expr
|
||||
&& let ExprKind::Unary(UnOp::Deref, inner) = expr.kind
|
||||
&& let ExprKind::Path(qpath) = inner.kind
|
||||
&& last_path_segment(&qpath).ident.name == symbol::kw::SelfLower
|
||||
&& let ExprKind::Unary(UnOp::Deref, deref) = expr.kind
|
||||
&& let ExprKind::Path(qpath) = deref.kind
|
||||
&& last_path_segment(&qpath).ident.name == kw::SelfLower
|
||||
{} else {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
|
|
@ -112,7 +168,7 @@ impl LateLintPass<'_> for IncorrectImpls {
|
|||
INCORRECT_CLONE_IMPL_ON_COPY_TYPE,
|
||||
impl_item.span,
|
||||
"incorrect implementation of `clone_from` on a `Copy` type",
|
||||
"remove this",
|
||||
"remove it",
|
||||
String::new(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
|
|
@ -120,5 +176,69 @@ impl LateLintPass<'_> for IncorrectImpls {
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if cx.tcx.is_diagnostic_item(sym::PartialOrd, trait_impl.def_id)
|
||||
&& impl_item.ident.name == sym::partial_cmp
|
||||
&& let Some(ord_def_id) = cx
|
||||
.tcx
|
||||
.diagnostic_items(trait_impl.def_id.krate)
|
||||
.name_to_id
|
||||
.get(&sym::Ord)
|
||||
&& implements_trait(
|
||||
cx,
|
||||
hir_ty_to_ty(cx.tcx, imp.self_ty),
|
||||
*ord_def_id,
|
||||
trait_impl.substs,
|
||||
)
|
||||
{
|
||||
if block.stmts.is_empty()
|
||||
&& let Some(expr) = block.expr
|
||||
&& let ExprKind::Call(
|
||||
Expr {
|
||||
kind: ExprKind::Path(some_path),
|
||||
hir_id: some_hir_id,
|
||||
..
|
||||
},
|
||||
[cmp_expr],
|
||||
) = expr.kind
|
||||
&& is_res_lang_ctor(cx, cx.qpath_res(some_path, *some_hir_id), LangItem::OptionSome)
|
||||
&& let ExprKind::MethodCall(cmp_path, _, [other_expr], ..) = cmp_expr.kind
|
||||
&& cmp_path.ident.name == sym::cmp
|
||||
&& let Res::Local(..) = path_res(cx, other_expr)
|
||||
{} else {
|
||||
// If `Self` and `Rhs` are not the same type, bail. This makes creating a valid
|
||||
// suggestion tons more complex.
|
||||
if let [lhs, rhs, ..] = trait_impl.substs.as_slice() && lhs != rhs {
|
||||
return;
|
||||
}
|
||||
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
INCORRECT_PARTIAL_ORD_IMPL_ON_ORD_TYPE,
|
||||
item.span,
|
||||
"incorrect implementation of `partial_cmp` on an `Ord` type",
|
||||
|diag| {
|
||||
let [_, other] = body.params else {
|
||||
return;
|
||||
};
|
||||
|
||||
let suggs = if let Some(other_ident) = other.pat.simple_ident() {
|
||||
vec![(block.span, format!("{{ Some(self.cmp({})) }}", other_ident.name))]
|
||||
} else {
|
||||
vec![
|
||||
(block.span, "{ Some(self.cmp(other)) }".to_owned()),
|
||||
(other.pat.span, "other".to_owned()),
|
||||
]
|
||||
};
|
||||
|
||||
diag.multipart_suggestion(
|
||||
"change this to",
|
||||
suggs,
|
||||
Applicability::Unspecified,
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,8 @@ use rustc_lint::{LateContext, LateLintPass};
|
|||
use rustc_middle::hir::nested_filter;
|
||||
use rustc_middle::ty;
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::{symbol::Ident, Span};
|
||||
use rustc_span::symbol::Ident;
|
||||
use rustc_span::Span;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_note;
|
||||
use clippy_utils::is_lint_allowed;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir::{def_id::LocalDefId, Item, ItemKind, Node};
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_hir::{Item, ItemKind, Node};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::Span;
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for NumberedFields {
|
|||
INIT_NUMBERED_FIELDS,
|
||||
e.span,
|
||||
"used a field initializer for a tuple struct",
|
||||
"try this instead",
|
||||
"try",
|
||||
snippet,
|
||||
appl,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@ use rustc_errors::Applicability;
|
|||
use rustc_hir::{BinOpKind, Expr, ExprKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::{source_map::Spanned, sym};
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::sym;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use clippy_utils::{diagnostics::span_lint_and_help, is_from_proc_macro, is_in_cfg_test};
|
||||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::{is_from_proc_macro, is_in_cfg_test};
|
||||
use rustc_hir::{HirId, ItemId, ItemKind, Mod};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
|
|
@ -32,7 +33,7 @@ declare_clippy_lint! {
|
|||
/// // [...]
|
||||
/// }
|
||||
/// ```
|
||||
#[clippy::version = "1.70.0"]
|
||||
#[clippy::version = "1.71.0"]
|
||||
pub ITEMS_AFTER_TEST_MODULE,
|
||||
style,
|
||||
"An item was found after the testing module `tests`"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
use clippy_utils::{diagnostics::span_lint, get_parent_node, ty::implements_trait};
|
||||
use rustc_hir::{def_id::LocalDefId, FnSig, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind};
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::get_parent_node;
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_hir::{FnSig, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::symbol::sym;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
//! lint when there is a large size difference between variants on an enum
|
||||
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::{
|
||||
diagnostics::span_lint_and_then,
|
||||
ty::{approx_ty_size, is_copy, AdtVariantInfo},
|
||||
};
|
||||
use clippy_utils::ty::{approx_ty_size, is_copy, AdtVariantInfo};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Item, ItemKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::{diagnostics::span_lint_and_sugg, ty::implements_trait};
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind, LangItem, MatchSource, QPath};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
|
|
|
|||
|
|
@ -2,8 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_note;
|
|||
use clippy_utils::is_lint_allowed;
|
||||
use clippy_utils::macros::root_macro_call_first_node;
|
||||
use rustc_ast::LitKind;
|
||||
use rustc_hir::Expr;
|
||||
use rustc_hir::ExprKind;
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::sym;
|
||||
|
|
|
|||
|
|
@ -4,11 +4,9 @@ use clippy_utils::diagnostics::span_lint_and_note;
|
|||
use clippy_utils::fn_has_unsatisfiable_preds;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_hir::intravisit::FnKind;
|
||||
use rustc_hir::Body;
|
||||
use rustc_hir::FnDecl;
|
||||
use rustc_hir::{Body, FnDecl};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::declare_tool_lint;
|
||||
use rustc_session::impl_lint_pass;
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::Span;
|
||||
|
||||
declare_clippy_lint! {
|
||||
|
|
|
|||
|
|
@ -1,22 +1,23 @@
|
|||
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
use clippy_utils::{get_item_name, get_parent_as_impl, is_lint_allowed, peel_ref_operators, sugg::Sugg};
|
||||
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_id::DefIdSet;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::def_id::{DefId, DefIdSet};
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::{
|
||||
def::Res, def_id::DefId, lang_items::LangItem, AssocItemKind, BinOpKind, Expr, ExprKind, FnRetTy, GenericArg,
|
||||
GenericBound, ImplItem, ImplItemKind, ImplicitSelfKind, Item, ItemKind, Mutability, Node, PathSegment, PrimTy,
|
||||
QPath, TraitItemRef, TyKind, TypeBindingKind,
|
||||
AssocItemKind, BinOpKind, Expr, ExprKind, FnRetTy, GenericArg, GenericBound, ImplItem, ImplItemKind,
|
||||
ImplicitSelfKind, Item, ItemKind, Mutability, Node, PathSegment, PrimTy, QPath, TraitItemRef, TyKind,
|
||||
TypeBindingKind,
|
||||
};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::{self, AssocKind, FnSig, Ty};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::{
|
||||
source_map::{Span, Spanned, Symbol},
|
||||
symbol::sym,
|
||||
};
|
||||
use rustc_span::source_map::{Span, Spanned, Symbol};
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::path_to_local_id;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::{path_to_local_id, visitors::is_local_used};
|
||||
use clippy_utils::visitors::is_local_used;
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::is_from_proc_macro;
|
||||
use clippy_utils::ty::{implements_trait, is_must_use_ty, match_type};
|
||||
use clippy_utils::{is_must_use_func_call, paths};
|
||||
use clippy_utils::{is_from_proc_macro, is_must_use_func_call, paths};
|
||||
use rustc_hir::{Local, PatKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
|
|
|
|||
|
|
@ -183,6 +183,7 @@ mod manual_assert;
|
|||
mod manual_async_fn;
|
||||
mod manual_bits;
|
||||
mod manual_clamp;
|
||||
mod manual_float_methods;
|
||||
mod manual_is_ascii_check;
|
||||
mod manual_let_else;
|
||||
mod manual_main_separator_str;
|
||||
|
|
@ -228,6 +229,7 @@ mod needless_for_each;
|
|||
mod needless_if;
|
||||
mod needless_late_init;
|
||||
mod needless_parens_on_range_literals;
|
||||
mod needless_pass_by_ref_mut;
|
||||
mod needless_pass_by_value;
|
||||
mod needless_question_mark;
|
||||
mod needless_update;
|
||||
|
|
@ -345,11 +347,10 @@ mod zero_div_zero;
|
|||
mod zero_sized_map_values;
|
||||
// end lints modules, do not remove this comment, it’s used in `update_lints`
|
||||
|
||||
use crate::utils::conf::metadata::get_configuration_metadata;
|
||||
use crate::utils::conf::TryConf;
|
||||
pub use crate::utils::conf::{lookup_conf_file, Conf};
|
||||
use crate::utils::{
|
||||
conf::{metadata::get_configuration_metadata, TryConf},
|
||||
FindAll,
|
||||
};
|
||||
use crate::utils::FindAll;
|
||||
|
||||
/// Register all pre expansion lints
|
||||
///
|
||||
|
|
@ -662,7 +663,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
});
|
||||
store.register_late_pass(move |_| Box::new(matches::Matches::new(msrv())));
|
||||
let matches_for_let_else = conf.matches_for_let_else;
|
||||
store.register_late_pass(move |_| Box::new(manual_let_else::ManualLetElse::new(msrv(), matches_for_let_else)));
|
||||
store.register_early_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustiveStruct::new(msrv())));
|
||||
store.register_late_pass(move |_| Box::new(manual_non_exhaustive::ManualNonExhaustiveEnum::new(msrv())));
|
||||
store.register_late_pass(move |_| Box::new(manual_strip::ManualStrip::new(msrv())));
|
||||
|
|
@ -722,7 +722,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
store.register_late_pass(|_| Box::new(drop_forget_ref::DropForgetRef));
|
||||
store.register_late_pass(|_| Box::new(empty_enum::EmptyEnum));
|
||||
store.register_late_pass(|_| Box::new(invalid_upcast_comparisons::InvalidUpcastComparisons));
|
||||
store.register_late_pass(|_| Box::new(regex::Regex));
|
||||
store.register_late_pass(|_| Box::<regex::Regex>::default());
|
||||
let ignore_interior_mutability = conf.ignore_interior_mutability.clone();
|
||||
store.register_late_pass(move |_| Box::new(copies::CopyAndPaste::new(ignore_interior_mutability.clone())));
|
||||
store.register_late_pass(|_| Box::new(copy_iterator::CopyIterator));
|
||||
|
|
@ -771,7 +771,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
store.register_late_pass(|_| Box::<useless_conversion::UselessConversion>::default());
|
||||
store.register_late_pass(|_| Box::new(implicit_hasher::ImplicitHasher));
|
||||
store.register_late_pass(|_| Box::new(fallible_impl_from::FallibleImplFrom));
|
||||
store.register_late_pass(|_| Box::<question_mark::QuestionMark>::default());
|
||||
store.register_late_pass(move |_| Box::new(question_mark::QuestionMark::new(msrv(), matches_for_let_else)));
|
||||
store.register_late_pass(|_| Box::new(question_mark_used::QuestionMarkUsed));
|
||||
store.register_early_pass(|| Box::new(suspicious_operation_groupings::SuspiciousOperationGroupings));
|
||||
store.register_late_pass(|_| Box::new(suspicious_trait_impl::SuspiciousImpl));
|
||||
|
|
@ -1056,6 +1056,11 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
let stack_size_threshold = conf.stack_size_threshold;
|
||||
store.register_late_pass(move |_| Box::new(large_stack_frames::LargeStackFrames::new(stack_size_threshold)));
|
||||
store.register_late_pass(|_| Box::new(single_range_in_vec_init::SingleRangeInVecInit));
|
||||
store.register_late_pass(move |_| {
|
||||
Box::new(needless_pass_by_ref_mut::NeedlessPassByRefMut::new(
|
||||
avoid_breaking_exported_api,
|
||||
))
|
||||
});
|
||||
store.register_late_pass(|_| Box::new(incorrect_impls::IncorrectImpls));
|
||||
store.register_late_pass(move |_| {
|
||||
Box::new(single_call_fn::SingleCallFn {
|
||||
|
|
@ -1072,6 +1077,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
store.register_late_pass(|_| Box::new(manual_range_patterns::ManualRangePatterns));
|
||||
store.register_early_pass(|| Box::new(visibility::Visibility));
|
||||
store.register_late_pass(move |_| Box::new(tuple_array_conversions::TupleArrayConversions { msrv: msrv() }));
|
||||
store.register_late_pass(|_| Box::new(manual_float_methods::ManualFloatMethods));
|
||||
// add lints here, do not remove this comment, it's used in `new_lint`
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
use clippy_utils::{
|
||||
diagnostics::span_lint_and_then, is_diag_item_method, is_trait_method, match_def_path, path_to_local_id, paths,
|
||||
ty::match_type,
|
||||
};
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::ty::match_type;
|
||||
use clippy_utils::{is_diag_item_method, is_trait_method, match_def_path, path_to_local_id, paths};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Body, Closure, Expr, ExprKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
|
|
|
|||
|
|
@ -264,7 +264,7 @@ impl LiteralDigitGrouping {
|
|||
return;
|
||||
}
|
||||
|
||||
if Self::is_literal_uuid_formatted(&mut num_lit) {
|
||||
if Self::is_literal_uuid_formatted(&num_lit) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -376,7 +376,7 @@ impl LiteralDigitGrouping {
|
|||
///
|
||||
/// Returns `true` if the radix is hexadecimal, and the groups match the
|
||||
/// UUID format of 8-4-4-4-12.
|
||||
fn is_literal_uuid_formatted(num_lit: &mut NumericLiteral<'_>) -> bool {
|
||||
fn is_literal_uuid_formatted(num_lit: &NumericLiteral<'_>) -> bool {
|
||||
if num_lit.radix != Radix::Hexadecimal {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
use super::utils::make_iterator_snippet;
|
||||
use super::MANUAL_FIND;
|
||||
use clippy_utils::{
|
||||
diagnostics::span_lint_and_then, higher, is_res_lang_ctor, path_res, peel_blocks_with_stmt,
|
||||
source::snippet_with_applicability, ty::implements_trait,
|
||||
};
|
||||
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, lang_items::LangItem, BindingAnnotation, Block, Expr, ExprKind, HirId, Node, Pat, PatKind, Stmt, StmtKind,
|
||||
};
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Node, Pat, PatKind, Stmt, StmtKind};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::source_map::Span;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
use super::utils::make_iterator_snippet;
|
||||
use super::MANUAL_FLATTEN;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::higher;
|
||||
use clippy_utils::visitors::is_local_used;
|
||||
use clippy_utils::{path_to_local_id, peel_blocks_with_stmt};
|
||||
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};
|
||||
|
|
|
|||
|
|
@ -1,9 +1,6 @@
|
|||
use clippy_utils::{
|
||||
diagnostics::{multispan_sugg_with_applicability, span_lint_and_then},
|
||||
match_def_path, paths,
|
||||
source::snippet,
|
||||
SpanlessEq,
|
||||
};
|
||||
use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and_then};
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::{match_def_path, paths, SpanlessEq};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind, Pat, Stmt, StmtKind, UnOp};
|
||||
use rustc_lint::LateContext;
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, body: &'
|
|||
MISSING_SPIN_LOOP,
|
||||
body.span,
|
||||
"busy-waiting loop should at least have a spin loop hint",
|
||||
"try this",
|
||||
"try",
|
||||
(if is_no_std_crate(cx) {
|
||||
"{ core::hint::spin_loop() }"
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -601,7 +601,7 @@ declare_clippy_lint! {
|
|||
/// // use `number`
|
||||
/// }
|
||||
/// ```
|
||||
#[clippy::version = "1.70.0"]
|
||||
#[clippy::version = "1.71.0"]
|
||||
pub MANUAL_WHILE_LET_SOME,
|
||||
style,
|
||||
"checking for emptiness of a `Vec` in the loop condition and popping an element in the body"
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@ use rustc_hir::{BindingAnnotation, Expr, ExprKind, HirId, Node, PatKind};
|
|||
use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::{mir::FakeReadCause, ty};
|
||||
use rustc_middle::mir::FakeReadCause;
|
||||
use rustc_middle::ty;
|
||||
use rustc_span::source_map::Span;
|
||||
|
||||
pub(super) fn check(cx: &LateContext<'_>, arg: &Expr<'_>, body: &Expr<'_>) {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
use super::utils::make_iterator_snippet;
|
||||
use super::NEVER_LOOP;
|
||||
use clippy_utils::consts::constant;
|
||||
use clippy_utils::consts::{constant, Constant};
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::higher::ForLoop;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::{consts::Constant, diagnostics::span_lint_and_then};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Block, Destination, Expr, ExprKind, HirId, InlineAsmOperand, Pat, Stmt, StmtKind};
|
||||
use rustc_lint::LateContext;
|
||||
|
|
|
|||
|
|
@ -6,8 +6,7 @@ use if_chain::if_chain;
|
|||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::DefIdMap;
|
||||
use rustc_hir::intravisit::{walk_expr, Visitor};
|
||||
use rustc_hir::HirIdSet;
|
||||
use rustc_hir::{Expr, ExprKind, QPath};
|
||||
use rustc_hir::{Expr, ExprKind, HirIdSet, QPath};
|
||||
use rustc_lint::LateContext;
|
||||
|
||||
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, expr: &'tcx Expr<'_>) {
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
use super::WHILE_LET_ON_ITERATOR;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::higher;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::{
|
||||
get_enclosing_loop_or_multi_call_closure, is_refutable, is_res_lang_ctor, is_trait_method, visitors::is_res_used,
|
||||
};
|
||||
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};
|
||||
use rustc_hir::{def::Res, Closure, Expr, ExprKind, HirId, LangItem, Local, Mutability, PatKind, UnOp};
|
||||
use rustc_hir::{Closure, Expr, ExprKind, HirId, LangItem, Local, Mutability, PatKind, UnOp};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::hir::nested_filter::OnlyBodies;
|
||||
use rustc_middle::ty::adjustment::Adjust;
|
||||
use rustc_span::{symbol::sym, Symbol};
|
||||
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_chain! {
|
||||
|
|
@ -332,7 +332,7 @@ fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: &
|
|||
|
||||
if let Some(e) = get_enclosing_loop_or_multi_call_closure(cx, loop_expr) {
|
||||
let Res::Local(local_id) = iter_expr.path else {
|
||||
return true
|
||||
return true;
|
||||
};
|
||||
let mut v = NestedLoopVisitor {
|
||||
cx,
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@ use rustc_errors::Applicability;
|
|||
use rustc_hir as hir;
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::{edition::Edition, sym, Span};
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::{sym, Span};
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
|
|
@ -35,7 +36,8 @@ struct PathAndSpan {
|
|||
span: Span,
|
||||
}
|
||||
|
||||
/// `MacroRefData` includes the name of the macro.
|
||||
/// `MacroRefData` includes the name of the macro
|
||||
/// and the path from `SourceMap::span_to_filename`.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MacroRefData {
|
||||
name: String,
|
||||
|
|
|
|||
|
|
@ -4,21 +4,19 @@ use clippy_utils::msrvs::{self, Msrv};
|
|||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use clippy_utils::visitors::is_const_evaluatable;
|
||||
use clippy_utils::MaybePath;
|
||||
use clippy_utils::{
|
||||
eq_expr_value, in_constant, is_diag_trait_item, is_trait_method, path_res, path_to_local_id, peel_blocks,
|
||||
peel_blocks_with_stmt,
|
||||
peel_blocks_with_stmt, MaybePath,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_errors::Diagnostic;
|
||||
use rustc_hir::{
|
||||
def::Res, Arm, BinOpKind, Block, Expr, ExprKind, Guard, HirId, PatKind, PathSegment, PrimTy, QPath, StmtKind,
|
||||
};
|
||||
use rustc_errors::{Applicability, Diagnostic};
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::{Arm, BinOpKind, Block, Expr, ExprKind, Guard, HirId, PatKind, PathSegment, PrimTy, QPath, StmtKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::{symbol::sym, Span};
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::Span;
|
||||
use std::ops::Deref;
|
||||
|
||||
declare_clippy_lint! {
|
||||
|
|
|
|||
173
clippy_lints/src/manual_float_methods.rs
Normal file
173
clippy_lints/src/manual_float_methods.rs
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
use clippy_utils::consts::{constant, Constant};
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::{is_from_proc_macro, path_to_local};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BinOpKind, Expr, ExprKind};
|
||||
use rustc_lint::{LateContext, LateLintPass, Lint, LintContext};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for manual `is_infinite` reimplementations
|
||||
/// (i.e., `x == <float>::INFINITY || x == <float>::NEG_INFINITY`).
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// The method `is_infinite` is shorter and more readable.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// # let x = 1.0f32;
|
||||
/// if x == f32::INFINITY || x == f32::NEG_INFINITY {}
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// # let x = 1.0f32;
|
||||
/// if x.is_infinite() {}
|
||||
/// ```
|
||||
#[clippy::version = "1.72.0"]
|
||||
pub MANUAL_IS_INFINITE,
|
||||
style,
|
||||
"use dedicated method to check if a float is infinite"
|
||||
}
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for manual `is_finite` reimplementations
|
||||
/// (i.e., `x != <float>::INFINITY && x != <float>::NEG_INFINITY`).
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// The method `is_finite` is shorter and more readable.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// # let x = 1.0f32;
|
||||
/// if x != f32::INFINITY && x != f32::NEG_INFINITY {}
|
||||
/// if x.abs() < f32::INFINITY {}
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// # let x = 1.0f32;
|
||||
/// if x.is_finite() {}
|
||||
/// if x.is_finite() {}
|
||||
/// ```
|
||||
#[clippy::version = "1.72.0"]
|
||||
pub MANUAL_IS_FINITE,
|
||||
style,
|
||||
"use dedicated method to check if a float is finite"
|
||||
}
|
||||
declare_lint_pass!(ManualFloatMethods => [MANUAL_IS_INFINITE, MANUAL_IS_FINITE]);
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
enum Variant {
|
||||
ManualIsInfinite,
|
||||
ManualIsFinite,
|
||||
}
|
||||
|
||||
impl Variant {
|
||||
pub fn lint(self) -> &'static Lint {
|
||||
match self {
|
||||
Self::ManualIsInfinite => MANUAL_IS_INFINITE,
|
||||
Self::ManualIsFinite => MANUAL_IS_FINITE,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn msg(self) -> &'static str {
|
||||
match self {
|
||||
Self::ManualIsInfinite => "manually checking if a float is infinite",
|
||||
Self::ManualIsFinite => "manually checking if a float is finite",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
|
||||
if !in_external_macro(cx.sess(), expr.span)
|
||||
&& (!cx.param_env.is_const() || cx.tcx.features().active(sym!(const_float_classify)))
|
||||
&& let ExprKind::Binary(kind, lhs, rhs) = expr.kind
|
||||
&& let ExprKind::Binary(lhs_kind, lhs_lhs, lhs_rhs) = lhs.kind
|
||||
&& let ExprKind::Binary(rhs_kind, rhs_lhs, rhs_rhs) = rhs.kind
|
||||
// Checking all possible scenarios using a function would be a hopeless task, as we have
|
||||
// 16 possible alignments of constants/operands. For now, let's use `partition`.
|
||||
&& let (operands, constants) = [lhs_lhs, lhs_rhs, rhs_lhs, rhs_rhs]
|
||||
.into_iter()
|
||||
.partition::<Vec<&Expr<'_>>, _>(|i| path_to_local(i).is_some())
|
||||
&& let [first, second] = &*operands
|
||||
&& let Some([const_1, const_2]) = constants
|
||||
.into_iter()
|
||||
.map(|i| constant(cx, cx.typeck_results(), i))
|
||||
.collect::<Option<Vec<_>>>()
|
||||
.as_deref()
|
||||
&& path_to_local(first).is_some_and(|f| path_to_local(second).is_some_and(|s| f == s))
|
||||
// The actual infinity check, we also allow `NEG_INFINITY` before` INFINITY` just in
|
||||
// case somebody does that for some reason
|
||||
&& (is_infinity(const_1) && is_neg_infinity(const_2)
|
||||
|| is_neg_infinity(const_1) && is_infinity(const_2))
|
||||
&& !is_from_proc_macro(cx, expr)
|
||||
&& let Some(local_snippet) = snippet_opt(cx, first.span)
|
||||
{
|
||||
let variant = match (kind.node, lhs_kind.node, rhs_kind.node) {
|
||||
(BinOpKind::Or, BinOpKind::Eq, BinOpKind::Eq) => Variant::ManualIsInfinite,
|
||||
(BinOpKind::And, BinOpKind::Ne, BinOpKind::Ne) => Variant::ManualIsFinite,
|
||||
_ => return,
|
||||
};
|
||||
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
variant.lint(),
|
||||
expr.span,
|
||||
variant.msg(),
|
||||
|diag| {
|
||||
match variant {
|
||||
Variant::ManualIsInfinite => {
|
||||
diag.span_suggestion(
|
||||
expr.span,
|
||||
"use the dedicated method instead",
|
||||
format!("{local_snippet}.is_infinite()"),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
},
|
||||
Variant::ManualIsFinite => {
|
||||
// TODO: There's probably some better way to do this, i.e., create
|
||||
// multiple suggestions with notes between each of them
|
||||
diag.span_suggestion_verbose(
|
||||
expr.span,
|
||||
"use the dedicated method instead",
|
||||
format!("{local_snippet}.is_finite()"),
|
||||
Applicability::MaybeIncorrect,
|
||||
)
|
||||
.span_suggestion_verbose(
|
||||
expr.span,
|
||||
"this will alter how it handles NaN; if that is a problem, use instead",
|
||||
format!("{local_snippet}.is_finite() || {local_snippet}.is_nan()"),
|
||||
Applicability::MaybeIncorrect,
|
||||
)
|
||||
.span_suggestion_verbose(
|
||||
expr.span,
|
||||
"or, for conciseness",
|
||||
format!("!{local_snippet}.is_infinite()"),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_infinity(constant: &Constant<'_>) -> bool {
|
||||
match constant {
|
||||
Constant::F32(float) => *float == f32::INFINITY,
|
||||
Constant::F64(float) => *float == f64::INFINITY,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_neg_infinity(constant: &Constant<'_>) -> bool {
|
||||
match constant {
|
||||
Constant::F32(float) => *float == f32::NEG_INFINITY,
|
||||
Constant::F64(float) => *float == f64::NEG_INFINITY,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +1,16 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::macros::root_macro_call;
|
||||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::{diagnostics::span_lint_and_sugg, higher, in_constant, macros::root_macro_call, sugg::Sugg};
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::{higher, in_constant};
|
||||
use rustc_ast::ast::RangeLimits;
|
||||
use rustc_ast::LitKind::{Byte, Char};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BorrowKind, Expr, ExprKind, PatKind, RangeEnd};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::{def_id::DefId, sym, Span};
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_span::{sym, Span};
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
|
|
|
|||
|
|
@ -1,18 +1,17 @@
|
|||
use crate::question_mark::{QuestionMark, QUESTION_MARK};
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::higher::IfLetOrMatch;
|
||||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::peel_blocks;
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::visitors::{Descend, Visitable};
|
||||
use if_chain::if_chain;
|
||||
use clippy_utils::{is_lint_allowed, msrvs, pat_and_expr_can_be_question_mark, peel_blocks};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::intravisit::{walk_expr, Visitor};
|
||||
use rustc_hir::{Expr, ExprKind, HirId, ItemId, Local, MatchSource, Pat, PatKind, QPath, Stmt, StmtKind, Ty};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_lint::{LateContext, LintContext};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_session::declare_tool_lint;
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
use rustc_span::Span;
|
||||
use serde::Deserialize;
|
||||
|
|
@ -50,25 +49,8 @@ declare_clippy_lint! {
|
|||
"manual implementation of a let...else statement"
|
||||
}
|
||||
|
||||
pub struct ManualLetElse {
|
||||
msrv: Msrv,
|
||||
matches_behaviour: MatchLintBehaviour,
|
||||
}
|
||||
|
||||
impl ManualLetElse {
|
||||
#[must_use]
|
||||
pub fn new(msrv: Msrv, matches_behaviour: MatchLintBehaviour) -> Self {
|
||||
Self {
|
||||
msrv,
|
||||
matches_behaviour,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_lint_pass!(ManualLetElse => [MANUAL_LET_ELSE]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for ManualLetElse {
|
||||
fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &'tcx Stmt<'tcx>) {
|
||||
impl<'tcx> QuestionMark {
|
||||
pub(crate) fn check_manual_let_else(&mut self, cx: &LateContext<'_>, stmt: &'tcx Stmt<'tcx>) {
|
||||
if !self.msrv.meets(msrvs::LET_ELSE) || in_external_macro(cx.sess(), stmt.span) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -81,11 +63,14 @@ impl<'tcx> LateLintPass<'tcx> for ManualLetElse {
|
|||
let Some(if_let_or_match) = IfLetOrMatch::parse(cx, init)
|
||||
{
|
||||
match if_let_or_match {
|
||||
IfLetOrMatch::IfLet(if_let_expr, let_pat, if_then, if_else) => if_chain! {
|
||||
if let Some(ident_map) = expr_simple_identity_map(local.pat, let_pat, if_then);
|
||||
if let Some(if_else) = if_else;
|
||||
if expr_diverges(cx, if_else);
|
||||
then {
|
||||
IfLetOrMatch::IfLet(if_let_expr, let_pat, if_then, if_else) => {
|
||||
if
|
||||
let Some(ident_map) = expr_simple_identity_map(local.pat, let_pat, if_then) &&
|
||||
let Some(if_else) = if_else &&
|
||||
expr_diverges(cx, if_else) &&
|
||||
let qm_allowed = is_lint_allowed(cx, QUESTION_MARK, stmt.hir_id) &&
|
||||
(qm_allowed || pat_and_expr_can_be_question_mark(cx, let_pat, if_else).is_none())
|
||||
{
|
||||
emit_manual_let_else(cx, stmt.span, if_let_expr, &ident_map, let_pat, if_else);
|
||||
}
|
||||
},
|
||||
|
|
@ -128,8 +113,6 @@ impl<'tcx> LateLintPass<'tcx> for ManualLetElse {
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
extract_msrv_attr!(LateContext);
|
||||
}
|
||||
|
||||
fn emit_manual_let_else(
|
||||
|
|
@ -208,7 +191,9 @@ fn replace_in_pattern(
|
|||
|
||||
match pat.kind {
|
||||
PatKind::Binding(_ann, _id, binding_name, opt_subpt) => {
|
||||
let Some(pat_to_put) = ident_map.get(&binding_name.name) else { break 'a };
|
||||
let Some(pat_to_put) = ident_map.get(&binding_name.name) else {
|
||||
break 'a;
|
||||
};
|
||||
let (sn_ptp, _) = snippet_with_context(cx, pat_to_put.span, span.ctxt(), "", app);
|
||||
if let Some(subpt) = opt_subpt {
|
||||
let subpt = replace_in_pattern(cx, span, ident_map, subpt, app, false);
|
||||
|
|
|
|||
|
|
@ -2,12 +2,8 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
|
|||
use rustc_ast::LitKind;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::Expr;
|
||||
use rustc_hir::ExprKind;
|
||||
use rustc_hir::PatKind;
|
||||
use rustc_hir::RangeEnd;
|
||||
use rustc_lint::LintContext;
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_hir::{Expr, ExprKind, PatKind, RangeEnd, UnOp};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
|
||||
|
|
@ -19,6 +15,10 @@ declare_clippy_lint! {
|
|||
/// ### Why is this bad?
|
||||
/// Using an explicit range is more concise and easier to read.
|
||||
///
|
||||
/// ### Known issues
|
||||
/// This lint intentionally does not handle numbers greater than `i128::MAX` for `u128` literals
|
||||
/// in order to support negative numbers.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// let x = 6;
|
||||
|
|
@ -36,11 +36,14 @@ declare_clippy_lint! {
|
|||
}
|
||||
declare_lint_pass!(ManualRangePatterns => [MANUAL_RANGE_PATTERNS]);
|
||||
|
||||
fn expr_as_u128(expr: &Expr<'_>) -> Option<u128> {
|
||||
if let ExprKind::Lit(lit) = expr.kind
|
||||
fn expr_as_i128(expr: &Expr<'_>) -> Option<i128> {
|
||||
if let ExprKind::Unary(UnOp::Neg, expr) = expr.kind {
|
||||
expr_as_i128(expr).map(|num| -num)
|
||||
} else if let ExprKind::Lit(lit) = expr.kind
|
||||
&& let LitKind::Int(num, _) = lit.node
|
||||
{
|
||||
Some(num)
|
||||
// Intentionally not handling numbers greater than i128::MAX (for u128 literals) for now.
|
||||
num.try_into().ok()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
@ -56,22 +59,22 @@ impl LateLintPass<'_> for ManualRangePatterns {
|
|||
if let PatKind::Or(pats) = pat.kind
|
||||
&& pats.len() >= 3
|
||||
{
|
||||
let mut min = u128::MAX;
|
||||
let mut max = 0;
|
||||
let mut min = i128::MAX;
|
||||
let mut max = i128::MIN;
|
||||
let mut numbers_found = FxHashSet::default();
|
||||
let mut ranges_found = Vec::new();
|
||||
|
||||
for pat in pats {
|
||||
if let PatKind::Lit(lit) = pat.kind
|
||||
&& let Some(num) = expr_as_u128(lit)
|
||||
&& let Some(num) = expr_as_i128(lit)
|
||||
{
|
||||
numbers_found.insert(num);
|
||||
|
||||
min = min.min(num);
|
||||
max = max.max(num);
|
||||
} else if let PatKind::Range(Some(left), Some(right), end) = pat.kind
|
||||
&& let Some(left) = expr_as_u128(left)
|
||||
&& let Some(right) = expr_as_u128(right)
|
||||
&& let Some(left) = expr_as_i128(left)
|
||||
&& let Some(right) = expr_as_i128(right)
|
||||
&& right >= left
|
||||
{
|
||||
min = min.min(left);
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ fn check_for_either_unsigned_int_constant<'a>(
|
|||
}
|
||||
|
||||
fn check_for_unsigned_int_constant<'a>(cx: &'a LateContext<'_>, expr: &'a Expr<'_>) -> Option<u128> {
|
||||
let Some(int_const) = constant_full_int(cx, cx.typeck_results(), expr) else { return None };
|
||||
let int_const = constant_full_int(cx, cx.typeck_results(), expr)?;
|
||||
match int_const {
|
||||
FullInt::S(s) => s.try_into().ok(),
|
||||
FullInt::U(u) => Some(u),
|
||||
|
|
|
|||
|
|
@ -8,8 +8,7 @@ use if_chain::if_chain;
|
|||
use rustc_ast::ast::LitKind;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::intravisit::{walk_expr, Visitor};
|
||||
use rustc_hir::BinOpKind;
|
||||
use rustc_hir::{BorrowKind, Expr, ExprKind};
|
||||
use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty;
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
|
|
|
|||
|
|
@ -226,7 +226,7 @@ fn lint_map_unit_fn(
|
|||
);
|
||||
|
||||
span_lint_and_then(cx, lint, expr.span, &msg, |diag| {
|
||||
diag.span_suggestion(stmt.span, "try this", suggestion, applicability);
|
||||
diag.span_suggestion(stmt.span, "try", suggestion, applicability);
|
||||
});
|
||||
} else if let Some((binding, closure_expr)) = unit_closure(cx, fn_arg) {
|
||||
let msg = suggestion_msg("closure", map_type);
|
||||
|
|
@ -241,7 +241,7 @@ fn lint_map_unit_fn(
|
|||
snippet_with_applicability(cx, var_arg.span, "_", &mut applicability),
|
||||
snippet_with_context(cx, reduced_expr_span, var_arg.span.ctxt(), "_", &mut applicability).0,
|
||||
);
|
||||
diag.span_suggestion(stmt.span, "try this", suggestion, applicability);
|
||||
diag.span_suggestion(stmt.span, "try", suggestion, applicability);
|
||||
} else {
|
||||
let suggestion = format!(
|
||||
"if let {0}({1}) = {2} {{ ... }}",
|
||||
|
|
@ -249,7 +249,7 @@ fn lint_map_unit_fn(
|
|||
snippet(cx, binding.pat.span, "_"),
|
||||
snippet(cx, var_arg.span, "_"),
|
||||
);
|
||||
diag.span_suggestion(stmt.span, "try this", suggestion, Applicability::HasPlaceholders);
|
||||
diag.span_suggestion(stmt.span, "try", suggestion, Applicability::HasPlaceholders);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::higher;
|
||||
use clippy_utils::is_res_lang_ctor;
|
||||
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};
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ pub(crate) fn check(cx: &LateContext<'_>, local: &Local<'_>) -> bool {
|
|||
local.span,
|
||||
"you seem to be trying to use `match` to destructure a single infallible pattern. \
|
||||
Consider using `let`",
|
||||
"try this",
|
||||
"try",
|
||||
format!(
|
||||
"let {}({}{}) = {};",
|
||||
snippet_with_applicability(cx, variant_name.span, "..", &mut applicability),
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ fn check<'tcx>(
|
|||
MANUAL_FILTER,
|
||||
expr.span,
|
||||
"manual implementation of `Option::filter`",
|
||||
"try this",
|
||||
"try",
|
||||
if sugg_info.needs_brackets {
|
||||
format!(
|
||||
"{{ {}{}.filter({body_str}) }}",
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ fn check<'tcx>(
|
|||
MANUAL_MAP,
|
||||
expr.span,
|
||||
"manual implementation of `Option::map`",
|
||||
"try this",
|
||||
"try",
|
||||
if sugg_info.needs_brackets {
|
||||
format!(
|
||||
"{{ {}{}.map({}) }}",
|
||||
|
|
|
|||
|
|
@ -1,14 +1,17 @@
|
|||
use crate::{map_unit_fn::OPTION_MAP_UNIT_FN, matches::MATCH_AS_REF};
|
||||
use crate::map_unit_fn::OPTION_MAP_UNIT_FN;
|
||||
use crate::matches::MATCH_AS_REF;
|
||||
use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::ty::{is_copy, is_type_diagnostic_item, peel_mid_ty_refs_is_mutable, type_is_unsafe_function};
|
||||
use clippy_utils::{
|
||||
can_move_expr_to_closure, is_else_clause, is_lint_allowed, is_res_lang_ctor, path_res, path_to_local_id,
|
||||
peel_blocks, peel_hir_expr_refs, peel_hir_expr_while, sugg::Sugg, CaptureKind,
|
||||
peel_blocks, peel_hir_expr_refs, peel_hir_expr_while, CaptureKind,
|
||||
};
|
||||
use rustc_ast::util::parser::PREC_POSTFIX;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::LangItem::{OptionNone, OptionSome};
|
||||
use rustc_hir::{def::Res, BindingAnnotation, Expr, ExprKind, HirId, Mutability, Pat, PatKind, Path, QPath};
|
||||
use rustc_hir::{BindingAnnotation, Expr, ExprKind, HirId, Mutability, Pat, PatKind, Path, QPath};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::{sym, SyntaxContext};
|
||||
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr:
|
|||
MATCH_AS_REF,
|
||||
expr.span,
|
||||
&format!("use `{suggestion}()` instead"),
|
||||
"try this",
|
||||
"try",
|
||||
format!(
|
||||
"{}.{suggestion}(){cast}",
|
||||
snippet_with_applicability(cx, ex.span, "_", &mut applicability),
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
use super::REDUNDANT_PATTERN_MATCHING;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::is_lint_allowed;
|
||||
use clippy_utils::is_wild;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::span_contains_comment;
|
||||
use clippy_utils::{is_lint_allowed, is_wild, span_contains_comment};
|
||||
use rustc_ast::{Attribute, LitKind};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Arm, BorrowKind, Expr, ExprKind, Guard, Pat, PatKind, QPath};
|
||||
|
|
@ -139,7 +137,7 @@ where
|
|||
MATCH_LIKE_MATCHES_MACRO,
|
||||
expr.span,
|
||||
&format!("{} expression looks like `matches!` macro", if is_if_let { "if let .. else" } else { "match" }),
|
||||
"try this",
|
||||
"try",
|
||||
format!(
|
||||
"{}matches!({}, {pat_and_guard})",
|
||||
if b0 { "" } else { "!" },
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, scrutinee: &'tcx Expr<'_>) {
|
|||
MATCH_ON_VEC_ITEMS,
|
||||
scrutinee.span,
|
||||
"indexing into a vector may panic",
|
||||
"try this",
|
||||
"try",
|
||||
format!(
|
||||
"{}.get({})",
|
||||
snippet(cx, vec.span, ".."),
|
||||
|
|
|
|||
|
|
@ -2,8 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
|
|||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::{is_lint_allowed, path_to_local, search_same, SpanlessEq, SpanlessHash};
|
||||
use core::cmp::Ordering;
|
||||
use core::iter;
|
||||
use core::slice;
|
||||
use core::{iter, slice};
|
||||
use rustc_arena::DroplessArena;
|
||||
use rustc_ast::ast::LitKind;
|
||||
use rustc_errors::Applicability;
|
||||
|
|
@ -240,7 +239,7 @@ impl<'a> NormalizedPat<'a> {
|
|||
},
|
||||
PatKind::TupleStruct(ref path, pats, wild_idx) => {
|
||||
let Some(adt) = cx.typeck_results().pat_ty(pat).ty_adt_def() else {
|
||||
return Self::Wild
|
||||
return Self::Wild;
|
||||
};
|
||||
let (var_id, variant) = if adt.is_enum() {
|
||||
match cx.qpath_res(path, pat.hir_id).opt_def_id() {
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
|
|||
MATCH_WILDCARD_FOR_SINGLE_VARIANTS,
|
||||
wildcard_span,
|
||||
"wildcard matches only a single variant and will also match any future added variants",
|
||||
"try this",
|
||||
"try",
|
||||
format_suggestion(x),
|
||||
Applicability::MaybeIncorrect,
|
||||
),
|
||||
|
|
@ -161,7 +161,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
|
|||
WILDCARD_ENUM_MATCH_ARM,
|
||||
wildcard_span,
|
||||
message,
|
||||
"try this",
|
||||
"try",
|
||||
suggestions.join(" | "),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1125,8 +1125,8 @@ fn contains_cfg_arm(cx: &LateContext<'_>, e: &Expr<'_>, scrutinee: &Expr<'_>, ar
|
|||
//|^
|
||||
let found = arm_spans.try_fold(start, |start, range| {
|
||||
let Some((end, next_start)) = range else {
|
||||
// Shouldn't happen as macros can't expand to match arms, but treat this as though a `cfg` attribute were
|
||||
// found.
|
||||
// Shouldn't happen as macros can't expand to match arms, but treat this as though a `cfg` attribute
|
||||
// were found.
|
||||
return Err(());
|
||||
};
|
||||
let span = SpanData {
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@ use rustc_hir::def::{DefKind, Res};
|
|||
use rustc_hir::LangItem::{self, OptionNone, OptionSome, PollPending, PollReady, ResultErr, ResultOk};
|
||||
use rustc_hir::{Arm, Expr, ExprKind, Node, Pat, PatKind, QPath, UnOp};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::{self, subst::GenericArgKind, Ty};
|
||||
use rustc_middle::ty::subst::GenericArgKind;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_span::{sym, Symbol};
|
||||
|
||||
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
|
|
@ -45,6 +46,62 @@ fn try_get_generic_ty(ty: Ty<'_>, index: usize) -> Option<Ty<'_>> {
|
|||
}
|
||||
}
|
||||
|
||||
fn find_method_and_type<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
check_pat: &Pat<'_>,
|
||||
op_ty: Ty<'tcx>,
|
||||
) -> Option<(&'static str, Ty<'tcx>)> {
|
||||
match check_pat.kind {
|
||||
PatKind::TupleStruct(ref qpath, args, rest) => {
|
||||
let is_wildcard = matches!(args.first().map(|p| &p.kind), Some(PatKind::Wild));
|
||||
let is_rest = matches!((args, rest.as_opt_usize()), ([], Some(_)));
|
||||
|
||||
if is_wildcard || is_rest {
|
||||
let res = cx.typeck_results().qpath_res(qpath, check_pat.hir_id);
|
||||
let Some(id) = res.opt_def_id().map(|ctor_id| cx.tcx.parent(ctor_id)) else {
|
||||
return None;
|
||||
};
|
||||
let lang_items = cx.tcx.lang_items();
|
||||
if Some(id) == lang_items.result_ok_variant() {
|
||||
Some(("is_ok()", try_get_generic_ty(op_ty, 0).unwrap_or(op_ty)))
|
||||
} else if Some(id) == lang_items.result_err_variant() {
|
||||
Some(("is_err()", try_get_generic_ty(op_ty, 1).unwrap_or(op_ty)))
|
||||
} else if Some(id) == lang_items.option_some_variant() {
|
||||
Some(("is_some()", op_ty))
|
||||
} else if Some(id) == lang_items.poll_ready_variant() {
|
||||
Some(("is_ready()", op_ty))
|
||||
} else if is_pat_variant(cx, check_pat, qpath, Item::Diag(sym::IpAddr, sym!(V4))) {
|
||||
Some(("is_ipv4()", op_ty))
|
||||
} else if is_pat_variant(cx, check_pat, qpath, Item::Diag(sym::IpAddr, sym!(V6))) {
|
||||
Some(("is_ipv6()", op_ty))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
PatKind::Path(ref path) => {
|
||||
if let Res::Def(DefKind::Ctor(..), ctor_id) = cx.qpath_res(path, check_pat.hir_id)
|
||||
&& let Some(variant_id) = cx.tcx.opt_parent(ctor_id)
|
||||
{
|
||||
let method = if cx.tcx.lang_items().option_none_variant() == Some(variant_id) {
|
||||
"is_none()"
|
||||
} else if cx.tcx.lang_items().poll_pending_variant() == Some(variant_id) {
|
||||
"is_pending()"
|
||||
} else {
|
||||
return None;
|
||||
};
|
||||
// `None` and `Pending` don't have an inner type.
|
||||
Some((method, cx.tcx.types.unit))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn find_sugg_for_if_let<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
expr: &'tcx Expr<'_>,
|
||||
|
|
@ -62,52 +119,8 @@ fn find_sugg_for_if_let<'tcx>(
|
|||
let op_ty = cx.typeck_results().expr_ty(let_expr);
|
||||
// Determine which function should be used, and the type contained by the corresponding
|
||||
// variant.
|
||||
let (good_method, inner_ty) = match check_pat.kind {
|
||||
PatKind::TupleStruct(ref qpath, args, rest) => {
|
||||
let is_wildcard = matches!(args.first().map(|p| &p.kind), Some(PatKind::Wild));
|
||||
let is_rest = matches!((args, rest.as_opt_usize()), ([], Some(_)));
|
||||
|
||||
if is_wildcard || is_rest {
|
||||
let res = cx.typeck_results().qpath_res(qpath, check_pat.hir_id);
|
||||
let Some(id) = res.opt_def_id().map(|ctor_id| cx.tcx.parent(ctor_id)) else { return };
|
||||
let lang_items = cx.tcx.lang_items();
|
||||
if Some(id) == lang_items.result_ok_variant() {
|
||||
("is_ok()", try_get_generic_ty(op_ty, 0).unwrap_or(op_ty))
|
||||
} else if Some(id) == lang_items.result_err_variant() {
|
||||
("is_err()", try_get_generic_ty(op_ty, 1).unwrap_or(op_ty))
|
||||
} else if Some(id) == lang_items.option_some_variant() {
|
||||
("is_some()", op_ty)
|
||||
} else if Some(id) == lang_items.poll_ready_variant() {
|
||||
("is_ready()", op_ty)
|
||||
} else if is_pat_variant(cx, check_pat, qpath, Item::Diag(sym::IpAddr, sym!(V4))) {
|
||||
("is_ipv4()", op_ty)
|
||||
} else if is_pat_variant(cx, check_pat, qpath, Item::Diag(sym::IpAddr, sym!(V6))) {
|
||||
("is_ipv6()", op_ty)
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
},
|
||||
PatKind::Path(ref path) => {
|
||||
if let Res::Def(DefKind::Ctor(..), ctor_id) = cx.qpath_res(path, check_pat.hir_id)
|
||||
&& let Some(variant_id) = cx.tcx.opt_parent(ctor_id)
|
||||
{
|
||||
let method = if cx.tcx.lang_items().option_none_variant() == Some(variant_id) {
|
||||
"is_none()"
|
||||
} else if cx.tcx.lang_items().poll_pending_variant() == Some(variant_id) {
|
||||
"is_pending()"
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
// `None` and `Pending` don't have an inner type.
|
||||
(method, cx.tcx.types.unit)
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
},
|
||||
_ => return,
|
||||
let Some((good_method, inner_ty)) = find_method_and_type(cx, check_pat, op_ty) else {
|
||||
return;
|
||||
};
|
||||
|
||||
// If this is the last expression in a block or there is an else clause then the whole
|
||||
|
|
@ -175,7 +188,7 @@ fn find_sugg_for_if_let<'tcx>(
|
|||
.maybe_par()
|
||||
.to_string();
|
||||
|
||||
diag.span_suggestion(span, "try this", format!("{keyword} {sugg}.{good_method}"), app);
|
||||
diag.span_suggestion(span, "try", format!("{keyword} {sugg}.{good_method}"), app);
|
||||
|
||||
if needs_drop {
|
||||
diag.note("this will change drop order of the result, as well as all temporaries");
|
||||
|
|
@ -200,7 +213,7 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
|
|||
REDUNDANT_PATTERN_MATCHING,
|
||||
span,
|
||||
&format!("redundant pattern matching, consider using `{good_method}`"),
|
||||
"try this",
|
||||
"try",
|
||||
format!("{}.{good_method}", snippet(cx, result_expr.span, "_")),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
|
|
@ -336,7 +349,9 @@ enum Item {
|
|||
}
|
||||
|
||||
fn is_pat_variant(cx: &LateContext<'_>, pat: &Pat<'_>, path: &QPath<'_>, expected_item: Item) -> bool {
|
||||
let Some(id) = cx.typeck_results().qpath_res(path, pat.hir_id).opt_def_id() else { return false };
|
||||
let Some(id) = cx.typeck_results().qpath_res(path, pat.hir_id).opt_def_id() else {
|
||||
return false;
|
||||
};
|
||||
|
||||
match expected_item {
|
||||
Item::Lang(expected_lang_item) => cx
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ fn report_single_pattern(
|
|||
}
|
||||
};
|
||||
|
||||
span_lint_and_sugg(cx, lint, expr.span, msg, "try this", sugg, app);
|
||||
span_lint_and_sugg(cx, lint, expr.span, msg, "try", sugg, app);
|
||||
}
|
||||
|
||||
fn check_opt_like<'a>(
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, scrutine
|
|||
TRY_ERR,
|
||||
expr.span,
|
||||
"returning an `Err(_)` with the `?` operator",
|
||||
"try this",
|
||||
"try",
|
||||
suggestion,
|
||||
applicability,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
use super::{contains_return, BIND_INSTEAD_OF_MAP};
|
||||
use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and_sugg, span_lint_and_then};
|
||||
use clippy_utils::peel_blocks;
|
||||
use clippy_utils::source::{snippet, snippet_with_context};
|
||||
use clippy_utils::{peel_blocks, visitors::find_all_ret_expressions};
|
||||
use clippy_utils::visitors::find_all_ret_expressions;
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
|
|
@ -87,7 +88,7 @@ pub(crate) trait BindInsteadOfMap {
|
|||
BIND_INSTEAD_OF_MAP,
|
||||
expr.span,
|
||||
&msg,
|
||||
"try this",
|
||||
"try",
|
||||
note,
|
||||
app,
|
||||
);
|
||||
|
|
@ -124,7 +125,7 @@ pub(crate) trait BindInsteadOfMap {
|
|||
span_lint_and_then(cx, BIND_INSTEAD_OF_MAP, expr.span, &msg, |diag| {
|
||||
multispan_sugg_with_applicability(
|
||||
diag,
|
||||
"try this",
|
||||
"try",
|
||||
Applicability::MachineApplicable,
|
||||
std::iter::once((span, Self::GOOD_METHOD_NAME.into())).chain(
|
||||
suggs
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::source::{indent_of, reindent_multiline};
|
||||
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};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::{source_map::Spanned, Span};
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::Span;
|
||||
|
||||
use super::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS;
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue