Auto merge of #104688 - flip1995:clippyup, r=Manishearth,flip1995

Update Clippy

r? `@Manishearth`

Sorry for taking so long. There were so many blockers and so little time. This situation should be mitigated with #104007 in the future.
This commit is contained in:
bors 2022-11-22 17:09:06 +00:00
commit b33afd61ed
895 changed files with 8253 additions and 18379 deletions

View file

@ -1,6 +1,6 @@
[package]
name = "clippy_lints"
version = "0.1.66"
version = "0.1.67"
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
repository = "https://github.com/rust-lang/rust-clippy"
readme = "README.md"
@ -11,6 +11,7 @@ edition = "2021"
[dependencies]
cargo_metadata = "0.14"
clippy_utils = { path = "../clippy_utils" }
declare_clippy_lint = { path = "../declare_clippy_lint" }
if_chain = "1.0"
itertools = "0.10.1"
pulldown-cmark = { version = "0.9", default-features = false }

View file

@ -11,14 +11,14 @@ use rustc_errors::Applicability;
use rustc_hir::{
Block, Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, StmtKind, TraitFn, TraitItem, TraitItemKind,
};
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty;
use rustc_semver::RustcVersion;
use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Span;
use rustc_span::sym;
use rustc_span::symbol::Symbol;
use rustc_span::{sym, DUMMY_SP};
use semver::Version;
static UNIX_SYSTEMS: &[&str] = &[
@ -303,6 +303,26 @@ declare_lint_pass!(Attributes => [
]);
impl<'tcx> LateLintPass<'tcx> for Attributes {
fn check_crate(&mut self, cx: &LateContext<'tcx>) {
for (name, level) in &cx.sess().opts.lint_opts {
if name == "clippy::restriction" && *level > Level::Allow {
span_lint_and_then(
cx,
BLANKET_CLIPPY_RESTRICTION_LINTS,
DUMMY_SP,
"`clippy::restriction` is not meant to be enabled as a group",
|diag| {
diag.note(format!(
"because of the command line `--{} clippy::restriction`",
level.as_str()
));
diag.help("enable the restriction lints you need individually");
},
);
}
}
}
fn check_attribute(&mut self, cx: &LateContext<'tcx>, attr: &'tcx Attribute) {
if let Some(items) = &attr.meta_item_list() {
if let Some(ident) = attr.ident() {
@ -358,7 +378,9 @@ impl<'tcx> LateLintPass<'tcx> for Attributes {
| "enum_glob_use"
| "redundant_pub_crate"
| "macro_use_imports"
| "unsafe_removed_from_name",
| "unsafe_removed_from_name"
| "module_name_repetitions"
| "single_component_path_imports"
)
})
{
@ -441,9 +463,9 @@ fn check_clippy_lint_names(cx: &LateContext<'_>, name: Symbol, items: &[NestedMe
cx,
BLANKET_CLIPPY_RESTRICTION_LINTS,
lint.span(),
"restriction lints are not meant to be all enabled",
"`clippy::restriction` is not meant to be enabled as a group",
None,
"try enabling only the lints you really need",
"enable the restriction lints you need individually",
);
}
}
@ -464,6 +486,11 @@ fn check_lint_reason(cx: &LateContext<'_>, name: Symbol, items: &[NestedMetaItem
return;
}
// Check if the attribute is in an external macro and therefore out of the developer's control
if in_external_macro(cx.sess(), attr.span) {
return;
}
span_lint_and_help(
cx,
ALLOW_ATTRIBUTES_WITHOUT_REASON,

View file

@ -1,7 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::{match_def_path, paths};
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def::{Namespace, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::{AsyncGeneratorKind, Body, BodyId, GeneratorKind};
use rustc_lint::{LateContext, LateLintPass};
@ -189,7 +188,7 @@ impl LateLintPass<'_> for AwaitHolding {
fn check_crate(&mut self, cx: &LateContext<'_>) {
for conf in &self.conf_invalid_types {
let segs: Vec<_> = conf.path().split("::").collect();
if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &segs, Some(Namespace::TypeNS)) {
for id in clippy_utils::def_path_def_ids(cx, &segs) {
self.def_ids.insert(id, conf.clone());
}
}

View file

@ -1,9 +1,10 @@
use clippy_utils::higher::If;
use rustc_ast::LitKind;
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, is_else_clause, is_integer_literal, sugg::Sugg};
use clippy_utils::{diagnostics::span_lint_and_then, in_constant, is_else_clause, is_integer_literal, sugg::Sugg};
use rustc_errors::Applicability;
declare_clippy_lint! {
@ -12,7 +13,7 @@ declare_clippy_lint! {
/// this lint suggests using a `from()` function or an `as` coercion.
///
/// ### Why is this bad?
/// Coercion or `from()` is idiomatic way to convert bool to a number.
/// Coercion or `from()` is another way to convert bool to a number.
/// Both methods are guaranteed to return 1 for true, and 0 for false.
///
/// See https://doc.rust-lang.org/std/primitive.bool.html#impl-From%3Cbool%3E
@ -38,23 +39,23 @@ declare_clippy_lint! {
/// ```
#[clippy::version = "1.65.0"]
pub BOOL_TO_INT_WITH_IF,
style,
pedantic,
"using if to convert bool to int"
}
declare_lint_pass!(BoolToIntWithIf => [BOOL_TO_INT_WITH_IF]);
impl<'tcx> LateLintPass<'tcx> for BoolToIntWithIf {
fn check_expr(&mut self, ctx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) {
if !expr.span.from_expansion() {
check_if_else(ctx, expr);
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) {
if !expr.span.from_expansion() && !in_constant(cx, expr.hir_id) {
check_if_else(cx, expr);
}
}
}
fn check_if_else<'tcx>(ctx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) {
if let ExprKind::If(check, then, Some(else_)) = expr.kind
fn check_if_else<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) {
if let Some(If { cond, then, r#else: Some(r#else) }) = If::hir(expr)
&& let Some(then_lit) = int_literal(then)
&& let Some(else_lit) = int_literal(else_)
&& let Some(else_lit) = int_literal(r#else)
{
let inverted = if is_integer_literal(then_lit, 1) && is_integer_literal(else_lit, 0) {
false
@ -66,17 +67,17 @@ fn check_if_else<'tcx>(ctx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx
};
let mut applicability = Applicability::MachineApplicable;
let snippet = {
let mut sugg = Sugg::hir_with_applicability(ctx, check, "..", &mut applicability);
let mut sugg = Sugg::hir_with_applicability(cx, cond, "..", &mut applicability);
if inverted {
sugg = !sugg;
}
sugg
};
let ty = ctx.typeck_results().expr_ty(then_lit); // then and else must be of same type
let ty = cx.typeck_results().expr_ty(then_lit); // then and else must be of same type
let suggestion = {
let wrap_in_curly = is_else_clause(ctx.tcx, expr);
let wrap_in_curly = is_else_clause(cx.tcx, expr);
let mut s = Sugg::NonParen(format!("{ty}::from({snippet})").into());
if wrap_in_curly {
s = s.blockify();
@ -87,7 +88,7 @@ fn check_if_else<'tcx>(ctx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx
let into_snippet = snippet.clone().maybe_par();
let as_snippet = snippet.as_ty(ty);
span_lint_and_then(ctx,
span_lint_and_then(cx,
BOOL_TO_INT_WITH_IF,
expr.span,
"boolean to int conversion using if",

View file

@ -481,7 +481,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'a, 'tcx> {
}
}
fn implements_ord<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> bool {
fn implements_ord(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
let ty = cx.typeck_results().expr_ty(expr);
cx.tcx
.get_diagnostic_item(sym::Ord)

View file

@ -593,7 +593,7 @@ declare_clippy_lint! {
/// let _: *mut [u8] = std::ptr::slice_from_raw_parts_mut(ptr, len);
/// ```
/// [safety requirements]: https://doc.rust-lang.org/std/slice/fn.from_raw_parts.html#safety
#[clippy::version = "1.64.0"]
#[clippy::version = "1.65.0"]
pub CAST_SLICE_FROM_RAW_PARTS,
suspicious,
"casting a slice created from a pointer and length to a slice pointer"

View file

@ -4,11 +4,11 @@ use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::source::snippet_opt;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::visitors::for_each_expr;
use clippy_utils::LimitStack;
use clippy_utils::{get_async_fn_body, is_async_fn, LimitStack};
use core::ops::ControlFlow;
use rustc_ast::ast::Attribute;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{Body, ExprKind, FnDecl, HirId};
use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirId};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Span;
@ -56,15 +56,13 @@ impl CognitiveComplexity {
cx: &LateContext<'tcx>,
kind: FnKind<'tcx>,
decl: &'tcx FnDecl<'_>,
body: &'tcx Body<'_>,
expr: &'tcx Expr<'_>,
body_span: Span,
) {
if body_span.from_expansion() {
return;
}
let expr = body.value;
let mut cc = 1u64;
let mut returns = 0u64;
let _: Option<!> = for_each_expr(expr, |e| {
@ -146,7 +144,18 @@ impl<'tcx> LateLintPass<'tcx> for CognitiveComplexity {
) {
let def_id = cx.tcx.hir().local_def_id(hir_id);
if !cx.tcx.has_attr(def_id.to_def_id(), sym::test) {
self.check(cx, kind, decl, body, span);
let expr = if is_async_fn(kind) {
match get_async_fn_body(cx.tcx, body) {
Some(b) => b,
None => {
return;
},
}
} else {
body.value
};
self.check(cx, kind, decl, expr, span);
}
}

View file

@ -0,0 +1,628 @@
// This file was generated by `cargo dev update_lints`.
// Use that command to update this file and do not edit by hand.
// Manual edits will be overwritten.
pub(crate) static LINTS: &[&crate::LintInfo] = &[
#[cfg(feature = "internal")]
crate::utils::internal_lints::clippy_lints_internal::CLIPPY_LINTS_INTERNAL_INFO,
#[cfg(feature = "internal")]
crate::utils::internal_lints::collapsible_calls::COLLAPSIBLE_SPAN_LINT_CALLS_INFO,
#[cfg(feature = "internal")]
crate::utils::internal_lints::compiler_lint_functions::COMPILER_LINT_FUNCTIONS_INFO,
#[cfg(feature = "internal")]
crate::utils::internal_lints::if_chain_style::IF_CHAIN_STYLE_INFO,
#[cfg(feature = "internal")]
crate::utils::internal_lints::interning_defined_symbol::INTERNING_DEFINED_SYMBOL_INFO,
#[cfg(feature = "internal")]
crate::utils::internal_lints::interning_defined_symbol::UNNECESSARY_SYMBOL_STR_INFO,
#[cfg(feature = "internal")]
crate::utils::internal_lints::invalid_paths::INVALID_PATHS_INFO,
#[cfg(feature = "internal")]
crate::utils::internal_lints::lint_without_lint_pass::DEFAULT_DEPRECATION_REASON_INFO,
#[cfg(feature = "internal")]
crate::utils::internal_lints::lint_without_lint_pass::DEFAULT_LINT_INFO,
#[cfg(feature = "internal")]
crate::utils::internal_lints::lint_without_lint_pass::INVALID_CLIPPY_VERSION_ATTRIBUTE_INFO,
#[cfg(feature = "internal")]
crate::utils::internal_lints::lint_without_lint_pass::LINT_WITHOUT_LINT_PASS_INFO,
#[cfg(feature = "internal")]
crate::utils::internal_lints::lint_without_lint_pass::MISSING_CLIPPY_VERSION_ATTRIBUTE_INFO,
#[cfg(feature = "internal")]
crate::utils::internal_lints::msrv_attr_impl::MISSING_MSRV_ATTR_IMPL_INFO,
#[cfg(feature = "internal")]
crate::utils::internal_lints::outer_expn_data_pass::OUTER_EXPN_EXPN_DATA_INFO,
#[cfg(feature = "internal")]
crate::utils::internal_lints::produce_ice::PRODUCE_ICE_INFO,
#[cfg(feature = "internal")]
crate::utils::internal_lints::unnecessary_def_path::UNNECESSARY_DEF_PATH_INFO,
crate::almost_complete_letter_range::ALMOST_COMPLETE_LETTER_RANGE_INFO,
crate::approx_const::APPROX_CONSTANT_INFO,
crate::as_conversions::AS_CONVERSIONS_INFO,
crate::asm_syntax::INLINE_ASM_X86_ATT_SYNTAX_INFO,
crate::asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX_INFO,
crate::assertions_on_constants::ASSERTIONS_ON_CONSTANTS_INFO,
crate::assertions_on_result_states::ASSERTIONS_ON_RESULT_STATES_INFO,
crate::async_yields_async::ASYNC_YIELDS_ASYNC_INFO,
crate::attrs::ALLOW_ATTRIBUTES_WITHOUT_REASON_INFO,
crate::attrs::BLANKET_CLIPPY_RESTRICTION_LINTS_INFO,
crate::attrs::DEPRECATED_CFG_ATTR_INFO,
crate::attrs::DEPRECATED_SEMVER_INFO,
crate::attrs::EMPTY_LINE_AFTER_OUTER_ATTR_INFO,
crate::attrs::INLINE_ALWAYS_INFO,
crate::attrs::MISMATCHED_TARGET_OS_INFO,
crate::attrs::USELESS_ATTRIBUTE_INFO,
crate::await_holding_invalid::AWAIT_HOLDING_INVALID_TYPE_INFO,
crate::await_holding_invalid::AWAIT_HOLDING_LOCK_INFO,
crate::await_holding_invalid::AWAIT_HOLDING_REFCELL_REF_INFO,
crate::blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS_INFO,
crate::bool_assert_comparison::BOOL_ASSERT_COMPARISON_INFO,
crate::bool_to_int_with_if::BOOL_TO_INT_WITH_IF_INFO,
crate::booleans::NONMINIMAL_BOOL_INFO,
crate::booleans::OVERLY_COMPLEX_BOOL_EXPR_INFO,
crate::borrow_deref_ref::BORROW_DEREF_REF_INFO,
crate::box_default::BOX_DEFAULT_INFO,
crate::cargo::CARGO_COMMON_METADATA_INFO,
crate::cargo::MULTIPLE_CRATE_VERSIONS_INFO,
crate::cargo::NEGATIVE_FEATURE_NAMES_INFO,
crate::cargo::REDUNDANT_FEATURE_NAMES_INFO,
crate::cargo::WILDCARD_DEPENDENCIES_INFO,
crate::casts::AS_PTR_CAST_MUT_INFO,
crate::casts::AS_UNDERSCORE_INFO,
crate::casts::BORROW_AS_PTR_INFO,
crate::casts::CAST_ABS_TO_UNSIGNED_INFO,
crate::casts::CAST_ENUM_CONSTRUCTOR_INFO,
crate::casts::CAST_ENUM_TRUNCATION_INFO,
crate::casts::CAST_LOSSLESS_INFO,
crate::casts::CAST_NAN_TO_INT_INFO,
crate::casts::CAST_POSSIBLE_TRUNCATION_INFO,
crate::casts::CAST_POSSIBLE_WRAP_INFO,
crate::casts::CAST_PRECISION_LOSS_INFO,
crate::casts::CAST_PTR_ALIGNMENT_INFO,
crate::casts::CAST_REF_TO_MUT_INFO,
crate::casts::CAST_SIGN_LOSS_INFO,
crate::casts::CAST_SLICE_DIFFERENT_SIZES_INFO,
crate::casts::CAST_SLICE_FROM_RAW_PARTS_INFO,
crate::casts::CHAR_LIT_AS_U8_INFO,
crate::casts::FN_TO_NUMERIC_CAST_INFO,
crate::casts::FN_TO_NUMERIC_CAST_ANY_INFO,
crate::casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION_INFO,
crate::casts::PTR_AS_PTR_INFO,
crate::casts::UNNECESSARY_CAST_INFO,
crate::checked_conversions::CHECKED_CONVERSIONS_INFO,
crate::cognitive_complexity::COGNITIVE_COMPLEXITY_INFO,
crate::collapsible_if::COLLAPSIBLE_ELSE_IF_INFO,
crate::collapsible_if::COLLAPSIBLE_IF_INFO,
crate::comparison_chain::COMPARISON_CHAIN_INFO,
crate::copies::BRANCHES_SHARING_CODE_INFO,
crate::copies::IFS_SAME_COND_INFO,
crate::copies::IF_SAME_THEN_ELSE_INFO,
crate::copies::SAME_FUNCTIONS_IN_IF_CONDITION_INFO,
crate::copy_iterator::COPY_ITERATOR_INFO,
crate::crate_in_macro_def::CRATE_IN_MACRO_DEF_INFO,
crate::create_dir::CREATE_DIR_INFO,
crate::dbg_macro::DBG_MACRO_INFO,
crate::default::DEFAULT_TRAIT_ACCESS_INFO,
crate::default::FIELD_REASSIGN_WITH_DEFAULT_INFO,
crate::default_instead_of_iter_empty::DEFAULT_INSTEAD_OF_ITER_EMPTY_INFO,
crate::default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK_INFO,
crate::default_union_representation::DEFAULT_UNION_REPRESENTATION_INFO,
crate::dereference::EXPLICIT_AUTO_DEREF_INFO,
crate::dereference::EXPLICIT_DEREF_METHODS_INFO,
crate::dereference::NEEDLESS_BORROW_INFO,
crate::dereference::REF_BINDING_TO_REFERENCE_INFO,
crate::derivable_impls::DERIVABLE_IMPLS_INFO,
crate::derive::DERIVE_HASH_XOR_EQ_INFO,
crate::derive::DERIVE_ORD_XOR_PARTIAL_ORD_INFO,
crate::derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ_INFO,
crate::derive::EXPL_IMPL_CLONE_ON_COPY_INFO,
crate::derive::UNSAFE_DERIVE_DESERIALIZE_INFO,
crate::disallowed_macros::DISALLOWED_MACROS_INFO,
crate::disallowed_methods::DISALLOWED_METHODS_INFO,
crate::disallowed_names::DISALLOWED_NAMES_INFO,
crate::disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS_INFO,
crate::disallowed_types::DISALLOWED_TYPES_INFO,
crate::doc::DOC_LINK_WITH_QUOTES_INFO,
crate::doc::DOC_MARKDOWN_INFO,
crate::doc::MISSING_ERRORS_DOC_INFO,
crate::doc::MISSING_PANICS_DOC_INFO,
crate::doc::MISSING_SAFETY_DOC_INFO,
crate::doc::NEEDLESS_DOCTEST_MAIN_INFO,
crate::doc::UNNECESSARY_SAFETY_DOC_INFO,
crate::double_parens::DOUBLE_PARENS_INFO,
crate::drop_forget_ref::DROP_COPY_INFO,
crate::drop_forget_ref::DROP_NON_DROP_INFO,
crate::drop_forget_ref::DROP_REF_INFO,
crate::drop_forget_ref::FORGET_COPY_INFO,
crate::drop_forget_ref::FORGET_NON_DROP_INFO,
crate::drop_forget_ref::FORGET_REF_INFO,
crate::drop_forget_ref::UNDROPPED_MANUALLY_DROPS_INFO,
crate::duplicate_mod::DUPLICATE_MOD_INFO,
crate::else_if_without_else::ELSE_IF_WITHOUT_ELSE_INFO,
crate::empty_drop::EMPTY_DROP_INFO,
crate::empty_enum::EMPTY_ENUM_INFO,
crate::empty_structs_with_brackets::EMPTY_STRUCTS_WITH_BRACKETS_INFO,
crate::entry::MAP_ENTRY_INFO,
crate::enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT_INFO,
crate::enum_variants::ENUM_VARIANT_NAMES_INFO,
crate::enum_variants::MODULE_INCEPTION_INFO,
crate::enum_variants::MODULE_NAME_REPETITIONS_INFO,
crate::equatable_if_let::EQUATABLE_IF_LET_INFO,
crate::escape::BOXED_LOCAL_INFO,
crate::eta_reduction::REDUNDANT_CLOSURE_INFO,
crate::eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS_INFO,
crate::excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS_INFO,
crate::excessive_bools::STRUCT_EXCESSIVE_BOOLS_INFO,
crate::exhaustive_items::EXHAUSTIVE_ENUMS_INFO,
crate::exhaustive_items::EXHAUSTIVE_STRUCTS_INFO,
crate::exit::EXIT_INFO,
crate::explicit_write::EXPLICIT_WRITE_INFO,
crate::fallible_impl_from::FALLIBLE_IMPL_FROM_INFO,
crate::float_literal::EXCESSIVE_PRECISION_INFO,
crate::float_literal::LOSSY_FLOAT_LITERAL_INFO,
crate::floating_point_arithmetic::IMPRECISE_FLOPS_INFO,
crate::floating_point_arithmetic::SUBOPTIMAL_FLOPS_INFO,
crate::format::USELESS_FORMAT_INFO,
crate::format_args::FORMAT_IN_FORMAT_ARGS_INFO,
crate::format_args::TO_STRING_IN_FORMAT_ARGS_INFO,
crate::format_args::UNINLINED_FORMAT_ARGS_INFO,
crate::format_args::UNUSED_FORMAT_SPECS_INFO,
crate::format_impl::PRINT_IN_FORMAT_IMPL_INFO,
crate::format_impl::RECURSIVE_FORMAT_IMPL_INFO,
crate::format_push_string::FORMAT_PUSH_STRING_INFO,
crate::formatting::POSSIBLE_MISSING_COMMA_INFO,
crate::formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING_INFO,
crate::formatting::SUSPICIOUS_ELSE_FORMATTING_INFO,
crate::formatting::SUSPICIOUS_UNARY_OP_FORMATTING_INFO,
crate::from_over_into::FROM_OVER_INTO_INFO,
crate::from_raw_with_void_ptr::FROM_RAW_WITH_VOID_PTR_INFO,
crate::from_str_radix_10::FROM_STR_RADIX_10_INFO,
crate::functions::DOUBLE_MUST_USE_INFO,
crate::functions::MUST_USE_CANDIDATE_INFO,
crate::functions::MUST_USE_UNIT_INFO,
crate::functions::NOT_UNSAFE_PTR_ARG_DEREF_INFO,
crate::functions::RESULT_LARGE_ERR_INFO,
crate::functions::RESULT_UNIT_ERR_INFO,
crate::functions::TOO_MANY_ARGUMENTS_INFO,
crate::functions::TOO_MANY_LINES_INFO,
crate::future_not_send::FUTURE_NOT_SEND_INFO,
crate::if_let_mutex::IF_LET_MUTEX_INFO,
crate::if_not_else::IF_NOT_ELSE_INFO,
crate::if_then_some_else_none::IF_THEN_SOME_ELSE_NONE_INFO,
crate::implicit_hasher::IMPLICIT_HASHER_INFO,
crate::implicit_return::IMPLICIT_RETURN_INFO,
crate::implicit_saturating_add::IMPLICIT_SATURATING_ADD_INFO,
crate::implicit_saturating_sub::IMPLICIT_SATURATING_SUB_INFO,
crate::inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR_INFO,
crate::index_refutable_slice::INDEX_REFUTABLE_SLICE_INFO,
crate::indexing_slicing::INDEXING_SLICING_INFO,
crate::indexing_slicing::OUT_OF_BOUNDS_INDEXING_INFO,
crate::infinite_iter::INFINITE_ITER_INFO,
crate::infinite_iter::MAYBE_INFINITE_ITER_INFO,
crate::inherent_impl::MULTIPLE_INHERENT_IMPL_INFO,
crate::inherent_to_string::INHERENT_TO_STRING_INFO,
crate::inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY_INFO,
crate::init_numbered_fields::INIT_NUMBERED_FIELDS_INFO,
crate::inline_fn_without_body::INLINE_FN_WITHOUT_BODY_INFO,
crate::instant_subtraction::MANUAL_INSTANT_ELAPSED_INFO,
crate::instant_subtraction::UNCHECKED_DURATION_SUBTRACTION_INFO,
crate::int_plus_one::INT_PLUS_ONE_INFO,
crate::invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS_INFO,
crate::invalid_utf8_in_unchecked::INVALID_UTF8_IN_UNCHECKED_INFO,
crate::items_after_statements::ITEMS_AFTER_STATEMENTS_INFO,
crate::iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR_INFO,
crate::large_const_arrays::LARGE_CONST_ARRAYS_INFO,
crate::large_enum_variant::LARGE_ENUM_VARIANT_INFO,
crate::large_include_file::LARGE_INCLUDE_FILE_INFO,
crate::large_stack_arrays::LARGE_STACK_ARRAYS_INFO,
crate::len_zero::COMPARISON_TO_EMPTY_INFO,
crate::len_zero::LEN_WITHOUT_IS_EMPTY_INFO,
crate::len_zero::LEN_ZERO_INFO,
crate::let_if_seq::USELESS_LET_IF_SEQ_INFO,
crate::let_underscore::LET_UNDERSCORE_FUTURE_INFO,
crate::let_underscore::LET_UNDERSCORE_LOCK_INFO,
crate::let_underscore::LET_UNDERSCORE_MUST_USE_INFO,
crate::lifetimes::EXTRA_UNUSED_LIFETIMES_INFO,
crate::lifetimes::NEEDLESS_LIFETIMES_INFO,
crate::literal_representation::DECIMAL_LITERAL_REPRESENTATION_INFO,
crate::literal_representation::INCONSISTENT_DIGIT_GROUPING_INFO,
crate::literal_representation::LARGE_DIGIT_GROUPS_INFO,
crate::literal_representation::MISTYPED_LITERAL_SUFFIXES_INFO,
crate::literal_representation::UNREADABLE_LITERAL_INFO,
crate::literal_representation::UNUSUAL_BYTE_GROUPINGS_INFO,
crate::loops::EMPTY_LOOP_INFO,
crate::loops::EXPLICIT_COUNTER_LOOP_INFO,
crate::loops::EXPLICIT_INTO_ITER_LOOP_INFO,
crate::loops::EXPLICIT_ITER_LOOP_INFO,
crate::loops::FOR_KV_MAP_INFO,
crate::loops::ITER_NEXT_LOOP_INFO,
crate::loops::MANUAL_FIND_INFO,
crate::loops::MANUAL_FLATTEN_INFO,
crate::loops::MANUAL_MEMCPY_INFO,
crate::loops::MISSING_SPIN_LOOP_INFO,
crate::loops::MUT_RANGE_BOUND_INFO,
crate::loops::NEEDLESS_RANGE_LOOP_INFO,
crate::loops::NEVER_LOOP_INFO,
crate::loops::SAME_ITEM_PUSH_INFO,
crate::loops::SINGLE_ELEMENT_LOOP_INFO,
crate::loops::WHILE_IMMUTABLE_CONDITION_INFO,
crate::loops::WHILE_LET_LOOP_INFO,
crate::loops::WHILE_LET_ON_ITERATOR_INFO,
crate::macro_use::MACRO_USE_IMPORTS_INFO,
crate::main_recursion::MAIN_RECURSION_INFO,
crate::manual_assert::MANUAL_ASSERT_INFO,
crate::manual_async_fn::MANUAL_ASYNC_FN_INFO,
crate::manual_bits::MANUAL_BITS_INFO,
crate::manual_clamp::MANUAL_CLAMP_INFO,
crate::manual_is_ascii_check::MANUAL_IS_ASCII_CHECK_INFO,
crate::manual_let_else::MANUAL_LET_ELSE_INFO,
crate::manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE_INFO,
crate::manual_rem_euclid::MANUAL_REM_EUCLID_INFO,
crate::manual_retain::MANUAL_RETAIN_INFO,
crate::manual_string_new::MANUAL_STRING_NEW_INFO,
crate::manual_strip::MANUAL_STRIP_INFO,
crate::map_unit_fn::OPTION_MAP_UNIT_FN_INFO,
crate::map_unit_fn::RESULT_MAP_UNIT_FN_INFO,
crate::match_result_ok::MATCH_RESULT_OK_INFO,
crate::matches::COLLAPSIBLE_MATCH_INFO,
crate::matches::INFALLIBLE_DESTRUCTURING_MATCH_INFO,
crate::matches::MANUAL_FILTER_INFO,
crate::matches::MANUAL_MAP_INFO,
crate::matches::MANUAL_UNWRAP_OR_INFO,
crate::matches::MATCH_AS_REF_INFO,
crate::matches::MATCH_BOOL_INFO,
crate::matches::MATCH_LIKE_MATCHES_MACRO_INFO,
crate::matches::MATCH_ON_VEC_ITEMS_INFO,
crate::matches::MATCH_OVERLAPPING_ARM_INFO,
crate::matches::MATCH_REF_PATS_INFO,
crate::matches::MATCH_SAME_ARMS_INFO,
crate::matches::MATCH_SINGLE_BINDING_INFO,
crate::matches::MATCH_STR_CASE_MISMATCH_INFO,
crate::matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS_INFO,
crate::matches::MATCH_WILD_ERR_ARM_INFO,
crate::matches::NEEDLESS_MATCH_INFO,
crate::matches::REDUNDANT_PATTERN_MATCHING_INFO,
crate::matches::REST_PAT_IN_FULLY_BOUND_STRUCTS_INFO,
crate::matches::SIGNIFICANT_DROP_IN_SCRUTINEE_INFO,
crate::matches::SINGLE_MATCH_INFO,
crate::matches::SINGLE_MATCH_ELSE_INFO,
crate::matches::TRY_ERR_INFO,
crate::matches::WILDCARD_ENUM_MATCH_ARM_INFO,
crate::matches::WILDCARD_IN_OR_PATTERNS_INFO,
crate::mem_forget::MEM_FORGET_INFO,
crate::mem_replace::MEM_REPLACE_OPTION_WITH_NONE_INFO,
crate::mem_replace::MEM_REPLACE_WITH_DEFAULT_INFO,
crate::mem_replace::MEM_REPLACE_WITH_UNINIT_INFO,
crate::methods::BIND_INSTEAD_OF_MAP_INFO,
crate::methods::BYTES_COUNT_TO_LEN_INFO,
crate::methods::BYTES_NTH_INFO,
crate::methods::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS_INFO,
crate::methods::CHARS_LAST_CMP_INFO,
crate::methods::CHARS_NEXT_CMP_INFO,
crate::methods::CLONED_INSTEAD_OF_COPIED_INFO,
crate::methods::CLONE_DOUBLE_REF_INFO,
crate::methods::CLONE_ON_COPY_INFO,
crate::methods::CLONE_ON_REF_PTR_INFO,
crate::methods::COLLAPSIBLE_STR_REPLACE_INFO,
crate::methods::ERR_EXPECT_INFO,
crate::methods::EXPECT_FUN_CALL_INFO,
crate::methods::EXPECT_USED_INFO,
crate::methods::EXTEND_WITH_DRAIN_INFO,
crate::methods::FILETYPE_IS_FILE_INFO,
crate::methods::FILTER_MAP_IDENTITY_INFO,
crate::methods::FILTER_MAP_NEXT_INFO,
crate::methods::FILTER_NEXT_INFO,
crate::methods::FLAT_MAP_IDENTITY_INFO,
crate::methods::FLAT_MAP_OPTION_INFO,
crate::methods::FROM_ITER_INSTEAD_OF_COLLECT_INFO,
crate::methods::GET_FIRST_INFO,
crate::methods::GET_LAST_WITH_LEN_INFO,
crate::methods::GET_UNWRAP_INFO,
crate::methods::IMPLICIT_CLONE_INFO,
crate::methods::INEFFICIENT_TO_STRING_INFO,
crate::methods::INSPECT_FOR_EACH_INFO,
crate::methods::INTO_ITER_ON_REF_INFO,
crate::methods::IS_DIGIT_ASCII_RADIX_INFO,
crate::methods::ITERATOR_STEP_BY_ZERO_INFO,
crate::methods::ITER_CLONED_COLLECT_INFO,
crate::methods::ITER_COUNT_INFO,
crate::methods::ITER_KV_MAP_INFO,
crate::methods::ITER_NEXT_SLICE_INFO,
crate::methods::ITER_NTH_INFO,
crate::methods::ITER_NTH_ZERO_INFO,
crate::methods::ITER_ON_EMPTY_COLLECTIONS_INFO,
crate::methods::ITER_ON_SINGLE_ITEMS_INFO,
crate::methods::ITER_OVEREAGER_CLONED_INFO,
crate::methods::ITER_SKIP_NEXT_INFO,
crate::methods::ITER_WITH_DRAIN_INFO,
crate::methods::MANUAL_FILTER_MAP_INFO,
crate::methods::MANUAL_FIND_MAP_INFO,
crate::methods::MANUAL_OK_OR_INFO,
crate::methods::MANUAL_SATURATING_ARITHMETIC_INFO,
crate::methods::MANUAL_SPLIT_ONCE_INFO,
crate::methods::MANUAL_STR_REPEAT_INFO,
crate::methods::MAP_CLONE_INFO,
crate::methods::MAP_COLLECT_RESULT_UNIT_INFO,
crate::methods::MAP_ERR_IGNORE_INFO,
crate::methods::MAP_FLATTEN_INFO,
crate::methods::MAP_IDENTITY_INFO,
crate::methods::MAP_UNWRAP_OR_INFO,
crate::methods::MUT_MUTEX_LOCK_INFO,
crate::methods::NAIVE_BYTECOUNT_INFO,
crate::methods::NEEDLESS_COLLECT_INFO,
crate::methods::NEEDLESS_OPTION_AS_DEREF_INFO,
crate::methods::NEEDLESS_OPTION_TAKE_INFO,
crate::methods::NEEDLESS_SPLITN_INFO,
crate::methods::NEW_RET_NO_SELF_INFO,
crate::methods::NONSENSICAL_OPEN_OPTIONS_INFO,
crate::methods::NO_EFFECT_REPLACE_INFO,
crate::methods::OBFUSCATED_IF_ELSE_INFO,
crate::methods::OK_EXPECT_INFO,
crate::methods::OPTION_AS_REF_DEREF_INFO,
crate::methods::OPTION_FILTER_MAP_INFO,
crate::methods::OPTION_MAP_OR_NONE_INFO,
crate::methods::OR_FUN_CALL_INFO,
crate::methods::OR_THEN_UNWRAP_INFO,
crate::methods::PATH_BUF_PUSH_OVERWRITE_INFO,
crate::methods::RANGE_ZIP_WITH_LEN_INFO,
crate::methods::REPEAT_ONCE_INFO,
crate::methods::RESULT_MAP_OR_INTO_OPTION_INFO,
crate::methods::SEARCH_IS_SOME_INFO,
crate::methods::SEEK_FROM_CURRENT_INFO,
crate::methods::SEEK_TO_START_INSTEAD_OF_REWIND_INFO,
crate::methods::SHOULD_IMPLEMENT_TRAIT_INFO,
crate::methods::SINGLE_CHAR_ADD_STR_INFO,
crate::methods::SINGLE_CHAR_PATTERN_INFO,
crate::methods::SKIP_WHILE_NEXT_INFO,
crate::methods::STABLE_SORT_PRIMITIVE_INFO,
crate::methods::STRING_EXTEND_CHARS_INFO,
crate::methods::SUSPICIOUS_MAP_INFO,
crate::methods::SUSPICIOUS_SPLITN_INFO,
crate::methods::SUSPICIOUS_TO_OWNED_INFO,
crate::methods::UNINIT_ASSUMED_INIT_INFO,
crate::methods::UNIT_HASH_INFO,
crate::methods::UNNECESSARY_FILTER_MAP_INFO,
crate::methods::UNNECESSARY_FIND_MAP_INFO,
crate::methods::UNNECESSARY_FOLD_INFO,
crate::methods::UNNECESSARY_JOIN_INFO,
crate::methods::UNNECESSARY_LAZY_EVALUATIONS_INFO,
crate::methods::UNNECESSARY_SORT_BY_INFO,
crate::methods::UNNECESSARY_TO_OWNED_INFO,
crate::methods::UNWRAP_OR_ELSE_DEFAULT_INFO,
crate::methods::UNWRAP_USED_INFO,
crate::methods::USELESS_ASREF_INFO,
crate::methods::VEC_RESIZE_TO_ZERO_INFO,
crate::methods::VERBOSE_FILE_READS_INFO,
crate::methods::WRONG_SELF_CONVENTION_INFO,
crate::methods::ZST_OFFSET_INFO,
crate::minmax::MIN_MAX_INFO,
crate::misc::SHORT_CIRCUIT_STATEMENT_INFO,
crate::misc::TOPLEVEL_REF_ARG_INFO,
crate::misc::USED_UNDERSCORE_BINDING_INFO,
crate::misc::ZERO_PTR_INFO,
crate::misc_early::BUILTIN_TYPE_SHADOW_INFO,
crate::misc_early::DOUBLE_NEG_INFO,
crate::misc_early::DUPLICATE_UNDERSCORE_ARGUMENT_INFO,
crate::misc_early::MIXED_CASE_HEX_LITERALS_INFO,
crate::misc_early::REDUNDANT_PATTERN_INFO,
crate::misc_early::SEPARATED_LITERAL_SUFFIX_INFO,
crate::misc_early::UNNEEDED_FIELD_PATTERN_INFO,
crate::misc_early::UNNEEDED_WILDCARD_PATTERN_INFO,
crate::misc_early::UNSEPARATED_LITERAL_SUFFIX_INFO,
crate::misc_early::ZERO_PREFIXED_LITERAL_INFO,
crate::mismatching_type_param_order::MISMATCHING_TYPE_PARAM_ORDER_INFO,
crate::missing_const_for_fn::MISSING_CONST_FOR_FN_INFO,
crate::missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS_INFO,
crate::missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES_INFO,
crate::missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS_INFO,
crate::missing_trait_methods::MISSING_TRAIT_METHODS_INFO,
crate::mixed_read_write_in_expression::DIVERGING_SUB_EXPRESSION_INFO,
crate::mixed_read_write_in_expression::MIXED_READ_WRITE_IN_EXPRESSION_INFO,
crate::module_style::MOD_MODULE_FILES_INFO,
crate::module_style::SELF_NAMED_MODULE_FILES_INFO,
crate::multi_assignments::MULTI_ASSIGNMENTS_INFO,
crate::mut_key::MUTABLE_KEY_TYPE_INFO,
crate::mut_mut::MUT_MUT_INFO,
crate::mut_reference::UNNECESSARY_MUT_PASSED_INFO,
crate::mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL_INFO,
crate::mutex_atomic::MUTEX_ATOMIC_INFO,
crate::mutex_atomic::MUTEX_INTEGER_INFO,
crate::needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE_INFO,
crate::needless_bool::BOOL_COMPARISON_INFO,
crate::needless_bool::NEEDLESS_BOOL_INFO,
crate::needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE_INFO,
crate::needless_continue::NEEDLESS_CONTINUE_INFO,
crate::needless_for_each::NEEDLESS_FOR_EACH_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_value::NEEDLESS_PASS_BY_VALUE_INFO,
crate::needless_question_mark::NEEDLESS_QUESTION_MARK_INFO,
crate::needless_update::NEEDLESS_UPDATE_INFO,
crate::neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD_INFO,
crate::neg_multiply::NEG_MULTIPLY_INFO,
crate::new_without_default::NEW_WITHOUT_DEFAULT_INFO,
crate::no_effect::NO_EFFECT_INFO,
crate::no_effect::NO_EFFECT_UNDERSCORE_BINDING_INFO,
crate::no_effect::UNNECESSARY_OPERATION_INFO,
crate::non_copy_const::BORROW_INTERIOR_MUTABLE_CONST_INFO,
crate::non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST_INFO,
crate::non_expressive_names::JUST_UNDERSCORES_AND_DIGITS_INFO,
crate::non_expressive_names::MANY_SINGLE_CHAR_NAMES_INFO,
crate::non_expressive_names::SIMILAR_NAMES_INFO,
crate::non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS_INFO,
crate::non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY_INFO,
crate::nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES_INFO,
crate::octal_escapes::OCTAL_ESCAPES_INFO,
crate::only_used_in_recursion::ONLY_USED_IN_RECURSION_INFO,
crate::operators::ABSURD_EXTREME_COMPARISONS_INFO,
crate::operators::ARITHMETIC_SIDE_EFFECTS_INFO,
crate::operators::ASSIGN_OP_PATTERN_INFO,
crate::operators::BAD_BIT_MASK_INFO,
crate::operators::CMP_NAN_INFO,
crate::operators::CMP_OWNED_INFO,
crate::operators::DOUBLE_COMPARISONS_INFO,
crate::operators::DURATION_SUBSEC_INFO,
crate::operators::EQ_OP_INFO,
crate::operators::ERASING_OP_INFO,
crate::operators::FLOAT_ARITHMETIC_INFO,
crate::operators::FLOAT_CMP_INFO,
crate::operators::FLOAT_CMP_CONST_INFO,
crate::operators::FLOAT_EQUALITY_WITHOUT_ABS_INFO,
crate::operators::IDENTITY_OP_INFO,
crate::operators::INEFFECTIVE_BIT_MASK_INFO,
crate::operators::INTEGER_ARITHMETIC_INFO,
crate::operators::INTEGER_DIVISION_INFO,
crate::operators::MISREFACTORED_ASSIGN_OP_INFO,
crate::operators::MODULO_ARITHMETIC_INFO,
crate::operators::MODULO_ONE_INFO,
crate::operators::NEEDLESS_BITWISE_BOOL_INFO,
crate::operators::OP_REF_INFO,
crate::operators::PTR_EQ_INFO,
crate::operators::SELF_ASSIGNMENT_INFO,
crate::operators::VERBOSE_BIT_MASK_INFO,
crate::option_env_unwrap::OPTION_ENV_UNWRAP_INFO,
crate::option_if_let_else::OPTION_IF_LET_ELSE_INFO,
crate::overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL_INFO,
crate::panic_in_result_fn::PANIC_IN_RESULT_FN_INFO,
crate::panic_unimplemented::PANIC_INFO,
crate::panic_unimplemented::TODO_INFO,
crate::panic_unimplemented::UNIMPLEMENTED_INFO,
crate::panic_unimplemented::UNREACHABLE_INFO,
crate::partial_pub_fields::PARTIAL_PUB_FIELDS_INFO,
crate::partialeq_ne_impl::PARTIALEQ_NE_IMPL_INFO,
crate::partialeq_to_none::PARTIALEQ_TO_NONE_INFO,
crate::pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE_INFO,
crate::pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF_INFO,
crate::pattern_type_mismatch::PATTERN_TYPE_MISMATCH_INFO,
crate::precedence::PRECEDENCE_INFO,
crate::ptr::CMP_NULL_INFO,
crate::ptr::INVALID_NULL_PTR_USAGE_INFO,
crate::ptr::MUT_FROM_REF_INFO,
crate::ptr::PTR_ARG_INFO,
crate::ptr_offset_with_cast::PTR_OFFSET_WITH_CAST_INFO,
crate::pub_use::PUB_USE_INFO,
crate::question_mark::QUESTION_MARK_INFO,
crate::ranges::MANUAL_RANGE_CONTAINS_INFO,
crate::ranges::RANGE_MINUS_ONE_INFO,
crate::ranges::RANGE_PLUS_ONE_INFO,
crate::ranges::REVERSED_EMPTY_RANGES_INFO,
crate::rc_clone_in_vec_init::RC_CLONE_IN_VEC_INIT_INFO,
crate::read_zero_byte_vec::READ_ZERO_BYTE_VEC_INFO,
crate::redundant_clone::REDUNDANT_CLONE_INFO,
crate::redundant_closure_call::REDUNDANT_CLOSURE_CALL_INFO,
crate::redundant_else::REDUNDANT_ELSE_INFO,
crate::redundant_field_names::REDUNDANT_FIELD_NAMES_INFO,
crate::redundant_pub_crate::REDUNDANT_PUB_CRATE_INFO,
crate::redundant_slicing::DEREF_BY_SLICING_INFO,
crate::redundant_slicing::REDUNDANT_SLICING_INFO,
crate::redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES_INFO,
crate::ref_option_ref::REF_OPTION_REF_INFO,
crate::reference::DEREF_ADDROF_INFO,
crate::regex::INVALID_REGEX_INFO,
crate::regex::TRIVIAL_REGEX_INFO,
crate::return_self_not_must_use::RETURN_SELF_NOT_MUST_USE_INFO,
crate::returns::LET_AND_RETURN_INFO,
crate::returns::NEEDLESS_RETURN_INFO,
crate::same_name_method::SAME_NAME_METHOD_INFO,
crate::self_named_constructors::SELF_NAMED_CONSTRUCTORS_INFO,
crate::semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED_INFO,
crate::serde_api::SERDE_API_MISUSE_INFO,
crate::shadow::SHADOW_REUSE_INFO,
crate::shadow::SHADOW_SAME_INFO,
crate::shadow::SHADOW_UNRELATED_INFO,
crate::single_char_lifetime_names::SINGLE_CHAR_LIFETIME_NAMES_INFO,
crate::single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS_INFO,
crate::size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT_INFO,
crate::slow_vector_initialization::SLOW_VECTOR_INITIALIZATION_INFO,
crate::std_instead_of_core::ALLOC_INSTEAD_OF_CORE_INFO,
crate::std_instead_of_core::STD_INSTEAD_OF_ALLOC_INFO,
crate::std_instead_of_core::STD_INSTEAD_OF_CORE_INFO,
crate::strings::STRING_ADD_INFO,
crate::strings::STRING_ADD_ASSIGN_INFO,
crate::strings::STRING_FROM_UTF8_AS_BYTES_INFO,
crate::strings::STRING_LIT_AS_BYTES_INFO,
crate::strings::STRING_SLICE_INFO,
crate::strings::STRING_TO_STRING_INFO,
crate::strings::STR_TO_STRING_INFO,
crate::strings::TRIM_SPLIT_WHITESPACE_INFO,
crate::strlen_on_c_strings::STRLEN_ON_C_STRINGS_INFO,
crate::suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS_INFO,
crate::suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL_INFO,
crate::suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL_INFO,
crate::suspicious_xor_used_as_pow::SUSPICIOUS_XOR_USED_AS_POW_INFO,
crate::swap::ALMOST_SWAPPED_INFO,
crate::swap::MANUAL_SWAP_INFO,
crate::swap_ptr_to_ref::SWAP_PTR_TO_REF_INFO,
crate::tabs_in_doc_comments::TABS_IN_DOC_COMMENTS_INFO,
crate::temporary_assignment::TEMPORARY_ASSIGNMENT_INFO,
crate::to_digit_is_some::TO_DIGIT_IS_SOME_INFO,
crate::trailing_empty_array::TRAILING_EMPTY_ARRAY_INFO,
crate::trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS_INFO,
crate::trait_bounds::TYPE_REPETITION_IN_BOUNDS_INFO,
crate::transmute::CROSSPOINTER_TRANSMUTE_INFO,
crate::transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS_INFO,
crate::transmute::TRANSMUTE_BYTES_TO_STR_INFO,
crate::transmute::TRANSMUTE_FLOAT_TO_INT_INFO,
crate::transmute::TRANSMUTE_INT_TO_BOOL_INFO,
crate::transmute::TRANSMUTE_INT_TO_CHAR_INFO,
crate::transmute::TRANSMUTE_INT_TO_FLOAT_INFO,
crate::transmute::TRANSMUTE_NUM_TO_BYTES_INFO,
crate::transmute::TRANSMUTE_PTR_TO_PTR_INFO,
crate::transmute::TRANSMUTE_PTR_TO_REF_INFO,
crate::transmute::TRANSMUTE_UNDEFINED_REPR_INFO,
crate::transmute::TRANSMUTING_NULL_INFO,
crate::transmute::UNSOUND_COLLECTION_TRANSMUTE_INFO,
crate::transmute::USELESS_TRANSMUTE_INFO,
crate::transmute::WRONG_TRANSMUTE_INFO,
crate::types::BORROWED_BOX_INFO,
crate::types::BOX_COLLECTION_INFO,
crate::types::LINKEDLIST_INFO,
crate::types::OPTION_OPTION_INFO,
crate::types::RC_BUFFER_INFO,
crate::types::RC_MUTEX_INFO,
crate::types::REDUNDANT_ALLOCATION_INFO,
crate::types::TYPE_COMPLEXITY_INFO,
crate::types::VEC_BOX_INFO,
crate::undocumented_unsafe_blocks::UNDOCUMENTED_UNSAFE_BLOCKS_INFO,
crate::unicode::INVISIBLE_CHARACTERS_INFO,
crate::unicode::NON_ASCII_LITERAL_INFO,
crate::unicode::UNICODE_NOT_NFC_INFO,
crate::uninit_vec::UNINIT_VEC_INFO,
crate::unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD_INFO,
crate::unit_types::LET_UNIT_VALUE_INFO,
crate::unit_types::UNIT_ARG_INFO,
crate::unit_types::UNIT_CMP_INFO,
crate::unnamed_address::FN_ADDRESS_COMPARISONS_INFO,
crate::unnamed_address::VTABLE_ADDRESS_COMPARISONS_INFO,
crate::unnecessary_owned_empty_strings::UNNECESSARY_OWNED_EMPTY_STRINGS_INFO,
crate::unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS_INFO,
crate::unnecessary_wraps::UNNECESSARY_WRAPS_INFO,
crate::unnested_or_patterns::UNNESTED_OR_PATTERNS_INFO,
crate::unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME_INFO,
crate::unused_async::UNUSED_ASYNC_INFO,
crate::unused_io_amount::UNUSED_IO_AMOUNT_INFO,
crate::unused_peekable::UNUSED_PEEKABLE_INFO,
crate::unused_rounding::UNUSED_ROUNDING_INFO,
crate::unused_self::UNUSED_SELF_INFO,
crate::unused_unit::UNUSED_UNIT_INFO,
crate::unwrap::PANICKING_UNWRAP_INFO,
crate::unwrap::UNNECESSARY_UNWRAP_INFO,
crate::unwrap_in_result::UNWRAP_IN_RESULT_INFO,
crate::upper_case_acronyms::UPPER_CASE_ACRONYMS_INFO,
crate::use_self::USE_SELF_INFO,
crate::useless_conversion::USELESS_CONVERSION_INFO,
crate::vec::USELESS_VEC_INFO,
crate::vec_init_then_push::VEC_INIT_THEN_PUSH_INFO,
crate::wildcard_imports::ENUM_GLOB_USE_INFO,
crate::wildcard_imports::WILDCARD_IMPORTS_INFO,
crate::write::PRINTLN_EMPTY_STRING_INFO,
crate::write::PRINT_LITERAL_INFO,
crate::write::PRINT_STDERR_INFO,
crate::write::PRINT_STDOUT_INFO,
crate::write::PRINT_WITH_NEWLINE_INFO,
crate::write::USE_DEBUG_INFO,
crate::write::WRITELN_EMPTY_STRING_INFO,
crate::write::WRITE_LITERAL_INFO,
crate::write::WRITE_WITH_NEWLINE_INFO,
crate::zero_div_zero::ZERO_DIVIDED_BY_ZERO_INFO,
crate::zero_sized_map_values::ZERO_SIZED_MAP_VALUES_INFO,
];

View file

@ -9,6 +9,7 @@ use clippy_utils::{
};
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::intravisit::{walk_ty, Visitor};
use rustc_hir::{
@ -274,9 +275,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
}
let typeck = cx.typeck_results();
let (kind, sub_expr) = if let Some(x) = try_parse_ref_op(cx.tcx, typeck, expr) {
x
} else {
let Some((kind, sub_expr)) = try_parse_ref_op(cx.tcx, typeck, expr) else {
// The whole chain of reference operations has been seen
if let Some((state, data)) = self.state.take() {
report(cx, expr, state, data);
@ -806,30 +805,39 @@ fn walk_parents<'tcx>(
.position(|arg| arg.hir_id == child_id)
.zip(expr_sig(cx, func))
.and_then(|(i, sig)| {
sig.input_with_hir(i).map(|(hir_ty, ty)| match hir_ty {
// Type inference for closures can depend on how they're called. Only go by the explicit
// types here.
Some(hir_ty) => binding_ty_auto_deref_stability(cx, hir_ty, precedence, ty.bound_vars()),
None => {
if let ty::Param(param_ty) = ty.skip_binder().kind() {
needless_borrow_impl_arg_position(
cx,
possible_borrowers,
parent,
i,
*param_ty,
e,
precedence,
msrv,
)
} else {
ty_auto_deref_stability(cx, cx.tcx.erase_late_bound_regions(ty), precedence)
.position_for_arg()
}
},
sig.input_with_hir(i).map(|(hir_ty, ty)| {
match hir_ty {
// Type inference for closures can depend on how they're called. Only go by the explicit
// types here.
Some(hir_ty) => {
binding_ty_auto_deref_stability(cx, hir_ty, precedence, ty.bound_vars())
},
None => {
// `e.hir_id == child_id` for https://github.com/rust-lang/rust-clippy/issues/9739
// `!call_is_qualified(func)` for https://github.com/rust-lang/rust-clippy/issues/9782
if e.hir_id == child_id
&& !call_is_qualified(func)
&& let ty::Param(param_ty) = ty.skip_binder().kind()
{
needless_borrow_impl_arg_position(
cx,
possible_borrowers,
parent,
i,
*param_ty,
e,
precedence,
msrv,
)
} else {
ty_auto_deref_stability(cx, cx.tcx.erase_late_bound_regions(ty), precedence)
.position_for_arg()
}
},
}
})
}),
ExprKind::MethodCall(_, receiver, args, _) => {
ExprKind::MethodCall(method, receiver, args, _) => {
let id = cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap();
if receiver.hir_id == child_id {
// Check for calls to trait methods where the trait is implemented on a reference.
@ -863,7 +871,9 @@ fn walk_parents<'tcx>(
}
args.iter().position(|arg| arg.hir_id == child_id).map(|i| {
let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i + 1];
if let ty::Param(param_ty) = ty.kind() {
// `e.hir_id == child_id` for https://github.com/rust-lang/rust-clippy/issues/9739
// `method.args.is_none()` for https://github.com/rust-lang/rust-clippy/issues/9782
if e.hir_id == child_id && method.args.is_none() && let ty::Param(param_ty) = ty.kind() {
needless_borrow_impl_arg_position(
cx,
possible_borrowers,
@ -1041,13 +1051,25 @@ fn ty_contains_infer(ty: &hir::Ty<'_>) -> bool {
v.0
}
fn call_is_qualified(expr: &Expr<'_>) -> bool {
if let ExprKind::Path(path) = &expr.kind {
match path {
QPath::Resolved(_, path) => path.segments.last().map_or(false, |segment| segment.args.is_some()),
QPath::TypeRelative(_, segment) => segment.args.is_some(),
QPath::LangItem(..) => false,
}
} else {
false
}
}
// Checks whether:
// * child is an expression of the form `&e` in an argument position requiring an `impl Trait`
// * `e`'s type implements `Trait` and is copyable
// If the conditions are met, returns `Some(Position::ImplArg(..))`; otherwise, returns `None`.
// The "is copyable" condition is to avoid the case where removing the `&` means `e` would have to
// be moved, but it cannot be.
#[expect(clippy::too_many_arguments)]
#[expect(clippy::too_many_arguments, clippy::too_many_lines)]
fn needless_borrow_impl_arg_position<'tcx>(
cx: &LateContext<'tcx>,
possible_borrowers: &mut Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>,
@ -1109,6 +1131,16 @@ fn needless_borrow_impl_arg_position<'tcx>(
return Position::Other(precedence);
}
// See:
// - https://github.com/rust-lang/rust-clippy/pull/9674#issuecomment-1289294201
// - https://github.com/rust-lang/rust-clippy/pull/9674#issuecomment-1292225232
if projection_predicates
.iter()
.any(|projection_predicate| is_mixed_projection_predicate(cx, callee_def_id, projection_predicate))
{
return Position::Other(precedence);
}
// `substs_with_referent_ty` can be constructed outside of `check_referent` because the same
// elements are modified each time `check_referent` is called.
let mut substs_with_referent_ty = substs_with_expr_ty.to_vec();
@ -1188,6 +1220,37 @@ fn has_ref_mut_self_method(cx: &LateContext<'_>, trait_def_id: DefId) -> bool {
})
}
fn is_mixed_projection_predicate<'tcx>(
cx: &LateContext<'tcx>,
callee_def_id: DefId,
projection_predicate: &ProjectionPredicate<'tcx>,
) -> bool {
let generics = cx.tcx.generics_of(callee_def_id);
// The predicate requires the projected type to equal a type parameter from the parent context.
if let Some(term_ty) = projection_predicate.term.ty()
&& let ty::Param(term_param_ty) = term_ty.kind()
&& (term_param_ty.index as usize) < generics.parent_count
{
// The inner-most self type is a type parameter from the current function.
let mut projection_ty = projection_predicate.projection_ty;
loop {
match projection_ty.self_ty().kind() {
ty::Projection(inner_projection_ty) => {
projection_ty = *inner_projection_ty;
}
ty::Param(param_ty) => {
return (param_ty.index as usize) >= generics.parent_count;
}
_ => {
return false;
}
}
}
} else {
false
}
}
fn referent_used_exactly_once<'tcx>(
cx: &LateContext<'tcx>,
possible_borrowers: &mut Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>,
@ -1199,6 +1262,8 @@ fn referent_used_exactly_once<'tcx>(
&& let Some(statement) = mir.basic_blocks[location.block].statements.get(location.statement_index)
&& let StatementKind::Assign(box (_, Rvalue::Ref(_, _, place))) = statement.kind
&& !place.has_deref()
// Ensure not in a loop (https://github.com/rust-lang/rust-clippy/issues/9710)
&& TriColorDepthFirstSearch::new(&mir.basic_blocks).run_from(location.block, &mut CycleDetector).is_none()
{
let body_owner_local_def_id = cx.tcx.hir().enclosing_body_owner(reference.hir_id);
if possible_borrowers
@ -1316,6 +1381,7 @@ fn ty_auto_deref_stability<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, precedenc
continue;
},
ty::Param(_) => TyPosition::new_deref_stable_for_result(precedence, ty),
ty::Projection(_) if ty.has_non_region_param() => TyPosition::new_deref_stable_for_result(precedence, ty),
ty::Infer(_) | ty::Error(_) | ty::Bound(..) | ty::Opaque(..) | ty::Placeholder(_) | ty::Dynamic(..) => {
Position::ReborrowStable(precedence).into()
},
@ -1342,11 +1408,9 @@ fn ty_auto_deref_stability<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, precedenc
| ty::Closure(..)
| ty::Never
| ty::Tuple(_)
| ty::Projection(_) => Position::DerefStable(
precedence,
ty.is_sized(cx.tcx, cx.param_env.without_caller_bounds()),
)
.into(),
| ty::Projection(_) => {
Position::DerefStable(precedence, ty.is_sized(cx.tcx, cx.param_env.without_caller_bounds())).into()
},
};
}
}

View file

@ -1,7 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::macros::macro_backtrace;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir::def::{Namespace, Res};
use rustc_hir::def_id::DefIdMap;
use rustc_hir::{Expr, ForeignItem, HirId, ImplItem, Item, Pat, Path, Stmt, TraitItem, Ty};
use rustc_lint::{LateContext, LateLintPass};
@ -89,7 +88,7 @@ impl DisallowedMacros {
&format!("use of a disallowed macro `{}`", conf.path()),
|diag| {
if let Some(reason) = conf.reason() {
diag.note(&format!("{reason} (from clippy.toml)"));
diag.note(reason);
}
},
);
@ -104,7 +103,7 @@ impl LateLintPass<'_> for DisallowedMacros {
fn check_crate(&mut self, cx: &LateContext<'_>) {
for (index, conf) in self.conf_disallowed.iter().enumerate() {
let segs: Vec<_> = conf.path().split("::").collect();
if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &segs, Some(Namespace::MacroNS)) {
for id in clippy_utils::def_path_def_ids(cx, &segs) {
self.disallowed.insert(id, index);
}
}

View file

@ -1,7 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::{fn_def_id, get_parent_expr, path_def_id};
use rustc_hir::def::{Namespace, Res};
use rustc_hir::def_id::DefIdMap;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
@ -79,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods {
fn check_crate(&mut self, cx: &LateContext<'_>) {
for (index, conf) in self.conf_disallowed.iter().enumerate() {
let segs: Vec<_> = conf.path().split("::").collect();
if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &segs, Some(Namespace::ValueNS)) {
for id in clippy_utils::def_path_def_ids(cx, &segs) {
self.disallowed.insert(id, index);
}
}
@ -104,7 +103,7 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods {
let msg = format!("use of a disallowed method `{}`", conf.path());
span_lint_and_then(cx, DISALLOWED_METHODS, expr.span, &msg, |diag| {
if let Some(reason) = conf.reason() {
diag.note(&format!("{reason} (from clippy.toml)"));
diag.note(reason);
}
});
}

View file

@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_then;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def::{Namespace, Res};
use rustc_hir::def::Res;
use rustc_hir::def_id::DefId;
use rustc_hir::{Item, ItemKind, PolyTraitRef, PrimTy, Ty, TyKind, UseKind};
use rustc_lint::{LateContext, LateLintPass};
@ -53,8 +53,8 @@ declare_clippy_lint! {
#[derive(Clone, Debug)]
pub struct DisallowedTypes {
conf_disallowed: Vec<conf::DisallowedPath>,
def_ids: FxHashMap<DefId, Option<String>>,
prim_tys: FxHashMap<PrimTy, Option<String>>,
def_ids: FxHashMap<DefId, usize>,
prim_tys: FxHashMap<PrimTy, usize>,
}
impl DisallowedTypes {
@ -69,13 +69,13 @@ impl DisallowedTypes {
fn check_res_emit(&self, cx: &LateContext<'_>, res: &Res, span: Span) {
match res {
Res::Def(_, did) => {
if let Some(reason) = self.def_ids.get(did) {
emit(cx, &cx.tcx.def_path_str(*did), span, reason.as_deref());
if let Some(&index) = self.def_ids.get(did) {
emit(cx, &cx.tcx.def_path_str(*did), span, &self.conf_disallowed[index]);
}
},
Res::PrimTy(prim) => {
if let Some(reason) = self.prim_tys.get(prim) {
emit(cx, prim.name_str(), span, reason.as_deref());
if let Some(&index) = self.prim_tys.get(prim) {
emit(cx, prim.name_str(), span, &self.conf_disallowed[index]);
}
},
_ => {},
@ -87,17 +87,19 @@ impl_lint_pass!(DisallowedTypes => [DISALLOWED_TYPES]);
impl<'tcx> LateLintPass<'tcx> for DisallowedTypes {
fn check_crate(&mut self, cx: &LateContext<'_>) {
for conf in &self.conf_disallowed {
for (index, conf) in self.conf_disallowed.iter().enumerate() {
let segs: Vec<_> = conf.path().split("::").collect();
let reason = conf.reason().map(|reason| format!("{reason} (from clippy.toml)"));
match clippy_utils::def_path_res(cx, &segs, Some(Namespace::TypeNS)) {
Res::Def(_, id) => {
self.def_ids.insert(id, reason);
},
Res::PrimTy(ty) => {
self.prim_tys.insert(ty, reason);
},
_ => {},
for res in clippy_utils::def_path_res(cx, &segs) {
match res {
Res::Def(_, id) => {
self.def_ids.insert(id, index);
},
Res::PrimTy(ty) => {
self.prim_tys.insert(ty, index);
},
_ => {},
}
}
}
}
@ -119,14 +121,14 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedTypes {
}
}
fn emit(cx: &LateContext<'_>, name: &str, span: Span, reason: Option<&str>) {
fn emit(cx: &LateContext<'_>, name: &str, span: Span, conf: &conf::DisallowedPath) {
span_lint_and_then(
cx,
DISALLOWED_TYPES,
span,
&format!("`{name}` is not allowed according to config"),
|diag| {
if let Some(reason) = reason {
if let Some(reason) = conf.reason() {
diag.note(reason);
}
},

View file

@ -11,7 +11,7 @@ use rustc_ast::token::CommentKind;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::sync::Lrc;
use rustc_errors::emitter::EmitterWriter;
use rustc_errors::{Applicability, Handler, MultiSpan, SuggestionStyle};
use rustc_errors::{Applicability, Handler, SuggestionStyle};
use rustc_hir as hir;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{AnonConst, Expr};
@ -221,6 +221,42 @@ declare_clippy_lint! {
"possible typo for an intra-doc link"
}
declare_clippy_lint! {
/// ### What it does
/// Checks for the doc comments of publicly visible
/// safe functions and traits and warns if there is a `# Safety` section.
///
/// ### Why is this bad?
/// Safe functions and traits are safe to implement and therefore do not
/// need to describe safety preconditions that users are required to uphold.
///
/// ### Examples
/// ```rust
///# type Universe = ();
/// /// # Safety
/// ///
/// /// This function should not be called before the horsemen are ready.
/// pub fn start_apocalypse_but_safely(u: &mut Universe) {
/// unimplemented!();
/// }
/// ```
///
/// The function is safe, so there shouldn't be any preconditions
/// that have to be explained for safety reasons.
///
/// ```rust
///# type Universe = ();
/// /// This function should really be documented
/// pub fn start_apocalypse(u: &mut Universe) {
/// unimplemented!();
/// }
/// ```
#[clippy::version = "1.66.0"]
pub UNNECESSARY_SAFETY_DOC,
style,
"`pub fn` or `pub trait` with `# Safety` docs"
}
#[expect(clippy::module_name_repetitions)]
#[derive(Clone)]
pub struct DocMarkdown {
@ -243,7 +279,8 @@ impl_lint_pass!(DocMarkdown => [
MISSING_SAFETY_DOC,
MISSING_ERRORS_DOC,
MISSING_PANICS_DOC,
NEEDLESS_DOCTEST_MAIN
NEEDLESS_DOCTEST_MAIN,
UNNECESSARY_SAFETY_DOC,
]);
impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
@ -254,7 +291,7 @@ 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 headers = check_attrs(cx, &self.valid_idents, attrs);
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)) {
@ -265,29 +302,26 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
panic_span: None,
};
fpu.visit_expr(body.value);
lint_for_missing_headers(
cx,
item.owner_id.def_id,
item.span,
sig,
headers,
Some(body_id),
fpu.panic_span,
);
lint_for_missing_headers(cx, item.owner_id.def_id, sig, headers, Some(body_id), fpu.panic_span);
}
},
hir::ItemKind::Impl(impl_) => {
self.in_trait_impl = impl_.of_trait.is_some();
},
hir::ItemKind::Trait(_, unsafety, ..) => {
if !headers.safety && unsafety == hir::Unsafety::Unsafe {
span_lint(
cx,
MISSING_SAFETY_DOC,
item.span,
"docs for unsafe trait missing `# Safety` section",
);
}
hir::ItemKind::Trait(_, unsafety, ..) => match (headers.safety, unsafety) {
(false, hir::Unsafety::Unsafe) => span_lint(
cx,
MISSING_SAFETY_DOC,
cx.tcx.def_span(item.owner_id),
"docs for unsafe trait missing `# Safety` section",
),
(true, hir::Unsafety::Normal) => span_lint(
cx,
UNNECESSARY_SAFETY_DOC,
cx.tcx.def_span(item.owner_id),
"docs for safe trait have unnecessary `# Safety` section",
),
_ => (),
},
_ => (),
}
@ -301,17 +335,17 @@ 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 headers = check_attrs(cx, &self.valid_idents, attrs);
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.def_id, item.span, sig, headers, None, None);
lint_for_missing_headers(cx, item.owner_id.def_id, sig, headers, None, None);
}
}
}
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) {
let attrs = cx.tcx.hir().attrs(item.hir_id());
let headers = check_attrs(cx, &self.valid_idents, attrs);
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;
}
@ -323,23 +357,14 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
panic_span: None,
};
fpu.visit_expr(body.value);
lint_for_missing_headers(
cx,
item.owner_id.def_id,
item.span,
sig,
headers,
Some(body_id),
fpu.panic_span,
);
lint_for_missing_headers(cx, item.owner_id.def_id, sig, headers, Some(body_id), fpu.panic_span);
}
}
}
fn lint_for_missing_headers<'tcx>(
cx: &LateContext<'tcx>,
fn lint_for_missing_headers(
cx: &LateContext<'_>,
def_id: LocalDefId,
span: impl Into<MultiSpan> + Copy,
sig: &hir::FnSig<'_>,
headers: DocHeaders,
body_id: Option<hir::BodyId>,
@ -359,13 +384,21 @@ fn lint_for_missing_headers<'tcx>(
return;
}
if !headers.safety && sig.header.unsafety == hir::Unsafety::Unsafe {
span_lint(
let span = cx.tcx.def_span(def_id);
match (headers.safety, sig.header.unsafety) {
(false, hir::Unsafety::Unsafe) => span_lint(
cx,
MISSING_SAFETY_DOC,
span,
"unsafe function's docs miss `# Safety` section",
);
),
(true, hir::Unsafety::Normal) => span_lint(
cx,
UNNECESSARY_SAFETY_DOC,
span,
"safe function's docs have unnecessary `# Safety` section",
),
_ => (),
}
if !headers.panics && panic_span.is_some() {
span_lint_and_note(
@ -467,7 +500,7 @@ struct DocHeaders {
panics: bool,
}
fn check_attrs<'a>(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &'a [Attribute]) -> DocHeaders {
fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[Attribute]) -> Option<DocHeaders> {
use pulldown_cmark::{BrokenLink, CowStr, Options};
/// We don't want the parser to choke on intra doc links. Since we don't
/// actually care about rendering them, just pretend that all broken links are
@ -488,11 +521,7 @@ fn check_attrs<'a>(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs
} else if attr.has_name(sym::doc) {
// ignore mix of sugared and non-sugared doc
// don't trigger the safety or errors check
return DocHeaders {
safety: true,
errors: true,
panics: true,
};
return None;
}
}
@ -504,7 +533,7 @@ fn check_attrs<'a>(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs
}
if doc.is_empty() {
return DocHeaders::default();
return Some(DocHeaders::default());
}
let mut cb = fake_broken_link_callback;
@ -527,7 +556,7 @@ fn check_attrs<'a>(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs
(previous, current) => Err(((previous, previous_range), (current, current_range))),
}
});
check_doc(cx, valid_idents, events, &spans)
Some(check_doc(cx, valid_idents, events, &spans))
}
const RUST_CODE: &[&str] = &["rust", "no_run", "should_panic", "compile_fail"];

View file

@ -250,7 +250,7 @@ impl LateLintPass<'_> for EnumVariantNames {
let item_name = item.ident.name.as_str();
let item_camel = to_camel_case(item_name);
if !item.span.from_expansion() && is_present_in_source(cx, item.span) {
if let Some(&(ref mod_name, ref mod_camel)) = self.modules.last() {
if let Some((mod_name, mod_camel)) = self.modules.last() {
// constants don't have surrounding modules
if !mod_camel.is_empty() {
if mod_name == &item.ident.name {

View file

@ -1,7 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_context;
use clippy_utils::ty::implements_trait;
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, Pat, PatKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
@ -67,16 +66,14 @@ fn is_structural_partial_eq<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: T
impl<'tcx> LateLintPass<'tcx> for PatternEquality {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
if_chain! {
if !in_external_macro(cx.sess(), expr.span);
if let ExprKind::Let(let_expr) = expr.kind;
if unary_pattern(let_expr.pat);
if !in_external_macro(cx.sess(), expr.span)
&& let ExprKind::Let(let_expr) = expr.kind
&& unary_pattern(let_expr.pat) {
let exp_ty = cx.typeck_results().expr_ty(let_expr.init);
let pat_ty = cx.typeck_results().pat_ty(let_expr.pat);
if is_structural_partial_eq(cx, exp_ty, pat_ty);
then {
let mut applicability = Applicability::MachineApplicable;
let mut applicability = Applicability::MachineApplicable;
if is_structural_partial_eq(cx, exp_ty, pat_ty) {
let pat_str = match let_expr.pat.kind {
PatKind::Struct(..) => format!(
"({})",
@ -96,6 +93,20 @@ impl<'tcx> LateLintPass<'tcx> for PatternEquality {
),
applicability,
);
} else {
span_lint_and_sugg(
cx,
EQUATABLE_IF_LET,
expr.span,
"this pattern matching can be expressed using `matches!`",
"try",
format!(
"matches!({}, {})",
snippet_with_context(cx, let_expr.init.span, expr.span.ctxt(), "..", &mut applicability).0,
snippet_with_context(cx, let_expr.pat.span, expr.span.ctxt(), "..", &mut applicability).0,
),
applicability,
);
}
}
}

View file

@ -176,13 +176,7 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
}
}
fn fake_read(
&mut self,
_: &rustc_hir_typeck::expr_use_visitor::PlaceWithHirId<'tcx>,
_: FakeReadCause,
_: HirId,
) {
}
fn fake_read(&mut self, _: &rustc_hir_typeck::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
}
impl<'a, 'tcx> EscapeDelegate<'a, 'tcx> {

View file

@ -1,8 +1,11 @@
use clippy_utils::diagnostics::span_lint_and_help;
use rustc_ast::ast::{AssocItemKind, Extern, Fn, FnSig, Impl, Item, ItemKind, Trait, Ty, TyKind};
use rustc_lint::{EarlyContext, EarlyLintPass};
use clippy_utils::{get_parent_as_impl, has_repr_attr, is_bool};
use rustc_hir::intravisit::FnKind;
use rustc_hir::{Body, FnDecl, HirId, Item, ItemKind, TraitFn, TraitItem, TraitItemKind, Ty};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{sym, Span};
use rustc_span::Span;
use rustc_target::spec::abi::Abi;
declare_clippy_lint! {
/// ### What it does
@ -83,6 +86,12 @@ pub struct ExcessiveBools {
max_fn_params_bools: u64,
}
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
enum Kind {
Struct,
Fn,
}
impl ExcessiveBools {
#[must_use]
pub fn new(max_struct_bools: u64, max_fn_params_bools: u64) -> Self {
@ -92,21 +101,20 @@ impl ExcessiveBools {
}
}
fn check_fn_sig(&self, cx: &EarlyContext<'_>, fn_sig: &FnSig, span: Span) {
match fn_sig.header.ext {
Extern::Implicit(_) | Extern::Explicit(_, _) => return,
Extern::None => (),
fn too_many_bools<'tcx>(&self, tys: impl Iterator<Item = &'tcx Ty<'tcx>>, kind: Kind) -> bool {
if let Ok(bools) = tys.filter(|ty| is_bool(ty)).count().try_into() {
(if Kind::Fn == kind {
self.max_fn_params_bools
} else {
self.max_struct_bools
}) < bools
} else {
false
}
}
let fn_sig_bools = fn_sig
.decl
.inputs
.iter()
.filter(|param| is_bool_ty(&param.ty))
.count()
.try_into()
.unwrap();
if self.max_fn_params_bools < fn_sig_bools {
fn check_fn_sig(&self, cx: &LateContext<'_>, fn_decl: &FnDecl<'_>, span: Span) {
if !span.from_expansion() && self.too_many_bools(fn_decl.inputs.iter(), Kind::Fn) {
span_lint_and_help(
cx,
FN_PARAMS_EXCESSIVE_BOOLS,
@ -121,56 +129,55 @@ impl ExcessiveBools {
impl_lint_pass!(ExcessiveBools => [STRUCT_EXCESSIVE_BOOLS, FN_PARAMS_EXCESSIVE_BOOLS]);
fn is_bool_ty(ty: &Ty) -> bool {
if let TyKind::Path(None, path) = &ty.kind {
if let [name] = path.segments.as_slice() {
return name.ident.name == sym::bool;
}
}
false
}
impl EarlyLintPass for ExcessiveBools {
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
impl<'tcx> LateLintPass<'tcx> for ExcessiveBools {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
if item.span.from_expansion() {
return;
}
match &item.kind {
ItemKind::Struct(variant_data, _) => {
if item.attrs.iter().any(|attr| attr.has_name(sym::repr)) {
return;
}
if let ItemKind::Struct(variant_data, _) = &item.kind {
if has_repr_attr(cx, item.hir_id()) {
return;
}
let struct_bools = variant_data
.fields()
.iter()
.filter(|field| is_bool_ty(&field.ty))
.count()
.try_into()
.unwrap();
if self.max_struct_bools < struct_bools {
span_lint_and_help(
cx,
STRUCT_EXCESSIVE_BOOLS,
item.span,
&format!("more than {} bools in a struct", self.max_struct_bools),
None,
"consider using a state machine or refactoring bools into two-variant enums",
);
}
},
ItemKind::Impl(box Impl {
of_trait: None, items, ..
})
| ItemKind::Trait(box Trait { items, .. }) => {
for item in items {
if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
self.check_fn_sig(cx, sig, item.span);
}
}
},
ItemKind::Fn(box Fn { sig, .. }) => self.check_fn_sig(cx, sig, item.span),
_ => (),
if self.too_many_bools(variant_data.fields().iter().map(|field| field.ty), Kind::Struct) {
span_lint_and_help(
cx,
STRUCT_EXCESSIVE_BOOLS,
item.span,
&format!("more than {} bools in a struct", self.max_struct_bools),
None,
"consider using a state machine or refactoring bools into two-variant enums",
);
}
}
}
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx TraitItem<'tcx>) {
// functions with a body are already checked by `check_fn`
if let TraitItemKind::Fn(fn_sig, TraitFn::Required(_)) = &trait_item.kind
&& fn_sig.header.abi == Abi::Rust
{
self.check_fn_sig(cx, fn_sig.decl, fn_sig.span);
}
}
fn check_fn(
&mut self,
cx: &LateContext<'tcx>,
fn_kind: FnKind<'tcx>,
fn_decl: &'tcx FnDecl<'tcx>,
_: &'tcx Body<'tcx>,
span: Span,
hir_id: HirId,
) {
if let Some(fn_header) = fn_kind.header()
&& fn_header.abi == Abi::Rust
&& get_parent_as_impl(cx.tcx, hir_id)
.map_or(true,
|impl_item| impl_item.of_trait.is_none()
)
{
self.check_fn_sig(cx, fn_decl, span);
}
}
}

View file

@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for FallibleImplFrom {
}
}
fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_items: &[hir::ImplItemRef]) {
fn lint_impl_body(cx: &LateContext<'_>, impl_span: Span, impl_items: &[hir::ImplItemRef]) {
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{Expr, ImplItemKind};

View file

@ -0,0 +1,77 @@
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::ty::is_c_void;
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_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::sym;
declare_clippy_lint! {
/// ### What it does
/// Checks if we're passing a `c_void` raw pointer to `{Box,Rc,Arc,Weak}::from_raw(_)`
///
/// ### Why is this bad?
/// When dealing with `c_void` raw pointers in FFI, it is easy to run into the pitfall of calling `from_raw` with the `c_void` pointer.
/// The type signature of `Box::from_raw` is `fn from_raw(raw: *mut T) -> Box<T>`, so if you pass a `*mut c_void` you will get a `Box<c_void>` (and similarly for `Rc`, `Arc` and `Weak`).
/// For this to be safe, `c_void` would need to have the same memory layout as the original type, which is often not the case.
///
/// ### Example
/// ```rust
/// # use std::ffi::c_void;
/// let ptr = Box::into_raw(Box::new(42usize)) as *mut c_void;
/// let _ = unsafe { Box::from_raw(ptr) };
/// ```
/// Use instead:
/// ```rust
/// # use std::ffi::c_void;
/// # let ptr = Box::into_raw(Box::new(42usize)) as *mut c_void;
/// let _ = unsafe { Box::from_raw(ptr as *mut usize) };
/// ```
///
#[clippy::version = "1.66.0"]
pub FROM_RAW_WITH_VOID_PTR,
suspicious,
"creating a `Box` from a void raw pointer"
}
declare_lint_pass!(FromRawWithVoidPtr => [FROM_RAW_WITH_VOID_PTR]);
impl LateLintPass<'_> for FromRawWithVoidPtr {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
if let ExprKind::Call(box_from_raw, [arg]) = expr.kind
&& let ExprKind::Path(QPath::TypeRelative(ty, seg)) = box_from_raw.kind
&& seg.ident.name == sym!(from_raw)
&& let Some(type_str) = path_def_id(cx, ty).and_then(|id| def_id_matches_type(cx, id))
&& let arg_kind = cx.typeck_results().expr_ty(arg).kind()
&& let RawPtr(TypeAndMut { ty, .. }) = arg_kind
&& is_c_void(cx, *ty) {
let msg = format!("creating a `{type_str}` from a void raw pointer");
span_lint_and_help(cx, FROM_RAW_WITH_VOID_PTR, expr.span, &msg, Some(arg.span), "cast this to a pointer of the appropriate type");
}
}
}
/// Checks whether a `DefId` matches `Box`, `Rc`, `Arc`, or one of the `Weak` types.
/// Returns a static string slice with the name of the type, if one was found.
fn def_id_matches_type(cx: &LateContext<'_>, def_id: DefId) -> Option<&'static str> {
// Box
if Some(def_id) == cx.tcx.lang_items().owned_box() {
return Some("Box");
}
if let Some(symbol) = cx.tcx.get_diagnostic_name(def_id) {
if symbol == sym::Arc {
return Some("Arc");
} else if symbol == sym::Rc {
return Some("Rc");
}
}
if match_def_path(cx, def_id, &paths::WEAK_RC) || match_def_path(cx, def_id, &paths::WEAK_ARC) {
Some("Weak")
} else {
None
}
}

View file

@ -254,7 +254,7 @@ declare_clippy_lint! {
/// Ok(())
/// }
/// ```
#[clippy::version = "1.64.0"]
#[clippy::version = "1.65.0"]
pub RESULT_LARGE_ERR,
perf,
"function returning `Result` with large `Err` type"

View file

@ -50,7 +50,9 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp
let attr = cx.tcx.get_attr(item.owner_id.to_def_id(), sym::must_use);
if let Some(attr) = attr {
check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr);
} else if is_public && !is_proc_macro(cx.sess(), attrs) && trait_ref_of_method(cx, item.owner_id.def_id).is_none()
} else if is_public
&& !is_proc_macro(cx.sess(), attrs)
&& trait_ref_of_method(cx, item.owner_id.def_id).is_none()
{
check_must_use_candidate(
cx,
@ -175,7 +177,7 @@ fn is_mutable_pat(cx: &LateContext<'_>, pat: &hir::Pat<'_>, tys: &mut DefIdSet)
return false; // ignore `_` patterns
}
if cx.tcx.has_typeck_results(pat.hir_id.owner.to_def_id()) {
is_mutable_ty(cx, cx.tcx.typeck(pat.hir_id.owner.def_id).pat_ty(pat), pat.span, tys)
is_mutable_ty(cx, cx.tcx.typeck(pat.hir_id.owner.def_id).pat_ty(pat), tys)
} else {
false
}
@ -183,7 +185,7 @@ fn is_mutable_pat(cx: &LateContext<'_>, pat: &hir::Pat<'_>, tys: &mut DefIdSet)
static KNOWN_WRAPPER_TYS: &[Symbol] = &[sym::Rc, sym::Arc];
fn is_mutable_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Span, tys: &mut DefIdSet) -> bool {
fn is_mutable_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, tys: &mut DefIdSet) -> bool {
match *ty.kind() {
// primitive types are never mutable
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => false,
@ -192,12 +194,12 @@ fn is_mutable_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Span, tys: &m
|| KNOWN_WRAPPER_TYS
.iter()
.any(|&sym| cx.tcx.is_diagnostic_item(sym, adt.did()))
&& substs.types().any(|ty| is_mutable_ty(cx, ty, span, tys))
&& substs.types().any(|ty| is_mutable_ty(cx, ty, tys))
},
ty::Tuple(substs) => substs.iter().any(|ty| is_mutable_ty(cx, ty, span, tys)),
ty::Array(ty, _) | ty::Slice(ty) => is_mutable_ty(cx, ty, span, tys),
ty::Tuple(substs) => substs.iter().any(|ty| is_mutable_ty(cx, ty, tys)),
ty::Array(ty, _) | ty::Slice(ty) => is_mutable_ty(cx, ty, tys),
ty::RawPtr(ty::TypeAndMut { ty, mutbl }) | ty::Ref(_, ty, mutbl) => {
mutbl == hir::Mutability::Mut || is_mutable_ty(cx, ty, span, tys)
mutbl == hir::Mutability::Mut || is_mutable_ty(cx, ty, tys)
},
// calling something constitutes a side effect, so return true on all callables
// also never calls need not be used, so return true for them, too
@ -225,12 +227,7 @@ fn mutates_static<'tcx>(cx: &LateContext<'tcx>, body: &'tcx hir::Body<'_>) -> bo
let mut tys = DefIdSet::default();
for arg in args {
if cx.tcx.has_typeck_results(arg.hir_id.owner.to_def_id())
&& is_mutable_ty(
cx,
cx.tcx.typeck(arg.hir_id.owner.def_id).expr_ty(arg),
arg.span,
&mut tys,
)
&& is_mutable_ty(cx, cx.tcx.typeck(arg.hir_id.owner.def_id).expr_ty(arg), &mut tys)
&& is_mutated_static(arg)
{
return ControlFlow::Break(());
@ -243,12 +240,7 @@ fn mutates_static<'tcx>(cx: &LateContext<'tcx>, body: &'tcx hir::Body<'_>) -> bo
let mut tys = DefIdSet::default();
for arg in std::iter::once(receiver).chain(args.iter()) {
if cx.tcx.has_typeck_results(arg.hir_id.owner.to_def_id())
&& is_mutable_ty(
cx,
cx.tcx.typeck(arg.hir_id.owner.def_id).expr_ty(arg),
arg.span,
&mut tys,
)
&& is_mutable_ty(cx, cx.tcx.typeck(arg.hir_id.owner.def_id).expr_ty(arg), &mut tys)
&& is_mutated_static(arg)
{
return ControlFlow::Break(());

View file

@ -2,12 +2,12 @@ use rustc_errors::Diagnostic;
use rustc_hir as hir;
use rustc_lint::{LateContext, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::{self, Ty};
use rustc_middle::ty::{self, Adt, Ty};
use rustc_span::{sym, Span};
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then};
use clippy_utils::trait_ref_of_method;
use clippy_utils::ty::{approx_ty_size, is_type_diagnostic_item};
use clippy_utils::ty::{approx_ty_size, is_type_diagnostic_item, AdtVariantInfo};
use super::{RESULT_LARGE_ERR, RESULT_UNIT_ERR};
@ -84,17 +84,57 @@ fn check_result_unit_err(cx: &LateContext<'_>, err_ty: Ty<'_>, fn_header_span: S
}
fn check_result_large_err<'tcx>(cx: &LateContext<'tcx>, err_ty: Ty<'tcx>, hir_ty_span: Span, large_err_threshold: u64) {
let ty_size = approx_ty_size(cx, err_ty);
if ty_size >= large_err_threshold {
span_lint_and_then(
cx,
RESULT_LARGE_ERR,
hir_ty_span,
"the `Err`-variant returned from this function is very large",
|diag: &mut Diagnostic| {
diag.span_label(hir_ty_span, format!("the `Err`-variant is at least {ty_size} bytes"));
diag.help(format!("try reducing the size of `{err_ty}`, for example by boxing large elements or replacing it with `Box<{err_ty}>`"));
},
);
if_chain! {
if let Adt(adt, subst) = err_ty.kind();
if let Some(local_def_id) = err_ty.ty_adt_def().expect("already checked this is adt").did().as_local();
if let Some(hir::Node::Item(item)) = cx
.tcx
.hir()
.find_by_def_id(local_def_id);
if let hir::ItemKind::Enum(ref def, _) = item.kind;
then {
let variants_size = AdtVariantInfo::new(cx, *adt, subst);
if variants_size[0].size >= large_err_threshold {
span_lint_and_then(
cx,
RESULT_LARGE_ERR,
hir_ty_span,
"the `Err`-variant returned from this function is very large",
|diag| {
diag.span_label(
def.variants[variants_size[0].ind].span,
format!("the largest variant contains at least {} bytes", variants_size[0].size),
);
for variant in &variants_size[1..] {
if variant.size >= large_err_threshold {
let variant_def = &def.variants[variant.ind];
diag.span_label(
variant_def.span,
format!("the variant `{}` contains at least {} bytes", variant_def.ident, variant.size),
);
}
}
diag.help(format!("try reducing the size of `{err_ty}`, for example by boxing large elements or replacing it with `Box<{err_ty}>`"));
}
);
}
}
else {
let ty_size = approx_ty_size(cx, err_ty);
if ty_size >= large_err_threshold {
span_lint_and_then(
cx,
RESULT_LARGE_ERR,
hir_ty_span,
"the `Err`-variant returned from this function is very large",
|diag: &mut Diagnostic| {
diag.span_label(hir_ty_span, format!("the `Err`-variant is at least {ty_size} bytes"));
diag.help(format!("try reducing the size of `{err_ty}`, for example by boxing large elements or replacing it with `Box<{err_ty}>`"));
},
);
}
}
}
}

View file

@ -66,8 +66,8 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
use rustc_span::BytePos;
fn suggestion<'tcx>(
cx: &LateContext<'tcx>,
fn suggestion(
cx: &LateContext<'_>,
diag: &mut Diagnostic,
generics_span: Span,
generics_suggestion_span: Span,

View file

@ -207,8 +207,8 @@ impl SliceLintInformation {
}
}
fn filter_lintable_slices<'a, 'tcx>(
cx: &'a LateContext<'tcx>,
fn filter_lintable_slices<'tcx>(
cx: &LateContext<'tcx>,
slice_lint_info: FxIndexMap<hir::HirId, SliceLintInformation>,
max_suggested_slice: u64,
scope: &'tcx hir::Expr<'tcx>,

View file

@ -171,11 +171,7 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
/// Returns a tuple of options with the start and end (exclusive) values of
/// the range. If the start or end is not constant, None is returned.
fn to_const_range<'tcx>(
cx: &LateContext<'tcx>,
range: higher::Range<'_>,
array_size: u128,
) -> (Option<u128>, Option<u128>) {
fn to_const_range(cx: &LateContext<'_>, range: higher::Range<'_>, array_size: u128) -> (Option<u128>, Option<u128>) {
let s = range
.start
.map(|expr| constant(cx, cx.typeck_results(), expr).map(|(c, _)| c));

View file

@ -0,0 +1,184 @@
use clippy_utils::{
diagnostics::{self, span_lint_and_sugg},
meets_msrv, msrvs, source,
sugg::Sugg,
ty,
};
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{source_map::Spanned, sym};
declare_clippy_lint! {
/// ### What it does
/// Lints subtraction between `Instant::now()` and another `Instant`.
///
/// ### Why is this bad?
/// It is easy to accidentally write `prev_instant - Instant::now()`, which will always be 0ns
/// as `Instant` subtraction saturates.
///
/// `prev_instant.elapsed()` also more clearly signals intention.
///
/// ### Example
/// ```rust
/// use std::time::Instant;
/// let prev_instant = Instant::now();
/// let duration = Instant::now() - prev_instant;
/// ```
/// Use instead:
/// ```rust
/// use std::time::Instant;
/// let prev_instant = Instant::now();
/// let duration = prev_instant.elapsed();
/// ```
#[clippy::version = "1.65.0"]
pub MANUAL_INSTANT_ELAPSED,
pedantic,
"subtraction between `Instant::now()` and previous `Instant`"
}
declare_clippy_lint! {
/// ### What it does
/// Lints subtraction between an [`Instant`] and a [`Duration`].
///
/// ### Why is this bad?
/// Unchecked subtraction could cause underflow on certain platforms, leading to
/// unintentional panics.
///
/// ### Example
/// ```rust
/// # use std::time::{Instant, Duration};
/// let time_passed = Instant::now() - Duration::from_secs(5);
/// ```
///
/// Use instead:
/// ```rust
/// # use std::time::{Instant, Duration};
/// let time_passed = Instant::now().checked_sub(Duration::from_secs(5));
/// ```
///
/// [`Duration`]: std::time::Duration
/// [`Instant::now()`]: std::time::Instant::now;
#[clippy::version = "1.65.0"]
pub UNCHECKED_DURATION_SUBTRACTION,
suspicious,
"finds unchecked subtraction of a 'Duration' from an 'Instant'"
}
pub struct InstantSubtraction {
msrv: Option<RustcVersion>,
}
impl InstantSubtraction {
#[must_use]
pub fn new(msrv: Option<RustcVersion>) -> Self {
Self { msrv }
}
}
impl_lint_pass!(InstantSubtraction => [MANUAL_INSTANT_ELAPSED, UNCHECKED_DURATION_SUBTRACTION]);
impl LateLintPass<'_> for InstantSubtraction {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
if let ExprKind::Binary(
Spanned {
node: BinOpKind::Sub, ..
},
lhs,
rhs,
) = expr.kind
{
if_chain! {
if is_instant_now_call(cx, lhs);
if is_an_instant(cx, rhs);
if let Some(sugg) = Sugg::hir_opt(cx, rhs);
then {
print_manual_instant_elapsed_sugg(cx, expr, sugg)
} else {
if_chain! {
if !expr.span.from_expansion();
if meets_msrv(self.msrv, msrvs::TRY_FROM);
if is_an_instant(cx, lhs);
if is_a_duration(cx, rhs);
then {
print_unchecked_duration_subtraction_sugg(cx, lhs, rhs, expr)
}
}
}
}
}
}
extract_msrv_attr!(LateContext);
}
fn is_instant_now_call(cx: &LateContext<'_>, expr_block: &'_ Expr<'_>) -> bool {
if let ExprKind::Call(fn_expr, []) = expr_block.kind
&& let Some(fn_id) = clippy_utils::path_def_id(cx, fn_expr)
&& clippy_utils::match_def_path(cx, fn_id, &clippy_utils::paths::INSTANT_NOW)
{
true
} else {
false
}
}
fn is_an_instant(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
let expr_ty = cx.typeck_results().expr_ty(expr);
match expr_ty.kind() {
rustc_middle::ty::Adt(def, _) => clippy_utils::match_def_path(cx, def.did(), &clippy_utils::paths::INSTANT),
_ => false,
}
}
fn is_a_duration(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
let expr_ty = cx.typeck_results().expr_ty(expr);
ty::is_type_diagnostic_item(cx, expr_ty, sym::Duration)
}
fn print_manual_instant_elapsed_sugg(cx: &LateContext<'_>, expr: &Expr<'_>, sugg: Sugg<'_>) {
span_lint_and_sugg(
cx,
MANUAL_INSTANT_ELAPSED,
expr.span,
"manual implementation of `Instant::elapsed`",
"try",
format!("{}.elapsed()", sugg.maybe_par()),
Applicability::MachineApplicable,
);
}
fn print_unchecked_duration_subtraction_sugg(
cx: &LateContext<'_>,
left_expr: &Expr<'_>,
right_expr: &Expr<'_>,
expr: &Expr<'_>,
) {
let mut applicability = Applicability::MachineApplicable;
let left_expr =
source::snippet_with_applicability(cx, left_expr.span, "std::time::Instant::now()", &mut applicability);
let right_expr = source::snippet_with_applicability(
cx,
right_expr.span,
"std::time::Duration::from_secs(1)",
&mut applicability,
);
diagnostics::span_lint_and_sugg(
cx,
UNCHECKED_DURATION_SUBTRACTION,
expr.span,
"unchecked subtraction of a 'Duration' from an 'Instant'",
"try",
format!("{left_expr}.checked_sub({right_expr}).unwrap()"),
applicability,
);
}

View file

@ -63,58 +63,54 @@ impl IntPlusOne {
fn check_binop(cx: &EarlyContext<'_>, binop: BinOpKind, lhs: &Expr, rhs: &Expr) -> Option<String> {
match (binop, &lhs.kind, &rhs.kind) {
// case where `x - 1 >= ...` or `-1 + x >= ...`
(BinOpKind::Ge, &ExprKind::Binary(ref lhskind, ref lhslhs, ref lhsrhs), _) => {
(BinOpKind::Ge, ExprKind::Binary(lhskind, lhslhs, lhsrhs), _) => {
match (lhskind.node, &lhslhs.kind, &lhsrhs.kind) {
// `-1 + x`
(BinOpKind::Add, &ExprKind::Lit(lit), _) if Self::check_lit(lit, -1) => {
(BinOpKind::Add, ExprKind::Lit(lit), _) if Self::check_lit(*lit, -1) => {
Self::generate_recommendation(cx, binop, lhsrhs, rhs, Side::Lhs)
},
// `x - 1`
(BinOpKind::Sub, _, &ExprKind::Lit(lit)) if Self::check_lit(lit, 1) => {
(BinOpKind::Sub, _, ExprKind::Lit(lit)) if Self::check_lit(*lit, 1) => {
Self::generate_recommendation(cx, binop, lhslhs, rhs, Side::Lhs)
},
_ => None,
}
},
// case where `... >= y + 1` or `... >= 1 + y`
(BinOpKind::Ge, _, &ExprKind::Binary(ref rhskind, ref rhslhs, ref rhsrhs))
if rhskind.node == BinOpKind::Add =>
{
(BinOpKind::Ge, _, ExprKind::Binary(rhskind, rhslhs, rhsrhs)) if rhskind.node == BinOpKind::Add => {
match (&rhslhs.kind, &rhsrhs.kind) {
// `y + 1` and `1 + y`
(&ExprKind::Lit(lit), _) if Self::check_lit(lit, 1) => {
(ExprKind::Lit(lit), _) if Self::check_lit(*lit, 1) => {
Self::generate_recommendation(cx, binop, rhsrhs, lhs, Side::Rhs)
},
(_, &ExprKind::Lit(lit)) if Self::check_lit(lit, 1) => {
(_, ExprKind::Lit(lit)) if Self::check_lit(*lit, 1) => {
Self::generate_recommendation(cx, binop, rhslhs, lhs, Side::Rhs)
},
_ => None,
}
},
// case where `x + 1 <= ...` or `1 + x <= ...`
(BinOpKind::Le, &ExprKind::Binary(ref lhskind, ref lhslhs, ref lhsrhs), _)
if lhskind.node == BinOpKind::Add =>
{
(BinOpKind::Le, ExprKind::Binary(lhskind, lhslhs, lhsrhs), _) if lhskind.node == BinOpKind::Add => {
match (&lhslhs.kind, &lhsrhs.kind) {
// `1 + x` and `x + 1`
(&ExprKind::Lit(lit), _) if Self::check_lit(lit, 1) => {
(ExprKind::Lit(lit), _) if Self::check_lit(*lit, 1) => {
Self::generate_recommendation(cx, binop, lhsrhs, rhs, Side::Lhs)
},
(_, &ExprKind::Lit(lit)) if Self::check_lit(lit, 1) => {
(_, ExprKind::Lit(lit)) if Self::check_lit(*lit, 1) => {
Self::generate_recommendation(cx, binop, lhslhs, rhs, Side::Lhs)
},
_ => None,
}
},
// case where `... >= y - 1` or `... >= -1 + y`
(BinOpKind::Le, _, &ExprKind::Binary(ref rhskind, ref rhslhs, ref rhsrhs)) => {
(BinOpKind::Le, _, ExprKind::Binary(rhskind, rhslhs, rhsrhs)) => {
match (rhskind.node, &rhslhs.kind, &rhsrhs.kind) {
// `-1 + y`
(BinOpKind::Add, &ExprKind::Lit(lit), _) if Self::check_lit(lit, -1) => {
(BinOpKind::Add, ExprKind::Lit(lit), _) if Self::check_lit(*lit, -1) => {
Self::generate_recommendation(cx, binop, rhsrhs, lhs, Side::Rhs)
},
// `y - 1`
(BinOpKind::Sub, _, &ExprKind::Lit(lit)) if Self::check_lit(lit, 1) => {
(BinOpKind::Sub, _, ExprKind::Lit(lit)) if Self::check_lit(*lit, 1) => {
Self::generate_recommendation(cx, binop, rhslhs, lhs, Side::Rhs)
},
_ => None,

View file

@ -38,7 +38,7 @@ declare_clippy_lint! {
declare_lint_pass!(InvalidUpcastComparisons => [INVALID_UPCAST_COMPARISONS]);
fn numeric_cast_precast_bounds<'a>(cx: &LateContext<'_>, expr: &'a Expr<'_>) -> Option<(FullInt, FullInt)> {
fn numeric_cast_precast_bounds(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<(FullInt, FullInt)> {
if let ExprKind::Cast(cast_exp, _) = expr.kind {
let pre_cast_ty = cx.typeck_results().expr_ty(cast_exp);
let cast_ty = cx.typeck_results().expr_ty(expr);

View file

@ -1,12 +1,15 @@
//! lint when there is a large size difference between variants on an enum
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::{diagnostics::span_lint_and_then, ty::approx_ty_size, ty::is_copy};
use clippy_utils::{
diagnostics::span_lint_and_then,
ty::{approx_ty_size, is_copy, AdtVariantInfo},
};
use rustc_errors::Applicability;
use rustc_hir::{Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::{Adt, AdtDef, GenericArg, List, Ty};
use rustc_middle::ty::{Adt, Ty};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Span;
@ -72,49 +75,6 @@ impl LargeEnumVariant {
}
}
struct FieldInfo {
ind: usize,
size: u64,
}
struct VariantInfo {
ind: usize,
size: u64,
fields_size: Vec<FieldInfo>,
}
fn variants_size<'tcx>(
cx: &LateContext<'tcx>,
adt: AdtDef<'tcx>,
subst: &'tcx List<GenericArg<'tcx>>,
) -> Vec<VariantInfo> {
let mut variants_size = adt
.variants()
.iter()
.enumerate()
.map(|(i, variant)| {
let mut fields_size = variant
.fields
.iter()
.enumerate()
.map(|(i, f)| FieldInfo {
ind: i,
size: approx_ty_size(cx, f.ty(cx.tcx, subst)),
})
.collect::<Vec<_>>();
fields_size.sort_by(|a, b| (a.size.cmp(&b.size)));
VariantInfo {
ind: i,
size: fields_size.iter().map(|info| info.size).sum(),
fields_size,
}
})
.collect::<Vec<_>>();
variants_size.sort_by(|a, b| (b.size.cmp(&a.size)));
variants_size
}
impl_lint_pass!(LargeEnumVariant => [LARGE_ENUM_VARIANT]);
impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
@ -130,7 +90,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
if adt.variants().len() <= 1 {
return;
}
let variants_size = variants_size(cx, *adt, subst);
let variants_size = AdtVariantInfo::new(cx, *adt, subst);
let mut difference = variants_size[0].size - variants_size[1].size;
if difference > self.maximum_size_difference_allowed {
@ -173,16 +133,16 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
.fields_size
.iter()
.rev()
.map_while(|val| {
.map_while(|&(ind, size)| {
if difference > self.maximum_size_difference_allowed {
difference = difference.saturating_sub(val.size);
difference = difference.saturating_sub(size);
Some((
fields[val.ind].ty.span,
fields[ind].ty.span,
format!(
"Box<{}>",
snippet_with_applicability(
cx,
fields[val.ind].ty.span,
fields[ind].ty.span,
"..",
&mut applicability
)

View file

@ -366,8 +366,7 @@ fn check_for_is_empty<'tcx>(
}
fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>, op: &str, compare_to: u32) {
if let (&ExprKind::MethodCall(method_path, receiver, args, _), &ExprKind::Lit(ref lit)) = (&method.kind, &lit.kind)
{
if let (&ExprKind::MethodCall(method_path, receiver, args, _), ExprKind::Lit(lit)) = (&method.kind, &lit.kind) {
// check if we are in an is_empty() method
if let Some(name) = get_item_name(cx, method) {
if name.as_str() == "is_empty" {

View file

@ -1,13 +1,11 @@
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::ty::{is_must_use_ty, is_type_diagnostic_item, match_type};
use clippy_utils::ty::{implements_trait, is_must_use_ty, match_type};
use clippy_utils::{is_must_use_func_call, paths};
use if_chain::if_chain;
use rustc_hir::{Local, PatKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::subst::GenericArgKind;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::{sym, Symbol};
declare_clippy_lint! {
/// ### What it does
@ -30,13 +28,14 @@ declare_clippy_lint! {
#[clippy::version = "1.42.0"]
pub LET_UNDERSCORE_MUST_USE,
restriction,
"non-binding let on a `#[must_use]` expression"
"non-binding `let` on a `#[must_use]` expression"
}
declare_clippy_lint! {
/// ### What it does
/// Checks for `let _ = sync_lock`.
/// This supports `mutex` and `rwlock` in `std::sync` and `parking_lot`.
/// Checks for `let _ = sync_lock`. This supports `mutex` and `rwlock` in
/// `parking_lot`. For `std` locks see the `rustc` lint
/// [`let_underscore_lock`](https://doc.rust-lang.org/nightly/rustc/lints/listing/deny-by-default.html#let-underscore-lock)
///
/// ### Why is this bad?
/// This statement immediately drops the lock instead of
@ -57,50 +56,41 @@ declare_clippy_lint! {
#[clippy::version = "1.43.0"]
pub LET_UNDERSCORE_LOCK,
correctness,
"non-binding let on a synchronization lock"
"non-binding `let` on a synchronization lock"
}
declare_clippy_lint! {
/// ### What it does
/// Checks for `let _ = <expr>`
/// where expr has a type that implements `Drop`
/// Checks for `let _ = <expr>` where the resulting type of expr implements `Future`
///
/// ### Why is this bad?
/// This statement immediately drops the initializer
/// expression instead of extending its lifetime to the end of the scope, which
/// is often not intended. To extend the expression's lifetime to the end of the
/// scope, use an underscore-prefixed name instead (i.e. _var). If you want to
/// explicitly drop the expression, `std::mem::drop` conveys your intention
/// better and is less error-prone.
/// Futures must be polled for work to be done. The original intention was most likely to await the future
/// and ignore the resulting value.
///
/// ### Example
/// ```rust
/// # struct DroppableItem;
/// {
/// let _ = DroppableItem;
/// // ^ dropped here
/// /* more code */
/// async fn foo() -> Result<(), ()> {
/// Ok(())
/// }
/// let _ = foo();
/// ```
///
/// Use instead:
/// ```rust
/// # struct DroppableItem;
/// {
/// let _droppable = DroppableItem;
/// /* more code */
/// // dropped at end of scope
/// # async fn context() {
/// async fn foo() -> Result<(), ()> {
/// Ok(())
/// }
/// let _ = foo().await;
/// # }
/// ```
#[clippy::version = "1.50.0"]
pub LET_UNDERSCORE_DROP,
pedantic,
"non-binding let on a type that implements `Drop`"
#[clippy::version = "1.66"]
pub LET_UNDERSCORE_FUTURE,
suspicious,
"non-binding `let` on a future"
}
declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_MUST_USE, LET_UNDERSCORE_LOCK, LET_UNDERSCORE_DROP]);
const SYNC_GUARD_SYMS: [Symbol; 3] = [sym::MutexGuard, sym::RwLockReadGuard, sym::RwLockWriteGuard];
declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_MUST_USE, LET_UNDERSCORE_LOCK, LET_UNDERSCORE_FUTURE]);
const SYNC_GUARD_PATHS: [&[&str]; 3] = [
&paths::PARKING_LOT_MUTEX_GUARD,
@ -110,64 +100,53 @@ const SYNC_GUARD_PATHS: [&[&str]; 3] = [
impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) {
if in_external_macro(cx.tcx.sess, local.span) {
return;
}
if_chain! {
if let PatKind::Wild = local.pat.kind;
if let Some(init) = local.init;
then {
let init_ty = cx.typeck_results().expr_ty(init);
let contains_sync_guard = init_ty.walk().any(|inner| match inner.unpack() {
GenericArgKind::Type(inner_ty) => {
SYNC_GUARD_SYMS
.iter()
.any(|&sym| is_type_diagnostic_item(cx, inner_ty, sym))
|| SYNC_GUARD_PATHS.iter().any(|path| match_type(cx, inner_ty, path))
},
GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
});
if contains_sync_guard {
span_lint_and_help(
cx,
LET_UNDERSCORE_LOCK,
local.span,
"non-binding let on a synchronization lock",
None,
"consider using an underscore-prefixed named \
if !in_external_macro(cx.tcx.sess, local.span)
&& let PatKind::Wild = local.pat.kind
&& let Some(init) = local.init
{
let init_ty = cx.typeck_results().expr_ty(init);
let contains_sync_guard = init_ty.walk().any(|inner| match inner.unpack() {
GenericArgKind::Type(inner_ty) => SYNC_GUARD_PATHS.iter().any(|path| match_type(cx, inner_ty, path)),
GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
});
if contains_sync_guard {
span_lint_and_help(
cx,
LET_UNDERSCORE_LOCK,
local.span,
"non-binding `let` on a synchronization lock",
None,
"consider using an underscore-prefixed named \
binding or dropping explicitly with `std::mem::drop`",
);
} else if init_ty.needs_drop(cx.tcx, cx.param_env) {
span_lint_and_help(
cx,
LET_UNDERSCORE_DROP,
local.span,
"non-binding `let` on a type that implements `Drop`",
None,
"consider using an underscore-prefixed named \
binding or dropping explicitly with `std::mem::drop`",
);
} else if is_must_use_ty(cx, cx.typeck_results().expr_ty(init)) {
span_lint_and_help(
cx,
LET_UNDERSCORE_MUST_USE,
local.span,
"non-binding let on an expression with `#[must_use]` type",
None,
"consider explicitly using expression value",
);
} else if is_must_use_func_call(cx, init) {
span_lint_and_help(
cx,
LET_UNDERSCORE_MUST_USE,
local.span,
"non-binding let on a result of a `#[must_use]` function",
None,
"consider explicitly using function result",
);
}
);
} else if let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait()
&& implements_trait(cx, cx.typeck_results().expr_ty(init), future_trait_def_id, &[]) {
span_lint_and_help(
cx,
LET_UNDERSCORE_FUTURE,
local.span,
"non-binding `let` on a future",
None,
"consider awaiting the future or dropping explicitly with `std::mem::drop`"
);
} else if is_must_use_ty(cx, cx.typeck_results().expr_ty(init)) {
span_lint_and_help(
cx,
LET_UNDERSCORE_MUST_USE,
local.span,
"non-binding `let` on an expression with `#[must_use]` type",
None,
"consider explicitly using expression value",
);
} else if is_must_use_func_call(cx, init) {
span_lint_and_help(
cx,
LET_UNDERSCORE_MUST_USE,
local.span,
"non-binding `let` on a result of a `#[must_use]` function",
None,
"consider explicitly using function result",
);
}
}
}

View file

@ -1,368 +0,0 @@
// This file was generated by `cargo dev update_lints`.
// Use that command to update this file and do not edit by hand.
// Manual edits will be overwritten.
store.register_group(true, "clippy::all", Some("clippy_all"), vec![
LintId::of(almost_complete_letter_range::ALMOST_COMPLETE_LETTER_RANGE),
LintId::of(approx_const::APPROX_CONSTANT),
LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS),
LintId::of(async_yields_async::ASYNC_YIELDS_ASYNC),
LintId::of(attrs::BLANKET_CLIPPY_RESTRICTION_LINTS),
LintId::of(attrs::DEPRECATED_CFG_ATTR),
LintId::of(attrs::DEPRECATED_SEMVER),
LintId::of(attrs::MISMATCHED_TARGET_OS),
LintId::of(attrs::USELESS_ATTRIBUTE),
LintId::of(await_holding_invalid::AWAIT_HOLDING_INVALID_TYPE),
LintId::of(await_holding_invalid::AWAIT_HOLDING_LOCK),
LintId::of(await_holding_invalid::AWAIT_HOLDING_REFCELL_REF),
LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS),
LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON),
LintId::of(bool_to_int_with_if::BOOL_TO_INT_WITH_IF),
LintId::of(booleans::NONMINIMAL_BOOL),
LintId::of(booleans::OVERLY_COMPLEX_BOOL_EXPR),
LintId::of(borrow_deref_ref::BORROW_DEREF_REF),
LintId::of(box_default::BOX_DEFAULT),
LintId::of(casts::CAST_ABS_TO_UNSIGNED),
LintId::of(casts::CAST_ENUM_CONSTRUCTOR),
LintId::of(casts::CAST_ENUM_TRUNCATION),
LintId::of(casts::CAST_NAN_TO_INT),
LintId::of(casts::CAST_REF_TO_MUT),
LintId::of(casts::CAST_SLICE_DIFFERENT_SIZES),
LintId::of(casts::CAST_SLICE_FROM_RAW_PARTS),
LintId::of(casts::CHAR_LIT_AS_U8),
LintId::of(casts::FN_TO_NUMERIC_CAST),
LintId::of(casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION),
LintId::of(casts::UNNECESSARY_CAST),
LintId::of(collapsible_if::COLLAPSIBLE_ELSE_IF),
LintId::of(collapsible_if::COLLAPSIBLE_IF),
LintId::of(comparison_chain::COMPARISON_CHAIN),
LintId::of(copies::IFS_SAME_COND),
LintId::of(copies::IF_SAME_THEN_ELSE),
LintId::of(crate_in_macro_def::CRATE_IN_MACRO_DEF),
LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT),
LintId::of(default_instead_of_iter_empty::DEFAULT_INSTEAD_OF_ITER_EMPTY),
LintId::of(dereference::EXPLICIT_AUTO_DEREF),
LintId::of(dereference::NEEDLESS_BORROW),
LintId::of(derivable_impls::DERIVABLE_IMPLS),
LintId::of(derive::DERIVE_HASH_XOR_EQ),
LintId::of(derive::DERIVE_ORD_XOR_PARTIAL_ORD),
LintId::of(disallowed_macros::DISALLOWED_MACROS),
LintId::of(disallowed_methods::DISALLOWED_METHODS),
LintId::of(disallowed_names::DISALLOWED_NAMES),
LintId::of(disallowed_types::DISALLOWED_TYPES),
LintId::of(doc::MISSING_SAFETY_DOC),
LintId::of(doc::NEEDLESS_DOCTEST_MAIN),
LintId::of(double_parens::DOUBLE_PARENS),
LintId::of(drop_forget_ref::DROP_COPY),
LintId::of(drop_forget_ref::DROP_NON_DROP),
LintId::of(drop_forget_ref::DROP_REF),
LintId::of(drop_forget_ref::FORGET_COPY),
LintId::of(drop_forget_ref::FORGET_NON_DROP),
LintId::of(drop_forget_ref::FORGET_REF),
LintId::of(drop_forget_ref::UNDROPPED_MANUALLY_DROPS),
LintId::of(duplicate_mod::DUPLICATE_MOD),
LintId::of(entry::MAP_ENTRY),
LintId::of(enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT),
LintId::of(enum_variants::ENUM_VARIANT_NAMES),
LintId::of(enum_variants::MODULE_INCEPTION),
LintId::of(escape::BOXED_LOCAL),
LintId::of(eta_reduction::REDUNDANT_CLOSURE),
LintId::of(explicit_write::EXPLICIT_WRITE),
LintId::of(float_literal::EXCESSIVE_PRECISION),
LintId::of(format::USELESS_FORMAT),
LintId::of(format_args::FORMAT_IN_FORMAT_ARGS),
LintId::of(format_args::TO_STRING_IN_FORMAT_ARGS),
LintId::of(format_args::UNUSED_FORMAT_SPECS),
LintId::of(format_impl::PRINT_IN_FORMAT_IMPL),
LintId::of(format_impl::RECURSIVE_FORMAT_IMPL),
LintId::of(formatting::POSSIBLE_MISSING_COMMA),
LintId::of(formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING),
LintId::of(formatting::SUSPICIOUS_ELSE_FORMATTING),
LintId::of(formatting::SUSPICIOUS_UNARY_OP_FORMATTING),
LintId::of(from_over_into::FROM_OVER_INTO),
LintId::of(from_str_radix_10::FROM_STR_RADIX_10),
LintId::of(functions::DOUBLE_MUST_USE),
LintId::of(functions::MUST_USE_UNIT),
LintId::of(functions::NOT_UNSAFE_PTR_ARG_DEREF),
LintId::of(functions::RESULT_LARGE_ERR),
LintId::of(functions::RESULT_UNIT_ERR),
LintId::of(functions::TOO_MANY_ARGUMENTS),
LintId::of(if_let_mutex::IF_LET_MUTEX),
LintId::of(implicit_saturating_add::IMPLICIT_SATURATING_ADD),
LintId::of(implicit_saturating_sub::IMPLICIT_SATURATING_SUB),
LintId::of(indexing_slicing::OUT_OF_BOUNDS_INDEXING),
LintId::of(infinite_iter::INFINITE_ITER),
LintId::of(inherent_to_string::INHERENT_TO_STRING),
LintId::of(inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY),
LintId::of(init_numbered_fields::INIT_NUMBERED_FIELDS),
LintId::of(inline_fn_without_body::INLINE_FN_WITHOUT_BODY),
LintId::of(int_plus_one::INT_PLUS_ONE),
LintId::of(invalid_utf8_in_unchecked::INVALID_UTF8_IN_UNCHECKED),
LintId::of(large_const_arrays::LARGE_CONST_ARRAYS),
LintId::of(large_enum_variant::LARGE_ENUM_VARIANT),
LintId::of(len_zero::COMPARISON_TO_EMPTY),
LintId::of(len_zero::LEN_WITHOUT_IS_EMPTY),
LintId::of(len_zero::LEN_ZERO),
LintId::of(let_underscore::LET_UNDERSCORE_LOCK),
LintId::of(lifetimes::EXTRA_UNUSED_LIFETIMES),
LintId::of(lifetimes::NEEDLESS_LIFETIMES),
LintId::of(literal_representation::INCONSISTENT_DIGIT_GROUPING),
LintId::of(literal_representation::MISTYPED_LITERAL_SUFFIXES),
LintId::of(literal_representation::UNUSUAL_BYTE_GROUPINGS),
LintId::of(loops::EMPTY_LOOP),
LintId::of(loops::EXPLICIT_COUNTER_LOOP),
LintId::of(loops::FOR_KV_MAP),
LintId::of(loops::ITER_NEXT_LOOP),
LintId::of(loops::MANUAL_FIND),
LintId::of(loops::MANUAL_FLATTEN),
LintId::of(loops::MANUAL_MEMCPY),
LintId::of(loops::MISSING_SPIN_LOOP),
LintId::of(loops::MUT_RANGE_BOUND),
LintId::of(loops::NEEDLESS_COLLECT),
LintId::of(loops::NEEDLESS_RANGE_LOOP),
LintId::of(loops::NEVER_LOOP),
LintId::of(loops::SAME_ITEM_PUSH),
LintId::of(loops::SINGLE_ELEMENT_LOOP),
LintId::of(loops::WHILE_IMMUTABLE_CONDITION),
LintId::of(loops::WHILE_LET_LOOP),
LintId::of(loops::WHILE_LET_ON_ITERATOR),
LintId::of(main_recursion::MAIN_RECURSION),
LintId::of(manual_async_fn::MANUAL_ASYNC_FN),
LintId::of(manual_bits::MANUAL_BITS),
LintId::of(manual_clamp::MANUAL_CLAMP),
LintId::of(manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
LintId::of(manual_rem_euclid::MANUAL_REM_EUCLID),
LintId::of(manual_retain::MANUAL_RETAIN),
LintId::of(manual_strip::MANUAL_STRIP),
LintId::of(map_unit_fn::OPTION_MAP_UNIT_FN),
LintId::of(map_unit_fn::RESULT_MAP_UNIT_FN),
LintId::of(match_result_ok::MATCH_RESULT_OK),
LintId::of(matches::COLLAPSIBLE_MATCH),
LintId::of(matches::INFALLIBLE_DESTRUCTURING_MATCH),
LintId::of(matches::MANUAL_FILTER),
LintId::of(matches::MANUAL_MAP),
LintId::of(matches::MANUAL_UNWRAP_OR),
LintId::of(matches::MATCH_AS_REF),
LintId::of(matches::MATCH_LIKE_MATCHES_MACRO),
LintId::of(matches::MATCH_OVERLAPPING_ARM),
LintId::of(matches::MATCH_REF_PATS),
LintId::of(matches::MATCH_SINGLE_BINDING),
LintId::of(matches::MATCH_STR_CASE_MISMATCH),
LintId::of(matches::NEEDLESS_MATCH),
LintId::of(matches::REDUNDANT_PATTERN_MATCHING),
LintId::of(matches::SINGLE_MATCH),
LintId::of(matches::WILDCARD_IN_OR_PATTERNS),
LintId::of(mem_replace::MEM_REPLACE_OPTION_WITH_NONE),
LintId::of(mem_replace::MEM_REPLACE_WITH_DEFAULT),
LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT),
LintId::of(methods::BIND_INSTEAD_OF_MAP),
LintId::of(methods::BYTES_COUNT_TO_LEN),
LintId::of(methods::BYTES_NTH),
LintId::of(methods::CHARS_LAST_CMP),
LintId::of(methods::CHARS_NEXT_CMP),
LintId::of(methods::CLONE_DOUBLE_REF),
LintId::of(methods::CLONE_ON_COPY),
LintId::of(methods::COLLAPSIBLE_STR_REPLACE),
LintId::of(methods::ERR_EXPECT),
LintId::of(methods::EXPECT_FUN_CALL),
LintId::of(methods::EXTEND_WITH_DRAIN),
LintId::of(methods::FILTER_MAP_IDENTITY),
LintId::of(methods::FILTER_NEXT),
LintId::of(methods::FLAT_MAP_IDENTITY),
LintId::of(methods::GET_FIRST),
LintId::of(methods::GET_LAST_WITH_LEN),
LintId::of(methods::INSPECT_FOR_EACH),
LintId::of(methods::INTO_ITER_ON_REF),
LintId::of(methods::IS_DIGIT_ASCII_RADIX),
LintId::of(methods::ITERATOR_STEP_BY_ZERO),
LintId::of(methods::ITER_CLONED_COLLECT),
LintId::of(methods::ITER_COUNT),
LintId::of(methods::ITER_KV_MAP),
LintId::of(methods::ITER_NEXT_SLICE),
LintId::of(methods::ITER_NTH),
LintId::of(methods::ITER_NTH_ZERO),
LintId::of(methods::ITER_OVEREAGER_CLONED),
LintId::of(methods::ITER_SKIP_NEXT),
LintId::of(methods::MANUAL_FILTER_MAP),
LintId::of(methods::MANUAL_FIND_MAP),
LintId::of(methods::MANUAL_SATURATING_ARITHMETIC),
LintId::of(methods::MANUAL_SPLIT_ONCE),
LintId::of(methods::MANUAL_STR_REPEAT),
LintId::of(methods::MAP_CLONE),
LintId::of(methods::MAP_COLLECT_RESULT_UNIT),
LintId::of(methods::MAP_FLATTEN),
LintId::of(methods::MAP_IDENTITY),
LintId::of(methods::MUT_MUTEX_LOCK),
LintId::of(methods::NEEDLESS_OPTION_AS_DEREF),
LintId::of(methods::NEEDLESS_OPTION_TAKE),
LintId::of(methods::NEEDLESS_SPLITN),
LintId::of(methods::NEW_RET_NO_SELF),
LintId::of(methods::NONSENSICAL_OPEN_OPTIONS),
LintId::of(methods::NO_EFFECT_REPLACE),
LintId::of(methods::OBFUSCATED_IF_ELSE),
LintId::of(methods::OK_EXPECT),
LintId::of(methods::OPTION_AS_REF_DEREF),
LintId::of(methods::OPTION_FILTER_MAP),
LintId::of(methods::OPTION_MAP_OR_NONE),
LintId::of(methods::OR_FUN_CALL),
LintId::of(methods::OR_THEN_UNWRAP),
LintId::of(methods::RANGE_ZIP_WITH_LEN),
LintId::of(methods::REPEAT_ONCE),
LintId::of(methods::RESULT_MAP_OR_INTO_OPTION),
LintId::of(methods::SEARCH_IS_SOME),
LintId::of(methods::SHOULD_IMPLEMENT_TRAIT),
LintId::of(methods::SINGLE_CHAR_ADD_STR),
LintId::of(methods::SINGLE_CHAR_PATTERN),
LintId::of(methods::SKIP_WHILE_NEXT),
LintId::of(methods::STRING_EXTEND_CHARS),
LintId::of(methods::SUSPICIOUS_MAP),
LintId::of(methods::SUSPICIOUS_SPLITN),
LintId::of(methods::SUSPICIOUS_TO_OWNED),
LintId::of(methods::UNINIT_ASSUMED_INIT),
LintId::of(methods::UNIT_HASH),
LintId::of(methods::UNNECESSARY_FILTER_MAP),
LintId::of(methods::UNNECESSARY_FIND_MAP),
LintId::of(methods::UNNECESSARY_FOLD),
LintId::of(methods::UNNECESSARY_LAZY_EVALUATIONS),
LintId::of(methods::UNNECESSARY_SORT_BY),
LintId::of(methods::UNNECESSARY_TO_OWNED),
LintId::of(methods::UNWRAP_OR_ELSE_DEFAULT),
LintId::of(methods::USELESS_ASREF),
LintId::of(methods::VEC_RESIZE_TO_ZERO),
LintId::of(methods::WRONG_SELF_CONVENTION),
LintId::of(methods::ZST_OFFSET),
LintId::of(minmax::MIN_MAX),
LintId::of(misc::SHORT_CIRCUIT_STATEMENT),
LintId::of(misc::TOPLEVEL_REF_ARG),
LintId::of(misc::ZERO_PTR),
LintId::of(misc_early::BUILTIN_TYPE_SHADOW),
LintId::of(misc_early::DOUBLE_NEG),
LintId::of(misc_early::DUPLICATE_UNDERSCORE_ARGUMENT),
LintId::of(misc_early::MIXED_CASE_HEX_LITERALS),
LintId::of(misc_early::REDUNDANT_PATTERN),
LintId::of(misc_early::UNNEEDED_WILDCARD_PATTERN),
LintId::of(misc_early::ZERO_PREFIXED_LITERAL),
LintId::of(mixed_read_write_in_expression::DIVERGING_SUB_EXPRESSION),
LintId::of(multi_assignments::MULTI_ASSIGNMENTS),
LintId::of(mut_key::MUTABLE_KEY_TYPE),
LintId::of(mut_reference::UNNECESSARY_MUT_PASSED),
LintId::of(needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE),
LintId::of(needless_bool::BOOL_COMPARISON),
LintId::of(needless_bool::NEEDLESS_BOOL),
LintId::of(needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE),
LintId::of(needless_late_init::NEEDLESS_LATE_INIT),
LintId::of(needless_parens_on_range_literals::NEEDLESS_PARENS_ON_RANGE_LITERALS),
LintId::of(needless_question_mark::NEEDLESS_QUESTION_MARK),
LintId::of(needless_update::NEEDLESS_UPDATE),
LintId::of(neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD),
LintId::of(neg_multiply::NEG_MULTIPLY),
LintId::of(new_without_default::NEW_WITHOUT_DEFAULT),
LintId::of(no_effect::NO_EFFECT),
LintId::of(no_effect::UNNECESSARY_OPERATION),
LintId::of(non_copy_const::BORROW_INTERIOR_MUTABLE_CONST),
LintId::of(non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST),
LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS),
LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS),
LintId::of(octal_escapes::OCTAL_ESCAPES),
LintId::of(only_used_in_recursion::ONLY_USED_IN_RECURSION),
LintId::of(operators::ABSURD_EXTREME_COMPARISONS),
LintId::of(operators::ASSIGN_OP_PATTERN),
LintId::of(operators::BAD_BIT_MASK),
LintId::of(operators::CMP_NAN),
LintId::of(operators::CMP_OWNED),
LintId::of(operators::DOUBLE_COMPARISONS),
LintId::of(operators::DURATION_SUBSEC),
LintId::of(operators::EQ_OP),
LintId::of(operators::ERASING_OP),
LintId::of(operators::FLOAT_EQUALITY_WITHOUT_ABS),
LintId::of(operators::IDENTITY_OP),
LintId::of(operators::INEFFECTIVE_BIT_MASK),
LintId::of(operators::MISREFACTORED_ASSIGN_OP),
LintId::of(operators::MODULO_ONE),
LintId::of(operators::OP_REF),
LintId::of(operators::PTR_EQ),
LintId::of(operators::SELF_ASSIGNMENT),
LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP),
LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL),
LintId::of(partialeq_ne_impl::PARTIALEQ_NE_IMPL),
LintId::of(partialeq_to_none::PARTIALEQ_TO_NONE),
LintId::of(precedence::PRECEDENCE),
LintId::of(ptr::CMP_NULL),
LintId::of(ptr::INVALID_NULL_PTR_USAGE),
LintId::of(ptr::MUT_FROM_REF),
LintId::of(ptr::PTR_ARG),
LintId::of(ptr_offset_with_cast::PTR_OFFSET_WITH_CAST),
LintId::of(question_mark::QUESTION_MARK),
LintId::of(ranges::MANUAL_RANGE_CONTAINS),
LintId::of(ranges::REVERSED_EMPTY_RANGES),
LintId::of(rc_clone_in_vec_init::RC_CLONE_IN_VEC_INIT),
LintId::of(read_zero_byte_vec::READ_ZERO_BYTE_VEC),
LintId::of(redundant_clone::REDUNDANT_CLONE),
LintId::of(redundant_closure_call::REDUNDANT_CLOSURE_CALL),
LintId::of(redundant_field_names::REDUNDANT_FIELD_NAMES),
LintId::of(redundant_slicing::REDUNDANT_SLICING),
LintId::of(redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES),
LintId::of(reference::DEREF_ADDROF),
LintId::of(regex::INVALID_REGEX),
LintId::of(returns::LET_AND_RETURN),
LintId::of(returns::NEEDLESS_RETURN),
LintId::of(self_named_constructors::SELF_NAMED_CONSTRUCTORS),
LintId::of(serde_api::SERDE_API_MISUSE),
LintId::of(single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
LintId::of(size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT),
LintId::of(slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
LintId::of(strings::STRING_FROM_UTF8_AS_BYTES),
LintId::of(strings::TRIM_SPLIT_WHITESPACE),
LintId::of(strlen_on_c_strings::STRLEN_ON_C_STRINGS),
LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
LintId::of(swap::ALMOST_SWAPPED),
LintId::of(swap::MANUAL_SWAP),
LintId::of(swap_ptr_to_ref::SWAP_PTR_TO_REF),
LintId::of(tabs_in_doc_comments::TABS_IN_DOC_COMMENTS),
LintId::of(temporary_assignment::TEMPORARY_ASSIGNMENT),
LintId::of(to_digit_is_some::TO_DIGIT_IS_SOME),
LintId::of(transmute::CROSSPOINTER_TRANSMUTE),
LintId::of(transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS),
LintId::of(transmute::TRANSMUTE_BYTES_TO_STR),
LintId::of(transmute::TRANSMUTE_FLOAT_TO_INT),
LintId::of(transmute::TRANSMUTE_INT_TO_BOOL),
LintId::of(transmute::TRANSMUTE_INT_TO_CHAR),
LintId::of(transmute::TRANSMUTE_INT_TO_FLOAT),
LintId::of(transmute::TRANSMUTE_NUM_TO_BYTES),
LintId::of(transmute::TRANSMUTE_PTR_TO_REF),
LintId::of(transmute::TRANSMUTING_NULL),
LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE),
LintId::of(transmute::USELESS_TRANSMUTE),
LintId::of(transmute::WRONG_TRANSMUTE),
LintId::of(types::BORROWED_BOX),
LintId::of(types::BOX_COLLECTION),
LintId::of(types::REDUNDANT_ALLOCATION),
LintId::of(types::TYPE_COMPLEXITY),
LintId::of(types::VEC_BOX),
LintId::of(unicode::INVISIBLE_CHARACTERS),
LintId::of(uninit_vec::UNINIT_VEC),
LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
LintId::of(unit_types::LET_UNIT_VALUE),
LintId::of(unit_types::UNIT_ARG),
LintId::of(unit_types::UNIT_CMP),
LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS),
LintId::of(unnamed_address::VTABLE_ADDRESS_COMPARISONS),
LintId::of(unnecessary_owned_empty_strings::UNNECESSARY_OWNED_EMPTY_STRINGS),
LintId::of(unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME),
LintId::of(unused_io_amount::UNUSED_IO_AMOUNT),
LintId::of(unused_unit::UNUSED_UNIT),
LintId::of(unwrap::PANICKING_UNWRAP),
LintId::of(unwrap::UNNECESSARY_UNWRAP),
LintId::of(upper_case_acronyms::UPPER_CASE_ACRONYMS),
LintId::of(useless_conversion::USELESS_CONVERSION),
LintId::of(vec::USELESS_VEC),
LintId::of(vec_init_then_push::VEC_INIT_THEN_PUSH),
LintId::of(write::PRINTLN_EMPTY_STRING),
LintId::of(write::PRINT_LITERAL),
LintId::of(write::PRINT_WITH_NEWLINE),
LintId::of(write::WRITELN_EMPTY_STRING),
LintId::of(write::WRITE_LITERAL),
LintId::of(write::WRITE_WITH_NEWLINE),
LintId::of(zero_div_zero::ZERO_DIVIDED_BY_ZERO),
])

View file

@ -1,11 +0,0 @@
// This file was generated by `cargo dev update_lints`.
// Use that command to update this file and do not edit by hand.
// Manual edits will be overwritten.
store.register_group(true, "clippy::cargo", Some("clippy_cargo"), vec![
LintId::of(cargo::CARGO_COMMON_METADATA),
LintId::of(cargo::MULTIPLE_CRATE_VERSIONS),
LintId::of(cargo::NEGATIVE_FEATURE_NAMES),
LintId::of(cargo::REDUNDANT_FEATURE_NAMES),
LintId::of(cargo::WILDCARD_DEPENDENCIES),
])

View file

@ -1,111 +0,0 @@
// This file was generated by `cargo dev update_lints`.
// Use that command to update this file and do not edit by hand.
// Manual edits will be overwritten.
store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec![
LintId::of(attrs::DEPRECATED_CFG_ATTR),
LintId::of(booleans::NONMINIMAL_BOOL),
LintId::of(borrow_deref_ref::BORROW_DEREF_REF),
LintId::of(casts::CHAR_LIT_AS_U8),
LintId::of(casts::UNNECESSARY_CAST),
LintId::of(dereference::EXPLICIT_AUTO_DEREF),
LintId::of(derivable_impls::DERIVABLE_IMPLS),
LintId::of(double_parens::DOUBLE_PARENS),
LintId::of(explicit_write::EXPLICIT_WRITE),
LintId::of(format::USELESS_FORMAT),
LintId::of(format_args::UNUSED_FORMAT_SPECS),
LintId::of(functions::TOO_MANY_ARGUMENTS),
LintId::of(int_plus_one::INT_PLUS_ONE),
LintId::of(lifetimes::EXTRA_UNUSED_LIFETIMES),
LintId::of(lifetimes::NEEDLESS_LIFETIMES),
LintId::of(loops::EXPLICIT_COUNTER_LOOP),
LintId::of(loops::MANUAL_FIND),
LintId::of(loops::MANUAL_FLATTEN),
LintId::of(loops::SINGLE_ELEMENT_LOOP),
LintId::of(loops::WHILE_LET_LOOP),
LintId::of(manual_clamp::MANUAL_CLAMP),
LintId::of(manual_rem_euclid::MANUAL_REM_EUCLID),
LintId::of(manual_strip::MANUAL_STRIP),
LintId::of(map_unit_fn::OPTION_MAP_UNIT_FN),
LintId::of(map_unit_fn::RESULT_MAP_UNIT_FN),
LintId::of(matches::MANUAL_FILTER),
LintId::of(matches::MANUAL_UNWRAP_OR),
LintId::of(matches::MATCH_AS_REF),
LintId::of(matches::MATCH_SINGLE_BINDING),
LintId::of(matches::NEEDLESS_MATCH),
LintId::of(matches::WILDCARD_IN_OR_PATTERNS),
LintId::of(methods::BIND_INSTEAD_OF_MAP),
LintId::of(methods::BYTES_COUNT_TO_LEN),
LintId::of(methods::CLONE_ON_COPY),
LintId::of(methods::FILTER_MAP_IDENTITY),
LintId::of(methods::FILTER_NEXT),
LintId::of(methods::FLAT_MAP_IDENTITY),
LintId::of(methods::GET_LAST_WITH_LEN),
LintId::of(methods::INSPECT_FOR_EACH),
LintId::of(methods::ITER_COUNT),
LintId::of(methods::ITER_KV_MAP),
LintId::of(methods::MANUAL_FILTER_MAP),
LintId::of(methods::MANUAL_FIND_MAP),
LintId::of(methods::MANUAL_SPLIT_ONCE),
LintId::of(methods::MAP_FLATTEN),
LintId::of(methods::MAP_IDENTITY),
LintId::of(methods::NEEDLESS_OPTION_AS_DEREF),
LintId::of(methods::NEEDLESS_OPTION_TAKE),
LintId::of(methods::NEEDLESS_SPLITN),
LintId::of(methods::OPTION_AS_REF_DEREF),
LintId::of(methods::OPTION_FILTER_MAP),
LintId::of(methods::OR_THEN_UNWRAP),
LintId::of(methods::RANGE_ZIP_WITH_LEN),
LintId::of(methods::REPEAT_ONCE),
LintId::of(methods::SEARCH_IS_SOME),
LintId::of(methods::SKIP_WHILE_NEXT),
LintId::of(methods::UNNECESSARY_FILTER_MAP),
LintId::of(methods::UNNECESSARY_FIND_MAP),
LintId::of(methods::UNNECESSARY_SORT_BY),
LintId::of(methods::USELESS_ASREF),
LintId::of(misc::SHORT_CIRCUIT_STATEMENT),
LintId::of(misc_early::UNNEEDED_WILDCARD_PATTERN),
LintId::of(misc_early::ZERO_PREFIXED_LITERAL),
LintId::of(mixed_read_write_in_expression::DIVERGING_SUB_EXPRESSION),
LintId::of(needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE),
LintId::of(needless_bool::BOOL_COMPARISON),
LintId::of(needless_bool::NEEDLESS_BOOL),
LintId::of(needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE),
LintId::of(needless_question_mark::NEEDLESS_QUESTION_MARK),
LintId::of(needless_update::NEEDLESS_UPDATE),
LintId::of(neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD),
LintId::of(no_effect::NO_EFFECT),
LintId::of(no_effect::UNNECESSARY_OPERATION),
LintId::of(only_used_in_recursion::ONLY_USED_IN_RECURSION),
LintId::of(operators::DOUBLE_COMPARISONS),
LintId::of(operators::DURATION_SUBSEC),
LintId::of(operators::IDENTITY_OP),
LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL),
LintId::of(partialeq_ne_impl::PARTIALEQ_NE_IMPL),
LintId::of(precedence::PRECEDENCE),
LintId::of(ptr_offset_with_cast::PTR_OFFSET_WITH_CAST),
LintId::of(redundant_closure_call::REDUNDANT_CLOSURE_CALL),
LintId::of(redundant_slicing::REDUNDANT_SLICING),
LintId::of(reference::DEREF_ADDROF),
LintId::of(strings::STRING_FROM_UTF8_AS_BYTES),
LintId::of(strlen_on_c_strings::STRLEN_ON_C_STRINGS),
LintId::of(swap::MANUAL_SWAP),
LintId::of(temporary_assignment::TEMPORARY_ASSIGNMENT),
LintId::of(transmute::CROSSPOINTER_TRANSMUTE),
LintId::of(transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS),
LintId::of(transmute::TRANSMUTE_BYTES_TO_STR),
LintId::of(transmute::TRANSMUTE_FLOAT_TO_INT),
LintId::of(transmute::TRANSMUTE_INT_TO_BOOL),
LintId::of(transmute::TRANSMUTE_INT_TO_CHAR),
LintId::of(transmute::TRANSMUTE_INT_TO_FLOAT),
LintId::of(transmute::TRANSMUTE_NUM_TO_BYTES),
LintId::of(transmute::TRANSMUTE_PTR_TO_REF),
LintId::of(transmute::USELESS_TRANSMUTE),
LintId::of(types::BORROWED_BOX),
LintId::of(types::TYPE_COMPLEXITY),
LintId::of(types::VEC_BOX),
LintId::of(unit_types::UNIT_ARG),
LintId::of(unwrap::UNNECESSARY_UNWRAP),
LintId::of(useless_conversion::USELESS_CONVERSION),
LintId::of(zero_div_zero::ZERO_DIVIDED_BY_ZERO),
])

View file

@ -1,78 +0,0 @@
// This file was generated by `cargo dev update_lints`.
// Use that command to update this file and do not edit by hand.
// Manual edits will be overwritten.
store.register_group(true, "clippy::correctness", Some("clippy_correctness"), vec![
LintId::of(approx_const::APPROX_CONSTANT),
LintId::of(async_yields_async::ASYNC_YIELDS_ASYNC),
LintId::of(attrs::DEPRECATED_SEMVER),
LintId::of(attrs::MISMATCHED_TARGET_OS),
LintId::of(attrs::USELESS_ATTRIBUTE),
LintId::of(booleans::OVERLY_COMPLEX_BOOL_EXPR),
LintId::of(casts::CAST_REF_TO_MUT),
LintId::of(casts::CAST_SLICE_DIFFERENT_SIZES),
LintId::of(copies::IFS_SAME_COND),
LintId::of(copies::IF_SAME_THEN_ELSE),
LintId::of(derive::DERIVE_HASH_XOR_EQ),
LintId::of(derive::DERIVE_ORD_XOR_PARTIAL_ORD),
LintId::of(drop_forget_ref::DROP_COPY),
LintId::of(drop_forget_ref::DROP_REF),
LintId::of(drop_forget_ref::FORGET_COPY),
LintId::of(drop_forget_ref::FORGET_REF),
LintId::of(drop_forget_ref::UNDROPPED_MANUALLY_DROPS),
LintId::of(enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT),
LintId::of(format_impl::RECURSIVE_FORMAT_IMPL),
LintId::of(formatting::POSSIBLE_MISSING_COMMA),
LintId::of(functions::NOT_UNSAFE_PTR_ARG_DEREF),
LintId::of(if_let_mutex::IF_LET_MUTEX),
LintId::of(indexing_slicing::OUT_OF_BOUNDS_INDEXING),
LintId::of(infinite_iter::INFINITE_ITER),
LintId::of(inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY),
LintId::of(inline_fn_without_body::INLINE_FN_WITHOUT_BODY),
LintId::of(invalid_utf8_in_unchecked::INVALID_UTF8_IN_UNCHECKED),
LintId::of(let_underscore::LET_UNDERSCORE_LOCK),
LintId::of(literal_representation::MISTYPED_LITERAL_SUFFIXES),
LintId::of(loops::ITER_NEXT_LOOP),
LintId::of(loops::NEVER_LOOP),
LintId::of(loops::WHILE_IMMUTABLE_CONDITION),
LintId::of(matches::MATCH_STR_CASE_MISMATCH),
LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT),
LintId::of(methods::CLONE_DOUBLE_REF),
LintId::of(methods::ITERATOR_STEP_BY_ZERO),
LintId::of(methods::NONSENSICAL_OPEN_OPTIONS),
LintId::of(methods::SUSPICIOUS_SPLITN),
LintId::of(methods::UNINIT_ASSUMED_INIT),
LintId::of(methods::UNIT_HASH),
LintId::of(methods::VEC_RESIZE_TO_ZERO),
LintId::of(methods::ZST_OFFSET),
LintId::of(minmax::MIN_MAX),
LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS),
LintId::of(operators::ABSURD_EXTREME_COMPARISONS),
LintId::of(operators::BAD_BIT_MASK),
LintId::of(operators::CMP_NAN),
LintId::of(operators::EQ_OP),
LintId::of(operators::ERASING_OP),
LintId::of(operators::INEFFECTIVE_BIT_MASK),
LintId::of(operators::MODULO_ONE),
LintId::of(operators::SELF_ASSIGNMENT),
LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP),
LintId::of(ptr::INVALID_NULL_PTR_USAGE),
LintId::of(ptr::MUT_FROM_REF),
LintId::of(ranges::REVERSED_EMPTY_RANGES),
LintId::of(read_zero_byte_vec::READ_ZERO_BYTE_VEC),
LintId::of(regex::INVALID_REGEX),
LintId::of(serde_api::SERDE_API_MISUSE),
LintId::of(size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT),
LintId::of(swap::ALMOST_SWAPPED),
LintId::of(transmute::TRANSMUTING_NULL),
LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE),
LintId::of(transmute::WRONG_TRANSMUTE),
LintId::of(unicode::INVISIBLE_CHARACTERS),
LintId::of(uninit_vec::UNINIT_VEC),
LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
LintId::of(unit_types::UNIT_CMP),
LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS),
LintId::of(unnamed_address::VTABLE_ADDRESS_COMPARISONS),
LintId::of(unused_io_amount::UNUSED_IO_AMOUNT),
LintId::of(unwrap::PANICKING_UNWRAP),
])

View file

@ -1,22 +0,0 @@
// This file was generated by `cargo dev update_lints`.
// Use that command to update this file and do not edit by hand.
// Manual edits will be overwritten.
store.register_group(true, "clippy::internal", Some("clippy_internal"), vec![
LintId::of(utils::internal_lints::clippy_lints_internal::CLIPPY_LINTS_INTERNAL),
LintId::of(utils::internal_lints::collapsible_calls::COLLAPSIBLE_SPAN_LINT_CALLS),
LintId::of(utils::internal_lints::compiler_lint_functions::COMPILER_LINT_FUNCTIONS),
LintId::of(utils::internal_lints::if_chain_style::IF_CHAIN_STYLE),
LintId::of(utils::internal_lints::interning_defined_symbol::INTERNING_DEFINED_SYMBOL),
LintId::of(utils::internal_lints::interning_defined_symbol::UNNECESSARY_SYMBOL_STR),
LintId::of(utils::internal_lints::invalid_paths::INVALID_PATHS),
LintId::of(utils::internal_lints::lint_without_lint_pass::DEFAULT_DEPRECATION_REASON),
LintId::of(utils::internal_lints::lint_without_lint_pass::DEFAULT_LINT),
LintId::of(utils::internal_lints::lint_without_lint_pass::INVALID_CLIPPY_VERSION_ATTRIBUTE),
LintId::of(utils::internal_lints::lint_without_lint_pass::LINT_WITHOUT_LINT_PASS),
LintId::of(utils::internal_lints::lint_without_lint_pass::MISSING_CLIPPY_VERSION_ATTRIBUTE),
LintId::of(utils::internal_lints::msrv_attr_impl::MISSING_MSRV_ATTR_IMPL),
LintId::of(utils::internal_lints::outer_expn_data_pass::OUTER_EXPN_EXPN_DATA),
LintId::of(utils::internal_lints::produce_ice::PRODUCE_ICE),
LintId::of(utils::internal_lints::unnecessary_def_path::UNNECESSARY_DEF_PATH),
])

View file

@ -1,620 +0,0 @@
// This file was generated by `cargo dev update_lints`.
// Use that command to update this file and do not edit by hand.
// Manual edits will be overwritten.
store.register_lints(&[
#[cfg(feature = "internal")]
utils::internal_lints::clippy_lints_internal::CLIPPY_LINTS_INTERNAL,
#[cfg(feature = "internal")]
utils::internal_lints::collapsible_calls::COLLAPSIBLE_SPAN_LINT_CALLS,
#[cfg(feature = "internal")]
utils::internal_lints::compiler_lint_functions::COMPILER_LINT_FUNCTIONS,
#[cfg(feature = "internal")]
utils::internal_lints::if_chain_style::IF_CHAIN_STYLE,
#[cfg(feature = "internal")]
utils::internal_lints::interning_defined_symbol::INTERNING_DEFINED_SYMBOL,
#[cfg(feature = "internal")]
utils::internal_lints::interning_defined_symbol::UNNECESSARY_SYMBOL_STR,
#[cfg(feature = "internal")]
utils::internal_lints::invalid_paths::INVALID_PATHS,
#[cfg(feature = "internal")]
utils::internal_lints::lint_without_lint_pass::DEFAULT_DEPRECATION_REASON,
#[cfg(feature = "internal")]
utils::internal_lints::lint_without_lint_pass::DEFAULT_LINT,
#[cfg(feature = "internal")]
utils::internal_lints::lint_without_lint_pass::INVALID_CLIPPY_VERSION_ATTRIBUTE,
#[cfg(feature = "internal")]
utils::internal_lints::lint_without_lint_pass::LINT_WITHOUT_LINT_PASS,
#[cfg(feature = "internal")]
utils::internal_lints::lint_without_lint_pass::MISSING_CLIPPY_VERSION_ATTRIBUTE,
#[cfg(feature = "internal")]
utils::internal_lints::msrv_attr_impl::MISSING_MSRV_ATTR_IMPL,
#[cfg(feature = "internal")]
utils::internal_lints::outer_expn_data_pass::OUTER_EXPN_EXPN_DATA,
#[cfg(feature = "internal")]
utils::internal_lints::produce_ice::PRODUCE_ICE,
#[cfg(feature = "internal")]
utils::internal_lints::unnecessary_def_path::UNNECESSARY_DEF_PATH,
almost_complete_letter_range::ALMOST_COMPLETE_LETTER_RANGE,
approx_const::APPROX_CONSTANT,
as_conversions::AS_CONVERSIONS,
asm_syntax::INLINE_ASM_X86_ATT_SYNTAX,
asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX,
assertions_on_constants::ASSERTIONS_ON_CONSTANTS,
assertions_on_result_states::ASSERTIONS_ON_RESULT_STATES,
async_yields_async::ASYNC_YIELDS_ASYNC,
attrs::ALLOW_ATTRIBUTES_WITHOUT_REASON,
attrs::BLANKET_CLIPPY_RESTRICTION_LINTS,
attrs::DEPRECATED_CFG_ATTR,
attrs::DEPRECATED_SEMVER,
attrs::EMPTY_LINE_AFTER_OUTER_ATTR,
attrs::INLINE_ALWAYS,
attrs::MISMATCHED_TARGET_OS,
attrs::USELESS_ATTRIBUTE,
await_holding_invalid::AWAIT_HOLDING_INVALID_TYPE,
await_holding_invalid::AWAIT_HOLDING_LOCK,
await_holding_invalid::AWAIT_HOLDING_REFCELL_REF,
blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS,
bool_assert_comparison::BOOL_ASSERT_COMPARISON,
bool_to_int_with_if::BOOL_TO_INT_WITH_IF,
booleans::NONMINIMAL_BOOL,
booleans::OVERLY_COMPLEX_BOOL_EXPR,
borrow_deref_ref::BORROW_DEREF_REF,
box_default::BOX_DEFAULT,
cargo::CARGO_COMMON_METADATA,
cargo::MULTIPLE_CRATE_VERSIONS,
cargo::NEGATIVE_FEATURE_NAMES,
cargo::REDUNDANT_FEATURE_NAMES,
cargo::WILDCARD_DEPENDENCIES,
casts::AS_PTR_CAST_MUT,
casts::AS_UNDERSCORE,
casts::BORROW_AS_PTR,
casts::CAST_ABS_TO_UNSIGNED,
casts::CAST_ENUM_CONSTRUCTOR,
casts::CAST_ENUM_TRUNCATION,
casts::CAST_LOSSLESS,
casts::CAST_NAN_TO_INT,
casts::CAST_POSSIBLE_TRUNCATION,
casts::CAST_POSSIBLE_WRAP,
casts::CAST_PRECISION_LOSS,
casts::CAST_PTR_ALIGNMENT,
casts::CAST_REF_TO_MUT,
casts::CAST_SIGN_LOSS,
casts::CAST_SLICE_DIFFERENT_SIZES,
casts::CAST_SLICE_FROM_RAW_PARTS,
casts::CHAR_LIT_AS_U8,
casts::FN_TO_NUMERIC_CAST,
casts::FN_TO_NUMERIC_CAST_ANY,
casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
casts::PTR_AS_PTR,
casts::UNNECESSARY_CAST,
checked_conversions::CHECKED_CONVERSIONS,
cognitive_complexity::COGNITIVE_COMPLEXITY,
collapsible_if::COLLAPSIBLE_ELSE_IF,
collapsible_if::COLLAPSIBLE_IF,
comparison_chain::COMPARISON_CHAIN,
copies::BRANCHES_SHARING_CODE,
copies::IFS_SAME_COND,
copies::IF_SAME_THEN_ELSE,
copies::SAME_FUNCTIONS_IN_IF_CONDITION,
copy_iterator::COPY_ITERATOR,
crate_in_macro_def::CRATE_IN_MACRO_DEF,
create_dir::CREATE_DIR,
dbg_macro::DBG_MACRO,
default::DEFAULT_TRAIT_ACCESS,
default::FIELD_REASSIGN_WITH_DEFAULT,
default_instead_of_iter_empty::DEFAULT_INSTEAD_OF_ITER_EMPTY,
default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK,
default_union_representation::DEFAULT_UNION_REPRESENTATION,
dereference::EXPLICIT_AUTO_DEREF,
dereference::EXPLICIT_DEREF_METHODS,
dereference::NEEDLESS_BORROW,
dereference::REF_BINDING_TO_REFERENCE,
derivable_impls::DERIVABLE_IMPLS,
derive::DERIVE_HASH_XOR_EQ,
derive::DERIVE_ORD_XOR_PARTIAL_ORD,
derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ,
derive::EXPL_IMPL_CLONE_ON_COPY,
derive::UNSAFE_DERIVE_DESERIALIZE,
disallowed_macros::DISALLOWED_MACROS,
disallowed_methods::DISALLOWED_METHODS,
disallowed_names::DISALLOWED_NAMES,
disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS,
disallowed_types::DISALLOWED_TYPES,
doc::DOC_LINK_WITH_QUOTES,
doc::DOC_MARKDOWN,
doc::MISSING_ERRORS_DOC,
doc::MISSING_PANICS_DOC,
doc::MISSING_SAFETY_DOC,
doc::NEEDLESS_DOCTEST_MAIN,
double_parens::DOUBLE_PARENS,
drop_forget_ref::DROP_COPY,
drop_forget_ref::DROP_NON_DROP,
drop_forget_ref::DROP_REF,
drop_forget_ref::FORGET_COPY,
drop_forget_ref::FORGET_NON_DROP,
drop_forget_ref::FORGET_REF,
drop_forget_ref::UNDROPPED_MANUALLY_DROPS,
duplicate_mod::DUPLICATE_MOD,
else_if_without_else::ELSE_IF_WITHOUT_ELSE,
empty_drop::EMPTY_DROP,
empty_enum::EMPTY_ENUM,
empty_structs_with_brackets::EMPTY_STRUCTS_WITH_BRACKETS,
entry::MAP_ENTRY,
enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT,
enum_variants::ENUM_VARIANT_NAMES,
enum_variants::MODULE_INCEPTION,
enum_variants::MODULE_NAME_REPETITIONS,
equatable_if_let::EQUATABLE_IF_LET,
escape::BOXED_LOCAL,
eta_reduction::REDUNDANT_CLOSURE,
eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS,
excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS,
excessive_bools::STRUCT_EXCESSIVE_BOOLS,
exhaustive_items::EXHAUSTIVE_ENUMS,
exhaustive_items::EXHAUSTIVE_STRUCTS,
exit::EXIT,
explicit_write::EXPLICIT_WRITE,
fallible_impl_from::FALLIBLE_IMPL_FROM,
float_literal::EXCESSIVE_PRECISION,
float_literal::LOSSY_FLOAT_LITERAL,
floating_point_arithmetic::IMPRECISE_FLOPS,
floating_point_arithmetic::SUBOPTIMAL_FLOPS,
format::USELESS_FORMAT,
format_args::FORMAT_IN_FORMAT_ARGS,
format_args::TO_STRING_IN_FORMAT_ARGS,
format_args::UNINLINED_FORMAT_ARGS,
format_args::UNUSED_FORMAT_SPECS,
format_impl::PRINT_IN_FORMAT_IMPL,
format_impl::RECURSIVE_FORMAT_IMPL,
format_push_string::FORMAT_PUSH_STRING,
formatting::POSSIBLE_MISSING_COMMA,
formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING,
formatting::SUSPICIOUS_ELSE_FORMATTING,
formatting::SUSPICIOUS_UNARY_OP_FORMATTING,
from_over_into::FROM_OVER_INTO,
from_str_radix_10::FROM_STR_RADIX_10,
functions::DOUBLE_MUST_USE,
functions::MUST_USE_CANDIDATE,
functions::MUST_USE_UNIT,
functions::NOT_UNSAFE_PTR_ARG_DEREF,
functions::RESULT_LARGE_ERR,
functions::RESULT_UNIT_ERR,
functions::TOO_MANY_ARGUMENTS,
functions::TOO_MANY_LINES,
future_not_send::FUTURE_NOT_SEND,
if_let_mutex::IF_LET_MUTEX,
if_not_else::IF_NOT_ELSE,
if_then_some_else_none::IF_THEN_SOME_ELSE_NONE,
implicit_hasher::IMPLICIT_HASHER,
implicit_return::IMPLICIT_RETURN,
implicit_saturating_add::IMPLICIT_SATURATING_ADD,
implicit_saturating_sub::IMPLICIT_SATURATING_SUB,
inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR,
index_refutable_slice::INDEX_REFUTABLE_SLICE,
indexing_slicing::INDEXING_SLICING,
indexing_slicing::OUT_OF_BOUNDS_INDEXING,
infinite_iter::INFINITE_ITER,
infinite_iter::MAYBE_INFINITE_ITER,
inherent_impl::MULTIPLE_INHERENT_IMPL,
inherent_to_string::INHERENT_TO_STRING,
inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY,
init_numbered_fields::INIT_NUMBERED_FIELDS,
inline_fn_without_body::INLINE_FN_WITHOUT_BODY,
int_plus_one::INT_PLUS_ONE,
invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS,
invalid_utf8_in_unchecked::INVALID_UTF8_IN_UNCHECKED,
items_after_statements::ITEMS_AFTER_STATEMENTS,
iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR,
large_const_arrays::LARGE_CONST_ARRAYS,
large_enum_variant::LARGE_ENUM_VARIANT,
large_include_file::LARGE_INCLUDE_FILE,
large_stack_arrays::LARGE_STACK_ARRAYS,
len_zero::COMPARISON_TO_EMPTY,
len_zero::LEN_WITHOUT_IS_EMPTY,
len_zero::LEN_ZERO,
let_if_seq::USELESS_LET_IF_SEQ,
let_underscore::LET_UNDERSCORE_DROP,
let_underscore::LET_UNDERSCORE_LOCK,
let_underscore::LET_UNDERSCORE_MUST_USE,
lifetimes::EXTRA_UNUSED_LIFETIMES,
lifetimes::NEEDLESS_LIFETIMES,
literal_representation::DECIMAL_LITERAL_REPRESENTATION,
literal_representation::INCONSISTENT_DIGIT_GROUPING,
literal_representation::LARGE_DIGIT_GROUPS,
literal_representation::MISTYPED_LITERAL_SUFFIXES,
literal_representation::UNREADABLE_LITERAL,
literal_representation::UNUSUAL_BYTE_GROUPINGS,
loops::EMPTY_LOOP,
loops::EXPLICIT_COUNTER_LOOP,
loops::EXPLICIT_INTO_ITER_LOOP,
loops::EXPLICIT_ITER_LOOP,
loops::FOR_KV_MAP,
loops::ITER_NEXT_LOOP,
loops::MANUAL_FIND,
loops::MANUAL_FLATTEN,
loops::MANUAL_MEMCPY,
loops::MISSING_SPIN_LOOP,
loops::MUT_RANGE_BOUND,
loops::NEEDLESS_COLLECT,
loops::NEEDLESS_RANGE_LOOP,
loops::NEVER_LOOP,
loops::SAME_ITEM_PUSH,
loops::SINGLE_ELEMENT_LOOP,
loops::WHILE_IMMUTABLE_CONDITION,
loops::WHILE_LET_LOOP,
loops::WHILE_LET_ON_ITERATOR,
macro_use::MACRO_USE_IMPORTS,
main_recursion::MAIN_RECURSION,
manual_assert::MANUAL_ASSERT,
manual_async_fn::MANUAL_ASYNC_FN,
manual_bits::MANUAL_BITS,
manual_clamp::MANUAL_CLAMP,
manual_instant_elapsed::MANUAL_INSTANT_ELAPSED,
manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE,
manual_rem_euclid::MANUAL_REM_EUCLID,
manual_retain::MANUAL_RETAIN,
manual_string_new::MANUAL_STRING_NEW,
manual_strip::MANUAL_STRIP,
map_unit_fn::OPTION_MAP_UNIT_FN,
map_unit_fn::RESULT_MAP_UNIT_FN,
match_result_ok::MATCH_RESULT_OK,
matches::COLLAPSIBLE_MATCH,
matches::INFALLIBLE_DESTRUCTURING_MATCH,
matches::MANUAL_FILTER,
matches::MANUAL_MAP,
matches::MANUAL_UNWRAP_OR,
matches::MATCH_AS_REF,
matches::MATCH_BOOL,
matches::MATCH_LIKE_MATCHES_MACRO,
matches::MATCH_ON_VEC_ITEMS,
matches::MATCH_OVERLAPPING_ARM,
matches::MATCH_REF_PATS,
matches::MATCH_SAME_ARMS,
matches::MATCH_SINGLE_BINDING,
matches::MATCH_STR_CASE_MISMATCH,
matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS,
matches::MATCH_WILD_ERR_ARM,
matches::NEEDLESS_MATCH,
matches::REDUNDANT_PATTERN_MATCHING,
matches::REST_PAT_IN_FULLY_BOUND_STRUCTS,
matches::SIGNIFICANT_DROP_IN_SCRUTINEE,
matches::SINGLE_MATCH,
matches::SINGLE_MATCH_ELSE,
matches::TRY_ERR,
matches::WILDCARD_ENUM_MATCH_ARM,
matches::WILDCARD_IN_OR_PATTERNS,
mem_forget::MEM_FORGET,
mem_replace::MEM_REPLACE_OPTION_WITH_NONE,
mem_replace::MEM_REPLACE_WITH_DEFAULT,
mem_replace::MEM_REPLACE_WITH_UNINIT,
methods::BIND_INSTEAD_OF_MAP,
methods::BYTES_COUNT_TO_LEN,
methods::BYTES_NTH,
methods::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
methods::CHARS_LAST_CMP,
methods::CHARS_NEXT_CMP,
methods::CLONED_INSTEAD_OF_COPIED,
methods::CLONE_DOUBLE_REF,
methods::CLONE_ON_COPY,
methods::CLONE_ON_REF_PTR,
methods::COLLAPSIBLE_STR_REPLACE,
methods::ERR_EXPECT,
methods::EXPECT_FUN_CALL,
methods::EXPECT_USED,
methods::EXTEND_WITH_DRAIN,
methods::FILETYPE_IS_FILE,
methods::FILTER_MAP_IDENTITY,
methods::FILTER_MAP_NEXT,
methods::FILTER_NEXT,
methods::FLAT_MAP_IDENTITY,
methods::FLAT_MAP_OPTION,
methods::FROM_ITER_INSTEAD_OF_COLLECT,
methods::GET_FIRST,
methods::GET_LAST_WITH_LEN,
methods::GET_UNWRAP,
methods::IMPLICIT_CLONE,
methods::INEFFICIENT_TO_STRING,
methods::INSPECT_FOR_EACH,
methods::INTO_ITER_ON_REF,
methods::IS_DIGIT_ASCII_RADIX,
methods::ITERATOR_STEP_BY_ZERO,
methods::ITER_CLONED_COLLECT,
methods::ITER_COUNT,
methods::ITER_KV_MAP,
methods::ITER_NEXT_SLICE,
methods::ITER_NTH,
methods::ITER_NTH_ZERO,
methods::ITER_ON_EMPTY_COLLECTIONS,
methods::ITER_ON_SINGLE_ITEMS,
methods::ITER_OVEREAGER_CLONED,
methods::ITER_SKIP_NEXT,
methods::ITER_WITH_DRAIN,
methods::MANUAL_FILTER_MAP,
methods::MANUAL_FIND_MAP,
methods::MANUAL_OK_OR,
methods::MANUAL_SATURATING_ARITHMETIC,
methods::MANUAL_SPLIT_ONCE,
methods::MANUAL_STR_REPEAT,
methods::MAP_CLONE,
methods::MAP_COLLECT_RESULT_UNIT,
methods::MAP_ERR_IGNORE,
methods::MAP_FLATTEN,
methods::MAP_IDENTITY,
methods::MAP_UNWRAP_OR,
methods::MUT_MUTEX_LOCK,
methods::NAIVE_BYTECOUNT,
methods::NEEDLESS_OPTION_AS_DEREF,
methods::NEEDLESS_OPTION_TAKE,
methods::NEEDLESS_SPLITN,
methods::NEW_RET_NO_SELF,
methods::NONSENSICAL_OPEN_OPTIONS,
methods::NO_EFFECT_REPLACE,
methods::OBFUSCATED_IF_ELSE,
methods::OK_EXPECT,
methods::OPTION_AS_REF_DEREF,
methods::OPTION_FILTER_MAP,
methods::OPTION_MAP_OR_NONE,
methods::OR_FUN_CALL,
methods::OR_THEN_UNWRAP,
methods::PATH_BUF_PUSH_OVERWRITE,
methods::RANGE_ZIP_WITH_LEN,
methods::REPEAT_ONCE,
methods::RESULT_MAP_OR_INTO_OPTION,
methods::SEARCH_IS_SOME,
methods::SHOULD_IMPLEMENT_TRAIT,
methods::SINGLE_CHAR_ADD_STR,
methods::SINGLE_CHAR_PATTERN,
methods::SKIP_WHILE_NEXT,
methods::STABLE_SORT_PRIMITIVE,
methods::STRING_EXTEND_CHARS,
methods::SUSPICIOUS_MAP,
methods::SUSPICIOUS_SPLITN,
methods::SUSPICIOUS_TO_OWNED,
methods::UNINIT_ASSUMED_INIT,
methods::UNIT_HASH,
methods::UNNECESSARY_FILTER_MAP,
methods::UNNECESSARY_FIND_MAP,
methods::UNNECESSARY_FOLD,
methods::UNNECESSARY_JOIN,
methods::UNNECESSARY_LAZY_EVALUATIONS,
methods::UNNECESSARY_SORT_BY,
methods::UNNECESSARY_TO_OWNED,
methods::UNWRAP_OR_ELSE_DEFAULT,
methods::UNWRAP_USED,
methods::USELESS_ASREF,
methods::VEC_RESIZE_TO_ZERO,
methods::VERBOSE_FILE_READS,
methods::WRONG_SELF_CONVENTION,
methods::ZST_OFFSET,
minmax::MIN_MAX,
misc::SHORT_CIRCUIT_STATEMENT,
misc::TOPLEVEL_REF_ARG,
misc::USED_UNDERSCORE_BINDING,
misc::ZERO_PTR,
misc_early::BUILTIN_TYPE_SHADOW,
misc_early::DOUBLE_NEG,
misc_early::DUPLICATE_UNDERSCORE_ARGUMENT,
misc_early::MIXED_CASE_HEX_LITERALS,
misc_early::REDUNDANT_PATTERN,
misc_early::SEPARATED_LITERAL_SUFFIX,
misc_early::UNNEEDED_FIELD_PATTERN,
misc_early::UNNEEDED_WILDCARD_PATTERN,
misc_early::UNSEPARATED_LITERAL_SUFFIX,
misc_early::ZERO_PREFIXED_LITERAL,
mismatching_type_param_order::MISMATCHING_TYPE_PARAM_ORDER,
missing_const_for_fn::MISSING_CONST_FOR_FN,
missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS,
missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES,
missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS,
missing_trait_methods::MISSING_TRAIT_METHODS,
mixed_read_write_in_expression::DIVERGING_SUB_EXPRESSION,
mixed_read_write_in_expression::MIXED_READ_WRITE_IN_EXPRESSION,
module_style::MOD_MODULE_FILES,
module_style::SELF_NAMED_MODULE_FILES,
multi_assignments::MULTI_ASSIGNMENTS,
mut_key::MUTABLE_KEY_TYPE,
mut_mut::MUT_MUT,
mut_reference::UNNECESSARY_MUT_PASSED,
mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL,
mutex_atomic::MUTEX_ATOMIC,
mutex_atomic::MUTEX_INTEGER,
needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE,
needless_bool::BOOL_COMPARISON,
needless_bool::NEEDLESS_BOOL,
needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE,
needless_continue::NEEDLESS_CONTINUE,
needless_for_each::NEEDLESS_FOR_EACH,
needless_late_init::NEEDLESS_LATE_INIT,
needless_parens_on_range_literals::NEEDLESS_PARENS_ON_RANGE_LITERALS,
needless_pass_by_value::NEEDLESS_PASS_BY_VALUE,
needless_question_mark::NEEDLESS_QUESTION_MARK,
needless_update::NEEDLESS_UPDATE,
neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD,
neg_multiply::NEG_MULTIPLY,
new_without_default::NEW_WITHOUT_DEFAULT,
no_effect::NO_EFFECT,
no_effect::NO_EFFECT_UNDERSCORE_BINDING,
no_effect::UNNECESSARY_OPERATION,
non_copy_const::BORROW_INTERIOR_MUTABLE_CONST,
non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST,
non_expressive_names::JUST_UNDERSCORES_AND_DIGITS,
non_expressive_names::MANY_SINGLE_CHAR_NAMES,
non_expressive_names::SIMILAR_NAMES,
non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS,
non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY,
nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES,
octal_escapes::OCTAL_ESCAPES,
only_used_in_recursion::ONLY_USED_IN_RECURSION,
operators::ABSURD_EXTREME_COMPARISONS,
operators::ARITHMETIC_SIDE_EFFECTS,
operators::ASSIGN_OP_PATTERN,
operators::BAD_BIT_MASK,
operators::CMP_NAN,
operators::CMP_OWNED,
operators::DOUBLE_COMPARISONS,
operators::DURATION_SUBSEC,
operators::EQ_OP,
operators::ERASING_OP,
operators::FLOAT_ARITHMETIC,
operators::FLOAT_CMP,
operators::FLOAT_CMP_CONST,
operators::FLOAT_EQUALITY_WITHOUT_ABS,
operators::IDENTITY_OP,
operators::INEFFECTIVE_BIT_MASK,
operators::INTEGER_ARITHMETIC,
operators::INTEGER_DIVISION,
operators::MISREFACTORED_ASSIGN_OP,
operators::MODULO_ARITHMETIC,
operators::MODULO_ONE,
operators::NEEDLESS_BITWISE_BOOL,
operators::OP_REF,
operators::PTR_EQ,
operators::SELF_ASSIGNMENT,
operators::VERBOSE_BIT_MASK,
option_env_unwrap::OPTION_ENV_UNWRAP,
option_if_let_else::OPTION_IF_LET_ELSE,
overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL,
panic_in_result_fn::PANIC_IN_RESULT_FN,
panic_unimplemented::PANIC,
panic_unimplemented::TODO,
panic_unimplemented::UNIMPLEMENTED,
panic_unimplemented::UNREACHABLE,
partial_pub_fields::PARTIAL_PUB_FIELDS,
partialeq_ne_impl::PARTIALEQ_NE_IMPL,
partialeq_to_none::PARTIALEQ_TO_NONE,
pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE,
pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF,
pattern_type_mismatch::PATTERN_TYPE_MISMATCH,
precedence::PRECEDENCE,
ptr::CMP_NULL,
ptr::INVALID_NULL_PTR_USAGE,
ptr::MUT_FROM_REF,
ptr::PTR_ARG,
ptr_offset_with_cast::PTR_OFFSET_WITH_CAST,
pub_use::PUB_USE,
question_mark::QUESTION_MARK,
ranges::MANUAL_RANGE_CONTAINS,
ranges::RANGE_MINUS_ONE,
ranges::RANGE_PLUS_ONE,
ranges::REVERSED_EMPTY_RANGES,
rc_clone_in_vec_init::RC_CLONE_IN_VEC_INIT,
read_zero_byte_vec::READ_ZERO_BYTE_VEC,
redundant_clone::REDUNDANT_CLONE,
redundant_closure_call::REDUNDANT_CLOSURE_CALL,
redundant_else::REDUNDANT_ELSE,
redundant_field_names::REDUNDANT_FIELD_NAMES,
redundant_pub_crate::REDUNDANT_PUB_CRATE,
redundant_slicing::DEREF_BY_SLICING,
redundant_slicing::REDUNDANT_SLICING,
redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES,
ref_option_ref::REF_OPTION_REF,
reference::DEREF_ADDROF,
regex::INVALID_REGEX,
regex::TRIVIAL_REGEX,
return_self_not_must_use::RETURN_SELF_NOT_MUST_USE,
returns::LET_AND_RETURN,
returns::NEEDLESS_RETURN,
same_name_method::SAME_NAME_METHOD,
self_named_constructors::SELF_NAMED_CONSTRUCTORS,
semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED,
serde_api::SERDE_API_MISUSE,
shadow::SHADOW_REUSE,
shadow::SHADOW_SAME,
shadow::SHADOW_UNRELATED,
single_char_lifetime_names::SINGLE_CHAR_LIFETIME_NAMES,
single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS,
size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT,
slow_vector_initialization::SLOW_VECTOR_INITIALIZATION,
std_instead_of_core::ALLOC_INSTEAD_OF_CORE,
std_instead_of_core::STD_INSTEAD_OF_ALLOC,
std_instead_of_core::STD_INSTEAD_OF_CORE,
strings::STRING_ADD,
strings::STRING_ADD_ASSIGN,
strings::STRING_FROM_UTF8_AS_BYTES,
strings::STRING_LIT_AS_BYTES,
strings::STRING_SLICE,
strings::STRING_TO_STRING,
strings::STR_TO_STRING,
strings::TRIM_SPLIT_WHITESPACE,
strlen_on_c_strings::STRLEN_ON_C_STRINGS,
suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS,
suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL,
suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL,
swap::ALMOST_SWAPPED,
swap::MANUAL_SWAP,
swap_ptr_to_ref::SWAP_PTR_TO_REF,
tabs_in_doc_comments::TABS_IN_DOC_COMMENTS,
temporary_assignment::TEMPORARY_ASSIGNMENT,
to_digit_is_some::TO_DIGIT_IS_SOME,
trailing_empty_array::TRAILING_EMPTY_ARRAY,
trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS,
trait_bounds::TYPE_REPETITION_IN_BOUNDS,
transmute::CROSSPOINTER_TRANSMUTE,
transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
transmute::TRANSMUTE_BYTES_TO_STR,
transmute::TRANSMUTE_FLOAT_TO_INT,
transmute::TRANSMUTE_INT_TO_BOOL,
transmute::TRANSMUTE_INT_TO_CHAR,
transmute::TRANSMUTE_INT_TO_FLOAT,
transmute::TRANSMUTE_NUM_TO_BYTES,
transmute::TRANSMUTE_PTR_TO_PTR,
transmute::TRANSMUTE_PTR_TO_REF,
transmute::TRANSMUTE_UNDEFINED_REPR,
transmute::TRANSMUTING_NULL,
transmute::UNSOUND_COLLECTION_TRANSMUTE,
transmute::USELESS_TRANSMUTE,
transmute::WRONG_TRANSMUTE,
types::BORROWED_BOX,
types::BOX_COLLECTION,
types::LINKEDLIST,
types::OPTION_OPTION,
types::RC_BUFFER,
types::RC_MUTEX,
types::REDUNDANT_ALLOCATION,
types::TYPE_COMPLEXITY,
types::VEC_BOX,
undocumented_unsafe_blocks::UNDOCUMENTED_UNSAFE_BLOCKS,
unicode::INVISIBLE_CHARACTERS,
unicode::NON_ASCII_LITERAL,
unicode::UNICODE_NOT_NFC,
uninit_vec::UNINIT_VEC,
unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD,
unit_types::LET_UNIT_VALUE,
unit_types::UNIT_ARG,
unit_types::UNIT_CMP,
unnamed_address::FN_ADDRESS_COMPARISONS,
unnamed_address::VTABLE_ADDRESS_COMPARISONS,
unnecessary_owned_empty_strings::UNNECESSARY_OWNED_EMPTY_STRINGS,
unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS,
unnecessary_wraps::UNNECESSARY_WRAPS,
unnested_or_patterns::UNNESTED_OR_PATTERNS,
unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME,
unused_async::UNUSED_ASYNC,
unused_io_amount::UNUSED_IO_AMOUNT,
unused_peekable::UNUSED_PEEKABLE,
unused_rounding::UNUSED_ROUNDING,
unused_self::UNUSED_SELF,
unused_unit::UNUSED_UNIT,
unwrap::PANICKING_UNWRAP,
unwrap::UNNECESSARY_UNWRAP,
unwrap_in_result::UNWRAP_IN_RESULT,
upper_case_acronyms::UPPER_CASE_ACRONYMS,
use_self::USE_SELF,
useless_conversion::USELESS_CONVERSION,
vec::USELESS_VEC,
vec_init_then_push::VEC_INIT_THEN_PUSH,
wildcard_imports::ENUM_GLOB_USE,
wildcard_imports::WILDCARD_IMPORTS,
write::PRINTLN_EMPTY_STRING,
write::PRINT_LITERAL,
write::PRINT_STDERR,
write::PRINT_STDOUT,
write::PRINT_WITH_NEWLINE,
write::USE_DEBUG,
write::WRITELN_EMPTY_STRING,
write::WRITE_LITERAL,
write::WRITE_WITH_NEWLINE,
zero_div_zero::ZERO_DIVIDED_BY_ZERO,
zero_sized_map_values::ZERO_SIZED_MAP_VALUES,
])

View file

@ -1,39 +0,0 @@
// This file was generated by `cargo dev update_lints`.
// Use that command to update this file and do not edit by hand.
// Manual edits will be overwritten.
store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![
LintId::of(attrs::EMPTY_LINE_AFTER_OUTER_ATTR),
LintId::of(casts::AS_PTR_CAST_MUT),
LintId::of(cognitive_complexity::COGNITIVE_COMPLEXITY),
LintId::of(copies::BRANCHES_SHARING_CODE),
LintId::of(derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ),
LintId::of(equatable_if_let::EQUATABLE_IF_LET),
LintId::of(fallible_impl_from::FALLIBLE_IMPL_FROM),
LintId::of(floating_point_arithmetic::IMPRECISE_FLOPS),
LintId::of(floating_point_arithmetic::SUBOPTIMAL_FLOPS),
LintId::of(future_not_send::FUTURE_NOT_SEND),
LintId::of(index_refutable_slice::INDEX_REFUTABLE_SLICE),
LintId::of(let_if_seq::USELESS_LET_IF_SEQ),
LintId::of(matches::SIGNIFICANT_DROP_IN_SCRUTINEE),
LintId::of(methods::ITER_ON_EMPTY_COLLECTIONS),
LintId::of(methods::ITER_ON_SINGLE_ITEMS),
LintId::of(methods::ITER_WITH_DRAIN),
LintId::of(methods::PATH_BUF_PUSH_OVERWRITE),
LintId::of(missing_const_for_fn::MISSING_CONST_FOR_FN),
LintId::of(mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL),
LintId::of(mutex_atomic::MUTEX_ATOMIC),
LintId::of(mutex_atomic::MUTEX_INTEGER),
LintId::of(non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY),
LintId::of(nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES),
LintId::of(option_if_let_else::OPTION_IF_LET_ELSE),
LintId::of(redundant_pub_crate::REDUNDANT_PUB_CRATE),
LintId::of(regex::TRIVIAL_REGEX),
LintId::of(strings::STRING_LIT_AS_BYTES),
LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS),
LintId::of(trailing_empty_array::TRAILING_EMPTY_ARRAY),
LintId::of(transmute::TRANSMUTE_UNDEFINED_REPR),
LintId::of(unused_peekable::UNUSED_PEEKABLE),
LintId::of(unused_rounding::UNUSED_ROUNDING),
LintId::of(use_self::USE_SELF),
])

View file

@ -1,104 +0,0 @@
// This file was generated by `cargo dev update_lints`.
// Use that command to update this file and do not edit by hand.
// Manual edits will be overwritten.
store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
LintId::of(attrs::INLINE_ALWAYS),
LintId::of(casts::BORROW_AS_PTR),
LintId::of(casts::CAST_LOSSLESS),
LintId::of(casts::CAST_POSSIBLE_TRUNCATION),
LintId::of(casts::CAST_POSSIBLE_WRAP),
LintId::of(casts::CAST_PRECISION_LOSS),
LintId::of(casts::CAST_PTR_ALIGNMENT),
LintId::of(casts::CAST_SIGN_LOSS),
LintId::of(casts::PTR_AS_PTR),
LintId::of(checked_conversions::CHECKED_CONVERSIONS),
LintId::of(copies::SAME_FUNCTIONS_IN_IF_CONDITION),
LintId::of(copy_iterator::COPY_ITERATOR),
LintId::of(default::DEFAULT_TRAIT_ACCESS),
LintId::of(dereference::EXPLICIT_DEREF_METHODS),
LintId::of(dereference::REF_BINDING_TO_REFERENCE),
LintId::of(derive::EXPL_IMPL_CLONE_ON_COPY),
LintId::of(derive::UNSAFE_DERIVE_DESERIALIZE),
LintId::of(doc::DOC_LINK_WITH_QUOTES),
LintId::of(doc::DOC_MARKDOWN),
LintId::of(doc::MISSING_ERRORS_DOC),
LintId::of(doc::MISSING_PANICS_DOC),
LintId::of(empty_enum::EMPTY_ENUM),
LintId::of(enum_variants::MODULE_NAME_REPETITIONS),
LintId::of(eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS),
LintId::of(excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS),
LintId::of(excessive_bools::STRUCT_EXCESSIVE_BOOLS),
LintId::of(format_args::UNINLINED_FORMAT_ARGS),
LintId::of(functions::MUST_USE_CANDIDATE),
LintId::of(functions::TOO_MANY_LINES),
LintId::of(if_not_else::IF_NOT_ELSE),
LintId::of(implicit_hasher::IMPLICIT_HASHER),
LintId::of(inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR),
LintId::of(infinite_iter::MAYBE_INFINITE_ITER),
LintId::of(invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS),
LintId::of(items_after_statements::ITEMS_AFTER_STATEMENTS),
LintId::of(iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR),
LintId::of(large_stack_arrays::LARGE_STACK_ARRAYS),
LintId::of(let_underscore::LET_UNDERSCORE_DROP),
LintId::of(literal_representation::LARGE_DIGIT_GROUPS),
LintId::of(literal_representation::UNREADABLE_LITERAL),
LintId::of(loops::EXPLICIT_INTO_ITER_LOOP),
LintId::of(loops::EXPLICIT_ITER_LOOP),
LintId::of(macro_use::MACRO_USE_IMPORTS),
LintId::of(manual_assert::MANUAL_ASSERT),
LintId::of(manual_instant_elapsed::MANUAL_INSTANT_ELAPSED),
LintId::of(manual_string_new::MANUAL_STRING_NEW),
LintId::of(matches::MATCH_BOOL),
LintId::of(matches::MATCH_ON_VEC_ITEMS),
LintId::of(matches::MATCH_SAME_ARMS),
LintId::of(matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS),
LintId::of(matches::MATCH_WILD_ERR_ARM),
LintId::of(matches::SINGLE_MATCH_ELSE),
LintId::of(methods::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS),
LintId::of(methods::CLONED_INSTEAD_OF_COPIED),
LintId::of(methods::FILTER_MAP_NEXT),
LintId::of(methods::FLAT_MAP_OPTION),
LintId::of(methods::FROM_ITER_INSTEAD_OF_COLLECT),
LintId::of(methods::IMPLICIT_CLONE),
LintId::of(methods::INEFFICIENT_TO_STRING),
LintId::of(methods::MANUAL_OK_OR),
LintId::of(methods::MAP_UNWRAP_OR),
LintId::of(methods::NAIVE_BYTECOUNT),
LintId::of(methods::STABLE_SORT_PRIMITIVE),
LintId::of(methods::UNNECESSARY_JOIN),
LintId::of(misc::USED_UNDERSCORE_BINDING),
LintId::of(mismatching_type_param_order::MISMATCHING_TYPE_PARAM_ORDER),
LintId::of(mut_mut::MUT_MUT),
LintId::of(needless_continue::NEEDLESS_CONTINUE),
LintId::of(needless_for_each::NEEDLESS_FOR_EACH),
LintId::of(needless_pass_by_value::NEEDLESS_PASS_BY_VALUE),
LintId::of(no_effect::NO_EFFECT_UNDERSCORE_BINDING),
LintId::of(non_expressive_names::MANY_SINGLE_CHAR_NAMES),
LintId::of(non_expressive_names::SIMILAR_NAMES),
LintId::of(operators::FLOAT_CMP),
LintId::of(operators::NEEDLESS_BITWISE_BOOL),
LintId::of(operators::VERBOSE_BIT_MASK),
LintId::of(pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE),
LintId::of(pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF),
LintId::of(ranges::RANGE_MINUS_ONE),
LintId::of(ranges::RANGE_PLUS_ONE),
LintId::of(redundant_else::REDUNDANT_ELSE),
LintId::of(ref_option_ref::REF_OPTION_REF),
LintId::of(return_self_not_must_use::RETURN_SELF_NOT_MUST_USE),
LintId::of(semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED),
LintId::of(strings::STRING_ADD_ASSIGN),
LintId::of(trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS),
LintId::of(trait_bounds::TYPE_REPETITION_IN_BOUNDS),
LintId::of(transmute::TRANSMUTE_PTR_TO_PTR),
LintId::of(types::LINKEDLIST),
LintId::of(types::OPTION_OPTION),
LintId::of(unicode::UNICODE_NOT_NFC),
LintId::of(unnecessary_wraps::UNNECESSARY_WRAPS),
LintId::of(unnested_or_patterns::UNNESTED_OR_PATTERNS),
LintId::of(unused_async::UNUSED_ASYNC),
LintId::of(unused_self::UNUSED_SELF),
LintId::of(wildcard_imports::ENUM_GLOB_USE),
LintId::of(wildcard_imports::WILDCARD_IMPORTS),
LintId::of(zero_sized_map_values::ZERO_SIZED_MAP_VALUES),
])

View file

@ -1,34 +0,0 @@
// This file was generated by `cargo dev update_lints`.
// Use that command to update this file and do not edit by hand.
// Manual edits will be overwritten.
store.register_group(true, "clippy::perf", Some("clippy_perf"), vec![
LintId::of(box_default::BOX_DEFAULT),
LintId::of(entry::MAP_ENTRY),
LintId::of(escape::BOXED_LOCAL),
LintId::of(format_args::FORMAT_IN_FORMAT_ARGS),
LintId::of(format_args::TO_STRING_IN_FORMAT_ARGS),
LintId::of(functions::RESULT_LARGE_ERR),
LintId::of(large_const_arrays::LARGE_CONST_ARRAYS),
LintId::of(large_enum_variant::LARGE_ENUM_VARIANT),
LintId::of(loops::MANUAL_MEMCPY),
LintId::of(loops::MISSING_SPIN_LOOP),
LintId::of(loops::NEEDLESS_COLLECT),
LintId::of(manual_retain::MANUAL_RETAIN),
LintId::of(methods::COLLAPSIBLE_STR_REPLACE),
LintId::of(methods::EXPECT_FUN_CALL),
LintId::of(methods::EXTEND_WITH_DRAIN),
LintId::of(methods::ITER_NTH),
LintId::of(methods::ITER_OVEREAGER_CLONED),
LintId::of(methods::MANUAL_STR_REPEAT),
LintId::of(methods::OR_FUN_CALL),
LintId::of(methods::SINGLE_CHAR_PATTERN),
LintId::of(methods::UNNECESSARY_TO_OWNED),
LintId::of(operators::CMP_OWNED),
LintId::of(redundant_clone::REDUNDANT_CLONE),
LintId::of(slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
LintId::of(types::BOX_COLLECTION),
LintId::of(types::REDUNDANT_ALLOCATION),
LintId::of(vec::USELESS_VEC),
LintId::of(vec_init_then_push::VEC_INIT_THEN_PUSH),
])

View file

@ -1,90 +0,0 @@
// This file was generated by `cargo dev update_lints`.
// Use that command to update this file and do not edit by hand.
// Manual edits will be overwritten.
store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
LintId::of(as_conversions::AS_CONVERSIONS),
LintId::of(asm_syntax::INLINE_ASM_X86_ATT_SYNTAX),
LintId::of(asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX),
LintId::of(assertions_on_result_states::ASSERTIONS_ON_RESULT_STATES),
LintId::of(attrs::ALLOW_ATTRIBUTES_WITHOUT_REASON),
LintId::of(casts::AS_UNDERSCORE),
LintId::of(casts::FN_TO_NUMERIC_CAST_ANY),
LintId::of(create_dir::CREATE_DIR),
LintId::of(dbg_macro::DBG_MACRO),
LintId::of(default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK),
LintId::of(default_union_representation::DEFAULT_UNION_REPRESENTATION),
LintId::of(disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS),
LintId::of(else_if_without_else::ELSE_IF_WITHOUT_ELSE),
LintId::of(empty_drop::EMPTY_DROP),
LintId::of(empty_structs_with_brackets::EMPTY_STRUCTS_WITH_BRACKETS),
LintId::of(exhaustive_items::EXHAUSTIVE_ENUMS),
LintId::of(exhaustive_items::EXHAUSTIVE_STRUCTS),
LintId::of(exit::EXIT),
LintId::of(float_literal::LOSSY_FLOAT_LITERAL),
LintId::of(format_push_string::FORMAT_PUSH_STRING),
LintId::of(if_then_some_else_none::IF_THEN_SOME_ELSE_NONE),
LintId::of(implicit_return::IMPLICIT_RETURN),
LintId::of(indexing_slicing::INDEXING_SLICING),
LintId::of(inherent_impl::MULTIPLE_INHERENT_IMPL),
LintId::of(large_include_file::LARGE_INCLUDE_FILE),
LintId::of(let_underscore::LET_UNDERSCORE_MUST_USE),
LintId::of(literal_representation::DECIMAL_LITERAL_REPRESENTATION),
LintId::of(matches::REST_PAT_IN_FULLY_BOUND_STRUCTS),
LintId::of(matches::TRY_ERR),
LintId::of(matches::WILDCARD_ENUM_MATCH_ARM),
LintId::of(mem_forget::MEM_FORGET),
LintId::of(methods::CLONE_ON_REF_PTR),
LintId::of(methods::EXPECT_USED),
LintId::of(methods::FILETYPE_IS_FILE),
LintId::of(methods::GET_UNWRAP),
LintId::of(methods::MAP_ERR_IGNORE),
LintId::of(methods::UNWRAP_USED),
LintId::of(methods::VERBOSE_FILE_READS),
LintId::of(misc_early::SEPARATED_LITERAL_SUFFIX),
LintId::of(misc_early::UNNEEDED_FIELD_PATTERN),
LintId::of(misc_early::UNSEPARATED_LITERAL_SUFFIX),
LintId::of(missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS),
LintId::of(missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES),
LintId::of(missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS),
LintId::of(missing_trait_methods::MISSING_TRAIT_METHODS),
LintId::of(mixed_read_write_in_expression::MIXED_READ_WRITE_IN_EXPRESSION),
LintId::of(module_style::MOD_MODULE_FILES),
LintId::of(module_style::SELF_NAMED_MODULE_FILES),
LintId::of(operators::ARITHMETIC_SIDE_EFFECTS),
LintId::of(operators::FLOAT_ARITHMETIC),
LintId::of(operators::FLOAT_CMP_CONST),
LintId::of(operators::INTEGER_ARITHMETIC),
LintId::of(operators::INTEGER_DIVISION),
LintId::of(operators::MODULO_ARITHMETIC),
LintId::of(panic_in_result_fn::PANIC_IN_RESULT_FN),
LintId::of(panic_unimplemented::PANIC),
LintId::of(panic_unimplemented::TODO),
LintId::of(panic_unimplemented::UNIMPLEMENTED),
LintId::of(panic_unimplemented::UNREACHABLE),
LintId::of(partial_pub_fields::PARTIAL_PUB_FIELDS),
LintId::of(pattern_type_mismatch::PATTERN_TYPE_MISMATCH),
LintId::of(pub_use::PUB_USE),
LintId::of(redundant_slicing::DEREF_BY_SLICING),
LintId::of(same_name_method::SAME_NAME_METHOD),
LintId::of(shadow::SHADOW_REUSE),
LintId::of(shadow::SHADOW_SAME),
LintId::of(shadow::SHADOW_UNRELATED),
LintId::of(single_char_lifetime_names::SINGLE_CHAR_LIFETIME_NAMES),
LintId::of(std_instead_of_core::ALLOC_INSTEAD_OF_CORE),
LintId::of(std_instead_of_core::STD_INSTEAD_OF_ALLOC),
LintId::of(std_instead_of_core::STD_INSTEAD_OF_CORE),
LintId::of(strings::STRING_ADD),
LintId::of(strings::STRING_SLICE),
LintId::of(strings::STRING_TO_STRING),
LintId::of(strings::STR_TO_STRING),
LintId::of(types::RC_BUFFER),
LintId::of(types::RC_MUTEX),
LintId::of(undocumented_unsafe_blocks::UNDOCUMENTED_UNSAFE_BLOCKS),
LintId::of(unicode::NON_ASCII_LITERAL),
LintId::of(unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS),
LintId::of(unwrap_in_result::UNWRAP_IN_RESULT),
LintId::of(write::PRINT_STDERR),
LintId::of(write::PRINT_STDOUT),
LintId::of(write::USE_DEBUG),
])

View file

@ -1,131 +0,0 @@
// This file was generated by `cargo dev update_lints`.
// Use that command to update this file and do not edit by hand.
// Manual edits will be overwritten.
store.register_group(true, "clippy::style", Some("clippy_style"), vec![
LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS),
LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS),
LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON),
LintId::of(bool_to_int_with_if::BOOL_TO_INT_WITH_IF),
LintId::of(casts::FN_TO_NUMERIC_CAST),
LintId::of(casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION),
LintId::of(collapsible_if::COLLAPSIBLE_ELSE_IF),
LintId::of(collapsible_if::COLLAPSIBLE_IF),
LintId::of(comparison_chain::COMPARISON_CHAIN),
LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT),
LintId::of(default_instead_of_iter_empty::DEFAULT_INSTEAD_OF_ITER_EMPTY),
LintId::of(dereference::NEEDLESS_BORROW),
LintId::of(disallowed_macros::DISALLOWED_MACROS),
LintId::of(disallowed_methods::DISALLOWED_METHODS),
LintId::of(disallowed_names::DISALLOWED_NAMES),
LintId::of(disallowed_types::DISALLOWED_TYPES),
LintId::of(doc::MISSING_SAFETY_DOC),
LintId::of(doc::NEEDLESS_DOCTEST_MAIN),
LintId::of(enum_variants::ENUM_VARIANT_NAMES),
LintId::of(enum_variants::MODULE_INCEPTION),
LintId::of(eta_reduction::REDUNDANT_CLOSURE),
LintId::of(float_literal::EXCESSIVE_PRECISION),
LintId::of(from_over_into::FROM_OVER_INTO),
LintId::of(from_str_radix_10::FROM_STR_RADIX_10),
LintId::of(functions::DOUBLE_MUST_USE),
LintId::of(functions::MUST_USE_UNIT),
LintId::of(functions::RESULT_UNIT_ERR),
LintId::of(implicit_saturating_add::IMPLICIT_SATURATING_ADD),
LintId::of(implicit_saturating_sub::IMPLICIT_SATURATING_SUB),
LintId::of(inherent_to_string::INHERENT_TO_STRING),
LintId::of(init_numbered_fields::INIT_NUMBERED_FIELDS),
LintId::of(len_zero::COMPARISON_TO_EMPTY),
LintId::of(len_zero::LEN_WITHOUT_IS_EMPTY),
LintId::of(len_zero::LEN_ZERO),
LintId::of(literal_representation::INCONSISTENT_DIGIT_GROUPING),
LintId::of(literal_representation::UNUSUAL_BYTE_GROUPINGS),
LintId::of(loops::FOR_KV_MAP),
LintId::of(loops::NEEDLESS_RANGE_LOOP),
LintId::of(loops::SAME_ITEM_PUSH),
LintId::of(loops::WHILE_LET_ON_ITERATOR),
LintId::of(main_recursion::MAIN_RECURSION),
LintId::of(manual_async_fn::MANUAL_ASYNC_FN),
LintId::of(manual_bits::MANUAL_BITS),
LintId::of(manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
LintId::of(match_result_ok::MATCH_RESULT_OK),
LintId::of(matches::COLLAPSIBLE_MATCH),
LintId::of(matches::INFALLIBLE_DESTRUCTURING_MATCH),
LintId::of(matches::MANUAL_MAP),
LintId::of(matches::MATCH_LIKE_MATCHES_MACRO),
LintId::of(matches::MATCH_OVERLAPPING_ARM),
LintId::of(matches::MATCH_REF_PATS),
LintId::of(matches::REDUNDANT_PATTERN_MATCHING),
LintId::of(matches::SINGLE_MATCH),
LintId::of(mem_replace::MEM_REPLACE_OPTION_WITH_NONE),
LintId::of(mem_replace::MEM_REPLACE_WITH_DEFAULT),
LintId::of(methods::BYTES_NTH),
LintId::of(methods::CHARS_LAST_CMP),
LintId::of(methods::CHARS_NEXT_CMP),
LintId::of(methods::ERR_EXPECT),
LintId::of(methods::GET_FIRST),
LintId::of(methods::INTO_ITER_ON_REF),
LintId::of(methods::IS_DIGIT_ASCII_RADIX),
LintId::of(methods::ITER_CLONED_COLLECT),
LintId::of(methods::ITER_NEXT_SLICE),
LintId::of(methods::ITER_NTH_ZERO),
LintId::of(methods::ITER_SKIP_NEXT),
LintId::of(methods::MANUAL_SATURATING_ARITHMETIC),
LintId::of(methods::MAP_CLONE),
LintId::of(methods::MAP_COLLECT_RESULT_UNIT),
LintId::of(methods::MUT_MUTEX_LOCK),
LintId::of(methods::NEW_RET_NO_SELF),
LintId::of(methods::OBFUSCATED_IF_ELSE),
LintId::of(methods::OK_EXPECT),
LintId::of(methods::OPTION_MAP_OR_NONE),
LintId::of(methods::RESULT_MAP_OR_INTO_OPTION),
LintId::of(methods::SHOULD_IMPLEMENT_TRAIT),
LintId::of(methods::SINGLE_CHAR_ADD_STR),
LintId::of(methods::STRING_EXTEND_CHARS),
LintId::of(methods::UNNECESSARY_FOLD),
LintId::of(methods::UNNECESSARY_LAZY_EVALUATIONS),
LintId::of(methods::UNWRAP_OR_ELSE_DEFAULT),
LintId::of(methods::WRONG_SELF_CONVENTION),
LintId::of(misc::TOPLEVEL_REF_ARG),
LintId::of(misc::ZERO_PTR),
LintId::of(misc_early::BUILTIN_TYPE_SHADOW),
LintId::of(misc_early::DOUBLE_NEG),
LintId::of(misc_early::DUPLICATE_UNDERSCORE_ARGUMENT),
LintId::of(misc_early::MIXED_CASE_HEX_LITERALS),
LintId::of(misc_early::REDUNDANT_PATTERN),
LintId::of(mut_reference::UNNECESSARY_MUT_PASSED),
LintId::of(needless_late_init::NEEDLESS_LATE_INIT),
LintId::of(needless_parens_on_range_literals::NEEDLESS_PARENS_ON_RANGE_LITERALS),
LintId::of(neg_multiply::NEG_MULTIPLY),
LintId::of(new_without_default::NEW_WITHOUT_DEFAULT),
LintId::of(non_copy_const::BORROW_INTERIOR_MUTABLE_CONST),
LintId::of(non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST),
LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS),
LintId::of(operators::ASSIGN_OP_PATTERN),
LintId::of(operators::OP_REF),
LintId::of(operators::PTR_EQ),
LintId::of(partialeq_to_none::PARTIALEQ_TO_NONE),
LintId::of(ptr::CMP_NULL),
LintId::of(ptr::PTR_ARG),
LintId::of(question_mark::QUESTION_MARK),
LintId::of(ranges::MANUAL_RANGE_CONTAINS),
LintId::of(redundant_field_names::REDUNDANT_FIELD_NAMES),
LintId::of(redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES),
LintId::of(returns::LET_AND_RETURN),
LintId::of(returns::NEEDLESS_RETURN),
LintId::of(self_named_constructors::SELF_NAMED_CONSTRUCTORS),
LintId::of(single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
LintId::of(strings::TRIM_SPLIT_WHITESPACE),
LintId::of(tabs_in_doc_comments::TABS_IN_DOC_COMMENTS),
LintId::of(to_digit_is_some::TO_DIGIT_IS_SOME),
LintId::of(unit_types::LET_UNIT_VALUE),
LintId::of(unnecessary_owned_empty_strings::UNNECESSARY_OWNED_EMPTY_STRINGS),
LintId::of(unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME),
LintId::of(unused_unit::UNUSED_UNIT),
LintId::of(upper_case_acronyms::UPPER_CASE_ACRONYMS),
LintId::of(write::PRINTLN_EMPTY_STRING),
LintId::of(write::PRINT_LITERAL),
LintId::of(write::PRINT_WITH_NEWLINE),
LintId::of(write::WRITELN_EMPTY_STRING),
LintId::of(write::WRITE_LITERAL),
LintId::of(write::WRITE_WITH_NEWLINE),
])

View file

@ -1,38 +0,0 @@
// This file was generated by `cargo dev update_lints`.
// Use that command to update this file and do not edit by hand.
// Manual edits will be overwritten.
store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec![
LintId::of(almost_complete_letter_range::ALMOST_COMPLETE_LETTER_RANGE),
LintId::of(attrs::BLANKET_CLIPPY_RESTRICTION_LINTS),
LintId::of(await_holding_invalid::AWAIT_HOLDING_INVALID_TYPE),
LintId::of(await_holding_invalid::AWAIT_HOLDING_LOCK),
LintId::of(await_holding_invalid::AWAIT_HOLDING_REFCELL_REF),
LintId::of(casts::CAST_ABS_TO_UNSIGNED),
LintId::of(casts::CAST_ENUM_CONSTRUCTOR),
LintId::of(casts::CAST_ENUM_TRUNCATION),
LintId::of(casts::CAST_NAN_TO_INT),
LintId::of(casts::CAST_SLICE_FROM_RAW_PARTS),
LintId::of(crate_in_macro_def::CRATE_IN_MACRO_DEF),
LintId::of(drop_forget_ref::DROP_NON_DROP),
LintId::of(drop_forget_ref::FORGET_NON_DROP),
LintId::of(duplicate_mod::DUPLICATE_MOD),
LintId::of(format_impl::PRINT_IN_FORMAT_IMPL),
LintId::of(formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING),
LintId::of(formatting::SUSPICIOUS_ELSE_FORMATTING),
LintId::of(formatting::SUSPICIOUS_UNARY_OP_FORMATTING),
LintId::of(loops::EMPTY_LOOP),
LintId::of(loops::MUT_RANGE_BOUND),
LintId::of(methods::NO_EFFECT_REPLACE),
LintId::of(methods::SUSPICIOUS_MAP),
LintId::of(methods::SUSPICIOUS_TO_OWNED),
LintId::of(multi_assignments::MULTI_ASSIGNMENTS),
LintId::of(mut_key::MUTABLE_KEY_TYPE),
LintId::of(octal_escapes::OCTAL_ESCAPES),
LintId::of(operators::FLOAT_EQUALITY_WITHOUT_ABS),
LintId::of(operators::MISREFACTORED_ASSIGN_OP),
LintId::of(rc_clone_in_vec_init::RC_CLONE_IN_VEC_INIT),
LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
LintId::of(swap_ptr_to_ref::SWAP_PTR_TO_REF),
])

View file

@ -32,8 +32,8 @@ extern crate rustc_driver;
extern crate rustc_errors;
extern crate rustc_hir;
extern crate rustc_hir_analysis;
extern crate rustc_hir_typeck;
extern crate rustc_hir_pretty;
extern crate rustc_hir_typeck;
extern crate rustc_index;
extern crate rustc_infer;
extern crate rustc_lexer;
@ -47,122 +47,24 @@ extern crate rustc_trait_selection;
#[macro_use]
extern crate clippy_utils;
#[macro_use]
extern crate declare_clippy_lint;
use std::io;
use std::path::PathBuf;
use clippy_utils::parse_msrv;
use rustc_data_structures::fx::FxHashSet;
use rustc_lint::LintId;
use rustc_lint::{Lint, LintId};
use rustc_semver::RustcVersion;
use rustc_session::Session;
/// Macro used to declare a Clippy lint.
///
/// Every lint declaration consists of 4 parts:
///
/// 1. The documentation, which is used for the website
/// 2. The `LINT_NAME`. See [lint naming][lint_naming] on lint naming conventions.
/// 3. The `lint_level`, which is a mapping from *one* of our lint groups to `Allow`, `Warn` or
/// `Deny`. The lint level here has nothing to do with what lint groups the lint is a part of.
/// 4. The `description` that contains a short explanation on what's wrong with code where the
/// lint is triggered.
///
/// Currently the categories `style`, `correctness`, `suspicious`, `complexity` and `perf` are
/// enabled by default. As said in the README.md of this repository, if the lint level mapping
/// changes, please update README.md.
///
/// # Example
///
/// ```
/// #![feature(rustc_private)]
/// extern crate rustc_session;
/// use rustc_session::declare_tool_lint;
/// use clippy_lints::declare_clippy_lint;
///
/// declare_clippy_lint! {
/// /// ### What it does
/// /// Checks for ... (describe what the lint matches).
/// ///
/// /// ### Why is this bad?
/// /// Supply the reason for linting the code.
/// ///
/// /// ### Example
/// /// ```rust
/// /// Insert a short example of code that triggers the lint
/// /// ```
/// ///
/// /// Use instead:
/// /// ```rust
/// /// Insert a short example of improved code that doesn't trigger the lint
/// /// ```
/// pub LINT_NAME,
/// pedantic,
/// "description"
/// }
/// ```
/// [lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints
#[macro_export]
macro_rules! declare_clippy_lint {
{ $(#[$attr:meta])* pub $name:tt, style, $description:tt } => {
declare_tool_lint! {
$(#[$attr])* pub clippy::$name, Warn, $description, report_in_external_macro: true
}
};
{ $(#[$attr:meta])* pub $name:tt, correctness, $description:tt } => {
declare_tool_lint! {
$(#[$attr])* pub clippy::$name, Deny, $description, report_in_external_macro: true
}
};
{ $(#[$attr:meta])* pub $name:tt, suspicious, $description:tt } => {
declare_tool_lint! {
$(#[$attr])* pub clippy::$name, Warn, $description, report_in_external_macro: true
}
};
{ $(#[$attr:meta])* pub $name:tt, complexity, $description:tt } => {
declare_tool_lint! {
$(#[$attr])* pub clippy::$name, Warn, $description, report_in_external_macro: true
}
};
{ $(#[$attr:meta])* pub $name:tt, perf, $description:tt } => {
declare_tool_lint! {
$(#[$attr])* pub clippy::$name, Warn, $description, report_in_external_macro: true
}
};
{ $(#[$attr:meta])* pub $name:tt, pedantic, $description:tt } => {
declare_tool_lint! {
$(#[$attr])* pub clippy::$name, Allow, $description, report_in_external_macro: true
}
};
{ $(#[$attr:meta])* pub $name:tt, restriction, $description:tt } => {
declare_tool_lint! {
$(#[$attr])* pub clippy::$name, Allow, $description, report_in_external_macro: true
}
};
{ $(#[$attr:meta])* pub $name:tt, cargo, $description:tt } => {
declare_tool_lint! {
$(#[$attr])* pub clippy::$name, Allow, $description, report_in_external_macro: true
}
};
{ $(#[$attr:meta])* pub $name:tt, nursery, $description:tt } => {
declare_tool_lint! {
$(#[$attr])* pub clippy::$name, Allow, $description, report_in_external_macro: true
}
};
{ $(#[$attr:meta])* pub $name:tt, internal, $description:tt } => {
declare_tool_lint! {
$(#[$attr])* pub clippy::$name, Allow, $description, report_in_external_macro: true
}
};
{ $(#[$attr:meta])* pub $name:tt, internal_warn, $description:tt } => {
declare_tool_lint! {
$(#[$attr])* pub clippy::$name, Warn, $description, report_in_external_macro: true
}
};
}
#[cfg(feature = "internal")]
pub mod deprecated_lints;
#[cfg_attr(feature = "internal", allow(clippy::missing_clippy_version_attribute))]
mod utils;
mod declared_lints;
mod renamed_lints;
// begin lints modules, do not remove this comment, its used in `update_lints`
@ -231,6 +133,7 @@ mod format_impl;
mod format_push_string;
mod formatting;
mod from_over_into;
mod from_raw_with_void_ptr;
mod from_str_radix_10;
mod functions;
mod future_not_send;
@ -249,6 +152,7 @@ mod inherent_impl;
mod inherent_to_string;
mod init_numbered_fields;
mod inline_fn_without_body;
mod instant_subtraction;
mod int_plus_one;
mod invalid_upcast_comparisons;
mod invalid_utf8_in_unchecked;
@ -270,7 +174,8 @@ mod manual_assert;
mod manual_async_fn;
mod manual_bits;
mod manual_clamp;
mod manual_instant_elapsed;
mod manual_is_ascii_check;
mod manual_let_else;
mod manual_non_exhaustive;
mod manual_rem_euclid;
mod manual_retain;
@ -365,6 +270,7 @@ mod strings;
mod strlen_on_c_strings;
mod suspicious_operation_groupings;
mod suspicious_trait_impl;
mod suspicious_xor_used_as_pow;
mod swap;
mod swap_ptr_to_ref;
mod tabs_in_doc_comments;
@ -404,8 +310,8 @@ mod zero_div_zero;
mod zero_sized_map_values;
// end lints modules, do not remove this comment, its used in `update_lints`
pub use crate::utils::conf::Conf;
use crate::utils::conf::{format_error, TryConf};
pub use crate::utils::conf::{lookup_conf_file, Conf};
/// Register all pre expansion lints
///
@ -462,8 +368,8 @@ fn read_msrv(conf: &Conf, sess: &Session) -> Option<RustcVersion> {
}
#[doc(hidden)]
pub fn read_conf(sess: &Session) -> Conf {
let file_name = match utils::conf::lookup_conf_file() {
pub fn read_conf(sess: &Session, path: &io::Result<Option<PathBuf>>) -> Conf {
let file_name = match path {
Ok(Some(path)) => path,
Ok(None) => return Conf::default(),
Err(error) => {
@ -473,7 +379,7 @@ pub fn read_conf(sess: &Session) -> Conf {
},
};
let TryConf { conf, errors, warnings } = utils::conf::read(&file_name);
let TryConf { conf, errors, warnings } = utils::conf::read(file_name);
// all conf errors are non-fatal, we just use the default conf in case of error
for error in errors {
sess.err(format!(
@ -495,31 +401,121 @@ pub fn read_conf(sess: &Session) -> Conf {
conf
}
#[derive(Default)]
struct RegistrationGroups {
all: Vec<LintId>,
cargo: Vec<LintId>,
complexity: Vec<LintId>,
correctness: Vec<LintId>,
nursery: Vec<LintId>,
pedantic: Vec<LintId>,
perf: Vec<LintId>,
restriction: Vec<LintId>,
style: Vec<LintId>,
suspicious: Vec<LintId>,
#[cfg(feature = "internal")]
internal: Vec<LintId>,
}
impl RegistrationGroups {
#[rustfmt::skip]
fn register(self, store: &mut rustc_lint::LintStore) {
store.register_group(true, "clippy::all", Some("clippy_all"), self.all);
store.register_group(true, "clippy::cargo", Some("clippy_cargo"), self.cargo);
store.register_group(true, "clippy::complexity", Some("clippy_complexity"), self.complexity);
store.register_group(true, "clippy::correctness", Some("clippy_correctness"), self.correctness);
store.register_group(true, "clippy::nursery", Some("clippy_nursery"), self.nursery);
store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), self.pedantic);
store.register_group(true, "clippy::perf", Some("clippy_perf"), self.perf);
store.register_group(true, "clippy::restriction", Some("clippy_restriction"), self.restriction);
store.register_group(true, "clippy::style", Some("clippy_style"), self.style);
store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), self.suspicious);
#[cfg(feature = "internal")]
store.register_group(true, "clippy::internal", Some("clippy_internal"), self.internal);
}
}
#[derive(Copy, Clone)]
pub(crate) enum LintCategory {
Cargo,
Complexity,
Correctness,
Nursery,
Pedantic,
Perf,
Restriction,
Style,
Suspicious,
#[cfg(feature = "internal")]
Internal,
}
#[allow(clippy::enum_glob_use)]
use LintCategory::*;
impl LintCategory {
fn is_all(self) -> bool {
matches!(self, Correctness | Suspicious | Style | Complexity | Perf)
}
fn group(self, groups: &mut RegistrationGroups) -> &mut Vec<LintId> {
match self {
Cargo => &mut groups.cargo,
Complexity => &mut groups.complexity,
Correctness => &mut groups.correctness,
Nursery => &mut groups.nursery,
Pedantic => &mut groups.pedantic,
Perf => &mut groups.perf,
Restriction => &mut groups.restriction,
Style => &mut groups.style,
Suspicious => &mut groups.suspicious,
#[cfg(feature = "internal")]
Internal => &mut groups.internal,
}
}
}
pub(crate) struct LintInfo {
/// Double reference to maintain pointer equality
lint: &'static &'static Lint,
category: LintCategory,
explanation: &'static str,
}
pub fn explain(name: &str) {
let target = format!("clippy::{}", name.to_ascii_uppercase());
match declared_lints::LINTS.iter().find(|info| info.lint.name == target) {
Some(info) => print!("{}", info.explanation),
None => println!("unknown lint: {name}"),
}
}
fn register_categories(store: &mut rustc_lint::LintStore) {
let mut groups = RegistrationGroups::default();
for LintInfo { lint, category, .. } in declared_lints::LINTS {
if category.is_all() {
groups.all.push(LintId::of(lint));
}
category.group(&mut groups).push(LintId::of(lint));
}
let lints: Vec<&'static Lint> = declared_lints::LINTS.iter().map(|info| *info.lint).collect();
store.register_lints(&lints);
groups.register(store);
}
/// Register all lints and lint groups with the rustc plugin registry
///
/// Used in `./src/driver.rs`.
#[expect(clippy::too_many_lines)]
pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &Conf) {
register_removed_non_tool_lints(store);
register_categories(store);
include!("lib.deprecated.rs");
include!("lib.register_lints.rs");
include!("lib.register_restriction.rs");
include!("lib.register_pedantic.rs");
#[cfg(feature = "internal")]
include!("lib.register_internal.rs");
include!("lib.register_all.rs");
include!("lib.register_style.rs");
include!("lib.register_complexity.rs");
include!("lib.register_correctness.rs");
include!("lib.register_suspicious.rs");
include!("lib.register_perf.rs");
include!("lib.register_cargo.rs");
include!("lib.register_nursery.rs");
#[cfg(feature = "internal")]
{
if std::env::var("ENABLE_METADATA_COLLECTION").eq(&Ok("1".to_string())) {
@ -614,6 +610,8 @@ 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)));
@ -735,7 +733,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
let max_trait_bounds = conf.max_trait_bounds;
store.register_late_pass(move |_| Box::new(trait_bounds::TraitBounds::new(max_trait_bounds)));
store.register_late_pass(|_| Box::new(comparison_chain::ComparisonChain));
store.register_late_pass(|_| Box::new(mut_key::MutableKeyType));
let ignore_interior_mutability = conf.ignore_interior_mutability.clone();
store.register_late_pass(move |_| Box::new(mut_key::MutableKeyType::new(ignore_interior_mutability.clone())));
store.register_early_pass(|| Box::new(reference::DerefAddrOf));
store.register_early_pass(|| Box::new(double_parens::DoubleParens));
store.register_late_pass(|_| Box::new(format_impl::FormatImpl::new()));
@ -794,10 +793,10 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|_| Box::new(floating_point_arithmetic::FloatingPointArithmetic));
store.register_early_pass(|| Box::new(as_conversions::AsConversions));
store.register_late_pass(|_| Box::new(let_underscore::LetUnderscore));
store.register_early_pass(|| Box::new(single_component_path_imports::SingleComponentPathImports));
store.register_early_pass(|| Box::<single_component_path_imports::SingleComponentPathImports>::default());
let max_fn_params_bools = conf.max_fn_params_bools;
let max_struct_bools = conf.max_struct_bools;
store.register_early_pass(move || {
store.register_late_pass(move |_| {
Box::new(excessive_bools::ExcessiveBools::new(
max_struct_bools,
max_fn_params_bools,
@ -879,13 +878,14 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|_| Box::<only_used_in_recursion::OnlyUsedInRecursion>::default());
let allow_dbg_in_tests = conf.allow_dbg_in_tests;
store.register_late_pass(move |_| Box::new(dbg_macro::DbgMacro::new(allow_dbg_in_tests)));
let allow_print_in_tests = conf.allow_print_in_tests;
store.register_late_pass(move |_| Box::new(write::Write::new(allow_print_in_tests)));
let cargo_ignore_publish = conf.cargo_ignore_publish;
store.register_late_pass(move |_| {
Box::new(cargo::Cargo {
ignore_publish: cargo_ignore_publish,
})
});
store.register_late_pass(|_| Box::<write::Write>::default());
store.register_early_pass(|| Box::new(crate_in_macro_def::CrateInMacroDef));
store.register_early_pass(|| Box::new(empty_structs_with_brackets::EmptyStructsWithBrackets));
store.register_late_pass(|_| Box::new(unnecessary_owned_empty_strings::UnnecessaryOwnedEmptyStrings));
@ -908,7 +908,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(move |_| Box::new(operators::Operators::new(verbose_bit_mask_threshold)));
store.register_late_pass(|_| Box::new(invalid_utf8_in_unchecked::InvalidUtf8InUnchecked));
store.register_late_pass(|_| Box::<std_instead_of_core::StdReexports>::default());
store.register_late_pass(|_| Box::new(manual_instant_elapsed::ManualInstantElapsed));
store.register_late_pass(move |_| Box::new(instant_subtraction::InstantSubtraction::new(msrv)));
store.register_late_pass(|_| Box::new(partialeq_to_none::PartialeqToNone));
store.register_late_pass(move |_| Box::new(manual_clamp::ManualClamp::new(msrv)));
store.register_late_pass(|_| Box::new(manual_string_new::ManualStringNew));
@ -919,6 +919,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|_| Box::new(implicit_saturating_add::ImplicitSaturatingAdd));
store.register_early_pass(|| Box::new(partial_pub_fields::PartialPubFields));
store.register_late_pass(|_| Box::new(missing_trait_methods::MissingTraitMethods));
store.register_late_pass(|_| Box::new(from_raw_with_void_ptr::FromRawWithVoidPtr));
store.register_late_pass(|_| Box::new(suspicious_xor_used_as_pow::ConfusingXorAndPow));
store.register_late_pass(move |_| Box::new(manual_is_ascii_check::ManualIsAsciiCheck::new(msrv)));
// add lints here, do not remove this comment, it's used in `new_lint`
}

View file

@ -1,4 +1,4 @@
use clippy_utils::diagnostics::span_lint;
use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
use clippy_utils::trait_ref_of_method;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir::intravisit::nested_filter::{self as hir_nested_filter, NestedFilter};
@ -152,6 +152,7 @@ fn check_fn_inner<'tcx>(
.params
.iter()
.filter(|param| matches!(param.kind, GenericParamKind::Type { .. }));
for typ in types {
for pred in generics.bounds_for_param(cx.tcx.hir().local_def_id(typ.hir_id)) {
if pred.origin == PredicateOrigin::WhereClause {
@ -188,15 +189,30 @@ fn check_fn_inner<'tcx>(
}
}
}
if could_use_elision(cx, decl, body, trait_sig, generics.params) {
span_lint(
if let Some(elidable_lts) = could_use_elision(cx, decl, body, trait_sig, generics.params) {
let lts = elidable_lts
.iter()
// In principle, the result of the call to `Node::ident` could be `unwrap`ped, as `DefId` should refer to a
// `Node::GenericParam`.
.filter_map(|&(def_id, _)| cx.tcx.hir().get_by_def_id(def_id).ident())
.map(|ident| ident.to_string())
.collect::<Vec<_>>()
.join(", ");
span_lint_and_then(
cx,
NEEDLESS_LIFETIMES,
span.with_hi(decl.output.span().hi()),
"explicit lifetimes given in parameter types where they could be elided \
(or replaced with `'_` if needed by type declaration)",
&format!("the following explicit lifetimes could be elided: {lts}"),
|diag| {
if let Some(span) = elidable_lts.iter().find_map(|&(_, span)| span) {
diag.span_help(span, "replace with `'_` in generic arguments such as here");
}
},
);
}
if report_extra_lifetimes {
self::report_extra_lifetimes(cx, decl, generics);
}
@ -227,7 +243,7 @@ fn could_use_elision<'tcx>(
body: Option<BodyId>,
trait_sig: Option<&[Ident]>,
named_generics: &'tcx [GenericParam<'_>],
) -> bool {
) -> Option<Vec<(LocalDefId, Option<Span>)>> {
// There are two scenarios where elision works:
// * no output references, all input references have different LT
// * output references, exactly one input reference with same LT
@ -254,7 +270,7 @@ fn could_use_elision<'tcx>(
}
if input_visitor.abort() || output_visitor.abort() {
return false;
return None;
}
let input_lts = input_visitor.lts;
@ -262,7 +278,7 @@ fn could_use_elision<'tcx>(
if let Some(trait_sig) = trait_sig {
if explicit_self_type(cx, func, trait_sig.first().copied()) {
return false;
return None;
}
}
@ -271,7 +287,7 @@ fn could_use_elision<'tcx>(
let first_ident = body.params.first().and_then(|param| param.pat.simple_ident());
if explicit_self_type(cx, func, first_ident) {
return false;
return None;
}
let mut checker = BodyLifetimeChecker {
@ -279,14 +295,14 @@ fn could_use_elision<'tcx>(
};
checker.visit_expr(body.value);
if checker.lifetimes_used_in_body {
return false;
return None;
}
}
// check for lifetimes from higher scopes
for lt in input_lts.iter().chain(output_lts.iter()) {
if !allowed_lts.contains(lt) {
return false;
return None;
}
}
@ -302,48 +318,45 @@ fn could_use_elision<'tcx>(
for lt in input_visitor.nested_elision_site_lts {
if let RefLt::Named(def_id) = lt {
if allowed_lts.contains(&cx.tcx.item_name(def_id.to_def_id())) {
return false;
return None;
}
}
}
for lt in output_visitor.nested_elision_site_lts {
if let RefLt::Named(def_id) = lt {
if allowed_lts.contains(&cx.tcx.item_name(def_id.to_def_id())) {
return false;
return None;
}
}
}
}
// no input lifetimes? easy case!
if input_lts.is_empty() {
false
} else if output_lts.is_empty() {
// no output lifetimes, check distinctness of input lifetimes
// only unnamed and static, ok
let unnamed_and_static = input_lts.iter().all(|lt| *lt == RefLt::Unnamed || *lt == RefLt::Static);
if unnamed_and_static {
return false;
}
// we have no output reference, so we only need all distinct lifetimes
input_lts.len() == unique_lifetimes(&input_lts)
} else {
// we have output references, so we need one input reference,
// and all output lifetimes must be the same
if unique_lifetimes(&output_lts) > 1 {
return false;
}
if input_lts.len() == 1 {
match (&input_lts[0], &output_lts[0]) {
(&RefLt::Named(n1), &RefLt::Named(n2)) if n1 == n2 => true,
(&RefLt::Named(_), &RefLt::Unnamed) => true,
_ => false, /* already elided, different named lifetimes
* or something static going on */
// A lifetime can be newly elided if:
// - It occurs only once among the inputs.
// - If there are multiple input lifetimes, then the newly elided lifetime does not occur among the
// outputs (because eliding such an lifetime would create an ambiguity).
let elidable_lts = named_lifetime_occurrences(&input_lts)
.into_iter()
.filter_map(|(def_id, occurrences)| {
if occurrences == 1 && (input_lts.len() == 1 || !output_lts.contains(&RefLt::Named(def_id))) {
Some((
def_id,
input_visitor
.lifetime_generic_arg_spans
.get(&def_id)
.or_else(|| output_visitor.lifetime_generic_arg_spans.get(&def_id))
.copied(),
))
} else {
None
}
} else {
false
}
})
.collect::<Vec<_>>();
if elidable_lts.is_empty() {
None
} else {
Some(elidable_lts)
}
}
@ -359,16 +372,31 @@ fn allowed_lts_from(tcx: TyCtxt<'_>, named_generics: &[GenericParam<'_>]) -> FxH
allowed_lts
}
/// Number of unique lifetimes in the given vector.
/// Number of times each named lifetime occurs in the given slice. Returns a vector to preserve
/// relative order.
#[must_use]
fn unique_lifetimes(lts: &[RefLt]) -> usize {
lts.iter().collect::<FxHashSet<_>>().len()
fn named_lifetime_occurrences(lts: &[RefLt]) -> Vec<(LocalDefId, usize)> {
let mut occurrences = Vec::new();
for lt in lts {
if let &RefLt::Named(curr_def_id) = lt {
if let Some(pair) = occurrences
.iter_mut()
.find(|(prev_def_id, _)| *prev_def_id == curr_def_id)
{
pair.1 += 1;
} else {
occurrences.push((curr_def_id, 1));
}
}
}
occurrences
}
/// A visitor usable for `rustc_front::visit::walk_ty()`.
struct RefVisitor<'a, 'tcx> {
cx: &'a LateContext<'tcx>,
lts: Vec<RefLt>,
lifetime_generic_arg_spans: FxHashMap<LocalDefId, Span>,
nested_elision_site_lts: Vec<RefLt>,
unelided_trait_object_lifetime: bool,
}
@ -378,6 +406,7 @@ impl<'a, 'tcx> RefVisitor<'a, 'tcx> {
Self {
cx,
lts: Vec::new(),
lifetime_generic_arg_spans: FxHashMap::default(),
nested_elision_site_lts: Vec::new(),
unelided_trait_object_lifetime: false,
}
@ -467,6 +496,22 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> {
_ => walk_ty(self, ty),
}
}
fn visit_generic_arg(&mut self, generic_arg: &'tcx GenericArg<'tcx>) {
if let GenericArg::Lifetime(l) = generic_arg
&& let LifetimeName::Param(def_id, _) = l.name
{
self.lifetime_generic_arg_spans.entry(def_id).or_insert(l.span);
}
// Replace with `walk_generic_arg` if/when https://github.com/rust-lang/rust/pull/103692 lands.
// walk_generic_arg(self, generic_arg);
match generic_arg {
GenericArg::Lifetime(lt) => self.visit_lifetime(lt),
GenericArg::Type(ty) => self.visit_ty(ty),
GenericArg::Const(ct) => self.visit_anon_const(&ct.value),
GenericArg::Infer(inf) => self.visit_infer(inf),
}
}
}
/// Are any lifetimes mentioned in the `where` clause? If so, we don't try to

View file

@ -9,7 +9,6 @@ mod manual_flatten;
mod manual_memcpy;
mod missing_spin_loop;
mod mut_range_bound;
mod needless_collect;
mod needless_range_loop;
mod never_loop;
mod same_item_push;
@ -205,28 +204,6 @@ declare_clippy_lint! {
"`loop { if let { ... } else break }`, which can be written as a `while let` loop"
}
declare_clippy_lint! {
/// ### What it does
/// Checks for functions collecting an iterator when collect
/// is not needed.
///
/// ### Why is this bad?
/// `collect` causes the allocation of a new data structure,
/// when this allocation may not be needed.
///
/// ### Example
/// ```rust
/// # let iterator = vec![1].into_iter();
/// let len = iterator.clone().collect::<Vec<_>>().len();
/// // should be
/// let len = iterator.count();
/// ```
#[clippy::version = "1.30.0"]
pub NEEDLESS_COLLECT,
perf,
"collecting an iterator when collect is not needed"
}
declare_clippy_lint! {
/// ### What it does
/// Checks `for` loops over slices with an explicit counter
@ -605,7 +582,6 @@ declare_lint_pass!(Loops => [
EXPLICIT_INTO_ITER_LOOP,
ITER_NEXT_LOOP,
WHILE_LET_LOOP,
NEEDLESS_COLLECT,
EXPLICIT_COUNTER_LOOP,
EMPTY_LOOP,
WHILE_LET_ON_ITERATOR,
@ -667,8 +643,6 @@ impl<'tcx> LateLintPass<'tcx> for Loops {
while_immutable_condition::check(cx, condition, body);
missing_spin_loop::check(cx, condition, body);
}
needless_collect::check(expr, cx);
}
}

View file

@ -52,8 +52,8 @@ fn check_for_mutability(cx: &LateContext<'_>, bound: &Expr<'_>) -> Option<HirId>
None
}
fn check_for_mutation<'tcx>(
cx: &LateContext<'tcx>,
fn check_for_mutation(
cx: &LateContext<'_>,
body: &Expr<'_>,
bound_id_start: Option<HirId>,
bound_id_end: Option<HirId>,
@ -113,13 +113,7 @@ impl<'tcx> Delegate<'tcx> for MutatePairDelegate<'_, 'tcx> {
}
}
fn fake_read(
&mut self,
_: &rustc_hir_typeck::expr_use_visitor::PlaceWithHirId<'tcx>,
_: FakeReadCause,
_: HirId,
) {
}
fn fake_read(&mut self, _: &rustc_hir_typeck::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
}
impl MutatePairDelegate<'_, '_> {

View file

@ -4,7 +4,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::higher::ForLoop;
use clippy_utils::source::snippet;
use rustc_errors::Applicability;
use rustc_hir::{Block, Expr, ExprKind, HirId, InlineAsmOperand, Pat, Stmt, StmtKind};
use rustc_hir::{Block, Destination, Expr, ExprKind, HirId, InlineAsmOperand, Pat, Stmt, StmtKind};
use rustc_lint::LateContext;
use rustc_span::Span;
use std::iter::{once, Iterator};
@ -16,7 +16,7 @@ pub(super) fn check(
span: Span,
for_loop: Option<&ForLoop<'_>>,
) {
match never_loop_block(block, loop_id) {
match never_loop_block(block, &mut Vec::new(), loop_id) {
NeverLoopResult::AlwaysBreak => {
span_lint_and_then(cx, NEVER_LOOP, span, "this loop never actually loops", |diag| {
if let Some(ForLoop {
@ -92,35 +92,34 @@ fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult) -> NeverLoopResult
}
}
fn never_loop_block(block: &Block<'_>, main_loop_id: HirId) -> NeverLoopResult {
let mut iter = block
fn never_loop_block(block: &Block<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: HirId) -> NeverLoopResult {
let iter = block
.stmts
.iter()
.filter_map(stmt_to_expr)
.chain(block.expr.map(|expr| (expr, None)));
never_loop_expr_seq(&mut iter, main_loop_id)
}
fn never_loop_expr_seq<'a, T: Iterator<Item = (&'a Expr<'a>, Option<&'a Block<'a>>)>>(
es: &mut T,
main_loop_id: HirId,
) -> NeverLoopResult {
es.map(|(e, els)| {
let e = never_loop_expr(e, main_loop_id);
els.map_or(e, |els| combine_branches(e, never_loop_block(els, main_loop_id)))
iter.map(|(e, els)| {
let e = never_loop_expr(e, ignore_ids, main_loop_id);
// els is an else block in a let...else binding
els.map_or(e, |els| {
combine_branches(e, never_loop_block(els, ignore_ids, main_loop_id))
})
})
.fold(NeverLoopResult::Otherwise, combine_seq)
}
fn stmt_to_expr<'tcx>(stmt: &Stmt<'tcx>) -> Option<(&'tcx Expr<'tcx>, Option<&'tcx Block<'tcx>>)> {
match stmt.kind {
StmtKind::Semi(e, ..) | StmtKind::Expr(e, ..) => Some((e, None)),
StmtKind::Semi(e) | StmtKind::Expr(e) => Some((e, None)),
// add the let...else expression (if present)
StmtKind::Local(local) => local.init.map(|init| (init, local.els)),
StmtKind::Item(..) => None,
}
}
fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
#[allow(clippy::too_many_lines)]
fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: HirId) -> NeverLoopResult {
match expr.kind {
ExprKind::Box(e)
| ExprKind::Unary(_, e)
@ -129,47 +128,56 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
| ExprKind::Field(e, _)
| ExprKind::AddrOf(_, _, e)
| ExprKind::Repeat(e, _)
| ExprKind::DropTemps(e) => never_loop_expr(e, main_loop_id),
ExprKind::Let(let_expr) => never_loop_expr(let_expr.init, main_loop_id),
ExprKind::Array(es) | ExprKind::Tup(es) => never_loop_expr_all(&mut es.iter(), main_loop_id),
ExprKind::MethodCall(_, receiver, es, _) => {
never_loop_expr_all(&mut std::iter::once(receiver).chain(es.iter()), main_loop_id)
},
| ExprKind::DropTemps(e) => never_loop_expr(e, ignore_ids, main_loop_id),
ExprKind::Let(let_expr) => never_loop_expr(let_expr.init, ignore_ids, main_loop_id),
ExprKind::Array(es) | ExprKind::Tup(es) => never_loop_expr_all(&mut es.iter(), ignore_ids, main_loop_id),
ExprKind::MethodCall(_, receiver, es, _) => never_loop_expr_all(
&mut std::iter::once(receiver).chain(es.iter()),
ignore_ids,
main_loop_id,
),
ExprKind::Struct(_, fields, base) => {
let fields = never_loop_expr_all(&mut fields.iter().map(|f| f.expr), main_loop_id);
let fields = never_loop_expr_all(&mut fields.iter().map(|f| f.expr), ignore_ids, main_loop_id);
if let Some(base) = base {
combine_both(fields, never_loop_expr(base, main_loop_id))
combine_both(fields, never_loop_expr(base, ignore_ids, main_loop_id))
} else {
fields
}
},
ExprKind::Call(e, es) => never_loop_expr_all(&mut once(e).chain(es.iter()), main_loop_id),
ExprKind::Call(e, es) => never_loop_expr_all(&mut once(e).chain(es.iter()), ignore_ids, main_loop_id),
ExprKind::Binary(_, e1, e2)
| ExprKind::Assign(e1, e2, _)
| ExprKind::AssignOp(_, e1, e2)
| ExprKind::Index(e1, e2) => never_loop_expr_all(&mut [e1, e2].iter().copied(), main_loop_id),
| ExprKind::Index(e1, e2) => never_loop_expr_all(&mut [e1, e2].iter().copied(), ignore_ids, main_loop_id),
ExprKind::Loop(b, _, _, _) => {
// Break can come from the inner loop so remove them.
absorb_break(never_loop_block(b, main_loop_id))
absorb_break(never_loop_block(b, ignore_ids, main_loop_id))
},
ExprKind::If(e, e2, e3) => {
let e1 = never_loop_expr(e, main_loop_id);
let e2 = never_loop_expr(e2, main_loop_id);
let e3 = e3
.as_ref()
.map_or(NeverLoopResult::Otherwise, |e| never_loop_expr(e, main_loop_id));
let e1 = never_loop_expr(e, ignore_ids, main_loop_id);
let e2 = never_loop_expr(e2, ignore_ids, main_loop_id);
let e3 = e3.as_ref().map_or(NeverLoopResult::Otherwise, |e| {
never_loop_expr(e, ignore_ids, main_loop_id)
});
combine_seq(e1, combine_branches(e2, e3))
},
ExprKind::Match(e, arms, _) => {
let e = never_loop_expr(e, main_loop_id);
let e = never_loop_expr(e, ignore_ids, main_loop_id);
if arms.is_empty() {
e
} else {
let arms = never_loop_expr_branch(&mut arms.iter().map(|a| a.body), main_loop_id);
let arms = never_loop_expr_branch(&mut arms.iter().map(|a| a.body), ignore_ids, main_loop_id);
combine_seq(e, arms)
}
},
ExprKind::Block(b, _) => never_loop_block(b, main_loop_id),
ExprKind::Block(b, l) => {
if l.is_some() {
ignore_ids.push(b.hir_id);
}
let ret = never_loop_block(b, ignore_ids, main_loop_id);
ignore_ids.pop();
ret
},
ExprKind::Continue(d) => {
let id = d
.target_id
@ -180,20 +188,32 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
NeverLoopResult::AlwaysBreak
}
},
// checks if break targets a block instead of a loop
ExprKind::Break(Destination { target_id: Ok(t), .. }, e) if ignore_ids.contains(&t) => e
.map_or(NeverLoopResult::Otherwise, |e| {
combine_seq(never_loop_expr(e, ignore_ids, main_loop_id), NeverLoopResult::Otherwise)
}),
ExprKind::Break(_, e) | ExprKind::Ret(e) => e.as_ref().map_or(NeverLoopResult::AlwaysBreak, |e| {
combine_seq(never_loop_expr(e, main_loop_id), NeverLoopResult::AlwaysBreak)
combine_seq(
never_loop_expr(e, ignore_ids, main_loop_id),
NeverLoopResult::AlwaysBreak,
)
}),
ExprKind::InlineAsm(asm) => asm
.operands
.iter()
.map(|(o, _)| match o {
InlineAsmOperand::In { expr, .. } | InlineAsmOperand::InOut { expr, .. } => {
never_loop_expr(expr, main_loop_id)
never_loop_expr(expr, ignore_ids, main_loop_id)
},
InlineAsmOperand::Out { expr, .. } => never_loop_expr_all(&mut expr.iter().copied(), main_loop_id),
InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => {
never_loop_expr_all(&mut once(*in_expr).chain(out_expr.iter().copied()), main_loop_id)
InlineAsmOperand::Out { expr, .. } => {
never_loop_expr_all(&mut expr.iter().copied(), ignore_ids, main_loop_id)
},
InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => never_loop_expr_all(
&mut once(*in_expr).chain(out_expr.iter().copied()),
ignore_ids,
main_loop_id,
),
InlineAsmOperand::Const { .. }
| InlineAsmOperand::SymFn { .. }
| InlineAsmOperand::SymStatic { .. } => NeverLoopResult::Otherwise,
@ -208,13 +228,21 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
}
}
fn never_loop_expr_all<'a, T: Iterator<Item = &'a Expr<'a>>>(es: &mut T, main_loop_id: HirId) -> NeverLoopResult {
es.map(|e| never_loop_expr(e, main_loop_id))
fn never_loop_expr_all<'a, T: Iterator<Item = &'a Expr<'a>>>(
es: &mut T,
ignore_ids: &mut Vec<HirId>,
main_loop_id: HirId,
) -> NeverLoopResult {
es.map(|e| never_loop_expr(e, ignore_ids, main_loop_id))
.fold(NeverLoopResult::Otherwise, combine_both)
}
fn never_loop_expr_branch<'a, T: Iterator<Item = &'a Expr<'a>>>(e: &mut T, main_loop_id: HirId) -> NeverLoopResult {
e.map(|e| never_loop_expr(e, main_loop_id))
fn never_loop_expr_branch<'a, T: Iterator<Item = &'a Expr<'a>>>(
e: &mut T,
ignore_ids: &mut Vec<HirId>,
main_loop_id: HirId,
) -> NeverLoopResult {
e.map(|e| never_loop_expr(e, ignore_ids, main_loop_id))
.fold(NeverLoopResult::AlwaysBreak, combine_branches)
}

View file

@ -1,69 +0,0 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Spanned;
declare_clippy_lint! {
/// ### What it does
/// Lints subtraction between `Instant::now()` and another `Instant`.
///
/// ### Why is this bad?
/// It is easy to accidentally write `prev_instant - Instant::now()`, which will always be 0ns
/// as `Instant` subtraction saturates.
///
/// `prev_instant.elapsed()` also more clearly signals intention.
///
/// ### Example
/// ```rust
/// use std::time::Instant;
/// let prev_instant = Instant::now();
/// let duration = Instant::now() - prev_instant;
/// ```
/// Use instead:
/// ```rust
/// use std::time::Instant;
/// let prev_instant = Instant::now();
/// let duration = prev_instant.elapsed();
/// ```
#[clippy::version = "1.64.0"]
pub MANUAL_INSTANT_ELAPSED,
pedantic,
"subtraction between `Instant::now()` and previous `Instant`"
}
declare_lint_pass!(ManualInstantElapsed => [MANUAL_INSTANT_ELAPSED]);
impl LateLintPass<'_> for ManualInstantElapsed {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
if let ExprKind::Binary(Spanned {node: BinOpKind::Sub, ..}, lhs, rhs) = expr.kind
&& check_instant_now_call(cx, lhs)
&& let ty_resolved = cx.typeck_results().expr_ty(rhs)
&& let rustc_middle::ty::Adt(def, _) = ty_resolved.kind()
&& clippy_utils::match_def_path(cx, def.did(), &clippy_utils::paths::INSTANT)
&& let Some(sugg) = clippy_utils::sugg::Sugg::hir_opt(cx, rhs)
{
span_lint_and_sugg(
cx,
MANUAL_INSTANT_ELAPSED,
expr.span,
"manual implementation of `Instant::elapsed`",
"try",
format!("{}.elapsed()", sugg.maybe_par()),
Applicability::MachineApplicable,
);
}
}
}
fn check_instant_now_call(cx: &LateContext<'_>, expr_block: &'_ Expr<'_>) -> bool {
if let ExprKind::Call(fn_expr, []) = expr_block.kind
&& let Some(fn_id) = clippy_utils::path_def_id(cx, fn_expr)
&& clippy_utils::match_def_path(cx, fn_id, &clippy_utils::paths::INSTANT_NOW)
{
true
} else {
false
}
}

View file

@ -0,0 +1,158 @@
use rustc_ast::LitKind::{Byte, Char};
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, PatKind, RangeEnd};
use rustc_lint::{LateContext, LateLintPass};
use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{def_id::DefId, sym};
use clippy_utils::{
diagnostics::span_lint_and_sugg, in_constant, macros::root_macro_call, meets_msrv, msrvs, source::snippet,
};
declare_clippy_lint! {
/// ### What it does
/// Suggests to use dedicated built-in methods,
/// `is_ascii_(lowercase|uppercase|digit)` for checking on corresponding ascii range
///
/// ### Why is this bad?
/// Using the built-in functions is more readable and makes it
/// clear that it's not a specific subset of characters, but all
/// ASCII (lowercase|uppercase|digit) characters.
/// ### Example
/// ```rust
/// fn main() {
/// assert!(matches!('x', 'a'..='z'));
/// assert!(matches!(b'X', b'A'..=b'Z'));
/// assert!(matches!('2', '0'..='9'));
/// assert!(matches!('x', 'A'..='Z' | 'a'..='z'));
/// }
/// ```
/// Use instead:
/// ```rust
/// fn main() {
/// assert!('x'.is_ascii_lowercase());
/// assert!(b'X'.is_ascii_uppercase());
/// assert!('2'.is_ascii_digit());
/// assert!('x'.is_ascii_alphabetic());
/// }
/// ```
#[clippy::version = "1.66.0"]
pub MANUAL_IS_ASCII_CHECK,
style,
"use dedicated method to check ascii range"
}
impl_lint_pass!(ManualIsAsciiCheck => [MANUAL_IS_ASCII_CHECK]);
pub struct ManualIsAsciiCheck {
msrv: Option<RustcVersion>,
}
impl ManualIsAsciiCheck {
#[must_use]
pub fn new(msrv: Option<RustcVersion>) -> Self {
Self { msrv }
}
}
#[derive(Debug, PartialEq)]
enum CharRange {
/// 'a'..='z' | b'a'..=b'z'
LowerChar,
/// 'A'..='Z' | b'A'..=b'Z'
UpperChar,
/// AsciiLower | AsciiUpper
FullChar,
/// '0..=9'
Digit,
Otherwise,
}
impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if !meets_msrv(self.msrv, msrvs::IS_ASCII_DIGIT) {
return;
}
if in_constant(cx, expr.hir_id) && !meets_msrv(self.msrv, msrvs::IS_ASCII_DIGIT_CONST) {
return;
}
let Some(macro_call) = root_macro_call(expr.span) else { return };
if is_matches_macro(cx, macro_call.def_id) {
if let ExprKind::Match(recv, [arm, ..], _) = expr.kind {
let range = check_pat(&arm.pat.kind);
if let Some(sugg) = match range {
CharRange::UpperChar => Some("is_ascii_uppercase"),
CharRange::LowerChar => Some("is_ascii_lowercase"),
CharRange::FullChar => Some("is_ascii_alphabetic"),
CharRange::Digit => Some("is_ascii_digit"),
CharRange::Otherwise => None,
} {
let default_snip = "..";
// `snippet_with_applicability` may set applicability to `MaybeIncorrect` for
// macro span, so we check applicability manually by comparing `recv` is not default.
let recv = snippet(cx, recv.span, default_snip);
let applicability = if recv == default_snip {
Applicability::HasPlaceholders
} else {
Applicability::MachineApplicable
};
span_lint_and_sugg(
cx,
MANUAL_IS_ASCII_CHECK,
macro_call.span,
"manual check for common ascii range",
"try",
format!("{recv}.{sugg}()"),
applicability,
);
}
}
}
}
extract_msrv_attr!(LateContext);
}
fn check_pat(pat_kind: &PatKind<'_>) -> CharRange {
match pat_kind {
PatKind::Or(pats) => {
let ranges = pats.iter().map(|p| check_pat(&p.kind)).collect::<Vec<_>>();
if ranges.len() == 2 && ranges.contains(&CharRange::UpperChar) && ranges.contains(&CharRange::LowerChar) {
CharRange::FullChar
} else {
CharRange::Otherwise
}
},
PatKind::Range(Some(start), Some(end), kind) if *kind == RangeEnd::Included => check_range(start, end),
_ => CharRange::Otherwise,
}
}
fn check_range(start: &Expr<'_>, end: &Expr<'_>) -> CharRange {
if let ExprKind::Lit(start_lit) = &start.kind
&& let ExprKind::Lit(end_lit) = &end.kind {
match (&start_lit.node, &end_lit.node) {
(Char('a'), Char('z')) | (Byte(b'a'), Byte(b'z')) => CharRange::LowerChar,
(Char('A'), Char('Z')) | (Byte(b'A'), Byte(b'Z')) => CharRange::UpperChar,
(Char('0'), Char('9')) | (Byte(b'0'), Byte(b'9')) => CharRange::Digit,
_ => CharRange::Otherwise,
}
} else {
CharRange::Otherwise
}
}
fn is_matches_macro(cx: &LateContext<'_>, macro_def_id: DefId) -> bool {
if let Some(name) = cx.tcx.get_diagnostic_name(macro_def_id) {
return sym::matches_macro == name;
}
false
}

View file

@ -0,0 +1,297 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::higher::IfLetOrMatch;
use clippy_utils::source::snippet_opt;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::visitors::{for_each_expr, Descend};
use clippy_utils::{meets_msrv, msrvs, peel_blocks};
use if_chain::if_chain;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, MatchSource, Pat, PatKind, QPath, Stmt, StmtKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::symbol::sym;
use rustc_span::Span;
use serde::Deserialize;
use std::ops::ControlFlow;
declare_clippy_lint! {
/// ### What it does
///
/// Warn of cases where `let...else` could be used
///
/// ### Why is this bad?
///
/// `let...else` provides a standard construct for this pattern
/// that people can easily recognize. It's also more compact.
///
/// ### Example
///
/// ```rust
/// # let w = Some(0);
/// let v = if let Some(v) = w { v } else { return };
/// ```
///
/// Could be written:
///
/// ```rust
/// # #![feature(let_else)]
/// # fn main () {
/// # let w = Some(0);
/// let Some(v) = w else { return };
/// # }
/// ```
#[clippy::version = "1.67.0"]
pub MANUAL_LET_ELSE,
pedantic,
"manual implementation of a let...else statement"
}
pub struct ManualLetElse {
msrv: Option<RustcVersion>,
matches_behaviour: MatchLintBehaviour,
}
impl ManualLetElse {
#[must_use]
pub fn new(msrv: Option<RustcVersion>, 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>) {
let if_let_or_match = if_chain! {
if meets_msrv(self.msrv, msrvs::LET_ELSE);
if !in_external_macro(cx.sess(), stmt.span);
if let StmtKind::Local(local) = stmt.kind;
if let Some(init) = local.init;
if local.els.is_none();
if local.ty.is_none();
if init.span.ctxt() == stmt.span.ctxt();
if let Some(if_let_or_match) = IfLetOrMatch::parse(cx, init);
then {
if_let_or_match
} else {
return;
}
};
match if_let_or_match {
IfLetOrMatch::IfLet(if_let_expr, let_pat, if_then, if_else) => if_chain! {
if expr_is_simple_identity(let_pat, if_then);
if let Some(if_else) = if_else;
if expr_diverges(cx, if_else);
then {
emit_manual_let_else(cx, stmt.span, if_let_expr, let_pat, if_else);
}
},
IfLetOrMatch::Match(match_expr, arms, source) => {
if self.matches_behaviour == MatchLintBehaviour::Never {
return;
}
if source != MatchSource::Normal {
return;
}
// Any other number than two arms doesn't (neccessarily)
// have a trivial mapping to let else.
if arms.len() != 2 {
return;
}
// Guards don't give us an easy mapping either
if arms.iter().any(|arm| arm.guard.is_some()) {
return;
}
let check_types = self.matches_behaviour == MatchLintBehaviour::WellKnownTypes;
let diverging_arm_opt = arms
.iter()
.enumerate()
.find(|(_, arm)| expr_diverges(cx, arm.body) && pat_allowed_for_else(cx, arm.pat, check_types));
let Some((idx, diverging_arm)) = diverging_arm_opt else { return; };
let pat_arm = &arms[1 - idx];
if !expr_is_simple_identity(pat_arm.pat, pat_arm.body) {
return;
}
emit_manual_let_else(cx, stmt.span, match_expr, pat_arm.pat, diverging_arm.body);
},
}
}
extract_msrv_attr!(LateContext);
}
fn emit_manual_let_else(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, pat: &Pat<'_>, else_body: &Expr<'_>) {
span_lint_and_then(
cx,
MANUAL_LET_ELSE,
span,
"this could be rewritten as `let...else`",
|diag| {
// This is far from perfect, for example there needs to be:
// * mut additions for the bindings
// * renamings of the bindings
// * unused binding collision detection with existing ones
// * putting patterns with at the top level | inside ()
// for this to be machine applicable.
let app = Applicability::HasPlaceholders;
if let Some(sn_pat) = snippet_opt(cx, pat.span) &&
let Some(sn_expr) = snippet_opt(cx, expr.span) &&
let Some(sn_else) = snippet_opt(cx, else_body.span)
{
let else_bl = if matches!(else_body.kind, ExprKind::Block(..)) {
sn_else
} else {
format!("{{ {sn_else} }}")
};
let sugg = format!("let {sn_pat} = {sn_expr} else {else_bl};");
diag.span_suggestion(span, "consider writing", sugg, app);
}
},
);
}
fn expr_diverges(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool {
fn is_never(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool {
if let Some(ty) = cx.typeck_results().expr_ty_opt(expr) {
return ty.is_never();
}
false
}
// We can't just call is_never on expr and be done, because the type system
// sometimes coerces the ! type to something different before we can get
// our hands on it. So instead, we do a manual search. We do fall back to
// is_never in some places when there is no better alternative.
for_each_expr(expr, |ex| {
match ex.kind {
ExprKind::Continue(_) | ExprKind::Break(_, _) | ExprKind::Ret(_) => ControlFlow::Break(()),
ExprKind::Call(call, _) => {
if is_never(cx, ex) || is_never(cx, call) {
return ControlFlow::Break(());
}
ControlFlow::Continue(Descend::Yes)
},
ExprKind::MethodCall(..) => {
if is_never(cx, ex) {
return ControlFlow::Break(());
}
ControlFlow::Continue(Descend::Yes)
},
ExprKind::If(if_expr, if_then, if_else) => {
let else_diverges = if_else.map_or(false, |ex| expr_diverges(cx, ex));
let diverges = expr_diverges(cx, if_expr) || (else_diverges && expr_diverges(cx, if_then));
if diverges {
return ControlFlow::Break(());
}
ControlFlow::Continue(Descend::No)
},
ExprKind::Match(match_expr, match_arms, _) => {
let diverges = expr_diverges(cx, match_expr)
|| match_arms.iter().all(|arm| {
let guard_diverges = arm.guard.as_ref().map_or(false, |g| expr_diverges(cx, g.body()));
guard_diverges || expr_diverges(cx, arm.body)
});
if diverges {
return ControlFlow::Break(());
}
ControlFlow::Continue(Descend::No)
},
// Don't continue into loops or labeled blocks, as they are breakable,
// and we'd have to start checking labels.
ExprKind::Block(_, Some(_)) | ExprKind::Loop(..) => ControlFlow::Continue(Descend::No),
// Default: descend
_ => ControlFlow::Continue(Descend::Yes),
}
})
.is_some()
}
fn pat_allowed_for_else(cx: &LateContext<'_>, pat: &'_ Pat<'_>, check_types: bool) -> bool {
// Check whether the pattern contains any bindings, as the
// binding might potentially be used in the body.
// TODO: only look for *used* bindings.
let mut has_bindings = false;
pat.each_binding_or_first(&mut |_, _, _, _| has_bindings = true);
if has_bindings {
return false;
}
// If we shouldn't check the types, exit early.
if !check_types {
return true;
}
// Check whether any possibly "unknown" patterns are included,
// because users might not know which values some enum has.
// Well-known enums are excepted, as we assume people know them.
// We do a deep check, to be able to disallow Err(En::Foo(_))
// for usage of the En::Foo variant, as we disallow En::Foo(_),
// but we allow Err(_).
let typeck_results = cx.typeck_results();
let mut has_disallowed = false;
pat.walk_always(|pat| {
// Only do the check if the type is "spelled out" in the pattern
if !matches!(
pat.kind,
PatKind::Struct(..) | PatKind::TupleStruct(..) | PatKind::Path(..)
) {
return;
};
let ty = typeck_results.pat_ty(pat);
// Option and Result are allowed, everything else isn't.
if !(is_type_diagnostic_item(cx, ty, sym::Option) || is_type_diagnostic_item(cx, ty, sym::Result)) {
has_disallowed = true;
}
});
!has_disallowed
}
/// Checks if the passed block is a simple identity referring to bindings created by the pattern
fn expr_is_simple_identity(pat: &'_ Pat<'_>, expr: &'_ Expr<'_>) -> bool {
// We support patterns with multiple bindings and tuples, like:
// let ... = if let (Some(foo), bar) = g() { (foo, bar) } else { ... }
let peeled = peel_blocks(expr);
let paths = match peeled.kind {
ExprKind::Tup(exprs) | ExprKind::Array(exprs) => exprs,
ExprKind::Path(_) => std::slice::from_ref(peeled),
_ => return false,
};
let mut pat_bindings = FxHashSet::default();
pat.each_binding_or_first(&mut |_ann, _hir_id, _sp, ident| {
pat_bindings.insert(ident);
});
if pat_bindings.len() < paths.len() {
return false;
}
for path in paths {
if_chain! {
if let ExprKind::Path(QPath::Resolved(_ty, path)) = path.kind;
if let [path_seg] = path.segments;
then {
if !pat_bindings.remove(&path_seg.ident) {
return false;
}
} else {
return false;
}
}
}
true
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize)]
pub enum MatchLintBehaviour {
AllTypes,
WellKnownTypes,
Never,
}

View file

@ -119,7 +119,7 @@ fn is_unit_expression(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
/// semicolons, which causes problems when generating a suggestion. Given an
/// expression that evaluates to '()' or '!', recursively remove useless braces
/// and semi-colons until is suitable for including in the suggestion template
fn reduce_unit_expression<'a>(cx: &LateContext<'_>, expr: &'a hir::Expr<'_>) -> Option<Span> {
fn reduce_unit_expression(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Span> {
if !is_unit_expression(cx, expr) {
return None;
}

View file

@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::{path_to_local_id, peel_blocks, strip_pat_refs};
use rustc_errors::Applicability;
use rustc_hir::{ExprKind, Local, MatchSource, PatKind, QPath};
use rustc_hir::{ByRef, ExprKind, Local, MatchSource, PatKind, QPath};
use rustc_lint::LateContext;
use super::INFALLIBLE_DESTRUCTURING_MATCH;
@ -16,7 +16,7 @@ pub(crate) fn check(cx: &LateContext<'_>, local: &Local<'_>) -> bool {
if let PatKind::TupleStruct(
QPath::Resolved(None, variant_name), args, _) = arms[0].pat.kind;
if args.len() == 1;
if let PatKind::Binding(_, arg, ..) = strip_pat_refs(&args[0]).kind;
if let PatKind::Binding(binding, arg, ..) = strip_pat_refs(&args[0]).kind;
let body = peel_blocks(arms[0].body);
if path_to_local_id(body, arg);
@ -30,8 +30,9 @@ pub(crate) fn check(cx: &LateContext<'_>, local: &Local<'_>) -> bool {
Consider using `let`",
"try this",
format!(
"let {}({}) = {};",
"let {}({}{}) = {};",
snippet_with_applicability(cx, variant_name.span, "..", &mut applicability),
if binding.0 == ByRef::Yes { "ref " } else { "" },
snippet_with_applicability(cx, local.pat.span, "..", &mut applicability),
snippet_with_applicability(cx, target.span, "..", &mut applicability),
),

View file

@ -62,7 +62,7 @@ fn peels_blocks_incl_unsafe<'a>(expr: &'a Expr<'a>) -> &'a Expr<'a> {
// <expr>
// }
// Returns true if <expr> resolves to `Some(x)`, `false` otherwise
fn is_some_expr<'tcx>(cx: &LateContext<'_>, target: HirId, ctxt: SyntaxContext, expr: &'tcx Expr<'_>) -> bool {
fn is_some_expr(cx: &LateContext<'_>, target: HirId, ctxt: SyntaxContext, expr: &Expr<'_>) -> bool {
if let Some(inner_expr) = peels_blocks_incl_unsafe_opt(expr) {
// there can be not statements in the block as they would be removed when switching to `.filter`
if let ExprKind::Call(callee, [arg]) = inner_expr.kind {

View file

@ -83,8 +83,8 @@ fn set_diagnostic<'tcx>(diag: &mut Diagnostic, cx: &LateContext<'tcx>, expr: &'t
/// If the expression is an `ExprKind::Match`, check if the scrutinee has a significant drop that
/// may have a surprising lifetime.
fn has_significant_drop_in_scrutinee<'tcx, 'a>(
cx: &'a LateContext<'tcx>,
fn has_significant_drop_in_scrutinee<'tcx>(
cx: &LateContext<'tcx>,
scrutinee: &'tcx Expr<'tcx>,
source: MatchSource,
) -> Option<(Vec<FoundSigDrop>, &'static str)> {
@ -226,7 +226,7 @@ impl<'a, 'tcx> SigDropHelper<'a, 'tcx> {
/// This will try to set the current suggestion (so it can be moved into the suggestions vec
/// later). If `allow_move_and_clone` is false, the suggestion *won't* be set -- this gives us
/// an opportunity to look for another type in the chain that will be trivially copyable.
/// However, if we are at the the end of the chain, we want to accept whatever is there. (The
/// However, if we are at the end of the chain, we want to accept whatever is there. (The
/// suggestion won't actually be output, but the diagnostic message will be output, so the user
/// can determine the best way to handle the lint.)
fn try_setting_current_suggestion(&mut self, expr: &'tcx Expr<'_>, allow_move_and_clone: bool) {
@ -377,7 +377,7 @@ impl<'a, 'tcx> ArmSigDropHelper<'a, 'tcx> {
}
}
fn has_significant_drop_in_arms<'tcx, 'a>(cx: &'a LateContext<'tcx>, arms: &'tcx [Arm<'_>]) -> FxHashSet<Span> {
fn has_significant_drop_in_arms<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) -> FxHashSet<Span> {
let mut helper = ArmSigDropHelper::new(cx);
for arm in arms {
helper.visit_expr(arm.body);

View file

@ -153,7 +153,7 @@ fn pat_in_candidate_enum<'a>(cx: &LateContext<'a>, ty: Ty<'a>, pat: &Pat<'_>) ->
}
/// Returns `true` if the given type is an enum we know won't be expanded in the future
fn in_candidate_enum<'a>(cx: &LateContext<'a>, ty: Ty<'_>) -> bool {
fn in_candidate_enum(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
// list of candidate `Enum`s we know will never get any more members
let candidates = [sym::Cow, sym::Option, sym::Result];

View file

@ -9,8 +9,8 @@ use rustc_lint::LateContext;
use rustc_lint::Lint;
/// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints with `unwrap()`.
pub(super) fn check<'tcx>(
cx: &LateContext<'tcx>,
pub(super) fn check(
cx: &LateContext<'_>,
info: &crate::methods::BinaryExprInfo<'_>,
chain_methods: &[&str],
lint: &'static Lint,

View file

@ -4,7 +4,7 @@ use rustc_lint::LateContext;
use super::CHARS_LAST_CMP;
/// Checks for the `CHARS_LAST_CMP` lint.
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, info: &crate::methods::BinaryExprInfo<'_>) -> bool {
pub(super) fn check(cx: &LateContext<'_>, info: &crate::methods::BinaryExprInfo<'_>) -> bool {
if chars_cmp::check(cx, info, &["chars", "last"], CHARS_LAST_CMP, "ends_with") {
true
} else {

View file

@ -4,7 +4,7 @@ use rustc_lint::LateContext;
use super::CHARS_LAST_CMP;
/// Checks for the `CHARS_LAST_CMP` lint with `unwrap()`.
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, info: &crate::methods::BinaryExprInfo<'_>) -> bool {
pub(super) fn check(cx: &LateContext<'_>, info: &crate::methods::BinaryExprInfo<'_>) -> bool {
if chars_cmp_with_unwrap::check(cx, info, &["chars", "last", "unwrap"], CHARS_LAST_CMP, "ends_with") {
true
} else {

View file

@ -3,6 +3,6 @@ use rustc_lint::LateContext;
use super::CHARS_NEXT_CMP;
/// Checks for the `CHARS_NEXT_CMP` lint.
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, info: &crate::methods::BinaryExprInfo<'_>) -> bool {
pub(super) fn check(cx: &LateContext<'_>, info: &crate::methods::BinaryExprInfo<'_>) -> bool {
crate::methods::chars_cmp::check(cx, info, &["chars", "next"], CHARS_NEXT_CMP, "starts_with")
}

View file

@ -3,6 +3,6 @@ use rustc_lint::LateContext;
use super::CHARS_NEXT_CMP;
/// Checks for the `CHARS_NEXT_CMP` lint with `unwrap()`.
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, info: &crate::methods::BinaryExprInfo<'_>) -> bool {
pub(super) fn check(cx: &LateContext<'_>, info: &crate::methods::BinaryExprInfo<'_>) -> bool {
crate::methods::chars_cmp_with_unwrap::check(cx, info, &["chars", "next", "unwrap"], CHARS_NEXT_CMP, "starts_with")
}

View file

@ -23,7 +23,7 @@ pub(super) fn check<'tcx>(
// If the parent node's `to` argument is the same as the `to` argument
// of the last replace call in the current chain, don't lint as it was already linted
if let Some(parent) = get_parent_expr(cx, expr)
&& let Some(("replace", _, [current_from, current_to], _)) = method_call(parent)
&& let Some(("replace", _, [current_from, current_to], _, _)) = method_call(parent)
&& eq_expr_value(cx, to, current_to)
&& from_kind == cx.typeck_results().expr_ty(current_from).peel_refs().kind()
{
@ -48,7 +48,7 @@ fn collect_replace_calls<'tcx>(
let mut from_args = VecDeque::new();
let _: Option<()> = for_each_expr(expr, |e| {
if let Some(("replace", _, [from, to], _)) = method_call(e) {
if let Some(("replace", _, [from, to], _, _)) = method_call(e) {
if eq_expr_value(cx, to_arg, to) && cx.typeck_results().expr_ty(from).peel_refs().is_char() {
methods.push_front(e);
from_args.push_front(from);
@ -78,7 +78,7 @@ fn check_consecutive_replace_calls<'tcx>(
.collect();
let app = Applicability::MachineApplicable;
let earliest_replace_call = replace_methods.methods.front().unwrap();
if let Some((_, _, [..], span_lo)) = method_call(earliest_replace_call) {
if let Some((_, _, [..], span_lo, _)) = method_call(earliest_replace_call) {
span_lint_and_sugg(
cx,
COLLAPSIBLE_STR_REPLACE,

View file

@ -1,5 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::is_in_test_function;
use clippy_utils::is_in_cfg_test;
use clippy_utils::ty::is_type_diagnostic_item;
use rustc_hir as hir;
use rustc_lint::LateContext;
@ -18,16 +18,16 @@ pub(super) fn check(
let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs();
let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) && !is_err {
Some((EXPECT_USED, "an Option", "None", ""))
Some((EXPECT_USED, "an `Option`", "None", ""))
} else if is_type_diagnostic_item(cx, obj_ty, sym::Result) {
Some((EXPECT_USED, "a Result", if is_err { "Ok" } else { "Err" }, "an "))
Some((EXPECT_USED, "a `Result`", if is_err { "Ok" } else { "Err" }, "an "))
} else {
None
};
let method = if is_err { "expect_err" } else { "expect" };
if allow_expect_in_tests && is_in_test_function(cx.tcx, expr.hir_id) {
if allow_expect_in_tests && is_in_cfg_test(cx.tcx, expr.hir_id) {
return;
}
@ -36,7 +36,7 @@ pub(super) fn check(
cx,
lint,
expr.span,
&format!("used `{method}()` on `{kind}` value"),
&format!("used `{method}()` on {kind} value"),
None,
&format!("if this value is {none_prefix}`{none_value}`, it will panic"),
);

View file

@ -17,7 +17,7 @@ use super::MANUAL_FILTER_MAP;
use super::MANUAL_FIND_MAP;
use super::OPTION_FILTER_MAP;
fn is_method<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Symbol) -> bool {
fn is_method(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol) -> bool {
match &expr.kind {
hir::ExprKind::Path(QPath::TypeRelative(_, mname)) => mname.ident.name == method_name,
hir::ExprKind::Path(QPath::Resolved(_, segments)) => {
@ -46,7 +46,7 @@ fn is_method<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Sy
}
}
fn is_option_filter_map<'tcx>(cx: &LateContext<'tcx>, filter_arg: &hir::Expr<'_>, map_arg: &hir::Expr<'_>) -> bool {
fn is_option_filter_map(cx: &LateContext<'_>, filter_arg: &hir::Expr<'_>, map_arg: &hir::Expr<'_>) -> bool {
is_method(cx, map_arg, sym::unwrap) && is_method(cx, filter_arg, sym!(is_some))
}
@ -66,8 +66,8 @@ fn is_filter_some_map_unwrap(
/// lint use of `filter().map()` or `find().map()` for `Iterators`
#[allow(clippy::too_many_arguments)]
pub(super) fn check<'tcx>(
cx: &LateContext<'tcx>,
pub(super) fn check(
cx: &LateContext<'_>,
expr: &hir::Expr<'_>,
filter_recv: &hir::Expr<'_>,
filter_arg: &hir::Expr<'_>,

View file

@ -12,8 +12,8 @@ use rustc_span::symbol::{Symbol, sym};
use super::INEFFICIENT_TO_STRING;
/// Checks for the `INEFFICIENT_TO_STRING` lint
pub fn check<'tcx>(
cx: &LateContext<'tcx>,
pub fn check(
cx: &LateContext<'_>,
expr: &hir::Expr<'_>,
method_name: Symbol,
receiver: &hir::Expr<'_>,

View file

@ -10,7 +10,7 @@ use rustc_span::sym;
use super::ITER_NTH_ZERO;
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) {
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) {
if_chain! {
if is_trait_method(cx, expr, sym::Iterator);
if let Some((Constant::Int(0), _)) = constant(cx, cx.typeck_results(), arg);

View file

@ -25,7 +25,7 @@ impl IterType {
}
}
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, method_name: &str, recv: &Expr<'_>) {
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: &str, recv: &Expr<'_>) {
let item = match recv.kind {
ExprKind::Array([]) => None,
ExprKind::Array([e]) => Some(e),

View file

@ -67,7 +67,7 @@ enum MinMax {
Max,
}
fn is_min_or_max<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) -> Option<MinMax> {
fn is_min_or_max(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<MinMax> {
// `T::max_value()` `T::min_value()` inherent methods
if_chain! {
if let hir::ExprKind::Call(func, args) = &expr.kind;

View file

@ -59,10 +59,8 @@ pub(super) fn check(
if let ExprKind::Call(repeat_fn, [repeat_arg]) = take_self_arg.kind;
if is_path_diagnostic_item(cx, repeat_fn, sym::iter_repeat);
if is_type_lang_item(cx, cx.typeck_results().expr_ty(collect_expr), LangItem::String);
if let Some(collect_id) = cx.typeck_results().type_dependent_def_id(collect_expr.hir_id);
if let Some(take_id) = cx.typeck_results().type_dependent_def_id(take_expr.hir_id);
if let Some(iter_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator);
if cx.tcx.trait_of_item(collect_id) == Some(iter_trait_id);
if cx.tcx.trait_of_item(take_id) == Some(iter_trait_id);
if let Some(repeat_kind) = parse_repeat_arg(cx, repeat_arg);
let ctxt = collect_expr.span.ctxt();

View file

@ -15,11 +15,11 @@ use rustc_span::{sym, Span};
use super::MAP_CLONE;
pub(super) fn check<'tcx>(
pub(super) fn check(
cx: &LateContext<'_>,
e: &hir::Expr<'_>,
recv: &hir::Expr<'_>,
arg: &'tcx hir::Expr<'_>,
arg: &hir::Expr<'_>,
msrv: Option<RustcVersion>,
) {
if_chain! {

View file

@ -1,5 +1,4 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::is_trait_method;
use clippy_utils::source::snippet;
use clippy_utils::ty::is_type_diagnostic_item;
use if_chain::if_chain;
@ -11,18 +10,10 @@ use rustc_span::symbol::sym;
use super::MAP_COLLECT_RESULT_UNIT;
pub(super) fn check(
cx: &LateContext<'_>,
expr: &hir::Expr<'_>,
iter: &hir::Expr<'_>,
map_fn: &hir::Expr<'_>,
collect_recv: &hir::Expr<'_>,
) {
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, iter: &hir::Expr<'_>, map_fn: &hir::Expr<'_>) {
// return of collect `Result<(),_>`
let collect_ret_ty = cx.typeck_results().expr_ty(expr);
if_chain! {
// called on Iterator
if is_trait_method(cx, collect_recv, sym::Iterator);
// return of collect `Result<(),_>`
let collect_ret_ty = cx.typeck_results().expr_ty(expr);
if is_type_diagnostic_item(cx, collect_ret_ty, sym::Result);
if let ty::Adt(_, substs) = collect_ret_ty.kind();
if let Some(result_t) = substs.types().next();

View file

@ -6,7 +6,7 @@ use rustc_span::sym;
use super::MAP_ERR_IGNORE;
pub(super) fn check<'tcx>(cx: &LateContext<'_>, e: &Expr<'_>, arg: &'tcx Expr<'_>) {
pub(super) fn check(cx: &LateContext<'_>, e: &Expr<'_>, arg: &Expr<'_>) {
if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
&& let Some(impl_id) = cx.tcx.impl_of_method(method_id)
&& is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id), sym::Result)

View file

@ -54,6 +54,7 @@ mod map_flatten;
mod map_identity;
mod map_unwrap_or;
mod mut_mutex_lock;
mod needless_collect;
mod needless_option_as_deref;
mod needless_option_take;
mod no_effect_replace;
@ -69,6 +70,8 @@ mod path_buf_push_overwrite;
mod range_zip_with_len;
mod repeat_once;
mod search_is_some;
mod seek_from_current;
mod seek_to_start_instead_of_rewind;
mod single_char_add_str;
mod single_char_insert_string;
mod single_char_pattern;
@ -101,12 +104,11 @@ mod zst_offset;
use bind_instead_of_map::BindInsteadOfMap;
use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
use clippy_utils::ty::{contains_adt_constructor, implements_trait, is_copy, is_type_diagnostic_item};
use clippy_utils::{contains_return, is_trait_method, iter_input_pats, meets_msrv, msrvs, return_ty};
use clippy_utils::ty::{contains_ty_adt_constructor_opaque, implements_trait, is_copy, is_type_diagnostic_item};
use clippy_utils::{contains_return, is_bool, is_trait_method, iter_input_pats, meets_msrv, msrvs, return_ty};
use if_chain::if_chain;
use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_hir::{Expr, ExprKind, PrimTy, QPath, TraitItem, TraitItemKind};
use rustc_hir::{Expr, ExprKind, TraitItem, TraitItemKind};
use rustc_hir_analysis::hir_ty_to_ty;
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
@ -156,9 +158,9 @@ declare_clippy_lint! {
/// ```
/// Use instead:
/// ```rust
/// let hello = "hesuo worpd".replace(&['s', 'u', 'p'], "l");
/// let hello = "hesuo worpd".replace(['s', 'u', 'p'], "l");
/// ```
#[clippy::version = "1.64.0"]
#[clippy::version = "1.65.0"]
pub COLLAPSIBLE_STR_REPLACE,
perf,
"collapse consecutive calls to str::replace (2 or more) into a single call"
@ -829,32 +831,30 @@ declare_clippy_lint! {
/// etc. instead.
///
/// ### Why is this bad?
/// The function will always be called and potentially
/// allocate an object acting as the default.
/// The function will always be called. This is only bad if it allocates or
/// does some non-trivial amount of work.
///
/// ### Known problems
/// If the function has side-effects, not calling it will
/// change the semantic of the program, but you shouldn't rely on that anyway.
/// If the function has side-effects, not calling it will change the
/// semantic of the program, but you shouldn't rely on that.
///
/// The lint also cannot figure out whether the function you call is
/// actually expensive to call or not.
///
/// ### Example
/// ```rust
/// # let foo = Some(String::new());
/// foo.unwrap_or(String::new());
/// foo.unwrap_or(String::from("empty"));
/// ```
///
/// Use instead:
/// ```rust
/// # let foo = Some(String::new());
/// foo.unwrap_or_else(String::new);
///
/// // or
///
/// # let foo = Some(String::new());
/// foo.unwrap_or_default();
/// foo.unwrap_or_else(|| String::from("empty"));
/// ```
#[clippy::version = "pre 1.29.0"]
pub OR_FUN_CALL,
perf,
nursery,
"using any `*or` method with a function call, which suggests `*or_else`"
}
@ -1728,7 +1728,7 @@ declare_clippy_lint! {
declare_clippy_lint! {
/// ### What it does
/// Checks for usage of `_.as_ref().map(Deref::deref)` or it's aliases (such as String::as_str).
/// Checks for usage of `_.as_ref().map(Deref::deref)` or its aliases (such as String::as_str).
///
/// ### Why is this bad?
/// Readability, this can be written more concisely as
@ -2094,8 +2094,7 @@ declare_clippy_lint! {
/// let s = "Hello world!";
/// let cow = Cow::Borrowed(s);
///
/// let data = cow.into_owned();
/// assert!(matches!(data, String))
/// let _data: String = cow.into_owned();
/// ```
#[clippy::version = "1.65.0"]
pub SUSPICIOUS_TO_OWNED,
@ -2426,7 +2425,7 @@ declare_clippy_lint! {
/// ### Known problems
///
/// The type of the resulting iterator might become incompatible with its usage
#[clippy::version = "1.64.0"]
#[clippy::version = "1.65.0"]
pub ITER_ON_SINGLE_ITEMS,
nursery,
"Iterator for array of length 1"
@ -2458,7 +2457,7 @@ declare_clippy_lint! {
/// ### Known problems
///
/// The type of the resulting iterator might become incompatible with its usage
#[clippy::version = "1.64.0"]
#[clippy::version = "1.65.0"]
pub ITER_ON_EMPTY_COLLECTIONS,
nursery,
"Iterator for empty array"
@ -3066,6 +3065,102 @@ declare_clippy_lint! {
"iterating on map using `iter` when `keys` or `values` would do"
}
declare_clippy_lint! {
/// ### What it does
///
/// Checks an argument of `seek` method of `Seek` trait
/// and if it start seek from `SeekFrom::Current(0)`, suggests `stream_position` instead.
///
/// ### Why is this bad?
///
/// Readability. Use dedicated method.
///
/// ### Example
///
/// ```rust,no_run
/// use std::fs::File;
/// use std::io::{self, Write, Seek, SeekFrom};
///
/// fn main() -> io::Result<()> {
/// let mut f = File::create("foo.txt")?;
/// f.write_all(b"Hello")?;
/// eprintln!("Written {} bytes", f.seek(SeekFrom::Current(0))?);
///
/// Ok(())
/// }
/// ```
/// Use instead:
/// ```rust,no_run
/// use std::fs::File;
/// use std::io::{self, Write, Seek, SeekFrom};
///
/// fn main() -> io::Result<()> {
/// let mut f = File::create("foo.txt")?;
/// f.write_all(b"Hello")?;
/// eprintln!("Written {} bytes", f.stream_position()?);
///
/// Ok(())
/// }
/// ```
#[clippy::version = "1.66.0"]
pub SEEK_FROM_CURRENT,
complexity,
"use dedicated method for seek from current position"
}
declare_clippy_lint! {
/// ### What it does
///
/// Checks for jumps to the start of a stream that implements `Seek`
/// and uses the `seek` method providing `Start` as parameter.
///
/// ### Why is this bad?
///
/// Readability. There is a specific method that was implemented for
/// this exact scenario.
///
/// ### Example
/// ```rust
/// # use std::io;
/// fn foo<T: io::Seek>(t: &mut T) {
/// t.seek(io::SeekFrom::Start(0));
/// }
/// ```
/// Use instead:
/// ```rust
/// # use std::io;
/// fn foo<T: io::Seek>(t: &mut T) {
/// t.rewind();
/// }
/// ```
#[clippy::version = "1.66.0"]
pub SEEK_TO_START_INSTEAD_OF_REWIND,
complexity,
"jumping to the start of stream using `seek` method"
}
declare_clippy_lint! {
/// ### What it does
/// Checks for functions collecting an iterator when collect
/// is not needed.
///
/// ### Why is this bad?
/// `collect` causes the allocation of a new data structure,
/// when this allocation may not be needed.
///
/// ### Example
/// ```rust
/// # let iterator = vec![1].into_iter();
/// let len = iterator.clone().collect::<Vec<_>>().len();
/// // should be
/// let len = iterator.count();
/// ```
#[clippy::version = "1.30.0"]
pub NEEDLESS_COLLECT,
nursery,
"collecting an iterator when collect is not needed"
}
pub struct Methods {
avoid_breaking_exported_api: bool,
msrv: Option<RustcVersion>,
@ -3190,16 +3285,19 @@ impl_lint_pass!(Methods => [
VEC_RESIZE_TO_ZERO,
VERBOSE_FILE_READS,
ITER_KV_MAP,
SEEK_FROM_CURRENT,
SEEK_TO_START_INSTEAD_OF_REWIND,
NEEDLESS_COLLECT,
]);
/// Extracts a method call name, args, and `Span` of the method name.
fn method_call<'tcx>(
recv: &'tcx hir::Expr<'tcx>,
) -> Option<(&'tcx str, &'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>], Span)> {
if let ExprKind::MethodCall(path, receiver, args, _) = recv.kind {
) -> Option<(&'tcx str, &'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>], Span, Span)> {
if let ExprKind::MethodCall(path, receiver, args, call_span) = recv.kind {
if !args.iter().any(|e| e.span.from_expansion()) && !receiver.span.from_expansion() {
let name = path.ident.name.as_str();
return Some((name, receiver, args, path.ident.span));
return Some((name, receiver, args, path.ident.span, call_span));
}
}
None
@ -3316,36 +3414,10 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
if let hir::ImplItemKind::Fn(_, _) = impl_item.kind {
let ret_ty = return_ty(cx, impl_item.hir_id());
// walk the return type and check for Self (this does not check associated types)
if let Some(self_adt) = self_ty.ty_adt_def() {
if contains_adt_constructor(ret_ty, self_adt) {
return;
}
} else if ret_ty.contains(self_ty) {
if contains_ty_adt_constructor_opaque(cx, ret_ty, self_ty) {
return;
}
// if return type is impl trait, check the associated types
if let ty::Opaque(def_id, _) = *ret_ty.kind() {
// one of the associated types must be Self
for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) {
if let ty::PredicateKind::Projection(projection_predicate) = predicate.kind().skip_binder() {
let assoc_ty = match projection_predicate.term.unpack() {
ty::TermKind::Ty(ty) => ty,
ty::TermKind::Const(_c) => continue,
};
// walk the associated type and check for Self
if let Some(self_adt) = self_ty.ty_adt_def() {
if contains_adt_constructor(assoc_ty, self_adt) {
return;
}
} else if assoc_ty.contains(self_ty) {
return;
}
}
}
}
if name == "new" && ret_ty != self_ty {
span_lint(
cx,
@ -3411,7 +3483,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
impl Methods {
#[allow(clippy::too_many_lines)]
fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if let Some((name, recv, args, span)) = method_call(expr) {
if let Some((name, recv, args, span, call_span)) = method_call(expr) {
match (name, args) {
("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [_arg]) => {
zst_offset::check(cx, expr, recv);
@ -3430,28 +3502,31 @@ impl Methods {
("as_ref", []) => useless_asref::check(cx, expr, "as_ref", recv),
("assume_init", []) => uninit_assumed_init::check(cx, expr, recv),
("cloned", []) => cloned_instead_of_copied::check(cx, expr, recv, span, self.msrv),
("collect", []) => match method_call(recv) {
Some((name @ ("cloned" | "copied"), recv2, [], _)) => {
iter_cloned_collect::check(cx, name, expr, recv2);
},
Some(("map", m_recv, [m_arg], _)) => {
map_collect_result_unit::check(cx, expr, m_recv, m_arg, recv);
},
Some(("take", take_self_arg, [take_arg], _)) => {
if meets_msrv(self.msrv, msrvs::STR_REPEAT) {
manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg);
}
},
_ => {},
("collect", []) if is_trait_method(cx, expr, sym::Iterator) => {
needless_collect::check(cx, span, expr, recv, call_span);
match method_call(recv) {
Some((name @ ("cloned" | "copied"), recv2, [], _, _)) => {
iter_cloned_collect::check(cx, name, expr, recv2);
},
Some(("map", m_recv, [m_arg], _, _)) => {
map_collect_result_unit::check(cx, expr, m_recv, m_arg);
},
Some(("take", take_self_arg, [take_arg], _, _)) => {
if meets_msrv(self.msrv, msrvs::STR_REPEAT) {
manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg);
}
},
_ => {},
}
},
("count", []) if is_trait_method(cx, expr, sym::Iterator) => match method_call(recv) {
Some(("cloned", recv2, [], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, true, false),
Some((name2 @ ("into_iter" | "iter" | "iter_mut"), recv2, [], _)) => {
Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, true, false),
Some((name2 @ ("into_iter" | "iter" | "iter_mut"), recv2, [], _, _)) => {
iter_count::check(cx, expr, recv2, name2);
},
Some(("map", _, [arg], _)) => suspicious_map::check(cx, expr, recv, arg),
Some(("filter", recv2, [arg], _)) => bytecount::check(cx, expr, recv2, arg),
Some(("bytes", recv2, [], _)) => bytes_count_to_len::check(cx, expr, recv, recv2),
Some(("map", _, [arg], _, _)) => suspicious_map::check(cx, expr, recv, arg),
Some(("filter", recv2, [arg], _, _)) => bytecount::check(cx, expr, recv2, arg),
Some(("bytes", recv2, [], _, _)) => bytes_count_to_len::check(cx, expr, recv, recv2),
_ => {},
},
("drain", [arg]) => {
@ -3463,8 +3538,8 @@ impl Methods {
}
},
("expect", [_]) => match method_call(recv) {
Some(("ok", recv, [], _)) => ok_expect::check(cx, expr, recv),
Some(("err", recv, [], err_span)) => err_expect::check(cx, expr, recv, self.msrv, span, err_span),
Some(("ok", recv, [], _, _)) => ok_expect::check(cx, expr, recv),
Some(("err", recv, [], err_span, _)) => err_expect::check(cx, expr, recv, self.msrv, span, err_span),
_ => expect_used::check(cx, expr, recv, false, self.allow_expect_in_tests),
},
("expect_err", [_]) => expect_used::check(cx, expr, recv, true, self.allow_expect_in_tests),
@ -3484,13 +3559,13 @@ impl Methods {
flat_map_option::check(cx, expr, arg, span);
},
("flatten", []) => match method_call(recv) {
Some(("map", recv, [map_arg], map_span)) => map_flatten::check(cx, expr, recv, map_arg, map_span),
Some(("cloned", recv2, [], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, true),
Some(("map", recv, [map_arg], map_span, _)) => map_flatten::check(cx, expr, recv, map_arg, map_span),
Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, true),
_ => {},
},
("fold", [init, acc]) => unnecessary_fold::check(cx, expr, init, acc, span),
("for_each", [_]) => {
if let Some(("inspect", _, [_], span2)) = method_call(recv) {
if let Some(("inspect", _, [_], span2, _)) = method_call(recv) {
inspect_for_each::check(cx, expr, span2);
}
},
@ -3510,12 +3585,12 @@ impl Methods {
iter_on_single_or_empty_collections::check(cx, expr, name, recv);
},
("join", [join_arg]) => {
if let Some(("collect", _, _, span)) = method_call(recv) {
if let Some(("collect", _, _, span, _)) = method_call(recv) {
unnecessary_join::check(cx, expr, recv, join_arg, span);
}
},
("last", []) | ("skip", [_]) => {
if let Some((name2, recv2, args2, _span2)) = method_call(recv) {
if let Some((name2, recv2, args2, _span2, _)) = method_call(recv) {
if let ("cloned", []) = (name2, args2) {
iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
}
@ -3527,13 +3602,13 @@ impl Methods {
(name @ ("map" | "map_err"), [m_arg]) => {
if name == "map" {
map_clone::check(cx, expr, recv, m_arg, self.msrv);
if let Some((map_name @ ("iter" | "into_iter"), recv2, _, _)) = method_call(recv) {
if let Some((map_name @ ("iter" | "into_iter"), recv2, _, _, _)) = method_call(recv) {
iter_kv_map::check(cx, map_name, expr, recv2, m_arg);
}
} else {
map_err_ignore::check(cx, expr, m_arg);
}
if let Some((name, recv2, args, span2)) = method_call(recv) {
if let Some((name, recv2, args, span2,_)) = method_call(recv) {
match (name, args) {
("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, self.msrv),
("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, self.msrv),
@ -3553,7 +3628,7 @@ impl Methods {
manual_ok_or::check(cx, expr, recv, def, map);
},
("next", []) => {
if let Some((name2, recv2, args2, _)) = method_call(recv) {
if let Some((name2, recv2, args2, _, _)) = method_call(recv) {
match (name2, args2) {
("cloned", []) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false),
("filter", [arg]) => filter_next::check(cx, expr, recv2, arg),
@ -3566,10 +3641,10 @@ impl Methods {
}
},
("nth", [n_arg]) => match method_call(recv) {
Some(("bytes", recv2, [], _)) => bytes_nth::check(cx, expr, recv2, n_arg),
Some(("cloned", recv2, [], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false),
Some(("iter", recv2, [], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, false),
Some(("iter_mut", recv2, [], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, true),
Some(("bytes", recv2, [], _, _)) => bytes_nth::check(cx, expr, recv2, n_arg),
Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false),
Some(("iter", recv2, [], _, _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, false),
Some(("iter_mut", recv2, [], _, _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, true),
_ => iter_nth_zero::check(cx, expr, recv, n_arg),
},
("ok_or_else", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or"),
@ -3604,6 +3679,14 @@ impl Methods {
("resize", [count_arg, default_arg]) => {
vec_resize_to_zero::check(cx, expr, count_arg, default_arg, span);
},
("seek", [arg]) => {
if meets_msrv(self.msrv, msrvs::SEEK_FROM_CURRENT) {
seek_from_current::check(cx, expr, recv, arg);
}
if meets_msrv(self.msrv, msrvs::SEEK_REWIND) {
seek_to_start_instead_of_rewind::check(cx, expr, recv, arg, span);
}
},
("sort", []) => {
stable_sort_primitive::check(cx, expr, recv);
},
@ -3626,7 +3709,7 @@ impl Methods {
},
("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg),
("take", [_arg]) => {
if let Some((name2, recv2, args2, _span2)) = method_call(recv) {
if let Some((name2, recv2, args2, _span2, _)) = method_call(recv) {
if let ("cloned", []) = (name2, args2) {
iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
}
@ -3649,13 +3732,13 @@ impl Methods {
},
("unwrap", []) => {
match method_call(recv) {
Some(("get", recv, [get_arg], _)) => {
Some(("get", recv, [get_arg], _, _)) => {
get_unwrap::check(cx, expr, recv, get_arg, false);
},
Some(("get_mut", recv, [get_arg], _)) => {
Some(("get_mut", recv, [get_arg], _, _)) => {
get_unwrap::check(cx, expr, recv, get_arg, true);
},
Some(("or", recv, [or_arg], or_span)) => {
Some(("or", recv, [or_arg], or_span, _)) => {
or_then_unwrap::check(cx, expr, recv, or_arg, or_span);
},
_ => {},
@ -3664,19 +3747,19 @@ impl Methods {
},
("unwrap_err", []) => unwrap_used::check(cx, expr, recv, true, self.allow_unwrap_in_tests),
("unwrap_or", [u_arg]) => match method_call(recv) {
Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), lhs, [rhs], _)) => {
Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), lhs, [rhs], _, _)) => {
manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]);
},
Some(("map", m_recv, [m_arg], span)) => {
Some(("map", m_recv, [m_arg], span, _)) => {
option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span);
},
Some(("then_some", t_recv, [t_arg], _)) => {
Some(("then_some", t_recv, [t_arg], _, _)) => {
obfuscated_if_else::check(cx, expr, t_recv, t_arg, u_arg);
},
_ => {},
},
("unwrap_or_else", [u_arg]) => match method_call(recv) {
Some(("map", recv, [map_arg], _))
Some(("map", recv, [map_arg], _, _))
if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, self.msrv) => {},
_ => {
unwrap_or_else_default::check(cx, expr, recv, u_arg);
@ -3697,7 +3780,7 @@ impl Methods {
}
fn check_is_some_is_none(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, is_some: bool) {
if let Some((name @ ("find" | "position" | "rposition"), f_recv, [arg], span)) = method_call(recv) {
if let Some((name @ ("find" | "position" | "rposition"), f_recv, [arg], span, _)) = method_call(recv) {
search_is_some::check(cx, expr, name, is_some, f_recv, arg, recv, span);
}
}
@ -3906,14 +3989,6 @@ impl OutType {
}
}
fn is_bool(ty: &hir::Ty<'_>) -> bool {
if let hir::TyKind::Path(QPath::Resolved(_, path)) = ty.kind {
matches!(path.res, Res::PrimTy(PrimTy::Bool))
} else {
false
}
}
fn fn_header_equals(expected: hir::FnHeader, actual: hir::FnHeader) -> bool {
expected.constness == actual.constness
&& expected.unsafety == actual.unsafety

View file

@ -3,94 +3,99 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
use clippy_utils::higher;
use clippy_utils::source::{snippet, snippet_with_applicability};
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{can_move_expr_to_closure, is_trait_method, path_to_local, path_to_local_id, CaptureKind};
use if_chain::if_chain;
use clippy_utils::ty::{is_type_diagnostic_item, make_normalized_projection, make_projection};
use clippy_utils::{
can_move_expr_to_closure, get_enclosing_block, get_parent_node, is_trait_method, path_to_local, path_to_local_id,
CaptureKind,
};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{Applicability, MultiSpan};
use rustc_hir::intravisit::{walk_block, walk_expr, Visitor};
use rustc_hir::{Block, Expr, ExprKind, HirId, HirIdSet, Local, Mutability, Node, PatKind, Stmt, StmtKind};
use rustc_hir::{
BindingAnnotation, Block, Expr, ExprKind, HirId, HirIdSet, Local, Mutability, Node, PatKind, Stmt, StmtKind,
};
use rustc_lint::LateContext;
use rustc_middle::hir::nested_filter;
use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::{self, Ty};
use rustc_span::sym;
use rustc_span::Span;
use rustc_middle::ty::{self, AssocKind, EarlyBinder, GenericArg, GenericArgKind, Ty};
use rustc_span::symbol::Ident;
use rustc_span::{sym, Span, Symbol};
const NEEDLESS_COLLECT_MSG: &str = "avoid using `collect()` when not needed";
pub(super) fn check<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
check_needless_collect_direct_usage(expr, cx);
check_needless_collect_indirect_usage(expr, cx);
}
fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
if_chain! {
if let ExprKind::MethodCall(method, receiver, args, _) = expr.kind;
if let ExprKind::MethodCall(chain_method, ..) = receiver.kind;
if chain_method.ident.name == sym!(collect) && is_trait_method(cx, receiver, sym::Iterator);
then {
let ty = cx.typeck_results().expr_ty(receiver);
let mut applicability = Applicability::MaybeIncorrect;
let is_empty_sugg = "next().is_none()".to_string();
let method_name = method.ident.name.as_str();
let sugg = if is_type_diagnostic_item(cx, ty, sym::Vec) ||
is_type_diagnostic_item(cx, ty, sym::VecDeque) ||
is_type_diagnostic_item(cx, ty, sym::LinkedList) ||
is_type_diagnostic_item(cx, ty, sym::BinaryHeap) {
match method_name {
"len" => "count()".to_string(),
"is_empty" => is_empty_sugg,
"contains" => {
let contains_arg = snippet_with_applicability(cx, args[0].span, "??", &mut applicability);
let (arg, pred) = contains_arg
.strip_prefix('&')
.map_or(("&x", &*contains_arg), |s| ("x", s));
format!("any(|{arg}| x == {pred})")
}
_ => return,
}
}
else if is_type_diagnostic_item(cx, ty, sym::BTreeMap) ||
is_type_diagnostic_item(cx, ty, sym::HashMap) {
match method_name {
"is_empty" => is_empty_sugg,
_ => return,
}
}
else {
return;
};
span_lint_and_sugg(
cx,
NEEDLESS_COLLECT,
chain_method.ident.span.with_hi(expr.span.hi()),
NEEDLESS_COLLECT_MSG,
"replace with",
sugg,
applicability,
);
}
}
}
pub(super) fn check<'tcx>(
cx: &LateContext<'tcx>,
name_span: Span,
collect_expr: &'tcx Expr<'_>,
iter_expr: &'tcx Expr<'tcx>,
call_span: Span,
) {
if let Some(parent) = get_parent_node(cx.tcx, collect_expr.hir_id) {
match parent {
Node::Expr(parent) => {
if let ExprKind::MethodCall(name, _, args @ ([] | [_]), _) = parent.kind {
let mut app = Applicability::MachineApplicable;
let name = name.ident.as_str();
let collect_ty = cx.typeck_results().expr_ty(collect_expr);
fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
if let ExprKind::Block(block, _) = expr.kind {
for stmt in block.stmts {
if_chain! {
if let StmtKind::Local(local) = stmt.kind;
if let PatKind::Binding(_, id, ..) = local.pat.kind;
if let Some(init_expr) = local.init;
if let ExprKind::MethodCall(method_name, iter_source, [], ..) = init_expr.kind;
if method_name.ident.name == sym!(collect) && is_trait_method(cx, init_expr, sym::Iterator);
let ty = cx.typeck_results().expr_ty(init_expr);
if is_type_diagnostic_item(cx, ty, sym::Vec) ||
is_type_diagnostic_item(cx, ty, sym::VecDeque) ||
is_type_diagnostic_item(cx, ty, sym::BinaryHeap) ||
is_type_diagnostic_item(cx, ty, sym::LinkedList);
let iter_ty = cx.typeck_results().expr_ty(iter_source);
if let Some(iter_calls) = detect_iter_and_into_iters(block, id, cx, get_captured_ids(cx, iter_ty));
if let [iter_call] = &*iter_calls;
then {
let sugg: String = match name {
"len" => {
if let Some(adt) = collect_ty.ty_adt_def()
&& matches!(
cx.tcx.get_diagnostic_name(adt.did()),
Some(sym::Vec | sym::VecDeque | sym::LinkedList | sym::BinaryHeap)
)
{
"count()".into()
} else {
return;
}
},
"is_empty"
if is_is_empty_sig(cx, parent.hir_id)
&& iterates_same_ty(cx, cx.typeck_results().expr_ty(iter_expr), collect_ty) =>
{
"next().is_none()".into()
},
"contains" => {
if is_contains_sig(cx, parent.hir_id, iter_expr)
&& let Some(arg) = args.first()
{
let (span, prefix) = if let ExprKind::AddrOf(_, _, arg) = arg.kind {
(arg.span, "")
} else {
(arg.span, "*")
};
let snip = snippet_with_applicability(cx, span, "??", &mut app);
format!("any(|x| x == {prefix}{snip})")
} else {
return;
}
},
_ => return,
};
span_lint_and_sugg(
cx,
NEEDLESS_COLLECT,
call_span.with_hi(parent.span.hi()),
NEEDLESS_COLLECT_MSG,
"replace with",
sugg,
app,
);
}
},
Node::Local(l) => {
if let PatKind::Binding(BindingAnnotation::NONE | BindingAnnotation::MUT, id, _, None)
= l.pat.kind
&& let ty = cx.typeck_results().expr_ty(collect_expr)
&& [sym::Vec, sym::VecDeque, sym::BinaryHeap, sym::LinkedList].into_iter()
.any(|item| is_type_diagnostic_item(cx, ty, item))
&& let iter_ty = cx.typeck_results().expr_ty(iter_expr)
&& let Some(block) = get_enclosing_block(cx, l.hir_id)
&& let Some(iter_calls) = detect_iter_and_into_iters(block, id, cx, get_captured_ids(cx, iter_ty))
&& let [iter_call] = &*iter_calls
{
let mut used_count_visitor = UsedCountVisitor {
cx,
id,
@ -102,20 +107,20 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo
}
// Suggest replacing iter_call with iter_replacement, and removing stmt
let mut span = MultiSpan::from_span(method_name.ident.span);
let mut span = MultiSpan::from_span(name_span);
span.push_span_label(iter_call.span, "the iterator could be used here instead");
span_lint_hir_and_then(
cx,
super::NEEDLESS_COLLECT,
init_expr.hir_id,
collect_expr.hir_id,
span,
NEEDLESS_COLLECT_MSG,
|diag| {
let iter_replacement = format!("{}{}", Sugg::hir(cx, iter_source, ".."), iter_call.get_iter_method(cx));
let iter_replacement = format!("{}{}", Sugg::hir(cx, iter_expr, ".."), iter_call.get_iter_method(cx));
diag.multipart_suggestion(
iter_call.get_suggestion_text(),
vec![
(stmt.span, String::new()),
(l.span, String::new()),
(iter_call.span, iter_replacement)
],
Applicability::MaybeIncorrect,
@ -123,11 +128,61 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo
},
);
}
}
},
_ => (),
}
}
}
/// Checks if the given method call matches the expected signature of `([&[mut]] self) -> bool`
fn is_is_empty_sig(cx: &LateContext<'_>, call_id: HirId) -> bool {
cx.typeck_results().type_dependent_def_id(call_id).map_or(false, |id| {
let sig = cx.tcx.fn_sig(id).skip_binder();
sig.inputs().len() == 1 && sig.output().is_bool()
})
}
/// Checks if `<iter_ty as Iterator>::Item` is the same as `<collect_ty as IntoIter>::Item`
fn iterates_same_ty<'tcx>(cx: &LateContext<'tcx>, iter_ty: Ty<'tcx>, collect_ty: Ty<'tcx>) -> bool {
let item = Symbol::intern("Item");
if let Some(iter_trait) = cx.tcx.get_diagnostic_item(sym::Iterator)
&& let Some(into_iter_trait) = cx.tcx.get_diagnostic_item(sym::IntoIterator)
&& let Some(iter_item_ty) = make_normalized_projection(cx.tcx, cx.param_env, iter_trait, item, [iter_ty])
&& let Some(into_iter_item_proj) = make_projection(cx.tcx, into_iter_trait, item, [collect_ty])
&& let Ok(into_iter_item_ty) = cx.tcx.try_normalize_erasing_regions(
cx.param_env,
cx.tcx.mk_projection(into_iter_item_proj.item_def_id, into_iter_item_proj.substs)
)
{
iter_item_ty == into_iter_item_ty
} else {
false
}
}
/// Checks if the given method call matches the expected signature of
/// `([&[mut]] self, &<iter_ty as Iterator>::Item) -> bool`
fn is_contains_sig(cx: &LateContext<'_>, call_id: HirId, iter_expr: &Expr<'_>) -> bool {
let typeck = cx.typeck_results();
if let Some(id) = typeck.type_dependent_def_id(call_id)
&& let sig = cx.tcx.fn_sig(id)
&& sig.skip_binder().output().is_bool()
&& let [_, search_ty] = *sig.skip_binder().inputs()
&& let ty::Ref(_, search_ty, Mutability::Not) = *cx.tcx.erase_late_bound_regions(sig.rebind(search_ty)).kind()
&& let Some(iter_trait) = cx.tcx.get_diagnostic_item(sym::Iterator)
&& let Some(iter_item) = cx.tcx
.associated_items(iter_trait)
.find_by_name_and_kind(cx.tcx, Ident::with_dummy_span(Symbol::intern("Item")), AssocKind::Type, iter_trait)
&& let substs = cx.tcx.mk_substs([GenericArg::from(typeck.expr_ty_adjusted(iter_expr))].into_iter())
&& let proj_ty = cx.tcx.mk_projection(iter_item.def_id, substs)
&& let Ok(item_ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, proj_ty)
{
item_ty == EarlyBinder(search_ty).subst(cx.tcx, cx.typeck_results().node_substs(call_id))
} else {
false
}
}
struct IterFunction {
func: IterFunctionKind,
span: Span,

View file

@ -13,8 +13,8 @@ use rustc_span::sym;
use super::OPTION_AS_REF_DEREF;
/// lint use of `_.as_ref().map(Deref::deref)` for `Option`s
pub(super) fn check<'tcx>(
cx: &LateContext<'tcx>,
pub(super) fn check(
cx: &LateContext<'_>,
expr: &hir::Expr<'_>,
as_ref_recv: &hir::Expr<'_>,
map_arg: &hir::Expr<'_>,

View file

@ -83,6 +83,8 @@ pub(super) fn check<'tcx>(
method_span: Span,
self_expr: &hir::Expr<'_>,
arg: &'tcx hir::Expr<'_>,
// `Some` if fn has second argument
second_arg: Option<&hir::Expr<'_>>,
span: Span,
// None if lambda is required
fun_span: Option<Span>,
@ -109,30 +111,40 @@ pub(super) fn check<'tcx>(
if poss.contains(&name);
then {
let macro_expanded_snipped;
let sugg: Cow<'_, str> = {
let sugg = {
let (snippet_span, use_lambda) = match (fn_has_arguments, fun_span) {
(false, Some(fun_span)) => (fun_span, false),
_ => (arg.span, true),
};
let snippet = {
let not_macro_argument_snippet = snippet_with_macro_callsite(cx, snippet_span, "..");
if not_macro_argument_snippet == "vec![]" {
macro_expanded_snipped = snippet(cx, snippet_span, "..");
let format_span = |span: Span| {
let not_macro_argument_snippet = snippet_with_macro_callsite(cx, span, "..");
let snip = if not_macro_argument_snippet == "vec![]" {
let macro_expanded_snipped = snippet(cx, snippet_span, "..");
match macro_expanded_snipped.strip_prefix("$crate::vec::") {
Some(stripped) => Cow::from(stripped),
Some(stripped) => Cow::Owned(stripped.to_owned()),
None => macro_expanded_snipped,
}
} else {
not_macro_argument_snippet
}
};
snip.to_string()
};
if use_lambda {
let snip = format_span(snippet_span);
let snip = if use_lambda {
let l_arg = if fn_has_arguments { "_" } else { "" };
format!("|{l_arg}| {snippet}").into()
format!("|{l_arg}| {snip}")
} else {
snippet
snip
};
if let Some(f) = second_arg {
let f = format_span(f.span);
format!("{snip}, {f}")
} else {
snip
}
};
let span_replace_word = method_span.with_hi(span.hi());
@ -149,8 +161,8 @@ pub(super) fn check<'tcx>(
}
}
if let [arg] = args {
let inner_arg = if let hir::ExprKind::Block(
let extract_inner_arg = |arg: &'tcx hir::Expr<'_>| {
if let hir::ExprKind::Block(
hir::Block {
stmts: [],
expr: Some(expr),
@ -162,19 +174,32 @@ pub(super) fn check<'tcx>(
expr
} else {
arg
};
}
};
if let [arg] = args {
let inner_arg = extract_inner_arg(arg);
match inner_arg.kind {
hir::ExprKind::Call(fun, or_args) => {
let or_has_args = !or_args.is_empty();
if !check_unwrap_or_default(cx, name, fun, arg, or_has_args, expr.span, method_span) {
let fun_span = if or_has_args { None } else { Some(fun.span) };
check_general_case(cx, name, method_span, receiver, arg, expr.span, fun_span);
check_general_case(cx, name, method_span, receiver, arg, None, expr.span, fun_span);
}
},
hir::ExprKind::Index(..) | hir::ExprKind::MethodCall(..) => {
check_general_case(cx, name, method_span, receiver, arg, expr.span, None);
check_general_case(cx, name, method_span, receiver, arg, None, expr.span, None);
},
_ => (),
}
}
// `map_or` takes two arguments
if let [arg, lambda] = args {
let inner_arg = extract_inner_arg(arg);
if let hir::ExprKind::Call(fun, or_args) = inner_arg.kind {
let fun_span = if or_args.is_empty() { Some(fun.span) } else { None };
check_general_case(cx, name, method_span, receiver, arg, Some(lambda), expr.span, fun_span);
}
}
}

View file

@ -0,0 +1,48 @@
use rustc_ast::ast::{LitIntType, LitKind};
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::LateContext;
use clippy_utils::{
diagnostics::span_lint_and_sugg, get_trait_def_id, match_def_path, paths, source::snippet_with_applicability,
ty::implements_trait,
};
use super::SEEK_FROM_CURRENT;
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>, arg: &'tcx Expr<'_>) {
let ty = cx.typeck_results().expr_ty(recv);
if let Some(def_id) = get_trait_def_id(cx, &paths::STD_IO_SEEK) {
if implements_trait(cx, ty, def_id, &[]) && arg_is_seek_from_current(cx, arg) {
let mut applicability = Applicability::MachineApplicable;
let snip = snippet_with_applicability(cx, recv.span, "..", &mut applicability);
span_lint_and_sugg(
cx,
SEEK_FROM_CURRENT,
expr.span,
"using `SeekFrom::Current` to start from current position",
"replace with",
format!("{snip}.stream_position()"),
applicability,
);
}
}
}
fn arg_is_seek_from_current<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool {
if let ExprKind::Call(f, args) = expr.kind &&
let ExprKind::Path(ref path) = f.kind &&
let Some(def_id) = cx.qpath_res(path, f.hir_id).opt_def_id() &&
match_def_path(cx, def_id, &paths::STD_IO_SEEK_FROM_CURRENT) {
// check if argument of `SeekFrom::Current` is `0`
if args.len() == 1 &&
let ExprKind::Lit(ref lit) = args[0].kind &&
let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node {
return true
}
}
false
}

View file

@ -0,0 +1,45 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::ty::implements_trait;
use clippy_utils::{get_trait_def_id, match_def_path, paths};
use rustc_ast::ast::{LitIntType, LitKind};
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::LateContext;
use rustc_span::Span;
use super::SEEK_TO_START_INSTEAD_OF_REWIND;
pub(super) fn check<'tcx>(
cx: &LateContext<'tcx>,
expr: &'tcx Expr<'_>,
recv: &'tcx Expr<'_>,
arg: &'tcx Expr<'_>,
name_span: Span,
) {
// Get receiver type
let ty = cx.typeck_results().expr_ty(recv).peel_refs();
if let Some(seek_trait_id) = get_trait_def_id(cx, &paths::STD_IO_SEEK) &&
implements_trait(cx, ty, seek_trait_id, &[]) &&
let ExprKind::Call(func, args1) = arg.kind &&
let ExprKind::Path(ref path) = func.kind &&
let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id() &&
match_def_path(cx, def_id, &paths::STD_IO_SEEKFROM_START) &&
args1.len() == 1 &&
let ExprKind::Lit(ref lit) = args1[0].kind &&
let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node
{
let method_call_span = expr.span.with_lo(name_span.lo());
span_lint_and_then(
cx,
SEEK_TO_START_INSTEAD_OF_REWIND,
method_call_span,
"used `seek` to go to the start of the stream",
|diag| {
let app = Applicability::MachineApplicable;
diag.span_suggestion(method_call_span, "replace with", "rewind()", app);
},
);
}
}

View file

@ -18,7 +18,11 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
let target = &arglists[0].0;
let self_ty = cx.typeck_results().expr_ty(target).peel_refs();
let ref_str = if *self_ty.kind() == ty::Str {
""
if matches!(target.kind, hir::ExprKind::Index(..)) {
"&"
} else {
""
}
} else if is_type_lang_item(cx, self_ty, hir::LangItem::String) {
"&"
} else {

View file

@ -8,7 +8,7 @@ use rustc_span::sym;
use super::SUSPICIOUS_MAP;
pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, count_recv: &hir::Expr<'_>, map_arg: &hir::Expr<'_>) {
pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, count_recv: &hir::Expr<'_>, map_arg: &hir::Expr<'_>) {
if_chain! {
if is_trait_method(cx, count_recv, sym::Iterator);
let closure = expr_or_init(cx, map_arg);

View file

@ -31,7 +31,7 @@ pub(super) fn check<'tcx>(
cx,
UNNECESSARY_JOIN,
span.with_hi(expr.span.hi()),
r#"called `.collect<Vec<String>>().join("")` on an iterator"#,
r#"called `.collect::<Vec<String>>().join("")` on an iterator"#,
"try using",
"collect::<String>()".to_owned(),
applicability,

View file

@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{is_in_test_function, is_lint_allowed};
use clippy_utils::{is_in_cfg_test, is_lint_allowed};
use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_span::sym;
@ -18,16 +18,16 @@ pub(super) fn check(
let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs();
let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) && !is_err {
Some((UNWRAP_USED, "an Option", "None", ""))
Some((UNWRAP_USED, "an `Option`", "None", ""))
} else if is_type_diagnostic_item(cx, obj_ty, sym::Result) {
Some((UNWRAP_USED, "a Result", if is_err { "Ok" } else { "Err" }, "an "))
Some((UNWRAP_USED, "a `Result`", if is_err { "Ok" } else { "Err" }, "an "))
} else {
None
};
let method_suffix = if is_err { "_err" } else { "" };
if allow_unwrap_in_tests && is_in_test_function(cx.tcx, expr.hir_id) {
if allow_unwrap_in_tests && is_in_cfg_test(cx.tcx, expr.hir_id) {
return;
}
@ -45,7 +45,7 @@ pub(super) fn check(
cx,
lint,
expr.span,
&format!("used `unwrap{method_suffix}()` on `{kind}` value"),
&format!("used `unwrap{method_suffix}()` on {kind} value"),
None,
&help,
);

View file

@ -59,7 +59,7 @@ impl LateLintPass<'_> for ImportRename {
fn check_crate(&mut self, cx: &LateContext<'_>) {
for Rename { path, rename } in &self.conf_renames {
let segs = path.split("::").collect::<Vec<_>>();
if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &segs, None) {
for id in clippy_utils::def_path_def_ids(cx, &segs) {
self.renames.insert(id, Symbol::intern(rename));
}
}

View file

@ -218,7 +218,7 @@ enum StopEarly {
Stop,
}
fn check_expr<'a, 'tcx>(vis: &mut ReadVisitor<'a, 'tcx>, expr: &'tcx Expr<'_>) -> StopEarly {
fn check_expr<'tcx>(vis: &mut ReadVisitor<'_, 'tcx>, expr: &'tcx Expr<'_>) -> StopEarly {
if expr.hir_id == vis.last_expr.hir_id {
return StopEarly::KeepGoing;
}
@ -265,7 +265,7 @@ fn check_expr<'a, 'tcx>(vis: &mut ReadVisitor<'a, 'tcx>, expr: &'tcx Expr<'_>) -
StopEarly::KeepGoing
}
fn check_stmt<'a, 'tcx>(vis: &mut ReadVisitor<'a, 'tcx>, stmt: &'tcx Stmt<'_>) -> StopEarly {
fn check_stmt<'tcx>(vis: &mut ReadVisitor<'_, 'tcx>, stmt: &'tcx Stmt<'_>) -> StopEarly {
match stmt.kind {
StmtKind::Expr(expr) | StmtKind::Semi(expr) => check_expr(vis, expr),
// If the declaration is of a local variable, check its initializer

View file

@ -1,10 +1,11 @@
use clippy_utils::diagnostics::span_lint;
use clippy_utils::trait_ref_of_method;
use clippy_utils::{def_path_def_ids, trait_ref_of_method};
use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::TypeVisitable;
use rustc_middle::ty::{Adt, Array, Ref, Slice, Tuple, Ty};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Span;
use rustc_span::symbol::sym;
use std::iter;
@ -78,26 +79,44 @@ declare_clippy_lint! {
"Check for mutable `Map`/`Set` key type"
}
declare_lint_pass!(MutableKeyType => [ MUTABLE_KEY_TYPE ]);
#[derive(Clone)]
pub struct MutableKeyType {
ignore_interior_mutability: Vec<String>,
ignore_mut_def_ids: FxHashSet<hir::def_id::DefId>,
}
impl_lint_pass!(MutableKeyType => [ MUTABLE_KEY_TYPE ]);
impl<'tcx> LateLintPass<'tcx> for MutableKeyType {
fn check_crate(&mut self, cx: &LateContext<'tcx>) {
self.ignore_mut_def_ids.clear();
let mut path = Vec::new();
for ty in &self.ignore_interior_mutability {
path.extend(ty.split("::"));
for id in def_path_def_ids(cx, &path[..]) {
self.ignore_mut_def_ids.insert(id);
}
path.clear();
}
}
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
if let hir::ItemKind::Fn(ref sig, ..) = item.kind {
check_sig(cx, item.hir_id(), sig.decl);
self.check_sig(cx, item.hir_id(), sig.decl);
}
}
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'tcx>) {
if let hir::ImplItemKind::Fn(ref sig, ..) = item.kind {
if trait_ref_of_method(cx, item.owner_id.def_id).is_none() {
check_sig(cx, item.hir_id(), sig.decl);
self.check_sig(cx, item.hir_id(), sig.decl);
}
}
}
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'tcx>) {
if let hir::TraitItemKind::Fn(ref sig, ..) = item.kind {
check_sig(cx, item.hir_id(), sig.decl);
self.check_sig(cx, item.hir_id(), sig.decl);
}
}
@ -105,73 +124,81 @@ impl<'tcx> LateLintPass<'tcx> for MutableKeyType {
if let hir::PatKind::Wild = local.pat.kind {
return;
}
check_ty(cx, local.span, cx.typeck_results().pat_ty(local.pat));
self.check_ty_(cx, local.span, cx.typeck_results().pat_ty(local.pat));
}
}
fn check_sig<'tcx>(cx: &LateContext<'tcx>, item_hir_id: hir::HirId, decl: &hir::FnDecl<'_>) {
let fn_def_id = cx.tcx.hir().local_def_id(item_hir_id);
let fn_sig = cx.tcx.fn_sig(fn_def_id);
for (hir_ty, ty) in iter::zip(decl.inputs, fn_sig.inputs().skip_binder()) {
check_ty(cx, hir_ty.span, *ty);
}
check_ty(cx, decl.output.span(), cx.tcx.erase_late_bound_regions(fn_sig.output()));
}
// We want to lint 1. sets or maps with 2. not immutable key types and 3. no unerased
// generics (because the compiler cannot ensure immutability for unknown types).
fn check_ty<'tcx>(cx: &LateContext<'tcx>, span: Span, ty: Ty<'tcx>) {
let ty = ty.peel_refs();
if let Adt(def, substs) = ty.kind() {
let is_keyed_type = [sym::HashMap, sym::BTreeMap, sym::HashSet, sym::BTreeSet]
.iter()
.any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def.did()));
if is_keyed_type && is_interior_mutable_type(cx, substs.type_at(0), span) {
span_lint(cx, MUTABLE_KEY_TYPE, span, "mutable key type");
impl MutableKeyType {
pub fn new(ignore_interior_mutability: Vec<String>) -> Self {
Self {
ignore_interior_mutability,
ignore_mut_def_ids: FxHashSet::default(),
}
}
}
/// Determines if a type contains interior mutability which would affect its implementation of
/// [`Hash`] or [`Ord`].
fn is_interior_mutable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Span) -> bool {
match *ty.kind() {
Ref(_, inner_ty, mutbl) => {
mutbl == hir::Mutability::Mut || is_interior_mutable_type(cx, inner_ty, span)
fn check_sig(&self, cx: &LateContext<'_>, item_hir_id: hir::HirId, decl: &hir::FnDecl<'_>) {
let fn_def_id = cx.tcx.hir().local_def_id(item_hir_id);
let fn_sig = cx.tcx.fn_sig(fn_def_id);
for (hir_ty, ty) in iter::zip(decl.inputs, fn_sig.inputs().skip_binder()) {
self.check_ty_(cx, hir_ty.span, *ty);
}
Slice(inner_ty) => is_interior_mutable_type(cx, inner_ty, span),
Array(inner_ty, size) => {
size.try_eval_usize(cx.tcx, cx.param_env).map_or(true, |u| u != 0)
&& is_interior_mutable_type(cx, inner_ty, span)
}
Tuple(fields) => fields.iter().any(|ty| is_interior_mutable_type(cx, ty, span)),
Adt(def, substs) => {
// Special case for collections in `std` who's impl of `Hash` or `Ord` delegates to
// that of their type parameters. Note: we don't include `HashSet` and `HashMap`
// because they have no impl for `Hash` or `Ord`.
let is_std_collection = [
sym::Option,
sym::Result,
sym::LinkedList,
sym::Vec,
sym::VecDeque,
sym::BTreeMap,
sym::BTreeSet,
sym::Rc,
sym::Arc,
]
.iter()
.any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def.did()));
let is_box = Some(def.did()) == cx.tcx.lang_items().owned_box();
if is_std_collection || is_box {
// The type is mutable if any of its type parameters are
substs.types().any(|ty| is_interior_mutable_type(cx, ty, span))
} else {
!ty.has_escaping_bound_vars()
&& cx.tcx.layout_of(cx.param_env.and(ty)).is_ok()
&& !ty.is_freeze(cx.tcx, cx.param_env)
self.check_ty_(cx, decl.output.span(), cx.tcx.erase_late_bound_regions(fn_sig.output()));
}
// We want to lint 1. sets or maps with 2. not immutable key types and 3. no unerased
// generics (because the compiler cannot ensure immutability for unknown types).
fn check_ty_<'tcx>(&self, cx: &LateContext<'tcx>, span: Span, ty: Ty<'tcx>) {
let ty = ty.peel_refs();
if let Adt(def, substs) = ty.kind() {
let is_keyed_type = [sym::HashMap, sym::BTreeMap, sym::HashSet, sym::BTreeSet]
.iter()
.any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def.did()));
if is_keyed_type && self.is_interior_mutable_type(cx, substs.type_at(0)) {
span_lint(cx, MUTABLE_KEY_TYPE, span, "mutable key type");
}
}
_ => false,
}
/// Determines if a type contains interior mutability which would affect its implementation of
/// [`Hash`] or [`Ord`].
fn is_interior_mutable_type<'tcx>(&self, cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
match *ty.kind() {
Ref(_, inner_ty, mutbl) => mutbl == hir::Mutability::Mut || self.is_interior_mutable_type(cx, inner_ty),
Slice(inner_ty) => self.is_interior_mutable_type(cx, inner_ty),
Array(inner_ty, size) => {
size.try_eval_usize(cx.tcx, cx.param_env).map_or(true, |u| u != 0)
&& self.is_interior_mutable_type(cx, inner_ty)
},
Tuple(fields) => fields.iter().any(|ty| self.is_interior_mutable_type(cx, ty)),
Adt(def, substs) => {
// Special case for collections in `std` who's impl of `Hash` or `Ord` delegates to
// that of their type parameters. Note: we don't include `HashSet` and `HashMap`
// because they have no impl for `Hash` or `Ord`.
let def_id = def.did();
let is_std_collection = [
sym::Option,
sym::Result,
sym::LinkedList,
sym::Vec,
sym::VecDeque,
sym::BTreeMap,
sym::BTreeSet,
sym::Rc,
sym::Arc,
]
.iter()
.any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def_id));
let is_box = Some(def_id) == cx.tcx.lang_items().owned_box();
if is_std_collection || is_box || self.ignore_mut_def_ids.contains(&def_id) {
// The type is mutable if any of its type parameters are
substs.types().any(|ty| self.is_interior_mutable_type(cx, ty))
} else {
!ty.has_escaping_bound_vars()
&& cx.tcx.layout_of(cx.param_env.and(ty)).is_ok()
&& !ty.is_freeze(cx.tcx, cx.param_env)
}
},
_ => false,
}
}
}

View file

@ -68,13 +68,15 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for MutVisitor<'a, 'tcx> {
expr.span,
"generally you want to avoid `&mut &mut _` if possible",
);
} else if let ty::Ref(_, _, hir::Mutability::Mut) = self.cx.typeck_results().expr_ty(e).kind() {
span_lint(
self.cx,
MUT_MUT,
expr.span,
"this expression mutably borrows a mutable reference. Consider reborrowing",
);
} else if let ty::Ref(_, ty, hir::Mutability::Mut) = self.cx.typeck_results().expr_ty(e).kind() {
if ty.peel_refs().is_sized(self.cx.tcx, self.cx.param_env) {
span_lint(
self.cx,
MUT_MUT,
expr.span,
"this expression mutably borrows a mutable reference. Consider reborrowing",
);
}
}
}
}

View file

@ -36,14 +36,14 @@ declare_clippy_lint! {
declare_lint_pass!(NeedlessBorrowedRef => [NEEDLESS_BORROWED_REFERENCE]);
impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowedRef {
fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
if pat.span.from_expansion() {
fn check_pat(&mut self, cx: &LateContext<'tcx>, ref_pat: &'tcx Pat<'_>) {
if ref_pat.span.from_expansion() {
// OK, simple enough, lints doesn't check in macro.
return;
}
// Do not lint patterns that are part of an OR `|` pattern, the binding mode must match in all arms
for (_, node) in cx.tcx.hir().parent_iter(pat.hir_id) {
for (_, node) in cx.tcx.hir().parent_iter(ref_pat.hir_id) {
let Node::Pat(pat) = node else { break };
if matches!(pat.kind, PatKind::Or(_)) {
@ -52,20 +52,20 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowedRef {
}
// Only lint immutable refs, because `&mut ref T` may be useful.
let PatKind::Ref(sub_pat, Mutability::Not) = pat.kind else { return };
let PatKind::Ref(pat, Mutability::Not) = ref_pat.kind else { return };
match sub_pat.kind {
match pat.kind {
// Check sub_pat got a `ref` keyword (excluding `ref mut`).
PatKind::Binding(BindingAnnotation::REF, _, ident, None) => {
span_lint_and_then(
cx,
NEEDLESS_BORROWED_REFERENCE,
pat.span,
ref_pat.span,
"this pattern takes a reference on something that is being dereferenced",
|diag| {
// `&ref ident`
// ^^^^^
let span = pat.span.until(ident.span);
let span = ref_pat.span.until(ident.span);
diag.span_suggestion_verbose(
span,
"try removing the `&ref` part",
@ -84,41 +84,71 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowedRef {
}),
after,
) => {
let mut suggestions = Vec::new();
for element_pat in itertools::chain(before, after) {
if let PatKind::Binding(BindingAnnotation::REF, _, ident, None) = element_pat.kind {
// `&[..., ref ident, ...]`
// ^^^^
let span = element_pat.span.until(ident.span);
suggestions.push((span, String::new()));
} else {
return;
}
}
if !suggestions.is_empty() {
span_lint_and_then(
cx,
NEEDLESS_BORROWED_REFERENCE,
pat.span,
"dereferencing a slice pattern where every element takes a reference",
|diag| {
// `&[...]`
// ^
let span = pat.span.until(sub_pat.span);
suggestions.push((span, String::new()));
diag.multipart_suggestion(
"try removing the `&` and `ref` parts",
suggestions,
Applicability::MachineApplicable,
);
},
);
}
check_subpatterns(
cx,
"dereferencing a slice pattern where every element takes a reference",
ref_pat,
pat,
itertools::chain(before, after),
);
},
PatKind::Tuple(subpatterns, _) | PatKind::TupleStruct(_, subpatterns, _) => {
check_subpatterns(
cx,
"dereferencing a tuple pattern where every element takes a reference",
ref_pat,
pat,
subpatterns,
);
},
PatKind::Struct(_, fields, _) => {
check_subpatterns(
cx,
"dereferencing a struct pattern where every field's pattern takes a reference",
ref_pat,
pat,
fields.iter().map(|field| field.pat),
);
},
_ => {},
}
}
}
fn check_subpatterns<'tcx>(
cx: &LateContext<'tcx>,
message: &str,
ref_pat: &Pat<'_>,
pat: &Pat<'_>,
subpatterns: impl IntoIterator<Item = &'tcx Pat<'tcx>>,
) {
let mut suggestions = Vec::new();
for subpattern in subpatterns {
match subpattern.kind {
PatKind::Binding(BindingAnnotation::REF, _, ident, None) => {
// `ref ident`
// ^^^^
let span = subpattern.span.until(ident.span);
suggestions.push((span, String::new()));
},
PatKind::Wild => {},
_ => return,
}
}
if !suggestions.is_empty() {
span_lint_and_then(cx, NEEDLESS_BORROWED_REFERENCE, ref_pat.span, message, |diag| {
// `&pat`
// ^
let span = ref_pat.span.until(pat.span);
suggestions.push((span, String::new()));
diag.multipart_suggestion(
"try removing the `&` and `ref` parts",
suggestions,
Applicability::MachineApplicable,
);
});
}
}

View file

@ -287,7 +287,7 @@ const DROP_ELSE_BLOCK_MSG: &str = "consider dropping the `else` clause";
const DROP_CONTINUE_EXPRESSION_MSG: &str = "consider dropping the `continue` expression";
fn emit_warning<'a>(cx: &EarlyContext<'_>, data: &'a LintData<'_>, header: &str, typ: LintType) {
fn emit_warning(cx: &EarlyContext<'_>, data: &LintData<'_>, header: &str, typ: LintType) {
// snip is the whole *help* message that appears after the warning.
// message is the warning message.
// expr is the expression which the lint warning message refers to.
@ -313,7 +313,7 @@ fn emit_warning<'a>(cx: &EarlyContext<'_>, data: &'a LintData<'_>, header: &str,
);
}
fn suggestion_snippet_for_continue_inside_if<'a>(cx: &EarlyContext<'_>, data: &'a LintData<'_>) -> String {
fn suggestion_snippet_for_continue_inside_if(cx: &EarlyContext<'_>, data: &LintData<'_>) -> String {
let cond_code = snippet(cx, data.if_cond.span, "..");
let continue_code = snippet_block(cx, data.if_block.span, "..", Some(data.if_expr.span));
@ -327,7 +327,7 @@ fn suggestion_snippet_for_continue_inside_if<'a>(cx: &EarlyContext<'_>, data: &'
)
}
fn suggestion_snippet_for_continue_inside_else<'a>(cx: &EarlyContext<'_>, data: &'a LintData<'_>) -> String {
fn suggestion_snippet_for_continue_inside_else(cx: &EarlyContext<'_>, data: &LintData<'_>) -> String {
let cond_code = snippet(cx, data.if_cond.span, "..");
// Region B
@ -361,7 +361,7 @@ fn suggestion_snippet_for_continue_inside_else<'a>(cx: &EarlyContext<'_>, data:
)
}
fn check_and_warn<'a>(cx: &EarlyContext<'_>, expr: &'a ast::Expr) {
fn check_and_warn(cx: &EarlyContext<'_>, expr: &ast::Expr) {
if_chain! {
if let ast::ExprKind::Loop(loop_block, ..) = &expr.kind;
if let Some(last_stmt) = loop_block.stmts.last();

View file

@ -340,11 +340,5 @@ impl<'tcx> euv::Delegate<'tcx> for MovedVariablesCtxt {
fn mutate(&mut self, _: &euv::PlaceWithHirId<'tcx>, _: HirId) {}
fn fake_read(
&mut self,
_: &rustc_hir_typeck::expr_use_visitor::PlaceWithHirId<'tcx>,
_: FakeReadCause,
_: HirId,
) {
}
fn fake_read(&mut self, _: &rustc_hir_typeck::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
}

View file

@ -58,9 +58,9 @@ impl EarlyLintPass for OctalEscapes {
if let ExprKind::Lit(token_lit) = &expr.kind {
if matches!(token_lit.kind, LitKind::Str) {
check_lit(cx, &token_lit, expr.span, true);
check_lit(cx, token_lit, expr.span, true);
} else if matches!(token_lit.kind, LitKind::ByteStr) {
check_lit(cx, &token_lit, expr.span, false);
check_lit(cx, token_lit, expr.span, false);
}
}
}

View file

@ -1,5 +1,9 @@
use super::ARITHMETIC_SIDE_EFFECTS;
use clippy_utils::{consts::constant_simple, diagnostics::span_lint};
use clippy_utils::{
consts::{constant, constant_simple},
diagnostics::span_lint,
peel_hir_expr_refs,
};
use rustc_ast as ast;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
@ -38,24 +42,6 @@ impl ArithmeticSideEffects {
}
}
/// Assuming that `expr` is a literal integer, checks operators (+=, -=, *, /) in a
/// non-constant environment that won't overflow.
fn has_valid_op(op: &Spanned<hir::BinOpKind>, expr: &hir::Expr<'_>) -> bool {
if let hir::ExprKind::Lit(ref lit) = expr.kind &&
let ast::LitKind::Int(value, _) = lit.node
{
match (&op.node, value) {
(hir::BinOpKind::Div | hir::BinOpKind::Rem, 0) => false,
(hir::BinOpKind::Add | hir::BinOpKind::Sub, 0)
| (hir::BinOpKind::Div | hir::BinOpKind::Rem, _)
| (hir::BinOpKind::Mul, 0 | 1) => true,
_ => false,
}
} else {
false
}
}
/// Checks if the given `expr` has any of the inner `allowed` elements.
fn is_allowed_ty(&self, ty: Ty<'_>) -> bool {
self.allowed
@ -74,15 +60,14 @@ impl ArithmeticSideEffects {
self.expr_span = Some(expr.span);
}
/// If `expr` does not match any variant of `LiteralIntegerTy`, returns `None`.
fn literal_integer<'expr, 'tcx>(expr: &'expr hir::Expr<'tcx>) -> Option<LiteralIntegerTy<'expr, 'tcx>> {
if matches!(expr.kind, hir::ExprKind::Lit(_)) {
return Some(LiteralIntegerTy::Value(expr));
/// If `expr` is not a literal integer like `1`, returns `None`.
fn literal_integer(expr: &hir::Expr<'_>) -> Option<u128> {
if let hir::ExprKind::Lit(ref lit) = expr.kind && let ast::LitKind::Int(n, _) = lit.node {
Some(n)
}
if let hir::ExprKind::AddrOf(.., inn) = expr.kind && let hir::ExprKind::Lit(_) = inn.kind {
return Some(LiteralIntegerTy::Ref(inn));
else {
None
}
None
}
/// Manages when the lint should be triggered. Operations in constant environments, hard coded
@ -117,10 +102,20 @@ impl ArithmeticSideEffects {
return;
}
let has_valid_op = if Self::is_integral(lhs_ty) && Self::is_integral(rhs_ty) {
match (Self::literal_integer(lhs), Self::literal_integer(rhs)) {
(None, Some(lit_int_ty)) | (Some(lit_int_ty), None) => Self::has_valid_op(op, lit_int_ty.into()),
(Some(LiteralIntegerTy::Value(_)), Some(LiteralIntegerTy::Value(_))) => true,
(None, None) | (Some(_), Some(_)) => false,
let (actual_lhs, lhs_ref_counter) = peel_hir_expr_refs(lhs);
let (actual_rhs, rhs_ref_counter) = peel_hir_expr_refs(rhs);
match (Self::literal_integer(actual_lhs), Self::literal_integer(actual_rhs)) {
(None, None) => false,
(None, Some(n)) | (Some(n), None) => match (&op.node, n) {
(hir::BinOpKind::Div | hir::BinOpKind::Rem, 0) => false,
(hir::BinOpKind::Add | hir::BinOpKind::Sub, 0)
| (hir::BinOpKind::Div | hir::BinOpKind::Rem, _)
| (hir::BinOpKind::Mul, 0 | 1) => true,
_ => false,
},
(Some(_), Some(_)) => {
matches!((lhs_ref_counter, rhs_ref_counter), (0, 0))
},
}
} else {
false
@ -129,21 +124,45 @@ impl ArithmeticSideEffects {
self.issue_lint(cx, expr);
}
}
fn manage_unary_ops<'tcx>(
&mut self,
cx: &LateContext<'tcx>,
expr: &hir::Expr<'tcx>,
un_expr: &hir::Expr<'tcx>,
un_op: hir::UnOp,
) {
let hir::UnOp::Neg = un_op else { return; };
if constant(cx, cx.typeck_results(), un_expr).is_some() {
return;
}
let ty = cx.typeck_results().expr_ty(expr).peel_refs();
if self.is_allowed_ty(ty) {
return;
}
let actual_un_expr = peel_hir_expr_refs(un_expr).0;
if Self::literal_integer(actual_un_expr).is_some() {
return;
}
self.issue_lint(cx, expr);
}
fn should_skip_expr(&mut self, expr: &hir::Expr<'_>) -> bool {
self.expr_span.is_some() || self.const_span.map_or(false, |sp| sp.contains(expr.span))
}
}
impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'tcx>) {
if self.expr_span.is_some() || self.const_span.map_or(false, |sp| sp.contains(expr.span)) {
if self.should_skip_expr(expr) {
return;
}
match &expr.kind {
hir::ExprKind::Binary(op, lhs, rhs) | hir::ExprKind::AssignOp(op, lhs, rhs) => {
hir::ExprKind::AssignOp(op, lhs, rhs) | hir::ExprKind::Binary(op, lhs, rhs) => {
self.manage_bin_ops(cx, expr, op, lhs, rhs);
},
hir::ExprKind::Unary(hir::UnOp::Neg, _) => {
if constant_simple(cx, cx.typeck_results(), expr).is_none() {
self.issue_lint(cx, expr);
}
hir::ExprKind::Unary(un_op, un_expr) => {
self.manage_unary_ops(cx, expr, un_expr, *un_op);
},
_ => {},
}
@ -177,22 +196,3 @@ impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects {
}
}
}
/// Tells if an expression is a integer declared by value or by reference.
///
/// If `LiteralIntegerTy::Ref`, then the contained value will be `hir::ExprKind::Lit` rather
/// than `hirExprKind::Addr`.
enum LiteralIntegerTy<'expr, 'tcx> {
/// For example, `&199`
Ref(&'expr hir::Expr<'tcx>),
/// For example, `1` or `i32::MAX`
Value(&'expr hir::Expr<'tcx>),
}
impl<'expr, 'tcx> From<LiteralIntegerTy<'expr, 'tcx>> for &'expr hir::Expr<'tcx> {
fn from(from: LiteralIntegerTy<'expr, 'tcx>) -> Self {
match from {
LiteralIntegerTy::Ref(elem) | LiteralIntegerTy::Value(elem) => elem,
}
}
}

View file

@ -199,7 +199,7 @@ fn in_impl<'tcx>(
}
}
fn are_equal<'tcx>(cx: &LateContext<'tcx>, middle_ty: Ty<'_>, hir_ty: &rustc_hir::Ty<'_>) -> bool {
fn are_equal(cx: &LateContext<'_>, middle_ty: Ty<'_>, hir_ty: &rustc_hir::Ty<'_>) -> bool {
if_chain! {
if let ty::Adt(adt_def, _) = middle_ty.kind();
if let Some(local_did) = adt_def.did().as_local();

View file

@ -213,11 +213,14 @@ fn try_convert_match<'tcx>(
cx: &LateContext<'tcx>,
arms: &[Arm<'tcx>],
) -> Option<(&'tcx Pat<'tcx>, &'tcx Expr<'tcx>, &'tcx Expr<'tcx>)> {
if arms.len() == 2 {
return if is_none_or_err_arm(cx, &arms[1]) {
Some((arms[0].pat, arms[0].body, arms[1].body))
} else if is_none_or_err_arm(cx, &arms[0]) {
Some((arms[1].pat, arms[1].body, arms[0].body))
if let [first_arm, second_arm] = arms
&& first_arm.guard.is_none()
&& second_arm.guard.is_none()
{
return if is_none_or_err_arm(cx, second_arm) {
Some((first_arm.pat, first_arm.body, second_arm.body))
} else if is_none_or_err_arm(cx, first_arm) {
Some((second_arm.pat, second_arm.body, first_arm.body))
} else {
None
};

View file

@ -33,7 +33,7 @@ declare_clippy_lint! {
/// if f.is_some() { "yay" } else { "nay" }
/// }
/// ```
#[clippy::version = "1.64.0"]
#[clippy::version = "1.65.0"]
pub PARTIALEQ_TO_NONE,
style,
"Binary comparison to `Option<T>::None` relies on `T: PartialEq`, which is unneeded"

View file

@ -130,7 +130,7 @@ enum DerefPossible {
Impossible,
}
fn apply_lint<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'_>, deref_possible: DerefPossible) -> bool {
fn apply_lint(cx: &LateContext<'_>, pat: &Pat<'_>, deref_possible: DerefPossible) -> bool {
let maybe_mismatch = find_first_mismatch(cx, pat);
if let Some((span, mutability, level)) = maybe_mismatch {
span_lint_and_help(
@ -163,7 +163,7 @@ enum Level {
Lower,
}
fn find_first_mismatch<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'_>) -> Option<(Span, Mutability, Level)> {
fn find_first_mismatch(cx: &LateContext<'_>, pat: &Pat<'_>) -> Option<(Span, Mutability, Level)> {
let mut result = None;
pat.walk(|p| {
if result.is_some() {

View file

@ -105,17 +105,17 @@ fn expr_as_ptr_offset_call<'tcx>(
}
// Is the type of the expression a usize?
fn is_expr_ty_usize<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> bool {
fn is_expr_ty_usize(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
cx.typeck_results().expr_ty(expr) == cx.tcx.types.usize
}
// Is the type of the expression a raw pointer?
fn is_expr_ty_raw_ptr<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> bool {
fn is_expr_ty_raw_ptr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
cx.typeck_results().expr_ty(expr).is_unsafe_ptr()
}
fn build_suggestion<'tcx>(
cx: &LateContext<'tcx>,
fn build_suggestion(
cx: &LateContext<'_>,
method: Method,
receiver_expr: &Expr<'_>,
cast_lhs_expr: &Expr<'_>,

View file

@ -189,6 +189,7 @@ fn is_early_return(smbl: Symbol, cx: &LateContext<'_>, if_block: &IfBlockType<'_
&& expr_return_none_or_err(smbl, cx, if_else.unwrap(), let_expr, Some(let_pat_sym)))
|| is_res_lang_ctor(cx, res, ResultErr)
&& expr_return_none_or_err(smbl, cx, if_then, let_expr, Some(let_pat_sym))
&& if_else.is_none()
},
_ => false,
}

View file

@ -105,8 +105,8 @@ impl EarlyLintPass for RedundantClosureCall {
impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall {
fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) {
fn count_closure_usage<'a, 'tcx>(
cx: &'a LateContext<'tcx>,
fn count_closure_usage<'tcx>(
cx: &LateContext<'tcx>,
block: &'tcx hir::Block<'_>,
path: &'tcx hir::Path<'tcx>,
) -> usize {

View file

@ -70,7 +70,8 @@ impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate {
}
if let ItemKind::Mod { .. } = item.kind {
self.is_exported.push(cx.effective_visibilities.is_exported(item.owner_id.def_id));
self.is_exported
.push(cx.effective_visibilities.is_exported(item.owner_id.def_id));
}
}

View file

@ -11,8 +11,6 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[
("clippy::disallowed_method", "clippy::disallowed_methods"),
("clippy::disallowed_type", "clippy::disallowed_types"),
("clippy::eval_order_dependence", "clippy::mixed_read_write_in_expression"),
("clippy::for_loop_over_option", "for_loops_over_fallibles"),
("clippy::for_loop_over_result", "for_loops_over_fallibles"),
("clippy::identity_conversion", "clippy::useless_conversion"),
("clippy::if_let_some_result", "clippy::match_result_ok"),
("clippy::logic_bug", "clippy::overly_complex_bool_expr"),
@ -31,10 +29,13 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[
("clippy::to_string_in_display", "clippy::recursive_format_impl"),
("clippy::zero_width_space", "clippy::invisible_characters"),
("clippy::drop_bounds", "drop_bounds"),
("clippy::for_loop_over_option", "for_loops_over_fallibles"),
("clippy::for_loop_over_result", "for_loops_over_fallibles"),
("clippy::for_loops_over_fallibles", "for_loops_over_fallibles"),
("clippy::into_iter_on_array", "array_into_iter"),
("clippy::invalid_atomic_ordering", "invalid_atomic_ordering"),
("clippy::invalid_ref", "invalid_value"),
("clippy::let_underscore_drop", "let_underscore_drop"),
("clippy::mem_discriminant_non_enum", "enum_intrinsics_non_enums"),
("clippy::panic_params", "non_fmt_panics"),
("clippy::positional_named_format_parameters", "named_arguments_used_positionally"),

Some files were not shown because too many files have changed in this diff Show more