From abd3e7eabb8712244ca4dfbed5455df591aed0fc Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Tue, 6 Sep 2022 14:23:03 -0400 Subject: [PATCH 001/114] Allow lint passes to be bound by `TyCtxt` --- clippy_dev/src/new_lint.rs | 6 +- clippy_lints/src/lib.rs | 414 ++++++++++++++++++------------------- 2 files changed, 211 insertions(+), 209 deletions(-) diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index be05e67d724df..331b76484b8a5 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -120,15 +120,17 @@ fn add_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> { let new_lint = if enable_msrv { format!( - "store.register_{lint_pass}_pass(move || Box::new({module_name}::{camel_name}::new(msrv)));\n ", + "store.register_{lint_pass}_pass(move |{ctor_arg}| Box::new({module_name}::{camel_name}::new(msrv)));\n ", lint_pass = lint.pass, + ctor_arg = if lint.pass == "late" { "_" } else { "" }, module_name = lint.name, camel_name = to_camel_case(lint.name), ) } else { format!( - "store.register_{lint_pass}_pass(|| Box::new({module_name}::{camel_name}));\n ", + "store.register_{lint_pass}_pass(|{ctor_arg}| Box::new({module_name}::{camel_name}));\n ", lint_pass = lint.pass, + ctor_arg = if lint.pass == "late" { "_" } else { "" }, module_name = lint.name, camel_name = to_camel_case(lint.name), ) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index dfdaf90f09f48..c70aa79ac8dcf 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -523,7 +523,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: #[cfg(feature = "internal")] { if std::env::var("ENABLE_METADATA_COLLECTION").eq(&Ok("1".to_string())) { - store.register_late_pass(|| Box::new(utils::internal_lints::metadata_collector::MetadataCollector::new())); + store.register_late_pass(|_| Box::new(utils::internal_lints::metadata_collector::MetadataCollector::new())); return; } } @@ -533,69 +533,69 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: { store.register_early_pass(|| Box::new(utils::internal_lints::ClippyLintsInternal)); store.register_early_pass(|| Box::new(utils::internal_lints::ProduceIce)); - store.register_late_pass(|| Box::new(utils::internal_lints::CollapsibleCalls)); - store.register_late_pass(|| Box::new(utils::internal_lints::CompilerLintFunctions::new())); - store.register_late_pass(|| Box::new(utils::internal_lints::IfChainStyle)); - store.register_late_pass(|| Box::new(utils::internal_lints::InvalidPaths)); - store.register_late_pass(|| Box::new(utils::internal_lints::InterningDefinedSymbol::default())); - store.register_late_pass(|| Box::new(utils::internal_lints::LintWithoutLintPass::default())); - store.register_late_pass(|| Box::new(utils::internal_lints::MatchTypeOnDiagItem)); - store.register_late_pass(|| Box::new(utils::internal_lints::OuterExpnDataPass)); - store.register_late_pass(|| Box::new(utils::internal_lints::MsrvAttrImpl)); + store.register_late_pass(|_| Box::new(utils::internal_lints::CollapsibleCalls)); + store.register_late_pass(|_| Box::new(utils::internal_lints::CompilerLintFunctions::new())); + store.register_late_pass(|_| Box::new(utils::internal_lints::IfChainStyle)); + store.register_late_pass(|_| Box::new(utils::internal_lints::InvalidPaths)); + store.register_late_pass(|_| Box::new(utils::internal_lints::InterningDefinedSymbol::default())); + store.register_late_pass(|_| Box::new(utils::internal_lints::LintWithoutLintPass::default())); + store.register_late_pass(|_| Box::new(utils::internal_lints::MatchTypeOnDiagItem)); + store.register_late_pass(|_| Box::new(utils::internal_lints::OuterExpnDataPass)); + store.register_late_pass(|_| Box::new(utils::internal_lints::MsrvAttrImpl)); } let arithmetic_allowed = conf.arithmetic_allowed.clone(); - store.register_late_pass(move || Box::new(operators::arithmetic::Arithmetic::new(arithmetic_allowed.clone()))); - store.register_late_pass(|| Box::new(utils::dump_hir::DumpHir)); - store.register_late_pass(|| Box::new(utils::author::Author)); + store.register_late_pass(move |_| Box::new(operators::arithmetic::Arithmetic::new(arithmetic_allowed.clone()))); + store.register_late_pass(|_| Box::new(utils::dump_hir::DumpHir)); + store.register_late_pass(|_| Box::new(utils::author::Author)); let await_holding_invalid_types = conf.await_holding_invalid_types.clone(); - store.register_late_pass(move || { + store.register_late_pass(move |_| { Box::new(await_holding_invalid::AwaitHolding::new( await_holding_invalid_types.clone(), )) }); - store.register_late_pass(|| Box::new(serde_api::SerdeApi)); + store.register_late_pass(|_| Box::new(serde_api::SerdeApi)); let vec_box_size_threshold = conf.vec_box_size_threshold; let type_complexity_threshold = conf.type_complexity_threshold; let avoid_breaking_exported_api = conf.avoid_breaking_exported_api; - store.register_late_pass(move || { + store.register_late_pass(move |_| { Box::new(types::Types::new( vec_box_size_threshold, type_complexity_threshold, avoid_breaking_exported_api, )) }); - store.register_late_pass(|| Box::new(booleans::NonminimalBool)); - store.register_late_pass(|| Box::new(enum_clike::UnportableVariant)); - store.register_late_pass(|| Box::new(float_literal::FloatLiteral)); - store.register_late_pass(|| Box::new(ptr::Ptr)); - store.register_late_pass(|| Box::new(needless_bool::NeedlessBool)); - store.register_late_pass(|| Box::new(needless_bool::BoolComparison)); - store.register_late_pass(|| Box::new(needless_for_each::NeedlessForEach)); - store.register_late_pass(|| Box::new(misc::MiscLints)); - store.register_late_pass(|| Box::new(eta_reduction::EtaReduction)); - store.register_late_pass(|| Box::new(mut_mut::MutMut)); - store.register_late_pass(|| Box::new(mut_reference::UnnecessaryMutPassed)); - store.register_late_pass(|| Box::new(len_zero::LenZero)); - store.register_late_pass(|| Box::new(attrs::Attributes)); - store.register_late_pass(|| Box::new(blocks_in_if_conditions::BlocksInIfConditions)); - store.register_late_pass(|| Box::new(unicode::Unicode)); - store.register_late_pass(|| Box::new(uninit_vec::UninitVec)); - store.register_late_pass(|| Box::new(unit_return_expecting_ord::UnitReturnExpectingOrd)); - store.register_late_pass(|| Box::new(strings::StringAdd)); - store.register_late_pass(|| Box::new(implicit_return::ImplicitReturn)); - store.register_late_pass(|| Box::new(implicit_saturating_sub::ImplicitSaturatingSub)); - store.register_late_pass(|| Box::new(default_numeric_fallback::DefaultNumericFallback)); - store.register_late_pass(|| Box::new(inconsistent_struct_constructor::InconsistentStructConstructor)); - store.register_late_pass(|| Box::new(non_octal_unix_permissions::NonOctalUnixPermissions)); + store.register_late_pass(|_| Box::new(booleans::NonminimalBool)); + store.register_late_pass(|_| Box::new(enum_clike::UnportableVariant)); + store.register_late_pass(|_| Box::new(float_literal::FloatLiteral)); + store.register_late_pass(|_| Box::new(ptr::Ptr)); + store.register_late_pass(|_| Box::new(needless_bool::NeedlessBool)); + store.register_late_pass(|_| Box::new(needless_bool::BoolComparison)); + store.register_late_pass(|_| Box::new(needless_for_each::NeedlessForEach)); + store.register_late_pass(|_| Box::new(misc::MiscLints)); + store.register_late_pass(|_| Box::new(eta_reduction::EtaReduction)); + store.register_late_pass(|_| Box::new(mut_mut::MutMut)); + store.register_late_pass(|_| Box::new(mut_reference::UnnecessaryMutPassed)); + store.register_late_pass(|_| Box::new(len_zero::LenZero)); + store.register_late_pass(|_| Box::new(attrs::Attributes)); + store.register_late_pass(|_| Box::new(blocks_in_if_conditions::BlocksInIfConditions)); + store.register_late_pass(|_| Box::new(unicode::Unicode)); + store.register_late_pass(|_| Box::new(uninit_vec::UninitVec)); + store.register_late_pass(|_| Box::new(unit_return_expecting_ord::UnitReturnExpectingOrd)); + store.register_late_pass(|_| Box::new(strings::StringAdd)); + store.register_late_pass(|_| Box::new(implicit_return::ImplicitReturn)); + store.register_late_pass(|_| Box::new(implicit_saturating_sub::ImplicitSaturatingSub)); + store.register_late_pass(|_| Box::new(default_numeric_fallback::DefaultNumericFallback)); + store.register_late_pass(|_| Box::new(inconsistent_struct_constructor::InconsistentStructConstructor)); + store.register_late_pass(|_| Box::new(non_octal_unix_permissions::NonOctalUnixPermissions)); store.register_early_pass(|| Box::new(unnecessary_self_imports::UnnecessarySelfImports)); let msrv = read_msrv(conf, sess); let avoid_breaking_exported_api = conf.avoid_breaking_exported_api; let allow_expect_in_tests = conf.allow_expect_in_tests; let allow_unwrap_in_tests = conf.allow_unwrap_in_tests; - store.register_late_pass(move || Box::new(approx_const::ApproxConstant::new(msrv))); - store.register_late_pass(move || { + store.register_late_pass(move |_| Box::new(approx_const::ApproxConstant::new(msrv))); + store.register_late_pass(move |_| { Box::new(methods::Methods::new( avoid_breaking_exported_api, msrv, @@ -603,74 +603,74 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: allow_unwrap_in_tests, )) }); - store.register_late_pass(move || Box::new(matches::Matches::new(msrv))); + store.register_late_pass(move |_| Box::new(matches::Matches::new(msrv))); 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))); + 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))); store.register_early_pass(move || Box::new(redundant_static_lifetimes::RedundantStaticLifetimes::new(msrv))); store.register_early_pass(move || Box::new(redundant_field_names::RedundantFieldNames::new(msrv))); - store.register_late_pass(move || Box::new(checked_conversions::CheckedConversions::new(msrv))); - store.register_late_pass(move || Box::new(mem_replace::MemReplace::new(msrv))); - store.register_late_pass(move || Box::new(ranges::Ranges::new(msrv))); - store.register_late_pass(move || Box::new(from_over_into::FromOverInto::new(msrv))); - store.register_late_pass(move || Box::new(use_self::UseSelf::new(msrv))); - store.register_late_pass(move || Box::new(missing_const_for_fn::MissingConstForFn::new(msrv))); - store.register_late_pass(move || Box::new(needless_question_mark::NeedlessQuestionMark)); - store.register_late_pass(move || Box::new(casts::Casts::new(msrv))); + store.register_late_pass(move |_| Box::new(checked_conversions::CheckedConversions::new(msrv))); + store.register_late_pass(move |_| Box::new(mem_replace::MemReplace::new(msrv))); + store.register_late_pass(move |_| Box::new(ranges::Ranges::new(msrv))); + store.register_late_pass(move |_| Box::new(from_over_into::FromOverInto::new(msrv))); + store.register_late_pass(move |_| Box::new(use_self::UseSelf::new(msrv))); + store.register_late_pass(move |_| Box::new(missing_const_for_fn::MissingConstForFn::new(msrv))); + store.register_late_pass(move |_| Box::new(needless_question_mark::NeedlessQuestionMark)); + store.register_late_pass(move |_| Box::new(casts::Casts::new(msrv))); store.register_early_pass(move || Box::new(unnested_or_patterns::UnnestedOrPatterns::new(msrv))); - store.register_late_pass(|| Box::new(size_of_in_element_count::SizeOfInElementCount)); - store.register_late_pass(|| Box::new(same_name_method::SameNameMethod)); + store.register_late_pass(|_| Box::new(size_of_in_element_count::SizeOfInElementCount)); + store.register_late_pass(|_| Box::new(same_name_method::SameNameMethod)); let max_suggested_slice_pattern_length = conf.max_suggested_slice_pattern_length; - store.register_late_pass(move || { + store.register_late_pass(move |_| { Box::new(index_refutable_slice::IndexRefutableSlice::new( max_suggested_slice_pattern_length, msrv, )) }); - store.register_late_pass(|| Box::new(shadow::Shadow::default())); - store.register_late_pass(|| Box::new(unit_types::UnitTypes)); - store.register_late_pass(|| Box::new(loops::Loops)); - store.register_late_pass(|| Box::new(main_recursion::MainRecursion::default())); - store.register_late_pass(|| Box::new(lifetimes::Lifetimes)); - store.register_late_pass(|| Box::new(entry::HashMapPass)); - store.register_late_pass(|| Box::new(minmax::MinMaxPass)); - store.register_late_pass(|| Box::new(zero_div_zero::ZeroDiv)); - store.register_late_pass(|| Box::new(mutex_atomic::Mutex)); - store.register_late_pass(|| Box::new(needless_update::NeedlessUpdate)); - store.register_late_pass(|| Box::new(needless_borrowed_ref::NeedlessBorrowedRef)); - store.register_late_pass(|| Box::new(borrow_deref_ref::BorrowDerefRef)); - store.register_late_pass(|| Box::new(no_effect::NoEffect)); - store.register_late_pass(|| Box::new(temporary_assignment::TemporaryAssignment)); - store.register_late_pass(move || Box::new(transmute::Transmute::new(msrv))); + store.register_late_pass(|_| Box::new(shadow::Shadow::default())); + store.register_late_pass(|_| Box::new(unit_types::UnitTypes)); + store.register_late_pass(|_| Box::new(loops::Loops)); + store.register_late_pass(|_| Box::new(main_recursion::MainRecursion::default())); + store.register_late_pass(|_| Box::new(lifetimes::Lifetimes)); + store.register_late_pass(|_| Box::new(entry::HashMapPass)); + store.register_late_pass(|_| Box::new(minmax::MinMaxPass)); + store.register_late_pass(|_| Box::new(zero_div_zero::ZeroDiv)); + store.register_late_pass(|_| Box::new(mutex_atomic::Mutex)); + store.register_late_pass(|_| Box::new(needless_update::NeedlessUpdate)); + store.register_late_pass(|_| Box::new(needless_borrowed_ref::NeedlessBorrowedRef)); + store.register_late_pass(|_| Box::new(borrow_deref_ref::BorrowDerefRef)); + store.register_late_pass(|_| Box::new(no_effect::NoEffect)); + store.register_late_pass(|_| Box::new(temporary_assignment::TemporaryAssignment)); + store.register_late_pass(move |_| Box::new(transmute::Transmute::new(msrv))); let cognitive_complexity_threshold = conf.cognitive_complexity_threshold; - store.register_late_pass(move || { + store.register_late_pass(move |_| { Box::new(cognitive_complexity::CognitiveComplexity::new( cognitive_complexity_threshold, )) }); let too_large_for_stack = conf.too_large_for_stack; - store.register_late_pass(move || Box::new(escape::BoxedLocal { too_large_for_stack })); - store.register_late_pass(move || Box::new(vec::UselessVec { too_large_for_stack })); - store.register_late_pass(|| Box::new(panic_unimplemented::PanicUnimplemented)); - store.register_late_pass(|| Box::new(strings::StringLitAsBytes)); - store.register_late_pass(|| Box::new(derive::Derive)); - store.register_late_pass(|| Box::new(derivable_impls::DerivableImpls)); - store.register_late_pass(|| Box::new(drop_forget_ref::DropForgetRef)); - store.register_late_pass(|| Box::new(empty_enum::EmptyEnum)); - store.register_late_pass(|| Box::new(invalid_upcast_comparisons::InvalidUpcastComparisons)); - store.register_late_pass(|| Box::new(regex::Regex)); - store.register_late_pass(|| Box::new(copies::CopyAndPaste)); - store.register_late_pass(|| Box::new(copy_iterator::CopyIterator)); - store.register_late_pass(|| Box::new(format::UselessFormat)); - store.register_late_pass(|| Box::new(swap::Swap)); - store.register_late_pass(|| Box::new(overflow_check_conditional::OverflowCheckConditional)); - store.register_late_pass(|| Box::new(new_without_default::NewWithoutDefault::default())); + store.register_late_pass(move |_| Box::new(escape::BoxedLocal { too_large_for_stack })); + store.register_late_pass(move |_| Box::new(vec::UselessVec { too_large_for_stack })); + store.register_late_pass(|_| Box::new(panic_unimplemented::PanicUnimplemented)); + store.register_late_pass(|_| Box::new(strings::StringLitAsBytes)); + store.register_late_pass(|_| Box::new(derive::Derive)); + store.register_late_pass(|_| Box::new(derivable_impls::DerivableImpls)); + store.register_late_pass(|_| Box::new(drop_forget_ref::DropForgetRef)); + store.register_late_pass(|_| Box::new(empty_enum::EmptyEnum)); + store.register_late_pass(|_| Box::new(invalid_upcast_comparisons::InvalidUpcastComparisons)); + store.register_late_pass(|_| Box::new(regex::Regex)); + store.register_late_pass(|_| Box::new(copies::CopyAndPaste)); + store.register_late_pass(|_| Box::new(copy_iterator::CopyIterator)); + store.register_late_pass(|_| Box::new(format::UselessFormat)); + store.register_late_pass(|_| Box::new(swap::Swap)); + store.register_late_pass(|_| Box::new(overflow_check_conditional::OverflowCheckConditional)); + store.register_late_pass(|_| Box::new(new_without_default::NewWithoutDefault::default())); let disallowed_names = conf.disallowed_names.iter().cloned().collect::>(); - store.register_late_pass(move || Box::new(disallowed_names::DisallowedNames::new(disallowed_names.clone()))); + store.register_late_pass(move |_| Box::new(disallowed_names::DisallowedNames::new(disallowed_names.clone()))); let too_many_arguments_threshold = conf.too_many_arguments_threshold; let too_many_lines_threshold = conf.too_many_lines_threshold; let large_error_threshold = conf.large_error_threshold; - store.register_late_pass(move || { + store.register_late_pass(move |_| { Box::new(functions::Functions::new( too_many_arguments_threshold, too_many_lines_threshold, @@ -678,73 +678,73 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: )) }); let doc_valid_idents = conf.doc_valid_idents.iter().cloned().collect::>(); - store.register_late_pass(move || Box::new(doc::DocMarkdown::new(doc_valid_idents.clone()))); - store.register_late_pass(|| Box::new(neg_multiply::NegMultiply)); - store.register_late_pass(|| Box::new(mem_forget::MemForget)); - store.register_late_pass(|| Box::new(let_if_seq::LetIfSeq)); - store.register_late_pass(|| Box::new(mixed_read_write_in_expression::EvalOrderDependence)); - store.register_late_pass(|| Box::new(missing_doc::MissingDoc::new())); - store.register_late_pass(|| Box::new(missing_inline::MissingInline)); - store.register_late_pass(move || Box::new(exhaustive_items::ExhaustiveItems)); - store.register_late_pass(|| Box::new(match_result_ok::MatchResultOk)); - store.register_late_pass(|| Box::new(partialeq_ne_impl::PartialEqNeImpl)); - store.register_late_pass(|| Box::new(unused_io_amount::UnusedIoAmount)); + store.register_late_pass(move |_| Box::new(doc::DocMarkdown::new(doc_valid_idents.clone()))); + store.register_late_pass(|_| Box::new(neg_multiply::NegMultiply)); + store.register_late_pass(|_| Box::new(mem_forget::MemForget)); + store.register_late_pass(|_| Box::new(let_if_seq::LetIfSeq)); + store.register_late_pass(|_| Box::new(mixed_read_write_in_expression::EvalOrderDependence)); + store.register_late_pass(|_| Box::new(missing_doc::MissingDoc::new())); + store.register_late_pass(|_| Box::new(missing_inline::MissingInline)); + store.register_late_pass(move |_| Box::new(exhaustive_items::ExhaustiveItems)); + store.register_late_pass(|_| Box::new(match_result_ok::MatchResultOk)); + store.register_late_pass(|_| Box::new(partialeq_ne_impl::PartialEqNeImpl)); + store.register_late_pass(|_| Box::new(unused_io_amount::UnusedIoAmount)); let enum_variant_size_threshold = conf.enum_variant_size_threshold; - store.register_late_pass(move || Box::new(large_enum_variant::LargeEnumVariant::new(enum_variant_size_threshold))); - store.register_late_pass(|| Box::new(explicit_write::ExplicitWrite)); - store.register_late_pass(|| Box::new(needless_pass_by_value::NeedlessPassByValue)); + store.register_late_pass(move |_| Box::new(large_enum_variant::LargeEnumVariant::new(enum_variant_size_threshold))); + store.register_late_pass(|_| Box::new(explicit_write::ExplicitWrite)); + store.register_late_pass(|_| Box::new(needless_pass_by_value::NeedlessPassByValue)); let pass_by_ref_or_value = pass_by_ref_or_value::PassByRefOrValue::new( conf.trivial_copy_size_limit, conf.pass_by_value_size_limit, conf.avoid_breaking_exported_api, &sess.target, ); - store.register_late_pass(move || Box::new(pass_by_ref_or_value)); - store.register_late_pass(|| Box::new(ref_option_ref::RefOptionRef)); - store.register_late_pass(|| Box::new(infinite_iter::InfiniteIter)); - store.register_late_pass(|| Box::new(inline_fn_without_body::InlineFnWithoutBody)); - store.register_late_pass(|| Box::new(useless_conversion::UselessConversion::default())); - store.register_late_pass(|| Box::new(implicit_hasher::ImplicitHasher)); - store.register_late_pass(|| Box::new(fallible_impl_from::FallibleImplFrom)); - store.register_late_pass(|| Box::new(question_mark::QuestionMark)); + store.register_late_pass(move |_| Box::new(pass_by_ref_or_value)); + store.register_late_pass(|_| Box::new(ref_option_ref::RefOptionRef)); + store.register_late_pass(|_| Box::new(infinite_iter::InfiniteIter)); + store.register_late_pass(|_| Box::new(inline_fn_without_body::InlineFnWithoutBody)); + store.register_late_pass(|_| Box::new(useless_conversion::UselessConversion::default())); + store.register_late_pass(|_| Box::new(implicit_hasher::ImplicitHasher)); + store.register_late_pass(|_| Box::new(fallible_impl_from::FallibleImplFrom)); + store.register_late_pass(|_| Box::new(question_mark::QuestionMark)); store.register_early_pass(|| Box::new(suspicious_operation_groupings::SuspiciousOperationGroupings)); - store.register_late_pass(|| Box::new(suspicious_trait_impl::SuspiciousImpl)); - store.register_late_pass(|| Box::new(map_unit_fn::MapUnit)); - store.register_late_pass(|| Box::new(inherent_impl::MultipleInherentImpl)); - store.register_late_pass(|| Box::new(neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd)); - store.register_late_pass(|| Box::new(unwrap::Unwrap)); - store.register_late_pass(|| Box::new(indexing_slicing::IndexingSlicing)); - store.register_late_pass(|| Box::new(non_copy_const::NonCopyConst)); - store.register_late_pass(|| Box::new(ptr_offset_with_cast::PtrOffsetWithCast)); - store.register_late_pass(|| Box::new(redundant_clone::RedundantClone)); - store.register_late_pass(|| Box::new(slow_vector_initialization::SlowVectorInit)); - store.register_late_pass(move || Box::new(unnecessary_wraps::UnnecessaryWraps::new(avoid_breaking_exported_api))); - store.register_late_pass(|| Box::new(assertions_on_constants::AssertionsOnConstants)); - store.register_late_pass(|| Box::new(assertions_on_result_states::AssertionsOnResultStates)); - store.register_late_pass(|| Box::new(inherent_to_string::InherentToString)); + store.register_late_pass(|_| Box::new(suspicious_trait_impl::SuspiciousImpl)); + store.register_late_pass(|_| Box::new(map_unit_fn::MapUnit)); + store.register_late_pass(|_| Box::new(inherent_impl::MultipleInherentImpl)); + store.register_late_pass(|_| Box::new(neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd)); + store.register_late_pass(|_| Box::new(unwrap::Unwrap)); + store.register_late_pass(|_| Box::new(indexing_slicing::IndexingSlicing)); + store.register_late_pass(|_| Box::new(non_copy_const::NonCopyConst)); + store.register_late_pass(|_| Box::new(ptr_offset_with_cast::PtrOffsetWithCast)); + store.register_late_pass(|_| Box::new(redundant_clone::RedundantClone)); + store.register_late_pass(|_| Box::new(slow_vector_initialization::SlowVectorInit)); + store.register_late_pass(move |_| Box::new(unnecessary_wraps::UnnecessaryWraps::new(avoid_breaking_exported_api))); + store.register_late_pass(|_| Box::new(assertions_on_constants::AssertionsOnConstants)); + store.register_late_pass(|_| Box::new(assertions_on_result_states::AssertionsOnResultStates)); + store.register_late_pass(|_| Box::new(inherent_to_string::InherentToString)); 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)); + 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)); 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())); + store.register_late_pass(|_| Box::new(format_impl::FormatImpl::new())); store.register_early_pass(|| Box::new(unsafe_removed_from_name::UnsafeNameRemoval)); store.register_early_pass(|| Box::new(else_if_without_else::ElseIfWithoutElse)); store.register_early_pass(|| Box::new(int_plus_one::IntPlusOne)); store.register_early_pass(|| Box::new(formatting::Formatting)); store.register_early_pass(|| Box::new(misc_early::MiscEarlyLints)); store.register_early_pass(|| Box::new(redundant_closure_call::RedundantClosureCall)); - store.register_late_pass(|| Box::new(redundant_closure_call::RedundantClosureCall)); + store.register_late_pass(|_| Box::new(redundant_closure_call::RedundantClosureCall)); store.register_early_pass(|| Box::new(unused_unit::UnusedUnit)); - store.register_late_pass(|| Box::new(returns::Return)); + store.register_late_pass(|_| Box::new(returns::Return)); store.register_early_pass(|| Box::new(collapsible_if::CollapsibleIf)); store.register_early_pass(|| Box::new(items_after_statements::ItemsAfterStatements)); store.register_early_pass(|| Box::new(precedence::Precedence)); - store.register_late_pass(|| Box::new(needless_parens_on_range_literals::NeedlessParensOnRangeLiterals)); + store.register_late_pass(|_| Box::new(needless_parens_on_range_literals::NeedlessParensOnRangeLiterals)); store.register_early_pass(|| Box::new(needless_continue::NeedlessContinue)); store.register_early_pass(|| Box::new(redundant_else::RedundantElse)); - store.register_late_pass(|| Box::new(create_dir::CreateDir)); + store.register_late_pass(|_| Box::new(create_dir::CreateDir)); store.register_early_pass(|| Box::new(needless_arbitrary_self_type::NeedlessArbitrarySelfType)); let literal_representation_lint_fraction_readability = conf.unreadable_literal_lint_fractions; store.register_early_pass(move || { @@ -759,7 +759,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: )) }); let enum_variant_name_threshold = conf.enum_variant_name_threshold; - store.register_late_pass(move || { + store.register_late_pass(move |_| { Box::new(enum_variants::EnumVariantNames::new( enum_variant_name_threshold, avoid_breaking_exported_api, @@ -767,23 +767,23 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: }); store.register_early_pass(|| Box::new(tabs_in_doc_comments::TabsInDocComments)); let upper_case_acronyms_aggressive = conf.upper_case_acronyms_aggressive; - store.register_late_pass(move || { + store.register_late_pass(move |_| { Box::new(upper_case_acronyms::UpperCaseAcronyms::new( avoid_breaking_exported_api, upper_case_acronyms_aggressive, )) }); - store.register_late_pass(|| Box::new(default::Default::default())); - store.register_late_pass(move || Box::new(unused_self::UnusedSelf::new(avoid_breaking_exported_api))); - store.register_late_pass(|| Box::new(mutable_debug_assertion::DebugAssertWithMutCall)); - store.register_late_pass(|| Box::new(exit::Exit)); - store.register_late_pass(|| Box::new(to_digit_is_some::ToDigitIsSome)); + store.register_late_pass(|_| Box::new(default::Default::default())); + store.register_late_pass(move |_| Box::new(unused_self::UnusedSelf::new(avoid_breaking_exported_api))); + store.register_late_pass(|_| Box::new(mutable_debug_assertion::DebugAssertWithMutCall)); + store.register_late_pass(|_| Box::new(exit::Exit)); + store.register_late_pass(|_| Box::new(to_digit_is_some::ToDigitIsSome)); let array_size_threshold = conf.array_size_threshold; - store.register_late_pass(move || Box::new(large_stack_arrays::LargeStackArrays::new(array_size_threshold))); - store.register_late_pass(move || Box::new(large_const_arrays::LargeConstArrays::new(array_size_threshold))); - store.register_late_pass(|| Box::new(floating_point_arithmetic::FloatingPointArithmetic)); + store.register_late_pass(move |_| Box::new(large_stack_arrays::LargeStackArrays::new(array_size_threshold))); + store.register_late_pass(move |_| Box::new(large_const_arrays::LargeConstArrays::new(array_size_threshold))); + 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_late_pass(|_| Box::new(let_underscore::LetUnderscore)); store.register_early_pass(|| Box::new(single_component_path_imports::SingleComponentPathImports)); let max_fn_params_bools = conf.max_fn_params_bools; let max_struct_bools = conf.max_struct_bools; @@ -795,17 +795,17 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: }); store.register_early_pass(|| Box::new(option_env_unwrap::OptionEnvUnwrap)); let warn_on_all_wildcard_imports = conf.warn_on_all_wildcard_imports; - store.register_late_pass(move || Box::new(wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports))); - store.register_late_pass(|| Box::new(redundant_pub_crate::RedundantPubCrate::default())); - store.register_late_pass(|| Box::new(unnamed_address::UnnamedAddress)); - store.register_late_pass(move || Box::new(dereference::Dereferencing::new(msrv))); - store.register_late_pass(|| Box::new(option_if_let_else::OptionIfLetElse)); - store.register_late_pass(|| Box::new(future_not_send::FutureNotSend)); - store.register_late_pass(|| Box::new(if_let_mutex::IfLetMutex)); - store.register_late_pass(|| Box::new(if_not_else::IfNotElse)); - store.register_late_pass(|| Box::new(equatable_if_let::PatternEquality)); - store.register_late_pass(|| Box::new(manual_async_fn::ManualAsyncFn)); - store.register_late_pass(|| Box::new(panic_in_result_fn::PanicInResultFn)); + store.register_late_pass(move |_| Box::new(wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports))); + store.register_late_pass(|_| Box::new(redundant_pub_crate::RedundantPubCrate::default())); + store.register_late_pass(|_| Box::new(unnamed_address::UnnamedAddress)); + store.register_late_pass(move |_| Box::new(dereference::Dereferencing::new(msrv))); + store.register_late_pass(|_| Box::new(option_if_let_else::OptionIfLetElse)); + store.register_late_pass(|_| Box::new(future_not_send::FutureNotSend)); + store.register_late_pass(|_| Box::new(if_let_mutex::IfLetMutex)); + store.register_late_pass(|_| Box::new(if_not_else::IfNotElse)); + store.register_late_pass(|_| Box::new(equatable_if_let::PatternEquality)); + store.register_late_pass(|_| Box::new(manual_async_fn::ManualAsyncFn)); + store.register_late_pass(|_| Box::new(panic_in_result_fn::PanicInResultFn)); let single_char_binding_names_threshold = conf.single_char_binding_names_threshold; store.register_early_pass(move || { Box::new(non_expressive_names::NonExpressiveNames { @@ -814,92 +814,92 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: }); let macro_matcher = conf.standard_macro_braces.iter().cloned().collect::>(); store.register_early_pass(move || Box::new(nonstandard_macro_braces::MacroBraces::new(¯o_matcher))); - store.register_late_pass(|| Box::new(macro_use::MacroUseImports::default())); - store.register_late_pass(|| Box::new(pattern_type_mismatch::PatternTypeMismatch)); - store.register_late_pass(|| Box::new(unwrap_in_result::UnwrapInResult)); - store.register_late_pass(|| Box::new(semicolon_if_nothing_returned::SemicolonIfNothingReturned)); - store.register_late_pass(|| Box::new(async_yields_async::AsyncYieldsAsync)); + store.register_late_pass(|_| Box::new(macro_use::MacroUseImports::default())); + store.register_late_pass(|_| Box::new(pattern_type_mismatch::PatternTypeMismatch)); + store.register_late_pass(|_| Box::new(unwrap_in_result::UnwrapInResult)); + store.register_late_pass(|_| Box::new(semicolon_if_nothing_returned::SemicolonIfNothingReturned)); + store.register_late_pass(|_| Box::new(async_yields_async::AsyncYieldsAsync)); let disallowed_methods = conf.disallowed_methods.clone(); - store.register_late_pass(move || Box::new(disallowed_methods::DisallowedMethods::new(disallowed_methods.clone()))); + store.register_late_pass(move |_| Box::new(disallowed_methods::DisallowedMethods::new(disallowed_methods.clone()))); store.register_early_pass(|| Box::new(asm_syntax::InlineAsmX86AttSyntax)); store.register_early_pass(|| Box::new(asm_syntax::InlineAsmX86IntelSyntax)); - store.register_late_pass(|| Box::new(empty_drop::EmptyDrop)); - store.register_late_pass(|| Box::new(strings::StrToString)); - store.register_late_pass(|| Box::new(strings::StringToString)); - store.register_late_pass(|| Box::new(zero_sized_map_values::ZeroSizedMapValues)); - store.register_late_pass(|| Box::new(vec_init_then_push::VecInitThenPush::default())); - store.register_late_pass(|| Box::new(redundant_slicing::RedundantSlicing)); - store.register_late_pass(|| Box::new(from_str_radix_10::FromStrRadix10)); - store.register_late_pass(move || Box::new(if_then_some_else_none::IfThenSomeElseNone::new(msrv))); - store.register_late_pass(|| Box::new(bool_assert_comparison::BoolAssertComparison)); + store.register_late_pass(|_| Box::new(empty_drop::EmptyDrop)); + store.register_late_pass(|_| Box::new(strings::StrToString)); + store.register_late_pass(|_| Box::new(strings::StringToString)); + store.register_late_pass(|_| Box::new(zero_sized_map_values::ZeroSizedMapValues)); + store.register_late_pass(|_| Box::new(vec_init_then_push::VecInitThenPush::default())); + store.register_late_pass(|_| Box::new(redundant_slicing::RedundantSlicing)); + store.register_late_pass(|_| Box::new(from_str_radix_10::FromStrRadix10)); + store.register_late_pass(move |_| Box::new(if_then_some_else_none::IfThenSomeElseNone::new(msrv))); + store.register_late_pass(|_| Box::new(bool_assert_comparison::BoolAssertComparison)); store.register_early_pass(move || Box::new(module_style::ModStyle)); - store.register_late_pass(|| Box::new(unused_async::UnusedAsync)); + store.register_late_pass(|_| Box::new(unused_async::UnusedAsync)); let disallowed_types = conf.disallowed_types.clone(); - store.register_late_pass(move || Box::new(disallowed_types::DisallowedTypes::new(disallowed_types.clone()))); + store.register_late_pass(move |_| Box::new(disallowed_types::DisallowedTypes::new(disallowed_types.clone()))); let import_renames = conf.enforced_import_renames.clone(); - store.register_late_pass(move || { + store.register_late_pass(move |_| { Box::new(missing_enforced_import_rename::ImportRename::new( import_renames.clone(), )) }); let scripts = conf.allowed_scripts.clone(); store.register_early_pass(move || Box::new(disallowed_script_idents::DisallowedScriptIdents::new(&scripts))); - store.register_late_pass(|| Box::new(strlen_on_c_strings::StrlenOnCStrings)); - store.register_late_pass(move || Box::new(self_named_constructors::SelfNamedConstructors)); - store.register_late_pass(move || Box::new(iter_not_returning_iterator::IterNotReturningIterator)); - store.register_late_pass(move || Box::new(manual_assert::ManualAssert)); + store.register_late_pass(|_| Box::new(strlen_on_c_strings::StrlenOnCStrings)); + store.register_late_pass(move |_| Box::new(self_named_constructors::SelfNamedConstructors)); + store.register_late_pass(move |_| Box::new(iter_not_returning_iterator::IterNotReturningIterator)); + store.register_late_pass(move |_| Box::new(manual_assert::ManualAssert)); let enable_raw_pointer_heuristic_for_send = conf.enable_raw_pointer_heuristic_for_send; - store.register_late_pass(move || { + store.register_late_pass(move |_| { Box::new(non_send_fields_in_send_ty::NonSendFieldInSendTy::new( enable_raw_pointer_heuristic_for_send, )) }); - store.register_late_pass(move || Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks)); - store.register_late_pass(move || Box::new(format_args::FormatArgs)); - store.register_late_pass(|| Box::new(trailing_empty_array::TrailingEmptyArray)); + store.register_late_pass(move |_| Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks)); + store.register_late_pass(move |_| Box::new(format_args::FormatArgs)); + store.register_late_pass(|_| Box::new(trailing_empty_array::TrailingEmptyArray)); store.register_early_pass(|| Box::new(octal_escapes::OctalEscapes)); - store.register_late_pass(|| Box::new(needless_late_init::NeedlessLateInit)); - store.register_late_pass(|| Box::new(return_self_not_must_use::ReturnSelfNotMustUse)); - store.register_late_pass(|| Box::new(init_numbered_fields::NumberedFields)); + store.register_late_pass(|_| Box::new(needless_late_init::NeedlessLateInit)); + store.register_late_pass(|_| Box::new(return_self_not_must_use::ReturnSelfNotMustUse)); + store.register_late_pass(|_| Box::new(init_numbered_fields::NumberedFields)); store.register_early_pass(|| Box::new(single_char_lifetime_names::SingleCharLifetimeNames)); - store.register_late_pass(move || Box::new(manual_bits::ManualBits::new(msrv))); - store.register_late_pass(|| Box::new(default_union_representation::DefaultUnionRepresentation)); + store.register_late_pass(move |_| Box::new(manual_bits::ManualBits::new(msrv))); + store.register_late_pass(|_| Box::new(default_union_representation::DefaultUnionRepresentation)); store.register_early_pass(|| Box::new(doc_link_with_quotes::DocLinkWithQuotes)); - store.register_late_pass(|| Box::new(only_used_in_recursion::OnlyUsedInRecursion::default())); + store.register_late_pass(|_| Box::new(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))); + store.register_late_pass(move |_| Box::new(dbg_macro::DbgMacro::new(allow_dbg_in_tests))); let cargo_ignore_publish = conf.cargo_ignore_publish; - store.register_late_pass(move || { + store.register_late_pass(move |_| { Box::new(cargo::Cargo { ignore_publish: cargo_ignore_publish, }) }); 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)); + store.register_late_pass(|_| Box::new(unnecessary_owned_empty_strings::UnnecessaryOwnedEmptyStrings)); store.register_early_pass(|| Box::new(pub_use::PubUse)); - store.register_late_pass(|| Box::new(format_push_string::FormatPushString)); + store.register_late_pass(|_| Box::new(format_push_string::FormatPushString)); let max_include_file_size = conf.max_include_file_size; - store.register_late_pass(move || Box::new(large_include_file::LargeIncludeFile::new(max_include_file_size))); - store.register_late_pass(|| Box::new(strings::TrimSplitWhitespace)); - store.register_late_pass(|| Box::new(rc_clone_in_vec_init::RcCloneInVecInit)); + store.register_late_pass(move |_| Box::new(large_include_file::LargeIncludeFile::new(max_include_file_size))); + store.register_late_pass(|_| Box::new(strings::TrimSplitWhitespace)); + store.register_late_pass(|_| Box::new(rc_clone_in_vec_init::RcCloneInVecInit)); store.register_early_pass(|| Box::new(duplicate_mod::DuplicateMod::default())); store.register_early_pass(|| Box::new(unused_rounding::UnusedRounding)); store.register_early_pass(move || Box::new(almost_complete_letter_range::AlmostCompleteLetterRange::new(msrv))); - store.register_late_pass(|| Box::new(swap_ptr_to_ref::SwapPtrToRef)); - store.register_late_pass(|| Box::new(mismatching_type_param_order::TypeParamMismatch)); - store.register_late_pass(|| Box::new(read_zero_byte_vec::ReadZeroByteVec)); - store.register_late_pass(|| Box::new(default_instead_of_iter_empty::DefaultIterEmpty)); - store.register_late_pass(move || Box::new(manual_rem_euclid::ManualRemEuclid::new(msrv))); - store.register_late_pass(move || Box::new(manual_retain::ManualRetain::new(msrv))); + store.register_late_pass(|_| Box::new(swap_ptr_to_ref::SwapPtrToRef)); + store.register_late_pass(|_| Box::new(mismatching_type_param_order::TypeParamMismatch)); + store.register_late_pass(|_| Box::new(read_zero_byte_vec::ReadZeroByteVec)); + store.register_late_pass(|_| Box::new(default_instead_of_iter_empty::DefaultIterEmpty)); + store.register_late_pass(move |_| Box::new(manual_rem_euclid::ManualRemEuclid::new(msrv))); + store.register_late_pass(move |_| Box::new(manual_retain::ManualRetain::new(msrv))); let verbose_bit_mask_threshold = conf.verbose_bit_mask_threshold; - 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::new(std_instead_of_core::StdReexports::default())); - store.register_late_pass(|| Box::new(manual_instant_elapsed::ManualInstantElapsed)); - store.register_late_pass(|| Box::new(partialeq_to_none::PartialeqToNone)); - store.register_late_pass(|| Box::new(manual_string_new::ManualStringNew)); - store.register_late_pass(|| Box::new(unused_peekable::UnusedPeekable)); + 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::new(std_instead_of_core::StdReexports::default())); + store.register_late_pass(|_| Box::new(manual_instant_elapsed::ManualInstantElapsed)); + store.register_late_pass(|_| Box::new(partialeq_to_none::PartialeqToNone)); + store.register_late_pass(|_| Box::new(manual_string_new::ManualStringNew)); + store.register_late_pass(|_| Box::new(unused_peekable::UnusedPeekable)); store.register_early_pass(|| Box::new(multi_assignments::MultiAssignments)); // add lints here, do not remove this comment, it's used in `new_lint` } From 91360966297a4cf2008a56f727b03012d3d9e4b3 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 28 Aug 2022 00:10:06 +0300 Subject: [PATCH 002/114] rustc: Parameterize `ty::Visibility` over used ID It allows using `LocalDefId` instead of `DefId` when possible, and also encode cheaper `Visibility` into metadata. --- clippy_lints/src/default.rs | 2 +- clippy_lints/src/derive.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs index 74f7df611778e..4e68d6810e29b 100644 --- a/clippy_lints/src/default.rs +++ b/clippy_lints/src/default.rs @@ -142,7 +142,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { if adt.is_struct(); let variant = adt.non_enum_variant(); if adt.did().is_local() || !variant.is_field_list_non_exhaustive(); - let module_did = cx.tcx.parent_module(stmt.hir_id).to_def_id(); + let module_did = cx.tcx.parent_module(stmt.hir_id); if variant .fields .iter() diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index 9ca443b7dff6c..23c86482b46cb 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -15,7 +15,7 @@ use rustc_middle::hir::nested_filter; use rustc_middle::traits::Reveal; use rustc_middle::ty::{ self, Binder, BoundConstness, GenericParamDefKind, ImplPolarity, ParamEnv, PredicateKind, TraitPredicate, TraitRef, - Ty, TyCtxt, Visibility, + Ty, TyCtxt, }; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; @@ -464,7 +464,7 @@ impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> { fn check_partial_eq_without_eq<'tcx>(cx: &LateContext<'tcx>, span: Span, trait_ref: &hir::TraitRef<'_>, ty: Ty<'tcx>) { if_chain! { if let ty::Adt(adt, substs) = ty.kind(); - if cx.tcx.visibility(adt.did()) == Visibility::Public; + if cx.tcx.visibility(adt.did()).is_public(); if let Some(eq_trait_def_id) = cx.tcx.get_diagnostic_item(sym::Eq); if let Some(def_id) = trait_ref.trait_def_id(); if cx.tcx.is_diagnostic_item(sym::PartialEq, def_id); From 977b6e29a345ee43acabd2e1a7eb8e454626e2f3 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 1 Sep 2022 12:06:48 +1000 Subject: [PATCH 003/114] Arena-allocate `hir::Lifetime`. This shrinks `hir::Ty` from 72 to 48 bytes. `visit_lifetime` is added to the HIR stats collector because these types are now stored in memory on their own, instead of being within other types. --- clippy_utils/src/hir_utils.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index 57448f716d494..ff23ed5fffa3c 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -929,7 +929,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { } } - pub fn hash_lifetime(&mut self, lifetime: Lifetime) { + pub fn hash_lifetime(&mut self, lifetime: &Lifetime) { std::mem::discriminant(&lifetime.name).hash(&mut self.s); if let LifetimeName::Param(param_id, ref name) = lifetime.name { std::mem::discriminant(name).hash(&mut self.s); From c86a9c077c3b3a8c04166934ec1465920419a2cd Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 1 Sep 2022 13:29:57 +1000 Subject: [PATCH 004/114] Introduce `DotDotPos`. This shrinks `hir::Pat` from 88 to 72 bytes. --- clippy_lints/src/equatable_if_let.rs | 4 +++- clippy_lints/src/matches/match_same_arms.rs | 4 ++-- clippy_lints/src/matches/single_match.rs | 2 ++ clippy_lints/src/question_mark.rs | 3 ++- clippy_lints/src/unit_types/let_unit_value.rs | 6 ++++-- clippy_utils/src/lib.rs | 3 ++- 6 files changed, 15 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/equatable_if_let.rs b/clippy_lints/src/equatable_if_let.rs index fdfb821ac7895..bce49165e5b18 100644 --- a/clippy_lints/src/equatable_if_let.rs +++ b/clippy_lints/src/equatable_if_let.rs @@ -51,7 +51,9 @@ fn unary_pattern(pat: &Pat<'_>) -> bool { false }, PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)), - PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => !etc.is_some() && array_rec(a), + PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => { + !etc.as_opt_usize().is_some() && array_rec(a) + } PatKind::Ref(x, _) | PatKind::Box(x) => unary_pattern(x), PatKind::Path(_) | PatKind::Lit(_) => true, } diff --git a/clippy_lints/src/matches/match_same_arms.rs b/clippy_lints/src/matches/match_same_arms.rs index e32ef9933afe5..93874b103b461 100644 --- a/clippy_lints/src/matches/match_same_arms.rs +++ b/clippy_lints/src/matches/match_same_arms.rs @@ -248,7 +248,7 @@ impl<'a> NormalizedPat<'a> { } else { (None, adt.non_enum_variant()) }; - let (front, back) = match wild_idx { + let (front, back) = match wild_idx.as_opt_usize() { Some(i) => pats.split_at(i), None => (pats, [].as_slice()), }; @@ -268,7 +268,7 @@ impl<'a> NormalizedPat<'a> { ty::Tuple(subs) => subs.len(), _ => return Self::Wild, }; - let (front, back) = match wild_idx { + let (front, back) = match wild_idx.as_opt_usize() { Some(i) => pats.split_at(i), None => (pats, [].as_slice()), }; diff --git a/clippy_lints/src/matches/single_match.rs b/clippy_lints/src/matches/single_match.rs index 95478af45b4bf..1bf1c4d107895 100644 --- a/clippy_lints/src/matches/single_match.rs +++ b/clippy_lints/src/matches/single_match.rs @@ -200,6 +200,8 @@ fn form_exhaustive_matches<'a>(cx: &LateContext<'a>, ty: Ty<'a>, left: &Pat<'_>, // We don't actually know the position and the presence of the `..` (dotdot) operator // in the arms, so we need to evaluate the correct offsets here in order to iterate in // both arms at the same time. + let left_pos = left_pos.as_opt_usize(); + let right_pos = right_pos.as_opt_usize(); let len = max( left_in.len() + { if left_pos.is_some() { 1 } else { 0 } diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index f4f1fd336df7c..569870ab2b7f4 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -122,7 +122,8 @@ fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: if_chain! { if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else }) = higher::IfLet::hir(cx, expr); if !is_else_clause(cx.tcx, expr); - if let PatKind::TupleStruct(ref path1, [field], None) = let_pat.kind; + if let PatKind::TupleStruct(ref path1, [field], ddpos) = let_pat.kind; + if ddpos.as_opt_usize().is_none(); if let PatKind::Binding(BindingAnnotation(by_ref, _), bind_id, ident, None) = field.kind; let caller_ty = cx.typeck_results().expr_ty(let_expr); let if_block = IfBlockType::IfLet(path1, caller_ty, ident.name, let_expr, if_then, if_else); diff --git a/clippy_lints/src/unit_types/let_unit_value.rs b/clippy_lints/src/unit_types/let_unit_value.rs index 35824b03170af..ce9ebad8c89a8 100644 --- a/clippy_lints/src/unit_types/let_unit_value.rs +++ b/clippy_lints/src/unit_types/let_unit_value.rs @@ -19,10 +19,12 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>) { && cx.typeck_results().pat_ty(local.pat).is_unit() { if (local.ty.map_or(false, |ty| !matches!(ty.kind, TyKind::Infer)) - || matches!(local.pat.kind, PatKind::Tuple([], None))) + || matches!(local.pat.kind, PatKind::Tuple([], ddpos) if ddpos.as_opt_usize().is_none())) && expr_needs_inferred_result(cx, init) { - if !matches!(local.pat.kind, PatKind::Wild | PatKind::Tuple([], None)) { + if !matches!(local.pat.kind, PatKind::Wild) + && !matches!(local.pat.kind, PatKind::Tuple([], ddpos) if ddpos.as_opt_usize().is_none()) + { span_lint_and_then( cx, LET_UNIT_VALUE, diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index b27439cbec278..3cf043f22df5d 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1552,7 +1552,8 @@ pub fn iter_input_pats<'tcx>(decl: &FnDecl<'_>, body: &'tcx Body<'_>) -> impl It pub fn is_try<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> { fn is_ok(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool { if_chain! { - if let PatKind::TupleStruct(ref path, pat, None) = arm.pat.kind; + if let PatKind::TupleStruct(ref path, pat, ddpos) = arm.pat.kind; + if ddpos.as_opt_usize().is_none(); if is_lang_ctor(cx, path, ResultOk); if let PatKind::Binding(_, hir_id, _, None) = pat[0].kind; if path_to_local_id(arm.body, hir_id); From b640eaa71da9c48712565b9de2a98d1e9551fc54 Mon Sep 17 00:00:00 2001 From: Jack Huey <31162821+jackh726@users.noreply.github.com> Date: Sun, 26 Jun 2022 15:40:45 -0400 Subject: [PATCH 005/114] Remove ReEmpty --- clippy_lints/src/needless_pass_by_value.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 6d17c7a7346f3..060037ed49691 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -173,7 +173,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { ( preds.iter().any(|t| cx.tcx.is_diagnostic_item(sym::Borrow, t.def_id())), !preds.is_empty() && { - let ty_empty_region = cx.tcx.mk_imm_ref(cx.tcx.lifetimes.re_root_empty, ty); + let ty_empty_region = cx.tcx.mk_imm_ref(cx.tcx.lifetimes.re_erased, ty); preds.iter().all(|t| { let ty_params = t.trait_ref.substs.iter().skip(1).collect::>(); implements_trait(cx, ty_empty_region, t.def_id(), &ty_params) From ac1c68a5e6a25bcf32f352328b69bcf32f5b9973 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 31 Aug 2022 05:29:36 +0000 Subject: [PATCH 006/114] Make clippy happy --- clippy_lints/src/dereference.rs | 2 +- clippy_lints/src/missing_doc.rs | 3 ++- clippy_lints/src/missing_inline.rs | 1 + clippy_utils/src/hir_utils.rs | 3 +++ 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index d1ab7fb67962e..09a073f4234d0 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -959,7 +959,7 @@ fn binding_ty_auto_deref_stability<'tcx>( )) .is_sized(cx.tcx.at(DUMMY_SP), cx.param_env.without_caller_bounds()), ), - TyKind::OpaqueDef(..) | TyKind::Infer | TyKind::Typeof(..) | TyKind::TraitObject(..) | TyKind::Err => { + TyKind::OpaqueDef(..) | TyKind::ImplTraitInTrait(..) | TyKind::Infer | TyKind::Typeof(..) | TyKind::TraitObject(..) | TyKind::Err => { Position::ReborrowStable(precedence) }, }; diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index 3701fdb4adbff..9f518c7aaa39f 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -147,7 +147,8 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { | hir::ItemKind::TraitAlias(..) | hir::ItemKind::TyAlias(..) | hir::ItemKind::Union(..) - | hir::ItemKind::OpaqueTy(..) => {}, + | hir::ItemKind::OpaqueTy(..) + | hir::ItemKind::ImplTraitPlaceholder(..) => {}, hir::ItemKind::ExternCrate(..) | hir::ItemKind::ForeignMod { .. } | hir::ItemKind::GlobalAsm(..) diff --git a/clippy_lints/src/missing_inline.rs b/clippy_lints/src/missing_inline.rs index 07bc2ca5d3cd2..9fd1a475d7496 100644 --- a/clippy_lints/src/missing_inline.rs +++ b/clippy_lints/src/missing_inline.rs @@ -128,6 +128,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline { | hir::ItemKind::TyAlias(..) | hir::ItemKind::Union(..) | hir::ItemKind::OpaqueTy(..) + | hir::ItemKind::ImplTraitPlaceholder(..) | hir::ItemKind::ExternCrate(..) | hir::ItemKind::ForeignMod { .. } | hir::ItemKind::Impl { .. } diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index ff23ed5fffa3c..9f8500d41a85f 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -990,6 +990,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { TyKind::OpaqueDef(_, arg_list) => { self.hash_generic_args(arg_list); }, + TyKind::ImplTraitInTrait(_) => { + // Do nothing + } TyKind::TraitObject(_, lifetime, _) => { self.hash_lifetime(*lifetime); }, From 854f751b263dfac06dc3f635f8a9f92b8bc51da6 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 6 Sep 2022 17:27:47 +0000 Subject: [PATCH 007/114] Appease clippy again --- clippy_lints/src/dereference.rs | 2 +- clippy_lints/src/lifetimes.rs | 2 +- clippy_lints/src/manual_async_fn.rs | 2 +- clippy_lints/src/missing_doc.rs | 3 +-- clippy_lints/src/missing_inline.rs | 1 - clippy_utils/src/hir_utils.rs | 6 ++---- 6 files changed, 6 insertions(+), 10 deletions(-) diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 09a073f4234d0..d1ab7fb67962e 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -959,7 +959,7 @@ fn binding_ty_auto_deref_stability<'tcx>( )) .is_sized(cx.tcx.at(DUMMY_SP), cx.param_env.without_caller_bounds()), ), - TyKind::OpaqueDef(..) | TyKind::ImplTraitInTrait(..) | TyKind::Infer | TyKind::Typeof(..) | TyKind::TraitObject(..) | TyKind::Err => { + TyKind::OpaqueDef(..) | TyKind::Infer | TyKind::Typeof(..) | TyKind::TraitObject(..) | TyKind::Err => { Position::ReborrowStable(precedence) }, }; diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 573a7c016b8e8..5995675bd969c 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -441,7 +441,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> { fn visit_ty(&mut self, ty: &'tcx Ty<'_>) { match ty.kind { - TyKind::OpaqueDef(item, bounds) => { + TyKind::OpaqueDef(item, bounds, _) => { let map = self.cx.tcx.hir(); let item = map.item(item); let len = self.lts.len(); diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index 2502c8f880ddc..754b0e78a148c 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -103,7 +103,7 @@ fn future_trait_ref<'tcx>( ty: &'tcx Ty<'tcx>, ) -> Option<(&'tcx TraitRef<'tcx>, Vec)> { if_chain! { - if let TyKind::OpaqueDef(item_id, bounds) = ty.kind; + if let TyKind::OpaqueDef(item_id, bounds, false) = ty.kind; let item = cx.tcx.hir().item(item_id); if let ItemKind::OpaqueTy(opaque) = &item.kind; if let Some(trait_ref) = opaque.bounds.iter().find_map(|bound| { diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index 9f518c7aaa39f..3701fdb4adbff 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -147,8 +147,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { | hir::ItemKind::TraitAlias(..) | hir::ItemKind::TyAlias(..) | hir::ItemKind::Union(..) - | hir::ItemKind::OpaqueTy(..) - | hir::ItemKind::ImplTraitPlaceholder(..) => {}, + | hir::ItemKind::OpaqueTy(..) => {}, hir::ItemKind::ExternCrate(..) | hir::ItemKind::ForeignMod { .. } | hir::ItemKind::GlobalAsm(..) diff --git a/clippy_lints/src/missing_inline.rs b/clippy_lints/src/missing_inline.rs index 9fd1a475d7496..07bc2ca5d3cd2 100644 --- a/clippy_lints/src/missing_inline.rs +++ b/clippy_lints/src/missing_inline.rs @@ -128,7 +128,6 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline { | hir::ItemKind::TyAlias(..) | hir::ItemKind::Union(..) | hir::ItemKind::OpaqueTy(..) - | hir::ItemKind::ImplTraitPlaceholder(..) | hir::ItemKind::ExternCrate(..) | hir::ItemKind::ForeignMod { .. } | hir::ItemKind::Impl { .. } diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index 9f8500d41a85f..f45cec9f0b430 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -987,12 +987,10 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { } }, TyKind::Path(ref qpath) => self.hash_qpath(qpath), - TyKind::OpaqueDef(_, arg_list) => { + TyKind::OpaqueDef(_, arg_list, in_trait) => { self.hash_generic_args(arg_list); + in_trait.hash(&mut self.s); }, - TyKind::ImplTraitInTrait(_) => { - // Do nothing - } TyKind::TraitObject(_, lifetime, _) => { self.hash_lifetime(*lifetime); }, From 98bf99e2f8cf8b357d63a67ce67d5fc5ceef8b3c Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Fri, 9 Sep 2022 13:36:26 +0200 Subject: [PATCH 008/114] Merge commit 'b52fb5234cd7c11ecfae51897a6f7fa52e8777fc' into clippyup --- CHANGELOG.md | 3 +- clippy_dev/src/update_lints.rs | 194 +++++- clippy_lints/src/async_yields_async.rs | 2 +- clippy_lints/src/attrs.rs | 6 +- clippy_lints/src/bool_to_int_with_if.rs | 125 ++++ clippy_lints/src/default_numeric_fallback.rs | 21 +- clippy_lints/src/dereference.rs | 31 +- clippy_lints/src/derivable_impls.rs | 2 +- clippy_lints/src/doc.rs | 8 +- clippy_lints/src/eta_reduction.rs | 9 +- clippy_lints/src/fallible_impl_from.rs | 4 +- clippy_lints/src/floating_point_arithmetic.rs | 30 +- clippy_lints/src/functions/must_use.rs | 2 +- clippy_lints/src/functions/result.rs | 10 +- clippy_lints/src/implicit_return.rs | 4 +- clippy_lints/src/infinite_iter.rs | 10 +- clippy_lints/src/large_enum_variant.rs | 96 +-- clippy_lints/src/len_zero.rs | 16 +- clippy_lints/src/lib.register_all.rs | 1 + clippy_lints/src/lib.register_lints.rs | 3 +- clippy_lints/src/lib.register_restriction.rs | 2 +- clippy_lints/src/lib.register_style.rs | 1 + clippy_lints/src/lib.rs | 12 +- clippy_lints/src/lifetimes.rs | 2 +- clippy_lints/src/loops/needless_range_loop.rs | 2 +- .../src/loops/while_let_on_iterator.rs | 2 +- .../src/matches/match_wild_err_arm.rs | 2 +- clippy_lints/src/matches/single_match.rs | 8 +- .../src/methods/bind_instead_of_map.rs | 2 +- clippy_lints/src/methods/chars_cmp.rs | 2 +- clippy_lints/src/methods/clone_on_copy.rs | 6 +- clippy_lints/src/methods/filter_map.rs | 2 +- clippy_lints/src/methods/map_clone.rs | 2 +- clippy_lints/src/methods/mod.rs | 5 +- clippy_lints/src/methods/mut_mutex_lock.rs | 3 +- clippy_lints/src/methods/open_options.rs | 2 +- .../src/methods/option_as_ref_deref.rs | 2 +- .../src/methods/option_map_or_none.rs | 2 +- clippy_lints/src/methods/or_fun_call.rs | 13 +- clippy_lints/src/methods/suspicious_map.rs | 4 +- .../src/methods/unnecessary_filter_map.rs | 11 +- clippy_lints/src/methods/unnecessary_fold.rs | 2 +- .../src/methods/unnecessary_sort_by.rs | 2 +- .../src/methods/unnecessary_to_owned.rs | 217 ++++--- .../src/methods/unwrap_or_else_default.rs | 24 +- clippy_lints/src/minmax.rs | 32 +- clippy_lints/src/needless_for_each.rs | 2 +- clippy_lints/src/only_used_in_recursion.rs | 15 +- clippy_lints/src/operators/arithmetic.rs | 119 ---- .../src/operators/arithmetic_side_effects.rs | 173 +++++ clippy_lints/src/operators/mod.rs | 32 +- clippy_lints/src/panic_in_result_fn.rs | 2 +- clippy_lints/src/ptr.rs | 4 +- clippy_lints/src/ranges.rs | 11 +- clippy_lints/src/returns.rs | 2 +- clippy_lints/src/suspicious_trait_impl.rs | 2 +- clippy_lints/src/unit_return_expecting_ord.rs | 2 +- clippy_lints/src/unit_types/unit_arg.rs | 2 +- clippy_lints/src/unnecessary_wraps.rs | 2 +- clippy_lints/src/unwrap.rs | 2 +- clippy_lints/src/unwrap_in_result.rs | 6 +- clippy_lints/src/utils/author.rs | 2 +- clippy_lints/src/utils/conf.rs | 2 +- clippy_lints/src/utils/internal_lints.rs | 41 +- .../internal_lints/metadata_collector.rs | 4 +- clippy_lints/src/vec_init_then_push.rs | 2 +- clippy_lints/src/write.rs | 6 +- clippy_utils/src/check_proc_macro.rs | 4 +- clippy_utils/src/eager_or_lazy.rs | 2 +- clippy_utils/src/hir_utils.rs | 10 +- clippy_utils/src/lib.rs | 8 +- clippy_utils/src/macros.rs | 6 +- clippy_utils/src/qualify_min_const_fn.rs | 8 +- clippy_utils/src/visitors.rs | 3 +- lintcheck/lintcheck_crates.toml | 2 +- rust-toolchain | 2 +- src/docs.rs | 596 ++++++++++++++++++ src/docs/absurd_extreme_comparisons.txt | 25 + src/docs/alloc_instead_of_core.txt | 18 + src/docs/allow_attributes_without_reason.txt | 22 + src/docs/almost_complete_letter_range.txt | 15 + src/docs/almost_swapped.txt | 15 + src/docs/approx_constant.txt | 24 + src/docs/arithmetic_side_effects.txt | 33 + src/docs/as_conversions.txt | 32 + src/docs/as_underscore.txt | 21 + src/docs/assertions_on_constants.txt | 14 + src/docs/assertions_on_result_states.txt | 14 + src/docs/assign_op_pattern.txt | 28 + src/docs/async_yields_async.txt | 28 + src/docs/await_holding_invalid_type.txt | 29 + src/docs/await_holding_lock.txt | 51 ++ src/docs/await_holding_refcell_ref.txt | 47 ++ src/docs/bad_bit_mask.txt | 30 + src/docs/bind_instead_of_map.txt | 22 + src/docs/blanket_clippy_restriction_lints.txt | 16 + src/docs/blocks_in_if_conditions.txt | 21 + src/docs/bool_assert_comparison.txt | 16 + src/docs/bool_comparison.txt | 18 + src/docs/bool_to_int_with_if.txt | 26 + src/docs/borrow_as_ptr.txt | 26 + src/docs/borrow_deref_ref.txt | 27 + src/docs/borrow_interior_mutable_const.txt | 40 ++ src/docs/borrowed_box.txt | 19 + src/docs/box_collection.txt | 23 + src/docs/boxed_local.txt | 18 + src/docs/branches_sharing_code.txt | 32 + src/docs/builtin_type_shadow.txt | 15 + src/docs/bytes_count_to_len.txt | 18 + src/docs/bytes_nth.txt | 16 + src/docs/cargo_common_metadata.txt | 33 + ...e_sensitive_file_extension_comparisons.txt | 21 + src/docs/cast_abs_to_unsigned.txt | 16 + src/docs/cast_enum_constructor.txt | 11 + src/docs/cast_enum_truncation.txt | 12 + src/docs/cast_lossless.txt | 26 + src/docs/cast_possible_truncation.txt | 16 + src/docs/cast_possible_wrap.txt | 17 + src/docs/cast_precision_loss.txt | 19 + src/docs/cast_ptr_alignment.txt | 21 + src/docs/cast_ref_to_mut.txt | 28 + src/docs/cast_sign_loss.txt | 15 + src/docs/cast_slice_different_sizes.txt | 38 ++ src/docs/cast_slice_from_raw_parts.txt | 20 + src/docs/char_lit_as_u8.txt | 21 + src/docs/chars_last_cmp.txt | 17 + src/docs/chars_next_cmp.txt | 19 + src/docs/checked_conversions.txt | 15 + src/docs/clone_double_ref.txt | 16 + src/docs/clone_on_copy.txt | 11 + src/docs/clone_on_ref_ptr.txt | 21 + src/docs/cloned_instead_of_copied.txt | 16 + src/docs/cmp_nan.txt | 16 + src/docs/cmp_null.txt | 23 + src/docs/cmp_owned.txt | 18 + src/docs/cognitive_complexity.txt | 13 + src/docs/collapsible_else_if.txt | 29 + src/docs/collapsible_if.txt | 23 + src/docs/collapsible_match.txt | 31 + src/docs/collapsible_str_replace.txt | 19 + src/docs/comparison_chain.txt | 36 ++ src/docs/comparison_to_empty.txt | 31 + src/docs/copy_iterator.txt | 20 + src/docs/crate_in_macro_def.txt | 35 + src/docs/create_dir.txt | 15 + src/docs/crosspointer_transmute.txt | 12 + src/docs/dbg_macro.txt | 16 + src/docs/debug_assert_with_mut_call.txt | 18 + src/docs/decimal_literal_representation.txt | 13 + src/docs/declare_interior_mutable_const.txt | 46 ++ src/docs/default_instead_of_iter_empty.txt | 15 + src/docs/default_numeric_fallback.txt | 28 + src/docs/default_trait_access.txt | 16 + src/docs/default_union_representation.txt | 36 ++ src/docs/deprecated_cfg_attr.txt | 24 + src/docs/deprecated_semver.txt | 13 + src/docs/deref_addrof.txt | 22 + src/docs/deref_by_slicing.txt | 17 + src/docs/derivable_impls.txt | 35 + src/docs/derive_hash_xor_eq.txt | 23 + src/docs/derive_ord_xor_partial_ord.txt | 44 ++ src/docs/derive_partial_eq_without_eq.txt | 25 + src/docs/disallowed_methods.txt | 41 ++ src/docs/disallowed_names.txt | 12 + src/docs/disallowed_script_idents.txt | 32 + src/docs/disallowed_types.txt | 33 + src/docs/diverging_sub_expression.txt | 19 + src/docs/doc_link_with_quotes.txt | 16 + src/docs/doc_markdown.txt | 35 + src/docs/double_comparisons.txt | 17 + src/docs/double_must_use.txt | 17 + src/docs/double_neg.txt | 12 + src/docs/double_parens.txt | 24 + src/docs/drop_copy.txt | 15 + src/docs/drop_non_drop.txt | 13 + src/docs/drop_ref.txt | 17 + src/docs/duplicate_mod.txt | 31 + src/docs/duplicate_underscore_argument.txt | 16 + src/docs/duration_subsec.txt | 19 + src/docs/else_if_without_else.txt | 27 + src/docs/empty_drop.txt | 20 + src/docs/empty_enum.txt | 27 + src/docs/empty_line_after_outer_attr.txt | 35 + src/docs/empty_loop.txt | 27 + src/docs/empty_structs_with_brackets.txt | 14 + src/docs/enum_clike_unportable_variant.txt | 16 + src/docs/enum_glob_use.txt | 24 + src/docs/enum_variant_names.txt | 30 + src/docs/eq_op.txt | 22 + src/docs/equatable_if_let.txt | 23 + src/docs/erasing_op.txt | 15 + src/docs/err_expect.txt | 16 + src/docs/excessive_precision.txt | 18 + src/docs/exhaustive_enums.txt | 23 + src/docs/exhaustive_structs.txt | 23 + src/docs/exit.txt | 12 + src/docs/expect_fun_call.txt | 24 + src/docs/expect_used.txt | 26 + src/docs/expl_impl_clone_on_copy.txt | 20 + src/docs/explicit_auto_deref.txt | 16 + src/docs/explicit_counter_loop.txt | 21 + src/docs/explicit_deref_methods.txt | 24 + src/docs/explicit_into_iter_loop.txt | 20 + src/docs/explicit_iter_loop.txt | 25 + src/docs/explicit_write.txt | 18 + src/docs/extend_with_drain.txt | 21 + src/docs/extra_unused_lifetimes.txt | 23 + src/docs/fallible_impl_from.txt | 32 + src/docs/field_reassign_with_default.txt | 23 + src/docs/filetype_is_file.txt | 29 + src/docs/filter_map_identity.txt | 14 + src/docs/filter_map_next.txt | 16 + src/docs/filter_next.txt | 16 + src/docs/flat_map_identity.txt | 14 + src/docs/flat_map_option.txt | 16 + src/docs/float_arithmetic.txt | 11 + src/docs/float_cmp.txt | 28 + src/docs/float_cmp_const.txt | 26 + src/docs/float_equality_without_abs.txt | 26 + src/docs/fn_address_comparisons.txt | 17 + src/docs/fn_params_excessive_bools.txt | 31 + src/docs/fn_to_numeric_cast.txt | 21 + src/docs/fn_to_numeric_cast_any.txt | 35 + .../fn_to_numeric_cast_with_truncation.txt | 26 + src/docs/for_kv_map.txt | 22 + src/docs/for_loops_over_fallibles.txt | 32 + src/docs/forget_copy.txt | 21 + src/docs/forget_non_drop.txt | 13 + src/docs/forget_ref.txt | 15 + src/docs/format_in_format_args.txt | 16 + src/docs/format_push_string.txt | 26 + src/docs/from_iter_instead_of_collect.txt | 24 + src/docs/from_over_into.txt | 26 + src/docs/from_str_radix_10.txt | 25 + src/docs/future_not_send.txt | 29 + src/docs/get_first.txt | 19 + src/docs/get_last_with_len.txt | 26 + src/docs/get_unwrap.txt | 30 + src/docs/identity_op.txt | 11 + src/docs/if_let_mutex.txt | 25 + src/docs/if_not_else.txt | 25 + src/docs/if_same_then_else.txt | 15 + src/docs/if_then_some_else_none.txt | 26 + src/docs/ifs_same_cond.txt | 25 + src/docs/implicit_clone.txt | 19 + src/docs/implicit_hasher.txt | 26 + src/docs/implicit_return.txt | 22 + src/docs/implicit_saturating_sub.txt | 21 + src/docs/imprecise_flops.txt | 23 + src/docs/inconsistent_digit_grouping.txt | 17 + src/docs/inconsistent_struct_constructor.txt | 40 ++ src/docs/index_refutable_slice.txt | 29 + src/docs/indexing_slicing.txt | 33 + src/docs/ineffective_bit_mask.txt | 25 + src/docs/inefficient_to_string.txt | 17 + src/docs/infallible_destructuring_match.txt | 29 + src/docs/infinite_iter.txt | 13 + src/docs/inherent_to_string.txt | 29 + .../inherent_to_string_shadow_display.txt | 37 ++ src/docs/init_numbered_fields.txt | 24 + src/docs/inline_always.txt | 23 + src/docs/inline_asm_x86_att_syntax.txt | 16 + src/docs/inline_asm_x86_intel_syntax.txt | 16 + src/docs/inline_fn_without_body.txt | 14 + src/docs/inspect_for_each.txt | 23 + src/docs/int_plus_one.txt | 15 + src/docs/integer_arithmetic.txt | 18 + src/docs/integer_division.txt | 19 + src/docs/into_iter_on_ref.txt | 18 + src/docs/invalid_null_ptr_usage.txt | 16 + src/docs/invalid_regex.txt | 12 + src/docs/invalid_upcast_comparisons.txt | 18 + src/docs/invalid_utf8_in_unchecked.txt | 12 + src/docs/invisible_characters.txt | 10 + src/docs/is_digit_ascii_radix.txt | 20 + src/docs/items_after_statements.txt | 37 ++ src/docs/iter_cloned_collect.txt | 17 + src/docs/iter_count.txt | 22 + src/docs/iter_next_loop.txt | 17 + src/docs/iter_next_slice.txt | 16 + src/docs/iter_not_returning_iterator.txt | 26 + src/docs/iter_nth.txt | 20 + src/docs/iter_nth_zero.txt | 17 + src/docs/iter_on_empty_collections.txt | 25 + src/docs/iter_on_single_items.txt | 24 + src/docs/iter_overeager_cloned.txt | 22 + src/docs/iter_skip_next.txt | 18 + src/docs/iter_with_drain.txt | 16 + src/docs/iterator_step_by_zero.txt | 13 + src/docs/just_underscores_and_digits.txt | 14 + src/docs/large_const_arrays.txt | 17 + src/docs/large_digit_groups.txt | 12 + src/docs/large_enum_variant.txt | 41 ++ src/docs/large_include_file.txt | 21 + src/docs/large_stack_arrays.txt | 10 + src/docs/large_types_passed_by_value.txt | 24 + src/docs/len_without_is_empty.txt | 19 + src/docs/len_zero.txt | 28 + src/docs/let_and_return.txt | 21 + src/docs/let_underscore_drop.txt | 29 + src/docs/let_underscore_lock.txt | 20 + src/docs/let_underscore_must_use.txt | 17 + src/docs/let_unit_value.txt | 13 + src/docs/linkedlist.txt | 32 + src/docs/lossy_float_literal.txt | 18 + src/docs/macro_use_imports.txt | 12 + src/docs/main_recursion.txt | 13 + src/docs/manual_assert.txt | 18 + src/docs/manual_async_fn.txt | 16 + src/docs/manual_bits.txt | 15 + src/docs/manual_filter_map.txt | 19 + src/docs/manual_find.txt | 24 + src/docs/manual_find_map.txt | 19 + src/docs/manual_flatten.txt | 25 + src/docs/manual_instant_elapsed.txt | 21 + src/docs/manual_map.txt | 17 + src/docs/manual_memcpy.txt | 18 + src/docs/manual_non_exhaustive.txt | 41 ++ src/docs/manual_ok_or.txt | 19 + src/docs/manual_range_contains.txt | 19 + src/docs/manual_rem_euclid.txt | 17 + src/docs/manual_retain.txt | 15 + src/docs/manual_saturating_arithmetic.txt | 18 + src/docs/manual_split_once.txt | 29 + src/docs/manual_str_repeat.txt | 15 + src/docs/manual_string_new.txt | 20 + src/docs/manual_strip.txt | 24 + src/docs/manual_swap.txt | 22 + src/docs/manual_unwrap_or.txt | 20 + src/docs/many_single_char_names.txt | 12 + src/docs/map_clone.txt | 22 + src/docs/map_collect_result_unit.txt | 14 + src/docs/map_entry.txt | 28 + src/docs/map_err_ignore.txt | 93 +++ src/docs/map_flatten.txt | 21 + src/docs/map_identity.txt | 16 + src/docs/map_unwrap_or.txt | 22 + src/docs/match_as_ref.txt | 23 + src/docs/match_bool.txt | 24 + src/docs/match_like_matches_macro.txt | 32 + src/docs/match_on_vec_items.txt | 29 + src/docs/match_overlapping_arm.txt | 16 + src/docs/match_ref_pats.txt | 26 + src/docs/match_result_ok.txt | 27 + src/docs/match_same_arms.txt | 38 ++ src/docs/match_single_binding.txt | 23 + src/docs/match_str_case_mismatch.txt | 22 + src/docs/match_wild_err_arm.txt | 16 + .../match_wildcard_for_single_variants.txt | 27 + src/docs/maybe_infinite_iter.txt | 16 + src/docs/mem_forget.txt | 12 + src/docs/mem_replace_option_with_none.txt | 21 + src/docs/mem_replace_with_default.txt | 18 + src/docs/mem_replace_with_uninit.txt | 24 + src/docs/min_max.txt | 18 + src/docs/mismatched_target_os.txt | 24 + src/docs/mismatching_type_param_order.txt | 33 + src/docs/misrefactored_assign_op.txt | 20 + src/docs/missing_const_for_fn.txt | 40 ++ src/docs/missing_docs_in_private_items.txt | 9 + src/docs/missing_enforced_import_renames.txt | 22 + src/docs/missing_errors_doc.txt | 21 + src/docs/missing_inline_in_public_items.txt | 45 ++ src/docs/missing_panics_doc.txt | 24 + src/docs/missing_safety_doc.txt | 26 + src/docs/missing_spin_loop.txt | 27 + src/docs/mistyped_literal_suffixes.txt | 15 + src/docs/mixed_case_hex_literals.txt | 16 + src/docs/mixed_read_write_in_expression.txt | 32 + src/docs/mod_module_files.txt | 22 + src/docs/module_inception.txt | 24 + src/docs/module_name_repetitions.txt | 20 + src/docs/modulo_arithmetic.txt | 15 + src/docs/modulo_one.txt | 16 + src/docs/multi_assignments.txt | 17 + src/docs/multiple_crate_versions.txt | 19 + src/docs/multiple_inherent_impl.txt | 26 + src/docs/must_use_candidate.txt | 23 + src/docs/must_use_unit.txt | 13 + src/docs/mut_from_ref.txt | 26 + src/docs/mut_mut.txt | 12 + src/docs/mut_mutex_lock.txt | 29 + src/docs/mut_range_bound.txt | 29 + src/docs/mutable_key_type.txt | 61 ++ src/docs/mutex_atomic.txt | 22 + src/docs/mutex_integer.txt | 22 + src/docs/naive_bytecount.txt | 22 + src/docs/needless_arbitrary_self_type.txt | 44 ++ src/docs/needless_bitwise_bool.txt | 22 + src/docs/needless_bool.txt | 26 + src/docs/needless_borrow.txt | 21 + src/docs/needless_borrowed_reference.txt | 30 + src/docs/needless_collect.txt | 14 + src/docs/needless_continue.txt | 61 ++ src/docs/needless_doctest_main.txt | 22 + src/docs/needless_for_each.txt | 24 + src/docs/needless_late_init.txt | 42 ++ src/docs/needless_lifetimes.txt | 29 + src/docs/needless_match.txt | 36 ++ src/docs/needless_option_as_deref.txt | 18 + src/docs/needless_option_take.txt | 17 + .../needless_parens_on_range_literals.txt | 23 + src/docs/needless_pass_by_value.txt | 27 + src/docs/needless_question_mark.txt | 43 ++ src/docs/needless_range_loop.txt | 23 + src/docs/needless_return.txt | 19 + src/docs/needless_splitn.txt | 16 + src/docs/needless_update.txt | 30 + src/docs/neg_cmp_op_on_partial_ord.txt | 26 + src/docs/neg_multiply.txt | 18 + src/docs/negative_feature_names.txt | 22 + src/docs/never_loop.txt | 15 + src/docs/new_ret_no_self.txt | 47 ++ src/docs/new_without_default.txt | 32 + src/docs/no_effect.txt | 12 + src/docs/no_effect_replace.txt | 11 + src/docs/no_effect_underscore_binding.txt | 16 + src/docs/non_ascii_literal.txt | 19 + src/docs/non_octal_unix_permissions.txt | 23 + src/docs/non_send_fields_in_send_ty.txt | 36 ++ src/docs/nonminimal_bool.txt | 23 + src/docs/nonsensical_open_options.txt | 14 + src/docs/nonstandard_macro_braces.txt | 15 + src/docs/not_unsafe_ptr_arg_deref.txt | 30 + src/docs/obfuscated_if_else.txt | 21 + src/docs/octal_escapes.txt | 33 + src/docs/ok_expect.txt | 19 + src/docs/only_used_in_recursion.txt | 58 ++ src/docs/op_ref.txt | 17 + src/docs/option_as_ref_deref.txt | 15 + src/docs/option_env_unwrap.txt | 19 + src/docs/option_filter_map.txt | 15 + src/docs/option_if_let_else.txt | 46 ++ src/docs/option_map_or_none.txt | 19 + src/docs/option_map_unit_fn.txt | 27 + src/docs/option_option.txt | 32 + src/docs/or_fun_call.txt | 27 + src/docs/or_then_unwrap.txt | 22 + src/docs/out_of_bounds_indexing.txt | 22 + src/docs/overflow_check_conditional.txt | 11 + src/docs/overly_complex_bool_expr.txt | 20 + src/docs/panic.txt | 10 + src/docs/panic_in_result_fn.txt | 22 + src/docs/panicking_unwrap.txt | 18 + src/docs/partialeq_ne_impl.txt | 18 + src/docs/partialeq_to_none.txt | 24 + src/docs/path_buf_push_overwrite.txt | 25 + src/docs/pattern_type_mismatch.txt | 64 ++ .../positional_named_format_parameters.txt | 15 + src/docs/possible_missing_comma.txt | 14 + src/docs/precedence.txt | 17 + src/docs/print_in_format_impl.txt | 34 + src/docs/print_literal.txt | 20 + src/docs/print_stderr.txt | 21 + src/docs/print_stdout.txt | 21 + src/docs/print_with_newline.txt | 16 + src/docs/println_empty_string.txt | 16 + src/docs/ptr_arg.txt | 29 + src/docs/ptr_as_ptr.txt | 22 + src/docs/ptr_eq.txt | 22 + src/docs/ptr_offset_with_cast.txt | 30 + src/docs/pub_use.txt | 28 + src/docs/question_mark.txt | 18 + src/docs/range_minus_one.txt | 27 + src/docs/range_plus_one.txt | 36 ++ src/docs/range_zip_with_len.txt | 16 + src/docs/rc_buffer.txt | 27 + src/docs/rc_clone_in_vec_init.txt | 29 + src/docs/rc_mutex.txt | 26 + src/docs/read_zero_byte_vec.txt | 30 + src/docs/recursive_format_impl.txt | 32 + src/docs/redundant_allocation.txt | 17 + src/docs/redundant_clone.txt | 23 + src/docs/redundant_closure.txt | 25 + src/docs/redundant_closure_call.txt | 17 + .../redundant_closure_for_method_calls.txt | 15 + src/docs/redundant_else.txt | 30 + src/docs/redundant_feature_names.txt | 23 + src/docs/redundant_field_names.txt | 22 + src/docs/redundant_pattern.txt | 22 + src/docs/redundant_pattern_matching.txt | 45 ++ src/docs/redundant_pub_crate.txt | 21 + src/docs/redundant_slicing.txt | 24 + src/docs/redundant_static_lifetimes.txt | 19 + src/docs/ref_binding_to_reference.txt | 21 + src/docs/ref_option_ref.txt | 19 + src/docs/repeat_once.txt | 25 + src/docs/rest_pat_in_fully_bound_structs.txt | 24 + src/docs/result_large_err.txt | 36 ++ src/docs/result_map_or_into_option.txt | 16 + src/docs/result_map_unit_fn.txt | 26 + src/docs/result_unit_err.txt | 40 ++ src/docs/return_self_not_must_use.txt | 46 ++ src/docs/reversed_empty_ranges.txt | 26 + src/docs/same_functions_in_if_condition.txt | 41 ++ src/docs/same_item_push.txt | 29 + src/docs/same_name_method.txt | 23 + src/docs/search_is_some.txt | 24 + src/docs/self_assignment.txt | 32 + src/docs/self_named_constructors.txt | 26 + src/docs/self_named_module_files.txt | 22 + src/docs/semicolon_if_nothing_returned.txt | 20 + src/docs/separated_literal_suffix.txt | 17 + src/docs/serde_api_misuse.txt | 10 + src/docs/shadow_reuse.txt | 20 + src/docs/shadow_same.txt | 18 + src/docs/shadow_unrelated.txt | 22 + src/docs/short_circuit_statement.txt | 14 + src/docs/should_implement_trait.txt | 22 + src/docs/significant_drop_in_scrutinee.txt | 43 ++ src/docs/similar_names.txt | 12 + src/docs/single_char_add_str.txt | 18 + src/docs/single_char_lifetime_names.txt | 28 + src/docs/single_char_pattern.txt | 20 + src/docs/single_component_path_imports.txt | 21 + src/docs/single_element_loop.txt | 21 + src/docs/single_match.txt | 21 + src/docs/single_match_else.txt | 29 + src/docs/size_of_in_element_count.txt | 16 + src/docs/skip_while_next.txt | 16 + src/docs/slow_vector_initialization.txt | 24 + src/docs/stable_sort_primitive.txt | 31 + src/docs/std_instead_of_alloc.txt | 18 + src/docs/std_instead_of_core.txt | 18 + src/docs/str_to_string.txt | 18 + src/docs/string_add.txt | 27 + src/docs/string_add_assign.txt | 17 + src/docs/string_extend_chars.txt | 23 + src/docs/string_from_utf8_as_bytes.txt | 15 + src/docs/string_lit_as_bytes.txt | 39 ++ src/docs/string_slice.txt | 17 + src/docs/string_to_string.txt | 19 + src/docs/strlen_on_c_strings.txt | 20 + src/docs/struct_excessive_bools.txt | 29 + src/docs/suboptimal_flops.txt | 50 ++ src/docs/suspicious_arithmetic_impl.txt | 17 + src/docs/suspicious_assignment_formatting.txt | 12 + src/docs/suspicious_else_formatting.txt | 30 + src/docs/suspicious_map.txt | 13 + src/docs/suspicious_op_assign_impl.txt | 15 + src/docs/suspicious_operation_groupings.txt | 41 ++ src/docs/suspicious_splitn.txt | 22 + src/docs/suspicious_to_owned.txt | 39 ++ src/docs/suspicious_unary_op_formatting.txt | 18 + src/docs/swap_ptr_to_ref.txt | 23 + src/docs/tabs_in_doc_comments.txt | 44 ++ src/docs/temporary_assignment.txt | 12 + src/docs/to_digit_is_some.txt | 15 + src/docs/to_string_in_format_args.txt | 17 + src/docs/todo.txt | 10 + src/docs/too_many_arguments.txt | 14 + src/docs/too_many_lines.txt | 17 + src/docs/toplevel_ref_arg.txt | 28 + src/docs/trailing_empty_array.txt | 22 + src/docs/trait_duplication_in_bounds.txt | 37 ++ src/docs/transmute_bytes_to_str.txt | 27 + src/docs/transmute_float_to_int.txt | 16 + src/docs/transmute_int_to_bool.txt | 16 + src/docs/transmute_int_to_char.txt | 27 + src/docs/transmute_int_to_float.txt | 16 + src/docs/transmute_num_to_bytes.txt | 16 + src/docs/transmute_ptr_to_ptr.txt | 21 + src/docs/transmute_ptr_to_ref.txt | 21 + src/docs/transmute_undefined_repr.txt | 22 + .../transmutes_expressible_as_ptr_casts.txt | 16 + src/docs/transmuting_null.txt | 15 + src/docs/trim_split_whitespace.txt | 14 + src/docs/trivial_regex.txt | 18 + src/docs/trivially_copy_pass_by_ref.txt | 43 ++ src/docs/try_err.txt | 28 + src/docs/type_complexity.txt | 14 + src/docs/type_repetition_in_bounds.txt | 16 + src/docs/undocumented_unsafe_blocks.txt | 43 ++ src/docs/undropped_manually_drops.txt | 22 + src/docs/unicode_not_nfc.txt | 12 + src/docs/unimplemented.txt | 10 + src/docs/uninit_assumed_init.txt | 28 + src/docs/uninit_vec.txt | 41 ++ src/docs/unit_arg.txt | 14 + src/docs/unit_cmp.txt | 33 + src/docs/unit_hash.txt | 20 + src/docs/unit_return_expecting_ord.txt | 20 + src/docs/unnecessary_cast.txt | 19 + src/docs/unnecessary_filter_map.txt | 23 + src/docs/unnecessary_find_map.txt | 23 + src/docs/unnecessary_fold.txt | 17 + src/docs/unnecessary_join.txt | 25 + src/docs/unnecessary_lazy_evaluations.txt | 32 + src/docs/unnecessary_mut_passed.txt | 17 + src/docs/unnecessary_operation.txt | 12 + src/docs/unnecessary_owned_empty_strings.txt | 16 + src/docs/unnecessary_self_imports.txt | 19 + src/docs/unnecessary_sort_by.txt | 21 + src/docs/unnecessary_to_owned.txt | 24 + src/docs/unnecessary_unwrap.txt | 20 + src/docs/unnecessary_wraps.txt | 36 ++ src/docs/unneeded_field_pattern.txt | 26 + src/docs/unneeded_wildcard_pattern.txt | 28 + src/docs/unnested_or_patterns.txt | 22 + src/docs/unreachable.txt | 10 + src/docs/unreadable_literal.txt | 16 + src/docs/unsafe_derive_deserialize.txt | 27 + src/docs/unsafe_removed_from_name.txt | 15 + src/docs/unseparated_literal_suffix.txt | 18 + src/docs/unsound_collection_transmute.txt | 25 + src/docs/unused_async.txt | 23 + src/docs/unused_io_amount.txt | 31 + src/docs/unused_peekable.txt | 26 + src/docs/unused_rounding.txt | 17 + src/docs/unused_self.txt | 23 + src/docs/unused_unit.txt | 18 + src/docs/unusual_byte_groupings.txt | 12 + src/docs/unwrap_in_result.txt | 39 ++ src/docs/unwrap_or_else_default.txt | 18 + src/docs/unwrap_used.txt | 37 ++ src/docs/upper_case_acronyms.txt | 25 + src/docs/use_debug.txt | 12 + src/docs/use_self.txt | 31 + src/docs/used_underscore_binding.txt | 19 + src/docs/useless_asref.txt | 17 + src/docs/useless_attribute.txt | 36 ++ src/docs/useless_conversion.txt | 17 + src/docs/useless_format.txt | 22 + src/docs/useless_let_if_seq.txt | 39 ++ src/docs/useless_transmute.txt | 12 + src/docs/useless_vec.txt | 18 + src/docs/vec_box.txt | 26 + src/docs/vec_init_then_push.txt | 23 + src/docs/vec_resize_to_zero.txt | 15 + src/docs/verbose_bit_mask.txt | 15 + src/docs/verbose_file_reads.txt | 17 + src/docs/vtable_address_comparisons.txt | 17 + src/docs/while_immutable_condition.txt | 20 + src/docs/while_let_loop.txt | 25 + src/docs/while_let_on_iterator.txt | 20 + src/docs/wildcard_dependencies.txt | 13 + src/docs/wildcard_enum_match_arm.txt | 25 + src/docs/wildcard_imports.txt | 45 ++ src/docs/wildcard_in_or_patterns.txt | 22 + src/docs/write_literal.txt | 21 + src/docs/write_with_newline.txt | 18 + src/docs/writeln_empty_string.txt | 16 + src/docs/wrong_self_convention.txt | 39 ++ src/docs/wrong_transmute.txt | 15 + src/docs/zero_divided_by_zero.txt | 15 + src/docs/zero_prefixed_literal.txt | 32 + src/docs/zero_ptr.txt | 16 + src/docs/zero_sized_map_values.txt | 24 + src/docs/zst_offset.txt | 11 + src/main.rs | 13 + tests/ui-toml/arithmetic_allowed/clippy.toml | 1 - .../arithmetic_side_effects_allowed.rs} | 2 +- .../clippy.toml | 1 + .../toml_unknown_key/conf_unknown_key.stderr | 2 +- tests/ui/arithmetic.fixed | 27 - tests/ui/arithmetic.rs | 27 - tests/ui/arithmetic_side_effects.rs | 57 ++ tests/ui/arithmetic_side_effects.stderr | 22 + tests/ui/author/struct.rs | 7 +- tests/ui/bool_to_int_with_if.fixed | 85 +++ tests/ui/bool_to_int_with_if.rs | 109 ++++ tests/ui/bool_to_int_with_if.stderr | 84 +++ tests/ui/crashes/ice-9405.rs | 11 + tests/ui/crashes/ice-9405.stderr | 11 + tests/ui/crashes/ice-9414.rs | 8 + tests/ui/floating_point_powf.fixed | 5 + tests/ui/floating_point_powf.rs | 5 + tests/ui/floating_point_powf.stderr | 50 +- tests/ui/large_enum_variant.rs | 24 + tests/ui/large_enum_variant.stderr | 256 +++++--- .../ui/match_wild_err_arm.edition2018.stderr | 8 +- .../ui/match_wild_err_arm.edition2021.stderr | 8 +- tests/ui/mut_mutex_lock.fixed | 7 + tests/ui/mut_mutex_lock.rs | 7 + tests/ui/or_fun_call.fixed | 8 +- tests/ui/or_fun_call.stderr | 26 +- tests/ui/range_plus_minus_one.fixed | 19 + tests/ui/range_plus_minus_one.rs | 19 + tests/ui/range_plus_minus_one.stderr | 18 +- tests/ui/result_large_err.rs | 1 + tests/ui/result_large_err.stderr | 22 +- tests/ui/unnecessary_to_owned.fixed | 60 ++ tests/ui/unnecessary_to_owned.rs | 60 ++ tests/ui/unnecessary_to_owned.stderr | 8 +- tests/ui/unwrap_or_else_default.fixed | 3 + tests/ui/unwrap_or_else_default.rs | 3 + tests/ui/unwrap_or_else_default.stderr | 8 +- tests/ui/vec_init_then_push.rs | 6 + tests/ui/vec_init_then_push.stderr | 9 +- 689 files changed, 15491 insertions(+), 686 deletions(-) create mode 100644 clippy_lints/src/bool_to_int_with_if.rs delete mode 100644 clippy_lints/src/operators/arithmetic.rs create mode 100644 clippy_lints/src/operators/arithmetic_side_effects.rs create mode 100644 src/docs.rs create mode 100644 src/docs/absurd_extreme_comparisons.txt create mode 100644 src/docs/alloc_instead_of_core.txt create mode 100644 src/docs/allow_attributes_without_reason.txt create mode 100644 src/docs/almost_complete_letter_range.txt create mode 100644 src/docs/almost_swapped.txt create mode 100644 src/docs/approx_constant.txt create mode 100644 src/docs/arithmetic_side_effects.txt create mode 100644 src/docs/as_conversions.txt create mode 100644 src/docs/as_underscore.txt create mode 100644 src/docs/assertions_on_constants.txt create mode 100644 src/docs/assertions_on_result_states.txt create mode 100644 src/docs/assign_op_pattern.txt create mode 100644 src/docs/async_yields_async.txt create mode 100644 src/docs/await_holding_invalid_type.txt create mode 100644 src/docs/await_holding_lock.txt create mode 100644 src/docs/await_holding_refcell_ref.txt create mode 100644 src/docs/bad_bit_mask.txt create mode 100644 src/docs/bind_instead_of_map.txt create mode 100644 src/docs/blanket_clippy_restriction_lints.txt create mode 100644 src/docs/blocks_in_if_conditions.txt create mode 100644 src/docs/bool_assert_comparison.txt create mode 100644 src/docs/bool_comparison.txt create mode 100644 src/docs/bool_to_int_with_if.txt create mode 100644 src/docs/borrow_as_ptr.txt create mode 100644 src/docs/borrow_deref_ref.txt create mode 100644 src/docs/borrow_interior_mutable_const.txt create mode 100644 src/docs/borrowed_box.txt create mode 100644 src/docs/box_collection.txt create mode 100644 src/docs/boxed_local.txt create mode 100644 src/docs/branches_sharing_code.txt create mode 100644 src/docs/builtin_type_shadow.txt create mode 100644 src/docs/bytes_count_to_len.txt create mode 100644 src/docs/bytes_nth.txt create mode 100644 src/docs/cargo_common_metadata.txt create mode 100644 src/docs/case_sensitive_file_extension_comparisons.txt create mode 100644 src/docs/cast_abs_to_unsigned.txt create mode 100644 src/docs/cast_enum_constructor.txt create mode 100644 src/docs/cast_enum_truncation.txt create mode 100644 src/docs/cast_lossless.txt create mode 100644 src/docs/cast_possible_truncation.txt create mode 100644 src/docs/cast_possible_wrap.txt create mode 100644 src/docs/cast_precision_loss.txt create mode 100644 src/docs/cast_ptr_alignment.txt create mode 100644 src/docs/cast_ref_to_mut.txt create mode 100644 src/docs/cast_sign_loss.txt create mode 100644 src/docs/cast_slice_different_sizes.txt create mode 100644 src/docs/cast_slice_from_raw_parts.txt create mode 100644 src/docs/char_lit_as_u8.txt create mode 100644 src/docs/chars_last_cmp.txt create mode 100644 src/docs/chars_next_cmp.txt create mode 100644 src/docs/checked_conversions.txt create mode 100644 src/docs/clone_double_ref.txt create mode 100644 src/docs/clone_on_copy.txt create mode 100644 src/docs/clone_on_ref_ptr.txt create mode 100644 src/docs/cloned_instead_of_copied.txt create mode 100644 src/docs/cmp_nan.txt create mode 100644 src/docs/cmp_null.txt create mode 100644 src/docs/cmp_owned.txt create mode 100644 src/docs/cognitive_complexity.txt create mode 100644 src/docs/collapsible_else_if.txt create mode 100644 src/docs/collapsible_if.txt create mode 100644 src/docs/collapsible_match.txt create mode 100644 src/docs/collapsible_str_replace.txt create mode 100644 src/docs/comparison_chain.txt create mode 100644 src/docs/comparison_to_empty.txt create mode 100644 src/docs/copy_iterator.txt create mode 100644 src/docs/crate_in_macro_def.txt create mode 100644 src/docs/create_dir.txt create mode 100644 src/docs/crosspointer_transmute.txt create mode 100644 src/docs/dbg_macro.txt create mode 100644 src/docs/debug_assert_with_mut_call.txt create mode 100644 src/docs/decimal_literal_representation.txt create mode 100644 src/docs/declare_interior_mutable_const.txt create mode 100644 src/docs/default_instead_of_iter_empty.txt create mode 100644 src/docs/default_numeric_fallback.txt create mode 100644 src/docs/default_trait_access.txt create mode 100644 src/docs/default_union_representation.txt create mode 100644 src/docs/deprecated_cfg_attr.txt create mode 100644 src/docs/deprecated_semver.txt create mode 100644 src/docs/deref_addrof.txt create mode 100644 src/docs/deref_by_slicing.txt create mode 100644 src/docs/derivable_impls.txt create mode 100644 src/docs/derive_hash_xor_eq.txt create mode 100644 src/docs/derive_ord_xor_partial_ord.txt create mode 100644 src/docs/derive_partial_eq_without_eq.txt create mode 100644 src/docs/disallowed_methods.txt create mode 100644 src/docs/disallowed_names.txt create mode 100644 src/docs/disallowed_script_idents.txt create mode 100644 src/docs/disallowed_types.txt create mode 100644 src/docs/diverging_sub_expression.txt create mode 100644 src/docs/doc_link_with_quotes.txt create mode 100644 src/docs/doc_markdown.txt create mode 100644 src/docs/double_comparisons.txt create mode 100644 src/docs/double_must_use.txt create mode 100644 src/docs/double_neg.txt create mode 100644 src/docs/double_parens.txt create mode 100644 src/docs/drop_copy.txt create mode 100644 src/docs/drop_non_drop.txt create mode 100644 src/docs/drop_ref.txt create mode 100644 src/docs/duplicate_mod.txt create mode 100644 src/docs/duplicate_underscore_argument.txt create mode 100644 src/docs/duration_subsec.txt create mode 100644 src/docs/else_if_without_else.txt create mode 100644 src/docs/empty_drop.txt create mode 100644 src/docs/empty_enum.txt create mode 100644 src/docs/empty_line_after_outer_attr.txt create mode 100644 src/docs/empty_loop.txt create mode 100644 src/docs/empty_structs_with_brackets.txt create mode 100644 src/docs/enum_clike_unportable_variant.txt create mode 100644 src/docs/enum_glob_use.txt create mode 100644 src/docs/enum_variant_names.txt create mode 100644 src/docs/eq_op.txt create mode 100644 src/docs/equatable_if_let.txt create mode 100644 src/docs/erasing_op.txt create mode 100644 src/docs/err_expect.txt create mode 100644 src/docs/excessive_precision.txt create mode 100644 src/docs/exhaustive_enums.txt create mode 100644 src/docs/exhaustive_structs.txt create mode 100644 src/docs/exit.txt create mode 100644 src/docs/expect_fun_call.txt create mode 100644 src/docs/expect_used.txt create mode 100644 src/docs/expl_impl_clone_on_copy.txt create mode 100644 src/docs/explicit_auto_deref.txt create mode 100644 src/docs/explicit_counter_loop.txt create mode 100644 src/docs/explicit_deref_methods.txt create mode 100644 src/docs/explicit_into_iter_loop.txt create mode 100644 src/docs/explicit_iter_loop.txt create mode 100644 src/docs/explicit_write.txt create mode 100644 src/docs/extend_with_drain.txt create mode 100644 src/docs/extra_unused_lifetimes.txt create mode 100644 src/docs/fallible_impl_from.txt create mode 100644 src/docs/field_reassign_with_default.txt create mode 100644 src/docs/filetype_is_file.txt create mode 100644 src/docs/filter_map_identity.txt create mode 100644 src/docs/filter_map_next.txt create mode 100644 src/docs/filter_next.txt create mode 100644 src/docs/flat_map_identity.txt create mode 100644 src/docs/flat_map_option.txt create mode 100644 src/docs/float_arithmetic.txt create mode 100644 src/docs/float_cmp.txt create mode 100644 src/docs/float_cmp_const.txt create mode 100644 src/docs/float_equality_without_abs.txt create mode 100644 src/docs/fn_address_comparisons.txt create mode 100644 src/docs/fn_params_excessive_bools.txt create mode 100644 src/docs/fn_to_numeric_cast.txt create mode 100644 src/docs/fn_to_numeric_cast_any.txt create mode 100644 src/docs/fn_to_numeric_cast_with_truncation.txt create mode 100644 src/docs/for_kv_map.txt create mode 100644 src/docs/for_loops_over_fallibles.txt create mode 100644 src/docs/forget_copy.txt create mode 100644 src/docs/forget_non_drop.txt create mode 100644 src/docs/forget_ref.txt create mode 100644 src/docs/format_in_format_args.txt create mode 100644 src/docs/format_push_string.txt create mode 100644 src/docs/from_iter_instead_of_collect.txt create mode 100644 src/docs/from_over_into.txt create mode 100644 src/docs/from_str_radix_10.txt create mode 100644 src/docs/future_not_send.txt create mode 100644 src/docs/get_first.txt create mode 100644 src/docs/get_last_with_len.txt create mode 100644 src/docs/get_unwrap.txt create mode 100644 src/docs/identity_op.txt create mode 100644 src/docs/if_let_mutex.txt create mode 100644 src/docs/if_not_else.txt create mode 100644 src/docs/if_same_then_else.txt create mode 100644 src/docs/if_then_some_else_none.txt create mode 100644 src/docs/ifs_same_cond.txt create mode 100644 src/docs/implicit_clone.txt create mode 100644 src/docs/implicit_hasher.txt create mode 100644 src/docs/implicit_return.txt create mode 100644 src/docs/implicit_saturating_sub.txt create mode 100644 src/docs/imprecise_flops.txt create mode 100644 src/docs/inconsistent_digit_grouping.txt create mode 100644 src/docs/inconsistent_struct_constructor.txt create mode 100644 src/docs/index_refutable_slice.txt create mode 100644 src/docs/indexing_slicing.txt create mode 100644 src/docs/ineffective_bit_mask.txt create mode 100644 src/docs/inefficient_to_string.txt create mode 100644 src/docs/infallible_destructuring_match.txt create mode 100644 src/docs/infinite_iter.txt create mode 100644 src/docs/inherent_to_string.txt create mode 100644 src/docs/inherent_to_string_shadow_display.txt create mode 100644 src/docs/init_numbered_fields.txt create mode 100644 src/docs/inline_always.txt create mode 100644 src/docs/inline_asm_x86_att_syntax.txt create mode 100644 src/docs/inline_asm_x86_intel_syntax.txt create mode 100644 src/docs/inline_fn_without_body.txt create mode 100644 src/docs/inspect_for_each.txt create mode 100644 src/docs/int_plus_one.txt create mode 100644 src/docs/integer_arithmetic.txt create mode 100644 src/docs/integer_division.txt create mode 100644 src/docs/into_iter_on_ref.txt create mode 100644 src/docs/invalid_null_ptr_usage.txt create mode 100644 src/docs/invalid_regex.txt create mode 100644 src/docs/invalid_upcast_comparisons.txt create mode 100644 src/docs/invalid_utf8_in_unchecked.txt create mode 100644 src/docs/invisible_characters.txt create mode 100644 src/docs/is_digit_ascii_radix.txt create mode 100644 src/docs/items_after_statements.txt create mode 100644 src/docs/iter_cloned_collect.txt create mode 100644 src/docs/iter_count.txt create mode 100644 src/docs/iter_next_loop.txt create mode 100644 src/docs/iter_next_slice.txt create mode 100644 src/docs/iter_not_returning_iterator.txt create mode 100644 src/docs/iter_nth.txt create mode 100644 src/docs/iter_nth_zero.txt create mode 100644 src/docs/iter_on_empty_collections.txt create mode 100644 src/docs/iter_on_single_items.txt create mode 100644 src/docs/iter_overeager_cloned.txt create mode 100644 src/docs/iter_skip_next.txt create mode 100644 src/docs/iter_with_drain.txt create mode 100644 src/docs/iterator_step_by_zero.txt create mode 100644 src/docs/just_underscores_and_digits.txt create mode 100644 src/docs/large_const_arrays.txt create mode 100644 src/docs/large_digit_groups.txt create mode 100644 src/docs/large_enum_variant.txt create mode 100644 src/docs/large_include_file.txt create mode 100644 src/docs/large_stack_arrays.txt create mode 100644 src/docs/large_types_passed_by_value.txt create mode 100644 src/docs/len_without_is_empty.txt create mode 100644 src/docs/len_zero.txt create mode 100644 src/docs/let_and_return.txt create mode 100644 src/docs/let_underscore_drop.txt create mode 100644 src/docs/let_underscore_lock.txt create mode 100644 src/docs/let_underscore_must_use.txt create mode 100644 src/docs/let_unit_value.txt create mode 100644 src/docs/linkedlist.txt create mode 100644 src/docs/lossy_float_literal.txt create mode 100644 src/docs/macro_use_imports.txt create mode 100644 src/docs/main_recursion.txt create mode 100644 src/docs/manual_assert.txt create mode 100644 src/docs/manual_async_fn.txt create mode 100644 src/docs/manual_bits.txt create mode 100644 src/docs/manual_filter_map.txt create mode 100644 src/docs/manual_find.txt create mode 100644 src/docs/manual_find_map.txt create mode 100644 src/docs/manual_flatten.txt create mode 100644 src/docs/manual_instant_elapsed.txt create mode 100644 src/docs/manual_map.txt create mode 100644 src/docs/manual_memcpy.txt create mode 100644 src/docs/manual_non_exhaustive.txt create mode 100644 src/docs/manual_ok_or.txt create mode 100644 src/docs/manual_range_contains.txt create mode 100644 src/docs/manual_rem_euclid.txt create mode 100644 src/docs/manual_retain.txt create mode 100644 src/docs/manual_saturating_arithmetic.txt create mode 100644 src/docs/manual_split_once.txt create mode 100644 src/docs/manual_str_repeat.txt create mode 100644 src/docs/manual_string_new.txt create mode 100644 src/docs/manual_strip.txt create mode 100644 src/docs/manual_swap.txt create mode 100644 src/docs/manual_unwrap_or.txt create mode 100644 src/docs/many_single_char_names.txt create mode 100644 src/docs/map_clone.txt create mode 100644 src/docs/map_collect_result_unit.txt create mode 100644 src/docs/map_entry.txt create mode 100644 src/docs/map_err_ignore.txt create mode 100644 src/docs/map_flatten.txt create mode 100644 src/docs/map_identity.txt create mode 100644 src/docs/map_unwrap_or.txt create mode 100644 src/docs/match_as_ref.txt create mode 100644 src/docs/match_bool.txt create mode 100644 src/docs/match_like_matches_macro.txt create mode 100644 src/docs/match_on_vec_items.txt create mode 100644 src/docs/match_overlapping_arm.txt create mode 100644 src/docs/match_ref_pats.txt create mode 100644 src/docs/match_result_ok.txt create mode 100644 src/docs/match_same_arms.txt create mode 100644 src/docs/match_single_binding.txt create mode 100644 src/docs/match_str_case_mismatch.txt create mode 100644 src/docs/match_wild_err_arm.txt create mode 100644 src/docs/match_wildcard_for_single_variants.txt create mode 100644 src/docs/maybe_infinite_iter.txt create mode 100644 src/docs/mem_forget.txt create mode 100644 src/docs/mem_replace_option_with_none.txt create mode 100644 src/docs/mem_replace_with_default.txt create mode 100644 src/docs/mem_replace_with_uninit.txt create mode 100644 src/docs/min_max.txt create mode 100644 src/docs/mismatched_target_os.txt create mode 100644 src/docs/mismatching_type_param_order.txt create mode 100644 src/docs/misrefactored_assign_op.txt create mode 100644 src/docs/missing_const_for_fn.txt create mode 100644 src/docs/missing_docs_in_private_items.txt create mode 100644 src/docs/missing_enforced_import_renames.txt create mode 100644 src/docs/missing_errors_doc.txt create mode 100644 src/docs/missing_inline_in_public_items.txt create mode 100644 src/docs/missing_panics_doc.txt create mode 100644 src/docs/missing_safety_doc.txt create mode 100644 src/docs/missing_spin_loop.txt create mode 100644 src/docs/mistyped_literal_suffixes.txt create mode 100644 src/docs/mixed_case_hex_literals.txt create mode 100644 src/docs/mixed_read_write_in_expression.txt create mode 100644 src/docs/mod_module_files.txt create mode 100644 src/docs/module_inception.txt create mode 100644 src/docs/module_name_repetitions.txt create mode 100644 src/docs/modulo_arithmetic.txt create mode 100644 src/docs/modulo_one.txt create mode 100644 src/docs/multi_assignments.txt create mode 100644 src/docs/multiple_crate_versions.txt create mode 100644 src/docs/multiple_inherent_impl.txt create mode 100644 src/docs/must_use_candidate.txt create mode 100644 src/docs/must_use_unit.txt create mode 100644 src/docs/mut_from_ref.txt create mode 100644 src/docs/mut_mut.txt create mode 100644 src/docs/mut_mutex_lock.txt create mode 100644 src/docs/mut_range_bound.txt create mode 100644 src/docs/mutable_key_type.txt create mode 100644 src/docs/mutex_atomic.txt create mode 100644 src/docs/mutex_integer.txt create mode 100644 src/docs/naive_bytecount.txt create mode 100644 src/docs/needless_arbitrary_self_type.txt create mode 100644 src/docs/needless_bitwise_bool.txt create mode 100644 src/docs/needless_bool.txt create mode 100644 src/docs/needless_borrow.txt create mode 100644 src/docs/needless_borrowed_reference.txt create mode 100644 src/docs/needless_collect.txt create mode 100644 src/docs/needless_continue.txt create mode 100644 src/docs/needless_doctest_main.txt create mode 100644 src/docs/needless_for_each.txt create mode 100644 src/docs/needless_late_init.txt create mode 100644 src/docs/needless_lifetimes.txt create mode 100644 src/docs/needless_match.txt create mode 100644 src/docs/needless_option_as_deref.txt create mode 100644 src/docs/needless_option_take.txt create mode 100644 src/docs/needless_parens_on_range_literals.txt create mode 100644 src/docs/needless_pass_by_value.txt create mode 100644 src/docs/needless_question_mark.txt create mode 100644 src/docs/needless_range_loop.txt create mode 100644 src/docs/needless_return.txt create mode 100644 src/docs/needless_splitn.txt create mode 100644 src/docs/needless_update.txt create mode 100644 src/docs/neg_cmp_op_on_partial_ord.txt create mode 100644 src/docs/neg_multiply.txt create mode 100644 src/docs/negative_feature_names.txt create mode 100644 src/docs/never_loop.txt create mode 100644 src/docs/new_ret_no_self.txt create mode 100644 src/docs/new_without_default.txt create mode 100644 src/docs/no_effect.txt create mode 100644 src/docs/no_effect_replace.txt create mode 100644 src/docs/no_effect_underscore_binding.txt create mode 100644 src/docs/non_ascii_literal.txt create mode 100644 src/docs/non_octal_unix_permissions.txt create mode 100644 src/docs/non_send_fields_in_send_ty.txt create mode 100644 src/docs/nonminimal_bool.txt create mode 100644 src/docs/nonsensical_open_options.txt create mode 100644 src/docs/nonstandard_macro_braces.txt create mode 100644 src/docs/not_unsafe_ptr_arg_deref.txt create mode 100644 src/docs/obfuscated_if_else.txt create mode 100644 src/docs/octal_escapes.txt create mode 100644 src/docs/ok_expect.txt create mode 100644 src/docs/only_used_in_recursion.txt create mode 100644 src/docs/op_ref.txt create mode 100644 src/docs/option_as_ref_deref.txt create mode 100644 src/docs/option_env_unwrap.txt create mode 100644 src/docs/option_filter_map.txt create mode 100644 src/docs/option_if_let_else.txt create mode 100644 src/docs/option_map_or_none.txt create mode 100644 src/docs/option_map_unit_fn.txt create mode 100644 src/docs/option_option.txt create mode 100644 src/docs/or_fun_call.txt create mode 100644 src/docs/or_then_unwrap.txt create mode 100644 src/docs/out_of_bounds_indexing.txt create mode 100644 src/docs/overflow_check_conditional.txt create mode 100644 src/docs/overly_complex_bool_expr.txt create mode 100644 src/docs/panic.txt create mode 100644 src/docs/panic_in_result_fn.txt create mode 100644 src/docs/panicking_unwrap.txt create mode 100644 src/docs/partialeq_ne_impl.txt create mode 100644 src/docs/partialeq_to_none.txt create mode 100644 src/docs/path_buf_push_overwrite.txt create mode 100644 src/docs/pattern_type_mismatch.txt create mode 100644 src/docs/positional_named_format_parameters.txt create mode 100644 src/docs/possible_missing_comma.txt create mode 100644 src/docs/precedence.txt create mode 100644 src/docs/print_in_format_impl.txt create mode 100644 src/docs/print_literal.txt create mode 100644 src/docs/print_stderr.txt create mode 100644 src/docs/print_stdout.txt create mode 100644 src/docs/print_with_newline.txt create mode 100644 src/docs/println_empty_string.txt create mode 100644 src/docs/ptr_arg.txt create mode 100644 src/docs/ptr_as_ptr.txt create mode 100644 src/docs/ptr_eq.txt create mode 100644 src/docs/ptr_offset_with_cast.txt create mode 100644 src/docs/pub_use.txt create mode 100644 src/docs/question_mark.txt create mode 100644 src/docs/range_minus_one.txt create mode 100644 src/docs/range_plus_one.txt create mode 100644 src/docs/range_zip_with_len.txt create mode 100644 src/docs/rc_buffer.txt create mode 100644 src/docs/rc_clone_in_vec_init.txt create mode 100644 src/docs/rc_mutex.txt create mode 100644 src/docs/read_zero_byte_vec.txt create mode 100644 src/docs/recursive_format_impl.txt create mode 100644 src/docs/redundant_allocation.txt create mode 100644 src/docs/redundant_clone.txt create mode 100644 src/docs/redundant_closure.txt create mode 100644 src/docs/redundant_closure_call.txt create mode 100644 src/docs/redundant_closure_for_method_calls.txt create mode 100644 src/docs/redundant_else.txt create mode 100644 src/docs/redundant_feature_names.txt create mode 100644 src/docs/redundant_field_names.txt create mode 100644 src/docs/redundant_pattern.txt create mode 100644 src/docs/redundant_pattern_matching.txt create mode 100644 src/docs/redundant_pub_crate.txt create mode 100644 src/docs/redundant_slicing.txt create mode 100644 src/docs/redundant_static_lifetimes.txt create mode 100644 src/docs/ref_binding_to_reference.txt create mode 100644 src/docs/ref_option_ref.txt create mode 100644 src/docs/repeat_once.txt create mode 100644 src/docs/rest_pat_in_fully_bound_structs.txt create mode 100644 src/docs/result_large_err.txt create mode 100644 src/docs/result_map_or_into_option.txt create mode 100644 src/docs/result_map_unit_fn.txt create mode 100644 src/docs/result_unit_err.txt create mode 100644 src/docs/return_self_not_must_use.txt create mode 100644 src/docs/reversed_empty_ranges.txt create mode 100644 src/docs/same_functions_in_if_condition.txt create mode 100644 src/docs/same_item_push.txt create mode 100644 src/docs/same_name_method.txt create mode 100644 src/docs/search_is_some.txt create mode 100644 src/docs/self_assignment.txt create mode 100644 src/docs/self_named_constructors.txt create mode 100644 src/docs/self_named_module_files.txt create mode 100644 src/docs/semicolon_if_nothing_returned.txt create mode 100644 src/docs/separated_literal_suffix.txt create mode 100644 src/docs/serde_api_misuse.txt create mode 100644 src/docs/shadow_reuse.txt create mode 100644 src/docs/shadow_same.txt create mode 100644 src/docs/shadow_unrelated.txt create mode 100644 src/docs/short_circuit_statement.txt create mode 100644 src/docs/should_implement_trait.txt create mode 100644 src/docs/significant_drop_in_scrutinee.txt create mode 100644 src/docs/similar_names.txt create mode 100644 src/docs/single_char_add_str.txt create mode 100644 src/docs/single_char_lifetime_names.txt create mode 100644 src/docs/single_char_pattern.txt create mode 100644 src/docs/single_component_path_imports.txt create mode 100644 src/docs/single_element_loop.txt create mode 100644 src/docs/single_match.txt create mode 100644 src/docs/single_match_else.txt create mode 100644 src/docs/size_of_in_element_count.txt create mode 100644 src/docs/skip_while_next.txt create mode 100644 src/docs/slow_vector_initialization.txt create mode 100644 src/docs/stable_sort_primitive.txt create mode 100644 src/docs/std_instead_of_alloc.txt create mode 100644 src/docs/std_instead_of_core.txt create mode 100644 src/docs/str_to_string.txt create mode 100644 src/docs/string_add.txt create mode 100644 src/docs/string_add_assign.txt create mode 100644 src/docs/string_extend_chars.txt create mode 100644 src/docs/string_from_utf8_as_bytes.txt create mode 100644 src/docs/string_lit_as_bytes.txt create mode 100644 src/docs/string_slice.txt create mode 100644 src/docs/string_to_string.txt create mode 100644 src/docs/strlen_on_c_strings.txt create mode 100644 src/docs/struct_excessive_bools.txt create mode 100644 src/docs/suboptimal_flops.txt create mode 100644 src/docs/suspicious_arithmetic_impl.txt create mode 100644 src/docs/suspicious_assignment_formatting.txt create mode 100644 src/docs/suspicious_else_formatting.txt create mode 100644 src/docs/suspicious_map.txt create mode 100644 src/docs/suspicious_op_assign_impl.txt create mode 100644 src/docs/suspicious_operation_groupings.txt create mode 100644 src/docs/suspicious_splitn.txt create mode 100644 src/docs/suspicious_to_owned.txt create mode 100644 src/docs/suspicious_unary_op_formatting.txt create mode 100644 src/docs/swap_ptr_to_ref.txt create mode 100644 src/docs/tabs_in_doc_comments.txt create mode 100644 src/docs/temporary_assignment.txt create mode 100644 src/docs/to_digit_is_some.txt create mode 100644 src/docs/to_string_in_format_args.txt create mode 100644 src/docs/todo.txt create mode 100644 src/docs/too_many_arguments.txt create mode 100644 src/docs/too_many_lines.txt create mode 100644 src/docs/toplevel_ref_arg.txt create mode 100644 src/docs/trailing_empty_array.txt create mode 100644 src/docs/trait_duplication_in_bounds.txt create mode 100644 src/docs/transmute_bytes_to_str.txt create mode 100644 src/docs/transmute_float_to_int.txt create mode 100644 src/docs/transmute_int_to_bool.txt create mode 100644 src/docs/transmute_int_to_char.txt create mode 100644 src/docs/transmute_int_to_float.txt create mode 100644 src/docs/transmute_num_to_bytes.txt create mode 100644 src/docs/transmute_ptr_to_ptr.txt create mode 100644 src/docs/transmute_ptr_to_ref.txt create mode 100644 src/docs/transmute_undefined_repr.txt create mode 100644 src/docs/transmutes_expressible_as_ptr_casts.txt create mode 100644 src/docs/transmuting_null.txt create mode 100644 src/docs/trim_split_whitespace.txt create mode 100644 src/docs/trivial_regex.txt create mode 100644 src/docs/trivially_copy_pass_by_ref.txt create mode 100644 src/docs/try_err.txt create mode 100644 src/docs/type_complexity.txt create mode 100644 src/docs/type_repetition_in_bounds.txt create mode 100644 src/docs/undocumented_unsafe_blocks.txt create mode 100644 src/docs/undropped_manually_drops.txt create mode 100644 src/docs/unicode_not_nfc.txt create mode 100644 src/docs/unimplemented.txt create mode 100644 src/docs/uninit_assumed_init.txt create mode 100644 src/docs/uninit_vec.txt create mode 100644 src/docs/unit_arg.txt create mode 100644 src/docs/unit_cmp.txt create mode 100644 src/docs/unit_hash.txt create mode 100644 src/docs/unit_return_expecting_ord.txt create mode 100644 src/docs/unnecessary_cast.txt create mode 100644 src/docs/unnecessary_filter_map.txt create mode 100644 src/docs/unnecessary_find_map.txt create mode 100644 src/docs/unnecessary_fold.txt create mode 100644 src/docs/unnecessary_join.txt create mode 100644 src/docs/unnecessary_lazy_evaluations.txt create mode 100644 src/docs/unnecessary_mut_passed.txt create mode 100644 src/docs/unnecessary_operation.txt create mode 100644 src/docs/unnecessary_owned_empty_strings.txt create mode 100644 src/docs/unnecessary_self_imports.txt create mode 100644 src/docs/unnecessary_sort_by.txt create mode 100644 src/docs/unnecessary_to_owned.txt create mode 100644 src/docs/unnecessary_unwrap.txt create mode 100644 src/docs/unnecessary_wraps.txt create mode 100644 src/docs/unneeded_field_pattern.txt create mode 100644 src/docs/unneeded_wildcard_pattern.txt create mode 100644 src/docs/unnested_or_patterns.txt create mode 100644 src/docs/unreachable.txt create mode 100644 src/docs/unreadable_literal.txt create mode 100644 src/docs/unsafe_derive_deserialize.txt create mode 100644 src/docs/unsafe_removed_from_name.txt create mode 100644 src/docs/unseparated_literal_suffix.txt create mode 100644 src/docs/unsound_collection_transmute.txt create mode 100644 src/docs/unused_async.txt create mode 100644 src/docs/unused_io_amount.txt create mode 100644 src/docs/unused_peekable.txt create mode 100644 src/docs/unused_rounding.txt create mode 100644 src/docs/unused_self.txt create mode 100644 src/docs/unused_unit.txt create mode 100644 src/docs/unusual_byte_groupings.txt create mode 100644 src/docs/unwrap_in_result.txt create mode 100644 src/docs/unwrap_or_else_default.txt create mode 100644 src/docs/unwrap_used.txt create mode 100644 src/docs/upper_case_acronyms.txt create mode 100644 src/docs/use_debug.txt create mode 100644 src/docs/use_self.txt create mode 100644 src/docs/used_underscore_binding.txt create mode 100644 src/docs/useless_asref.txt create mode 100644 src/docs/useless_attribute.txt create mode 100644 src/docs/useless_conversion.txt create mode 100644 src/docs/useless_format.txt create mode 100644 src/docs/useless_let_if_seq.txt create mode 100644 src/docs/useless_transmute.txt create mode 100644 src/docs/useless_vec.txt create mode 100644 src/docs/vec_box.txt create mode 100644 src/docs/vec_init_then_push.txt create mode 100644 src/docs/vec_resize_to_zero.txt create mode 100644 src/docs/verbose_bit_mask.txt create mode 100644 src/docs/verbose_file_reads.txt create mode 100644 src/docs/vtable_address_comparisons.txt create mode 100644 src/docs/while_immutable_condition.txt create mode 100644 src/docs/while_let_loop.txt create mode 100644 src/docs/while_let_on_iterator.txt create mode 100644 src/docs/wildcard_dependencies.txt create mode 100644 src/docs/wildcard_enum_match_arm.txt create mode 100644 src/docs/wildcard_imports.txt create mode 100644 src/docs/wildcard_in_or_patterns.txt create mode 100644 src/docs/write_literal.txt create mode 100644 src/docs/write_with_newline.txt create mode 100644 src/docs/writeln_empty_string.txt create mode 100644 src/docs/wrong_self_convention.txt create mode 100644 src/docs/wrong_transmute.txt create mode 100644 src/docs/zero_divided_by_zero.txt create mode 100644 src/docs/zero_prefixed_literal.txt create mode 100644 src/docs/zero_ptr.txt create mode 100644 src/docs/zero_sized_map_values.txt create mode 100644 src/docs/zst_offset.txt delete mode 100644 tests/ui-toml/arithmetic_allowed/clippy.toml rename tests/ui-toml/{arithmetic_allowed/arithmetic_allowed.rs => arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs} (89%) create mode 100644 tests/ui-toml/arithmetic_side_effects_allowed/clippy.toml delete mode 100644 tests/ui/arithmetic.fixed delete mode 100644 tests/ui/arithmetic.rs create mode 100644 tests/ui/arithmetic_side_effects.rs create mode 100644 tests/ui/arithmetic_side_effects.stderr create mode 100644 tests/ui/bool_to_int_with_if.fixed create mode 100644 tests/ui/bool_to_int_with_if.rs create mode 100644 tests/ui/bool_to_int_with_if.stderr create mode 100644 tests/ui/crashes/ice-9405.rs create mode 100644 tests/ui/crashes/ice-9405.stderr create mode 100644 tests/ui/crashes/ice-9414.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index c488c142e46fc..d847e4c749481 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3583,7 +3583,7 @@ Released 2018-09-13 [`almost_complete_letter_range`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_complete_letter_range [`almost_swapped`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_swapped [`approx_constant`]: https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant -[`arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic +[`arithmetic_side_effects`]: https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic_side_effects [`as_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_conversions [`as_underscore`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_underscore [`assertions_on_constants`]: https://rust-lang.github.io/rust-clippy/master/index.html#assertions_on_constants @@ -3603,6 +3603,7 @@ Released 2018-09-13 [`blocks_in_if_conditions`]: https://rust-lang.github.io/rust-clippy/master/index.html#blocks_in_if_conditions [`bool_assert_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#bool_assert_comparison [`bool_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#bool_comparison +[`bool_to_int_with_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#bool_to_int_with_if [`borrow_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrow_as_ptr [`borrow_deref_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrow_deref_ref [`borrow_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrow_interior_mutable_const diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs index c503142e5e455..b95061bf81a25 100644 --- a/clippy_dev/src/update_lints.rs +++ b/clippy_dev/src/update_lints.rs @@ -3,7 +3,7 @@ use aho_corasick::AhoCorasickBuilder; use indoc::writedoc; use itertools::Itertools; use rustc_lexer::{tokenize, unescape, LiteralKind, TokenKind}; -use std::collections::{HashMap, HashSet}; +use std::collections::{BTreeSet, HashMap, HashSet}; use std::ffi::OsStr; use std::fmt::Write; use std::fs::{self, OpenOptions}; @@ -124,6 +124,8 @@ fn generate_lint_files( let content = gen_lint_group_list("all", all_group_lints); process_file("clippy_lints/src/lib.register_all.rs", update_mode, &content); + update_docs(update_mode, &usable_lints); + for (lint_group, lints) in Lint::by_lint_group(usable_lints.into_iter().chain(internal_lints)) { let content = gen_lint_group_list(&lint_group, lints.iter()); process_file( @@ -140,6 +142,62 @@ fn generate_lint_files( process_file("tests/ui/rename.rs", update_mode, &content); } +fn update_docs(update_mode: UpdateMode, usable_lints: &[Lint]) { + replace_region_in_file(update_mode, Path::new("src/docs.rs"), "docs! {\n", "\n}\n", |res| { + for name in usable_lints.iter().map(|lint| lint.name.clone()).sorted() { + writeln!(res, r#" "{name}","#).unwrap(); + } + }); + + if update_mode == UpdateMode::Check { + let mut extra = BTreeSet::new(); + let mut lint_names = usable_lints + .iter() + .map(|lint| lint.name.clone()) + .collect::>(); + for file in std::fs::read_dir("src/docs").unwrap() { + let filename = file.unwrap().file_name().into_string().unwrap(); + if let Some(name) = filename.strip_suffix(".txt") { + if !lint_names.remove(name) { + extra.insert(name.to_string()); + } + } + } + + let failed = print_lint_names("extra lint docs:", &extra) | print_lint_names("missing lint docs:", &lint_names); + + if failed { + exit_with_failure(); + } + } else { + if std::fs::remove_dir_all("src/docs").is_err() { + eprintln!("could not remove src/docs directory"); + } + if std::fs::create_dir("src/docs").is_err() { + eprintln!("could not recreate src/docs directory"); + } + } + for lint in usable_lints { + process_file( + Path::new("src/docs").join(lint.name.clone() + ".txt"), + update_mode, + &lint.documentation, + ); + } +} + +fn print_lint_names(header: &str, lints: &BTreeSet) -> bool { + if lints.is_empty() { + return false; + } + println!("{}", header); + for lint in lints.iter().sorted() { + println!(" {}", lint); + } + println!(); + true +} + pub fn print_lints() { let (lint_list, _, _) = gather_all(); let usable_lints = Lint::usable_lints(&lint_list); @@ -589,17 +647,26 @@ struct Lint { desc: String, module: String, declaration_range: Range, + documentation: String, } impl Lint { #[must_use] - fn new(name: &str, group: &str, desc: &str, module: &str, declaration_range: Range) -> Self { + fn new( + name: &str, + group: &str, + desc: &str, + module: &str, + declaration_range: Range, + documentation: String, + ) -> Self { Self { name: name.to_lowercase(), group: group.into(), desc: remove_line_splices(desc), module: module.into(), declaration_range, + documentation, } } @@ -852,27 +919,35 @@ fn parse_contents(contents: &str, module: &str, lints: &mut Vec) { }| token_kind == &TokenKind::Ident && *content == "declare_clippy_lint", ) { let start = range.start; - - let mut iter = iter - .by_ref() - .filter(|t| !matches!(t.token_kind, TokenKind::Whitespace | TokenKind::LineComment { .. })); + let mut docs = String::with_capacity(128); + let mut iter = iter.by_ref().filter(|t| !matches!(t.token_kind, TokenKind::Whitespace)); // matches `!{` match_tokens!(iter, Bang OpenBrace); - match iter.next() { - // #[clippy::version = "version"] pub - Some(LintDeclSearchResult { - token_kind: TokenKind::Pound, - .. - }) => { - match_tokens!(iter, OpenBracket Ident Colon Colon Ident Eq Literal{..} CloseBracket Ident); - }, - // pub - Some(LintDeclSearchResult { - token_kind: TokenKind::Ident, - .. - }) => (), - _ => continue, + let mut in_code = false; + while let Some(t) = iter.next() { + match t.token_kind { + TokenKind::LineComment { .. } => { + if let Some(line) = t.content.strip_prefix("/// ").or_else(|| t.content.strip_prefix("///")) { + if line.starts_with("```") { + docs += "```\n"; + in_code = !in_code; + } else if !(in_code && line.starts_with("# ")) { + docs += line; + docs.push('\n'); + } + } + }, + TokenKind::Pound => { + match_tokens!(iter, OpenBracket Ident Colon Colon Ident Eq Literal{..} CloseBracket Ident); + break; + }, + TokenKind::Ident => { + break; + }, + _ => {}, + } } + docs.pop(); // remove final newline let (name, group, desc) = match_tokens!( iter, @@ -890,7 +965,7 @@ fn parse_contents(contents: &str, module: &str, lints: &mut Vec) { .. }) = iter.next() { - lints.push(Lint::new(name, group, desc, module, start..range.end)); + lints.push(Lint::new(name, group, desc, module, start..range.end, docs)); } } } @@ -977,7 +1052,11 @@ fn remove_line_splices(s: &str) -> String { .and_then(|s| s.strip_suffix('"')) .unwrap_or_else(|| panic!("expected quoted string, found `{}`", s)); let mut res = String::with_capacity(s.len()); - unescape::unescape_literal(s, unescape::Mode::Str, &mut |range, _| res.push_str(&s[range])); + unescape::unescape_literal(s, unescape::Mode::Str, &mut |range, ch| { + if ch.is_ok() { + res.push_str(&s[range]); + } + }); res } @@ -1116,6 +1195,7 @@ mod tests { "\"really long text\"", "module_name", Range::default(), + String::new(), ), Lint::new( "doc_markdown", @@ -1123,6 +1203,7 @@ mod tests { "\"single line\"", "module_name", Range::default(), + String::new(), ), ]; assert_eq!(expected, result); @@ -1162,6 +1243,7 @@ mod tests { "\"abc\"", "module_name", Range::default(), + String::new(), ), Lint::new( "should_assert_eq2", @@ -1169,6 +1251,7 @@ mod tests { "\"abc\"", "module_name", Range::default(), + String::new(), ), Lint::new( "should_assert_eq2", @@ -1176,6 +1259,7 @@ mod tests { "\"abc\"", "module_name", Range::default(), + String::new(), ), ]; let expected = vec![Lint::new( @@ -1184,6 +1268,7 @@ mod tests { "\"abc\"", "module_name", Range::default(), + String::new(), )]; assert_eq!(expected, Lint::usable_lints(&lints)); } @@ -1191,22 +1276,51 @@ mod tests { #[test] fn test_by_lint_group() { let lints = vec![ - Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()), + Lint::new( + "should_assert_eq", + "group1", + "\"abc\"", + "module_name", + Range::default(), + String::new(), + ), Lint::new( "should_assert_eq2", "group2", "\"abc\"", "module_name", Range::default(), + String::new(), + ), + Lint::new( + "incorrect_match", + "group1", + "\"abc\"", + "module_name", + Range::default(), + String::new(), ), - Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()), ]; let mut expected: HashMap> = HashMap::new(); expected.insert( "group1".to_string(), vec![ - Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()), - Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()), + Lint::new( + "should_assert_eq", + "group1", + "\"abc\"", + "module_name", + Range::default(), + String::new(), + ), + Lint::new( + "incorrect_match", + "group1", + "\"abc\"", + "module_name", + Range::default(), + String::new(), + ), ], ); expected.insert( @@ -1217,6 +1331,7 @@ mod tests { "\"abc\"", "module_name", Range::default(), + String::new(), )], ); assert_eq!(expected, Lint::by_lint_group(lints.into_iter())); @@ -1255,9 +1370,30 @@ mod tests { #[test] fn test_gen_lint_group_list() { let lints = vec![ - Lint::new("abc", "group1", "\"abc\"", "module_name", Range::default()), - Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()), - Lint::new("internal", "internal_style", "\"abc\"", "module_name", Range::default()), + Lint::new( + "abc", + "group1", + "\"abc\"", + "module_name", + Range::default(), + String::new(), + ), + Lint::new( + "should_assert_eq", + "group1", + "\"abc\"", + "module_name", + Range::default(), + String::new(), + ), + Lint::new( + "internal", + "internal_style", + "\"abc\"", + "module_name", + Range::default(), + String::new(), + ), ]; let expected = GENERATED_FILE_COMMENT.to_string() + &[ diff --git a/clippy_lints/src/async_yields_async.rs b/clippy_lints/src/async_yields_async.rs index 27c2896e1e5ce..9464694a3b55a 100644 --- a/clippy_lints/src/async_yields_async.rs +++ b/clippy_lints/src/async_yields_async.rs @@ -54,7 +54,7 @@ impl<'tcx> LateLintPass<'tcx> for AsyncYieldsAsync { hir_id: body.value.hir_id, }; let typeck_results = cx.tcx.typeck_body(body_id); - let expr_ty = typeck_results.expr_ty(&body.value); + let expr_ty = typeck_results.expr_ty(body.value); if implements_trait(cx, expr_ty, future_trait_def_id, &[]) { let return_expr_span = match &body.value.kind { diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 4bcbeacf9feb5..732dc2b433091 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -475,7 +475,7 @@ fn check_lint_reason(cx: &LateContext<'_>, name: Symbol, items: &[NestedMetaItem fn is_relevant_item(cx: &LateContext<'_>, item: &Item<'_>) -> bool { if let ItemKind::Fn(_, _, eid) = item.kind { - is_relevant_expr(cx, cx.tcx.typeck_body(eid), &cx.tcx.hir().body(eid).value) + is_relevant_expr(cx, cx.tcx.typeck_body(eid), cx.tcx.hir().body(eid).value) } else { true } @@ -483,7 +483,7 @@ fn is_relevant_item(cx: &LateContext<'_>, item: &Item<'_>) -> bool { fn is_relevant_impl(cx: &LateContext<'_>, item: &ImplItem<'_>) -> bool { match item.kind { - ImplItemKind::Fn(_, eid) => is_relevant_expr(cx, cx.tcx.typeck_body(eid), &cx.tcx.hir().body(eid).value), + ImplItemKind::Fn(_, eid) => is_relevant_expr(cx, cx.tcx.typeck_body(eid), cx.tcx.hir().body(eid).value), _ => false, } } @@ -492,7 +492,7 @@ fn is_relevant_trait(cx: &LateContext<'_>, item: &TraitItem<'_>) -> bool { match item.kind { TraitItemKind::Fn(_, TraitFn::Required(_)) => true, TraitItemKind::Fn(_, TraitFn::Provided(eid)) => { - is_relevant_expr(cx, cx.tcx.typeck_body(eid), &cx.tcx.hir().body(eid).value) + is_relevant_expr(cx, cx.tcx.typeck_body(eid), cx.tcx.hir().body(eid).value) }, _ => false, } diff --git a/clippy_lints/src/bool_to_int_with_if.rs b/clippy_lints/src/bool_to_int_with_if.rs new file mode 100644 index 0000000000000..a4b8cbb0d82aa --- /dev/null +++ b/clippy_lints/src/bool_to_int_with_if.rs @@ -0,0 +1,125 @@ +use rustc_ast::{ExprPrecedence, 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, source::snippet_block_with_applicability}; +use rustc_errors::Applicability; + +declare_clippy_lint! { + /// ### What it does + /// Instead of using an if statement to convert a bool to an int, + /// 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. + /// 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 + /// + /// ### Example + /// ```rust + /// # let condition = false; + /// if condition { + /// 1_i64 + /// } else { + /// 0 + /// }; + /// ``` + /// Use instead: + /// ```rust + /// # let condition = false; + /// i64::from(condition); + /// ``` + /// or + /// ```rust + /// # let condition = false; + /// condition as i64; + /// ``` + #[clippy::version = "1.65.0"] + pub BOOL_TO_INT_WITH_IF, + style, + "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_if_else<'tcx>(ctx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) { + if let ExprKind::If(check, then, Some(else_)) = expr.kind + && let Some(then_lit) = int_literal(then) + && let Some(else_lit) = int_literal(else_) + && check_int_literal_equals_val(then_lit, 1) + && check_int_literal_equals_val(else_lit, 0) + { + let mut applicability = Applicability::MachineApplicable; + let snippet = snippet_block_with_applicability(ctx, check.span, "..", None, &mut applicability); + let snippet_with_braces = { + let need_parens = should_have_parentheses(check); + let (left_paren, right_paren) = if need_parens {("(", ")")} else {("", "")}; + format!("{left_paren}{snippet}{right_paren}") + }; + + let ty = ctx.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 (left_curly, right_curly) = if wrap_in_curly {("{", "}")} else {("", "")}; + format!( + "{left_curly}{ty}::from({snippet}){right_curly}" + ) + }; // when used in else clause if statement should be wrapped in curly braces + + span_lint_and_then(ctx, + BOOL_TO_INT_WITH_IF, + expr.span, + "boolean to int conversion using if", + |diag| { + diag.span_suggestion( + expr.span, + "replace with from", + suggestion, + applicability, + ); + diag.note(format!("`{snippet_with_braces} as {ty}` or `{snippet_with_braces}.into()` can also be valid options")); + }); + }; +} + +// If block contains only a int literal expression, return literal expression +fn int_literal<'tcx>(expr: &'tcx rustc_hir::Expr<'tcx>) -> Option<&'tcx rustc_hir::Expr<'tcx>> { + if let ExprKind::Block(block, _) = expr.kind + && let Block { + stmts: [], // Shouldn't lint if statements with side effects + expr: Some(expr), + .. + } = block + && let ExprKind::Lit(lit) = &expr.kind + && let LitKind::Int(_, _) = lit.node + { + Some(expr) + } else { + None + } +} + +fn check_int_literal_equals_val<'tcx>(expr: &'tcx rustc_hir::Expr<'tcx>, expected_value: u128) -> bool { + if let ExprKind::Lit(lit) = &expr.kind + && let LitKind::Int(val, _) = lit.node + && val == expected_value + { + true + } else { + false + } +} + +fn should_have_parentheses<'tcx>(check: &'tcx rustc_hir::Expr<'tcx>) -> bool { + check.precedence().order() < ExprPrecedence::Cast.order() +} diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs index 64c5de5104206..be02f328e989a 100644 --- a/clippy_lints/src/default_numeric_fallback.rs +++ b/clippy_lints/src/default_numeric_fallback.rs @@ -69,7 +69,10 @@ struct NumericFallbackVisitor<'a, 'tcx> { impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> { fn new(cx: &'a LateContext<'tcx>) -> Self { - Self { ty_bounds: vec![TyBound::Nothing], cx } + Self { + ty_bounds: vec![TyBound::Nothing], + cx, + } } /// Check whether a passed literal has potential to cause fallback or not. @@ -126,21 +129,19 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> { } return; } - } + }, ExprKind::MethodCall(_, receiver, args, _) => { if let Some(def_id) = self.cx.typeck_results().type_dependent_def_id(expr.hir_id) { let fn_sig = self.cx.tcx.fn_sig(def_id).skip_binder(); - for (expr, bound) in - iter::zip(std::iter::once(*receiver).chain(args.iter()), fn_sig.inputs()) - { + for (expr, bound) in iter::zip(std::iter::once(*receiver).chain(args.iter()), fn_sig.inputs()) { self.ty_bounds.push(TyBound::Ty(*bound)); self.visit_expr(expr); self.ty_bounds.pop(); } return; } - } + }, ExprKind::Struct(_, fields, base) => { let ty = self.cx.typeck_results().expr_ty(expr); @@ -175,15 +176,15 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> { return; } } - } + }, ExprKind::Lit(lit) => { let ty = self.cx.typeck_results().expr_ty(expr); self.check_lit(lit, ty, expr.hir_id); return; - } + }, - _ => {} + _ => {}, } walk_expr(self, expr); @@ -197,7 +198,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> { } else { self.ty_bounds.push(TyBound::Nothing); } - } + }, _ => self.ty_bounds.push(TyBound::Nothing), } diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index d1ab7fb67962e..88e28018e5d00 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -830,25 +830,22 @@ fn walk_parents<'tcx>( ) { return Some(Position::MethodReceiverRefImpl) - } else { - return Some(Position::MethodReceiver) } + return Some(Position::MethodReceiver); } - 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() { - needless_borrow_impl_arg_position(cx, parent, i + 1, *param_ty, e, precedence, msrv) - } else { - ty_auto_deref_stability( - cx, - cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i + 1)), - precedence, - ) - .position_for_arg() - } - }) + 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() { + needless_borrow_impl_arg_position(cx, parent, i + 1, *param_ty, e, precedence, msrv) + } else { + ty_auto_deref_stability( + cx, + cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i + 1)), + precedence, + ) + .position_for_arg() + } + }) }, ExprKind::Field(child, name) if child.hir_id == e.hir_id => Some(Position::FieldAccess(name.name)), ExprKind::Unary(UnOp::Deref, child) if child.hir_id == e.hir_id => Some(Position::Deref), diff --git a/clippy_lints/src/derivable_impls.rs b/clippy_lints/src/derivable_impls.rs index 4d7f4076d7b51..ef9eeecc6a934 100644 --- a/clippy_lints/src/derivable_impls.rs +++ b/clippy_lints/src/derivable_impls.rs @@ -40,7 +40,7 @@ declare_clippy_lint! { /// /// ### Known problems /// Derive macros [sometimes use incorrect bounds](https://github.com/rust-lang/rust/issues/26925) - /// in generic types and the user defined `impl` maybe is more generalized or + /// in generic types and the user defined `impl` may be more generalized or /// specialized than what derive will produce. This lint can't detect the manual `impl` /// has exactly equal bounds, and therefore this lint is disabled for types with /// generic parameters. diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index 512872cedc1ea..eb158d850fa72 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -236,7 +236,7 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown { typeck_results: cx.tcx.typeck(item.def_id), panic_span: None, }; - fpu.visit_expr(&body.value); + fpu.visit_expr(body.value); lint_for_missing_headers(cx, item.def_id, item.span, sig, headers, Some(body_id), fpu.panic_span); } }, @@ -286,7 +286,7 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown { typeck_results: cx.tcx.typeck(item.def_id), panic_span: None, }; - fpu.visit_expr(&body.value); + fpu.visit_expr(body.value); lint_for_missing_headers(cx, item.def_id, item.span, sig, headers, Some(body_id), fpu.panic_span); } } @@ -348,7 +348,7 @@ fn lint_for_missing_headers<'tcx>( if let Some(future) = cx.tcx.lang_items().future_trait(); let typeck = cx.tcx.typeck_body(body_id); let body = cx.tcx.hir().body(body_id); - let ret_ty = typeck.expr_ty(&body.value); + let ret_ty = typeck.expr_ty(body.value); if implements_trait(cx, ret_ty, future, &[]); if let ty::Opaque(_, subs) = ret_ty.kind(); if let Some(gen) = subs.types().next(); @@ -828,7 +828,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> { // check for `unwrap` if let Some(arglists) = method_chain_args(expr, &["unwrap"]) { - let receiver_ty = self.typeck_results.expr_ty(&arglists[0].0).peel_refs(); + let receiver_ty = self.typeck_results.expr_ty(arglists[0].0).peel_refs(); if is_type_diagnostic_item(self.cx, receiver_ty, sym::Option) || is_type_diagnostic_item(self.cx, receiver_ty, sym::Result) { diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index 1342a4697b991..53bc617a4f5b7 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -83,7 +83,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction { }; if body.value.span.from_expansion() { if body.params.is_empty() { - if let Some(VecArgs::Vec(&[])) = higher::VecArgs::hir(cx, &body.value) { + if let Some(VecArgs::Vec(&[])) = higher::VecArgs::hir(cx, body.value) { // replace `|| vec![]` with `Vec::new` span_lint_and_sugg( cx, @@ -103,7 +103,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction { let closure_ty = cx.typeck_results().expr_ty(expr); if_chain!( - if !is_adjusted(cx, &body.value); + if !is_adjusted(cx, body.value); if let ExprKind::Call(callee, args) = body.value.kind; if let ExprKind::Path(_) = callee.kind; if check_inputs(cx, body.params, None, args); @@ -145,7 +145,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction { ); if_chain!( - if !is_adjusted(cx, &body.value); + if !is_adjusted(cx, body.value); if let ExprKind::MethodCall(path, receiver, args, _) = body.value.kind; if check_inputs(cx, body.params, Some(receiver), args); let method_def_id = cx.typeck_results().type_dependent_def_id(body.value.hir_id).unwrap(); @@ -206,8 +206,7 @@ fn check_inputs( _ => false, } }; - std::iter::zip(params, receiver.into_iter().chain(call_args.iter())) - .all(|(param, arg)| check_inputs(param, arg)) + std::iter::zip(params, receiver.into_iter().chain(call_args.iter())).all(|(param, arg)| check_inputs(param, arg)) } fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure_ty: Ty<'tcx>, call_ty: Ty<'tcx>) -> bool { diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs index 790eea63f58c4..1f69f34a229df 100644 --- a/clippy_lints/src/fallible_impl_from.rs +++ b/clippy_lints/src/fallible_impl_from.rs @@ -84,7 +84,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_items: &[h // check for `unwrap` if let Some(arglists) = method_chain_args(expr, &["unwrap"]) { - let receiver_ty = self.typeck_results.expr_ty(&arglists[0].0).peel_refs(); + let receiver_ty = self.typeck_results.expr_ty(arglists[0].0).peel_refs(); if is_type_diagnostic_item(self.lcx, receiver_ty, sym::Option) || is_type_diagnostic_item(self.lcx, receiver_ty, sym::Result) { @@ -110,7 +110,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_items: &[h typeck_results: cx.tcx.typeck(impl_item.id.def_id), result: Vec::new(), }; - fpu.visit_expr(&body.value); + fpu.visit_expr(body.value); // if we've found one, lint if !fpu.result.is_empty() { diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index 728db41d60043..ba53a9678801c 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -238,23 +238,23 @@ fn get_integer_from_float_constant(value: &Constant) -> Option { fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) { // Check receiver if let Some((value, _)) = constant(cx, cx.typeck_results(), receiver) { - let method = if F32(f32_consts::E) == value || F64(f64_consts::E) == value { - "exp" + if let Some(method) = if F32(f32_consts::E) == value || F64(f64_consts::E) == value { + Some("exp") } else if F32(2.0) == value || F64(2.0) == value { - "exp2" + Some("exp2") } else { - return; - }; - - span_lint_and_sugg( - cx, - SUBOPTIMAL_FLOPS, - expr.span, - "exponent for bases 2 and e can be computed more accurately", - "consider using", - format!("{}.{}()", prepare_receiver_sugg(cx, &args[0]), method), - Applicability::MachineApplicable, - ); + None + } { + span_lint_and_sugg( + cx, + SUBOPTIMAL_FLOPS, + expr.span, + "exponent for bases 2 and e can be computed more accurately", + "consider using", + format!("{}.{}()", prepare_receiver_sugg(cx, &args[0]), method), + Applicability::MachineApplicable, + ); + } } // Check argument diff --git a/clippy_lints/src/functions/must_use.rs b/clippy_lints/src/functions/must_use.rs index a17b23f5edc86..00a4937763eb5 100644 --- a/clippy_lints/src/functions/must_use.rs +++ b/clippy_lints/src/functions/must_use.rs @@ -272,6 +272,6 @@ fn mutates_static<'tcx>(cx: &LateContext<'tcx>, body: &'tcx hir::Body<'_>) -> bo cx, mutates_static: false, }; - intravisit::walk_expr(&mut v, &body.value); + intravisit::walk_expr(&mut v, body.value); v.mutates_static } diff --git a/clippy_lints/src/functions/result.rs b/clippy_lints/src/functions/result.rs index af520a493eda1..9591405cb06f7 100644 --- a/clippy_lints/src/functions/result.rs +++ b/clippy_lints/src/functions/result.rs @@ -4,7 +4,6 @@ use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty}; use rustc_span::{sym, Span}; -use rustc_typeck::hir_ty_to_ty; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; use clippy_utils::trait_ref_of_method; @@ -17,11 +16,12 @@ use super::{RESULT_LARGE_ERR, RESULT_UNIT_ERR}; fn result_err_ty<'tcx>( cx: &LateContext<'tcx>, decl: &hir::FnDecl<'tcx>, + id: hir::def_id::LocalDefId, item_span: Span, ) -> Option<(&'tcx hir::Ty<'tcx>, Ty<'tcx>)> { if !in_external_macro(cx.sess(), item_span) && let hir::FnRetTy::Return(hir_ty) = decl.output - && let ty = hir_ty_to_ty(cx.tcx, hir_ty) + && let ty = cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).output()) && is_type_diagnostic_item(cx, ty, sym::Result) && let ty::Adt(_, substs) = ty.kind() { @@ -34,7 +34,7 @@ fn result_err_ty<'tcx>( pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::Item<'tcx>, large_err_threshold: u64) { if let hir::ItemKind::Fn(ref sig, _generics, _) = item.kind - && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.span) + && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.def_id, item.span) { if cx.access_levels.is_exported(item.def_id) { let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); @@ -47,7 +47,7 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::Item<'tcx>, l pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::ImplItem<'tcx>, large_err_threshold: u64) { // Don't lint if method is a trait's implementation, we can't do anything about those if let hir::ImplItemKind::Fn(ref sig, _) = item.kind - && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.span) + && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.def_id, item.span) && trait_ref_of_method(cx, item.def_id).is_none() { if cx.access_levels.is_exported(item.def_id) { @@ -61,7 +61,7 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::ImplItem pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::TraitItem<'tcx>, large_err_threshold: u64) { if let hir::TraitItemKind::Fn(ref sig, _) = item.kind { let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); - if let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.span) { + if let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.def_id, item.span) { if cx.access_levels.is_exported(item.def_id) { check_result_unit_err(cx, err_ty, fn_header_span); } diff --git a/clippy_lints/src/implicit_return.rs b/clippy_lints/src/implicit_return.rs index a6610ade37e56..feec8ec2e23f8 100644 --- a/clippy_lints/src/implicit_return.rs +++ b/clippy_lints/src/implicit_return.rs @@ -232,7 +232,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitReturn { return; } - let res_ty = cx.typeck_results().expr_ty(&body.value); + let res_ty = cx.typeck_results().expr_ty(body.value); if res_ty.is_unit() || res_ty.is_never() { return; } @@ -243,7 +243,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitReturn { None => return, } } else { - &body.value + body.value }; lint_implicit_returns(cx, expr, expr.span.ctxt(), None); } diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs index d55a8e1ead17d..8c2c96fa105af 100644 --- a/clippy_lints/src/infinite_iter.rs +++ b/clippy_lints/src/infinite_iter.rs @@ -59,7 +59,7 @@ impl<'tcx> LateLintPass<'tcx> for InfiniteIter { MaybeInfinite => (MAYBE_INFINITE_ITER, "possible infinite iteration detected"), Finite => { return; - } + }, }; span_lint(cx, lint, expr.span, msg); } @@ -161,7 +161,7 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { if method.ident.name == sym!(flat_map) && args.len() == 1 { if let ExprKind::Closure(&Closure { body, .. }) = args[0].kind { let body = cx.tcx.hir().body(body); - return is_infinite(cx, &body.value); + return is_infinite(cx, body.value); } } Finite @@ -230,8 +230,10 @@ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { } } if method.ident.name == sym!(last) && args.is_empty() { - let not_double_ended = - cx.tcx.get_diagnostic_item(sym::DoubleEndedIterator).map_or(false, |id| { + let not_double_ended = cx + .tcx + .get_diagnostic_item(sym::DoubleEndedIterator) + .map_or(false, |id| { !implements_trait(cx, cx.typeck_results().expr_ty(receiver), id, &[]) }); if not_double_ended { diff --git a/clippy_lints/src/large_enum_variant.rs b/clippy_lints/src/large_enum_variant.rs index c58df126d6244..eb13d0869c037 100644 --- a/clippy_lints/src/large_enum_variant.rs +++ b/clippy_lints/src/large_enum_variant.rs @@ -1,13 +1,12 @@ //! 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::is_copy}; +use clippy_utils::{diagnostics::span_lint_and_then, ty::approx_ty_size, ty::is_copy}; 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::layout::LayoutOf; -use rustc_middle::ty::{Adt, Ty}; +use rustc_middle::ty::{Adt, AdtDef, GenericArg, List, Ty}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; @@ -17,7 +16,7 @@ declare_clippy_lint! { /// `enum`s. /// /// ### Why is this bad? - /// Enum size is bounded by the largest variant. Having a + /// Enum size is bounded by the largest variant. Having one /// large variant can penalize the memory layout of that enum. /// /// ### Known problems @@ -33,8 +32,9 @@ declare_clippy_lint! { /// use case it may be possible to store the large data in an auxiliary /// structure (e.g. Arena or ECS). /// - /// The lint will ignore generic types if the layout depends on the - /// generics, even if the size difference will be large anyway. + /// The lint will ignore the impact of generic types to the type layout by + /// assuming every type parameter is zero-sized. Depending on your use case, + /// this may lead to a false positive. /// /// ### Example /// ```rust @@ -83,6 +83,38 @@ struct VariantInfo { fields_size: Vec, } +fn variants_size<'tcx>( + cx: &LateContext<'tcx>, + adt: AdtDef<'tcx>, + subst: &'tcx List>, +) -> Vec { + 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::>(); + 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::>(); + 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 { @@ -92,36 +124,14 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant { } if let ItemKind::Enum(ref def, _) = item.kind { let ty = cx.tcx.type_of(item.def_id); - let adt = ty.ty_adt_def().expect("already checked whether this is an enum"); + let (adt, subst) = match ty.kind() { + Adt(adt, subst) => (adt, subst), + _ => panic!("already checked whether this is an enum"), + }; if adt.variants().len() <= 1 { return; } - let mut variants_size: Vec = Vec::new(); - for (i, variant) in adt.variants().iter().enumerate() { - let mut fields_size = Vec::new(); - for (i, f) in variant.fields.iter().enumerate() { - let ty = cx.tcx.type_of(f.did); - // don't lint variants which have a field of generic type. - match cx.layout_of(ty) { - Ok(l) => { - let fsize = l.size.bytes(); - fields_size.push(FieldInfo { ind: i, size: fsize }); - }, - Err(_) => { - return; - }, - } - } - let size: u64 = fields_size.iter().map(|info| info.size).sum(); - - variants_size.push(VariantInfo { - ind: i, - size, - fields_size, - }); - } - - variants_size.sort_by(|a, b| (b.size.cmp(&a.size))); + let variants_size = variants_size(cx, *adt, subst); let mut difference = variants_size[0].size - variants_size[1].size; if difference > self.maximum_size_difference_allowed { @@ -129,20 +139,30 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant { span_lint_and_then( cx, LARGE_ENUM_VARIANT, - def.variants[variants_size[0].ind].span, + item.span, "large size difference between variants", |diag| { + diag.span_label( + item.span, + format!("the entire enum is at least {} bytes", approx_ty_size(cx, ty)), + ); diag.span_label( def.variants[variants_size[0].ind].span, - &format!("this variant is {} bytes", variants_size[0].size), + format!("the largest variant contains at least {} bytes", variants_size[0].size), ); - diag.span_note( + diag.span_label( def.variants[variants_size[1].ind].span, - &format!("and the second-largest variant is {} bytes:", variants_size[1].size), + &if variants_size[1].fields_size.is_empty() { + "the second-largest variant carries no data at all".to_owned() + } else { + format!( + "the second-largest variant contains at least {} bytes", + variants_size[1].size + ) + }, ); let fields = def.variants[variants_size[0].ind].data.fields(); - variants_size[0].fields_size.sort_by(|a, b| (a.size.cmp(&b.size))); let mut applicability = Applicability::MaybeIncorrect; if is_copy(cx, ty) || maybe_copy(cx, ty) { diag.span_note( diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 3cbdaff407b04..7ae8ef830faea 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -370,7 +370,8 @@ 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(ref 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" { @@ -378,12 +379,23 @@ fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_> } } - check_len(cx, span, method_path.ident.name, receiver, args, &lit.node, op, compare_to); + check_len( + cx, + span, + method_path.ident.name, + receiver, + args, + &lit.node, + op, + compare_to, + ); } else { check_empty_expr(cx, span, method, lit, op); } } +// FIXME(flip1995): Figure out how to reduce the number of arguments +#[allow(clippy::too_many_arguments)] fn check_len( cx: &LateContext<'_>, span: Span, diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index 134cbbf7b5c66..1f85382347aa1 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -17,6 +17,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ 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), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index fd20e016578a1..962e67220069a 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -56,6 +56,7 @@ store.register_lints(&[ 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, @@ -436,7 +437,7 @@ store.register_lints(&[ octal_escapes::OCTAL_ESCAPES, only_used_in_recursion::ONLY_USED_IN_RECURSION, operators::ABSURD_EXTREME_COMPARISONS, - operators::ARITHMETIC, + operators::ARITHMETIC_SIDE_EFFECTS, operators::ASSIGN_OP_PATTERN, operators::BAD_BIT_MASK, operators::CMP_NAN, diff --git a/clippy_lints/src/lib.register_restriction.rs b/clippy_lints/src/lib.register_restriction.rs index dd1e1e1a8e33d..6eb9b3d3b9b7a 100644 --- a/clippy_lints/src/lib.register_restriction.rs +++ b/clippy_lints/src/lib.register_restriction.rs @@ -50,7 +50,7 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve 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), + LintId::of(operators::ARITHMETIC_SIDE_EFFECTS), LintId::of(operators::FLOAT_ARITHMETIC), LintId::of(operators::FLOAT_CMP_CONST), LintId::of(operators::INTEGER_ARITHMETIC), diff --git a/clippy_lints/src/lib.register_style.rs b/clippy_lints/src/lib.register_style.rs index b5cb078e7a3cc..05d2ec2e9e1e6 100644 --- a/clippy_lints/src/lib.register_style.rs +++ b/clippy_lints/src/lib.register_style.rs @@ -6,6 +6,7 @@ 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), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index c70aa79ac8dcf..e984254bf2919 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -179,6 +179,7 @@ mod attrs; mod await_holding_invalid; mod blocks_in_if_conditions; mod bool_assert_comparison; +mod bool_to_int_with_if; mod booleans; mod borrow_deref_ref; mod cargo; @@ -523,7 +524,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: #[cfg(feature = "internal")] { if std::env::var("ENABLE_METADATA_COLLECTION").eq(&Ok("1".to_string())) { - store.register_late_pass(|_| Box::new(utils::internal_lints::metadata_collector::MetadataCollector::new())); + store.register_late_pass(|| Box::new(utils::internal_lints::metadata_collector::MetadataCollector::new())); return; } } @@ -544,8 +545,12 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(utils::internal_lints::MsrvAttrImpl)); } - let arithmetic_allowed = conf.arithmetic_allowed.clone(); - store.register_late_pass(move |_| Box::new(operators::arithmetic::Arithmetic::new(arithmetic_allowed.clone()))); + let arithmetic_side_effects_allowed = conf.arithmetic_side_effects_allowed.clone(); + store.register_late_pass(move |_| { + Box::new(operators::arithmetic_side_effects::ArithmeticSideEffects::new( + arithmetic_side_effects_allowed.clone(), + )) + }); store.register_late_pass(|_| Box::new(utils::dump_hir::DumpHir)); store.register_late_pass(|_| Box::new(utils::author::Author)); let await_holding_invalid_types = conf.await_holding_invalid_types.clone(); @@ -901,6 +906,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(manual_string_new::ManualStringNew)); store.register_late_pass(|_| Box::new(unused_peekable::UnusedPeekable)); store.register_early_pass(|| Box::new(multi_assignments::MultiAssignments)); + store.register_late_pass(|_| Box::new(bool_to_int_with_if::BoolToIntWithIf)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 5995675bd969c..f2b6e0b7ef9ba 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -276,7 +276,7 @@ fn could_use_elision<'tcx>( let mut checker = BodyLifetimeChecker { lifetimes_used_in_body: false, }; - checker.visit_expr(&body.value); + checker.visit_expr(body.value); if checker.lifetimes_used_in_body { return false; } diff --git a/clippy_lints/src/loops/needless_range_loop.rs b/clippy_lints/src/loops/needless_range_loop.rs index ffcf83e4605e2..8ab640051b635 100644 --- a/clippy_lints/src/loops/needless_range_loop.rs +++ b/clippy_lints/src/loops/needless_range_loop.rs @@ -373,7 +373,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> { }, ExprKind::Closure(&Closure { body, .. }) => { let body = self.cx.tcx.hir().body(body); - self.visit_expr(&body.value); + self.visit_expr(body.value); }, _ => walk_expr(self, expr), } diff --git a/clippy_lints/src/loops/while_let_on_iterator.rs b/clippy_lints/src/loops/while_let_on_iterator.rs index 2c54033f85975..deb21894f36a9 100644 --- a/clippy_lints/src/loops/while_let_on_iterator.rs +++ b/clippy_lints/src/loops/while_let_on_iterator.rs @@ -356,7 +356,7 @@ fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: & after_loop: false, used_iter: false, }; - v.visit_expr(&cx.tcx.hir().body(cx.enclosing_body.unwrap()).value); + v.visit_expr(cx.tcx.hir().body(cx.enclosing_body.unwrap()).value); v.used_iter } } diff --git a/clippy_lints/src/matches/match_wild_err_arm.rs b/clippy_lints/src/matches/match_wild_err_arm.rs index bc16f17b6196e..a3aa2e4b389af 100644 --- a/clippy_lints/src/matches/match_wild_err_arm.rs +++ b/clippy_lints/src/matches/match_wild_err_arm.rs @@ -40,7 +40,7 @@ pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm<' arm.pat.span, &format!("`Err({})` matches all errors", ident_bind_name), None, - "match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable", + "match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable", ); } } diff --git a/clippy_lints/src/matches/single_match.rs b/clippy_lints/src/matches/single_match.rs index 1bf1c4d107895..56bcdc01fe4d6 100644 --- a/clippy_lints/src/matches/single_match.rs +++ b/clippy_lints/src/matches/single_match.rs @@ -203,12 +203,8 @@ fn form_exhaustive_matches<'a>(cx: &LateContext<'a>, ty: Ty<'a>, left: &Pat<'_>, let left_pos = left_pos.as_opt_usize(); let right_pos = right_pos.as_opt_usize(); let len = max( - left_in.len() + { - if left_pos.is_some() { 1 } else { 0 } - }, - right_in.len() + { - if right_pos.is_some() { 1 } else { 0 } - }, + left_in.len() + usize::from(left_pos.is_some()), + right_in.len() + usize::from(right_pos.is_some()), ); let mut left_pos = left_pos.unwrap_or(usize::MAX); let mut right_pos = right_pos.unwrap_or(usize::MAX); diff --git a/clippy_lints/src/methods/bind_instead_of_map.rs b/clippy_lints/src/methods/bind_instead_of_map.rs index 2f117e4dcc374..22f5635a5bccb 100644 --- a/clippy_lints/src/methods/bind_instead_of_map.rs +++ b/clippy_lints/src/methods/bind_instead_of_map.rs @@ -152,7 +152,7 @@ pub(crate) trait BindInsteadOfMap { match arg.kind { hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }) => { let closure_body = cx.tcx.hir().body(body); - let closure_expr = peel_blocks(&closure_body.value); + let closure_expr = peel_blocks(closure_body.value); if Self::lint_closure_autofixable(cx, expr, recv, closure_expr, fn_decl_span) { true diff --git a/clippy_lints/src/methods/chars_cmp.rs b/clippy_lints/src/methods/chars_cmp.rs index 51aec21527a71..b2bc1ad5c9ed0 100644 --- a/clippy_lints/src/methods/chars_cmp.rs +++ b/clippy_lints/src/methods/chars_cmp.rs @@ -23,7 +23,7 @@ pub(super) fn check( if Some(id) == cx.tcx.lang_items().option_some_variant(); then { let mut applicability = Applicability::MachineApplicable; - let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0].0).peel_refs(); + let self_ty = cx.typeck_results().expr_ty_adjusted(args[0].0).peel_refs(); if *self_ty.kind() != ty::Str { return false; diff --git a/clippy_lints/src/methods/clone_on_copy.rs b/clippy_lints/src/methods/clone_on_copy.rs index f5bead387d7bd..7ab6b84c20749 100644 --- a/clippy_lints/src/methods/clone_on_copy.rs +++ b/clippy_lints/src/methods/clone_on_copy.rs @@ -21,7 +21,11 @@ pub(super) fn check( receiver: &Expr<'_>, args: &[Expr<'_>], ) { - let arg = if method_name == sym::clone && args.is_empty() { receiver } else { return }; + let arg = if method_name == sym::clone && args.is_empty() { + receiver + } else { + return; + }; if cx .typeck_results() .type_dependent_def_id(expr.hir_id) diff --git a/clippy_lints/src/methods/filter_map.rs b/clippy_lints/src/methods/filter_map.rs index 9dc839afc6256..9719b2f1c5125 100644 --- a/clippy_lints/src/methods/filter_map.rs +++ b/clippy_lints/src/methods/filter_map.rs @@ -25,7 +25,7 @@ fn is_method<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Sy }, hir::ExprKind::Closure(&hir::Closure { body, .. }) => { let body = cx.tcx.hir().body(body); - let closure_expr = peel_blocks(&body.value); + let closure_expr = peel_blocks(body.value); let arg_id = body.params[0].pat.hir_id; match closure_expr.kind { hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, receiver, ..) => { diff --git a/clippy_lints/src/methods/map_clone.rs b/clippy_lints/src/methods/map_clone.rs index e8442091fd306..8261ef5e1ce34 100644 --- a/clippy_lints/src/methods/map_clone.rs +++ b/clippy_lints/src/methods/map_clone.rs @@ -30,7 +30,7 @@ pub(super) fn check<'tcx>( if let hir::ExprKind::Closure(&hir::Closure{ body, .. }) = arg.kind; then { let closure_body = cx.tcx.hir().body(body); - let closure_expr = peel_blocks(&closure_body.value); + let closure_expr = peel_blocks(closure_body.value); match closure_body.params[0].pat.kind { hir::PatKind::Ref(inner, hir::Mutability::Not) => if let hir::PatKind::Binding( hir::BindingAnnotation::NONE, .., name, None diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 48a9d6e7c329e..41942b20ea163 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -825,8 +825,9 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does /// Checks for calls to `.or(foo(..))`, `.unwrap_or(foo(..))`, - /// etc., and suggests to use `or_else`, `unwrap_or_else`, etc., or - /// `unwrap_or_default` instead. + /// `.or_insert(foo(..))` etc., and suggests to use `.or_else(|| foo(..))`, + /// `.unwrap_or_else(|| foo(..))`, `.unwrap_or_default()` or `.or_default()` + /// etc. instead. /// /// ### Why is this bad? /// The function will always be called and potentially diff --git a/clippy_lints/src/methods/mut_mutex_lock.rs b/clippy_lints/src/methods/mut_mutex_lock.rs index bd8458a222e29..b9593b3687d9c 100644 --- a/clippy_lints/src/methods/mut_mutex_lock.rs +++ b/clippy_lints/src/methods/mut_mutex_lock.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{expr_custom_deref_adjustment, ty::is_type_diagnostic_item}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability}; @@ -11,6 +11,7 @@ use super::MUT_MUTEX_LOCK; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'tcx>, recv: &'tcx Expr<'tcx>, name_span: Span) { if_chain! { + if matches!(expr_custom_deref_adjustment(cx, recv), None | Some(Mutability::Mut)); if let ty::Ref(_, _, Mutability::Mut) = cx.typeck_results().expr_ty(recv).kind(); if let Some(method_id) = cx.typeck_results().type_dependent_def_id(ex.hir_id); if let Some(impl_id) = cx.tcx.impl_of_method(method_id); diff --git a/clippy_lints/src/methods/open_options.rs b/clippy_lints/src/methods/open_options.rs index 903fa306f935a..597af853dc681 100644 --- a/clippy_lints/src/methods/open_options.rs +++ b/clippy_lints/src/methods/open_options.rs @@ -40,7 +40,7 @@ fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec let obj_ty = cx.typeck_results().expr_ty(receiver).peel_refs(); // Only proceed if this is a call on some object of type std::fs::OpenOptions - if match_type(cx, obj_ty, &paths::OPEN_OPTIONS) && arguments.len() >= 1 { + if match_type(cx, obj_ty, &paths::OPEN_OPTIONS) && !arguments.is_empty() { let argument_option = match arguments[0].kind { ExprKind::Lit(ref span) => { if let Spanned { diff --git a/clippy_lints/src/methods/option_as_ref_deref.rs b/clippy_lints/src/methods/option_as_ref_deref.rs index 81c67b4ca6a59..c409268de769d 100644 --- a/clippy_lints/src/methods/option_as_ref_deref.rs +++ b/clippy_lints/src/methods/option_as_ref_deref.rs @@ -53,7 +53,7 @@ pub(super) fn check<'tcx>( }), hir::ExprKind::Closure(&hir::Closure { body, .. }) => { let closure_body = cx.tcx.hir().body(body); - let closure_expr = peel_blocks(&closure_body.value); + let closure_expr = peel_blocks(closure_body.value); match &closure_expr.kind { hir::ExprKind::MethodCall(_, receiver, [], _) => { diff --git a/clippy_lints/src/methods/option_map_or_none.rs b/clippy_lints/src/methods/option_map_or_none.rs index 5a39b82b027d1..6657cdccd010c 100644 --- a/clippy_lints/src/methods/option_map_or_none.rs +++ b/clippy_lints/src/methods/option_map_or_none.rs @@ -74,7 +74,7 @@ pub(super) fn check<'tcx>( if let hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }) = map_arg.kind; let arg_snippet = snippet(cx, fn_decl_span, ".."); let body = cx.tcx.hir().body(body); - if let Some((func, [arg_char])) = reduce_unit_expression(&body.value); + if let Some((func, [arg_char])) = reduce_unit_expression(body.value); if let Some(id) = path_def_id(cx, func).map(|ctor_id| cx.tcx.parent(ctor_id)); if Some(id) == cx.tcx.lang_items().option_some_variant(); then { diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index 76876d8662936..b43b9258c471d 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -23,7 +23,8 @@ pub(super) fn check<'tcx>( receiver: &'tcx hir::Expr<'_>, args: &'tcx [hir::Expr<'_>], ) { - /// Checks for `unwrap_or(T::new())` or `unwrap_or(T::default())`. + /// Checks for `unwrap_or(T::new())`, `unwrap_or(T::default())`, + /// `or_insert(T::new())` or `or_insert(T::default())`. #[allow(clippy::too_many_arguments)] fn check_unwrap_or_default( cx: &LateContext<'_>, @@ -43,7 +44,11 @@ pub(super) fn check<'tcx>( if_chain! { if !or_has_args; - if name == "unwrap_or"; + if let Some(sugg) = match name { + "unwrap_or" => Some("unwrap_or_default"), + "or_insert" => Some("or_default"), + _ => None, + }; if let hir::ExprKind::Path(ref qpath) = fun.kind; if let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default); let path = last_path_segment(qpath).ident.name; @@ -59,7 +64,7 @@ pub(super) fn check<'tcx>( method_span.with_hi(span.hi()), &format!("use of `{}` followed by a call to `{}`", name, path), "try this", - "unwrap_or_default()".to_string(), + format!("{}()", sugg), Applicability::MachineApplicable, ); @@ -83,7 +88,7 @@ pub(super) fn check<'tcx>( fun_span: Option, ) { // (path, fn_has_argument, methods, suffix) - static KNOW_TYPES: [(&[&str], bool, &[&str], &str); 4] = [ + const KNOW_TYPES: [(&[&str], bool, &[&str], &str); 4] = [ (&paths::BTREEMAP_ENTRY, false, &["or_insert"], "with"), (&paths::HASHMAP_ENTRY, false, &["or_insert"], "with"), (&paths::OPTION, false, &["map_or", "ok_or", "or", "unwrap_or"], "else"), diff --git a/clippy_lints/src/methods/suspicious_map.rs b/clippy_lints/src/methods/suspicious_map.rs index 9c3375bf35e7d..851cdf544550f 100644 --- a/clippy_lints/src/methods/suspicious_map.rs +++ b/clippy_lints/src/methods/suspicious_map.rs @@ -15,9 +15,9 @@ pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, count_recv: &hi if let Some(def_id) = cx.tcx.hir().opt_local_def_id(closure.hir_id); if let Some(body_id) = cx.tcx.hir().maybe_body_owned_by(def_id); let closure_body = cx.tcx.hir().body(body_id); - if !cx.typeck_results().expr_ty(&closure_body.value).is_unit(); + if !cx.typeck_results().expr_ty(closure_body.value).is_unit(); then { - if let Some(map_mutated_vars) = mutated_variables(&closure_body.value, cx) { + if let Some(map_mutated_vars) = mutated_variables(closure_body.value, cx) { // A variable is used mutably inside of the closure. Suppress the lint. if !map_mutated_vars.is_empty() { return; diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs index bafa6fc584d48..4e8c201f470ba 100644 --- a/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -21,14 +21,13 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr< if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = arg.kind { let body = cx.tcx.hir().body(body); let arg_id = body.params[0].pat.hir_id; - let mutates_arg = - mutated_variables(&body.value, cx).map_or(true, |used_mutably| used_mutably.contains(&arg_id)); - let (clone_or_copy_needed, _) = clone_or_copy_needed(cx, body.params[0].pat, &body.value); + let mutates_arg = mutated_variables(body.value, cx).map_or(true, |used_mutably| used_mutably.contains(&arg_id)); + let (clone_or_copy_needed, _) = clone_or_copy_needed(cx, body.params[0].pat, body.value); - let (mut found_mapping, mut found_filtering) = check_expression(cx, arg_id, &body.value); + let (mut found_mapping, mut found_filtering) = check_expression(cx, arg_id, body.value); let mut return_visitor = ReturnVisitor::new(cx, arg_id); - return_visitor.visit_expr(&body.value); + return_visitor.visit_expr(body.value); found_mapping |= return_visitor.found_mapping; found_filtering |= return_visitor.found_filtering; @@ -36,7 +35,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr< let sugg = if !found_filtering { if name == "filter_map" { "map" } else { "map(..).next()" } } else if !found_mapping && !mutates_arg && (!clone_or_copy_needed || is_copy(cx, in_ty)) { - match cx.typeck_results().expr_ty(&body.value).kind() { + match cx.typeck_results().expr_ty(body.value).kind() { ty::Adt(adt, subst) if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) && in_ty == subst.type_at(0) => { diff --git a/clippy_lints/src/methods/unnecessary_fold.rs b/clippy_lints/src/methods/unnecessary_fold.rs index c3531d4d0511e..c17ef6809f912 100644 --- a/clippy_lints/src/methods/unnecessary_fold.rs +++ b/clippy_lints/src/methods/unnecessary_fold.rs @@ -31,7 +31,7 @@ pub(super) fn check( // Extract the body of the closure passed to fold if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = acc.kind; let closure_body = cx.tcx.hir().body(body); - let closure_expr = peel_blocks(&closure_body.value); + let closure_expr = peel_blocks(closure_body.value); // Check if the closure body is of the form `acc some_expr(x)` if let hir::ExprKind::Binary(ref bin_op, left_expr, right_expr) = closure_expr.kind; diff --git a/clippy_lints/src/methods/unnecessary_sort_by.rs b/clippy_lints/src/methods/unnecessary_sort_by.rs index 6f25acca1de61..ed5a75b0f3ce5 100644 --- a/clippy_lints/src/methods/unnecessary_sort_by.rs +++ b/clippy_lints/src/methods/unnecessary_sort_by.rs @@ -131,7 +131,7 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Exp ] = &closure_body.params; if let ExprKind::MethodCall(method_path, left_expr, [right_expr], _) = closure_body.value.kind; if method_path.ident.name == sym::cmp; - if is_trait_method(cx, &closure_body.value, sym::Ord); + if is_trait_method(cx, closure_body.value, sym::Ord); then { let (closure_body, closure_arg, reverse) = if mirrored_exprs( left_expr, diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index 85da97a39f9a1..763bfafecef14 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -1,21 +1,25 @@ use super::implicit_clone::is_clone_like; use super::unnecessary_iter_cloned::{self, is_into_iter}; +use crate::rustc_middle::ty::Subst; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; -use clippy_utils::ty::{ - get_associated_type, get_iterator_item_ty, implements_trait, is_copy, is_type_diagnostic_item, peel_mid_ty_refs, -}; -use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item}; +use clippy_utils::ty::{get_associated_type, get_iterator_item_ty, implements_trait, is_copy, peel_mid_ty_refs}; +use clippy_utils::visitors::find_all_ret_expressions; +use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, return_ty}; use clippy_utils::{meets_msrv, msrvs}; use rustc_errors::Applicability; -use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind}; +use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind, ItemKind, Node}; +use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; use rustc_middle::mir::Mutability; use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref}; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; -use rustc_middle::ty::{self, PredicateKind, ProjectionPredicate, TraitPredicate, Ty}; +use rustc_middle::ty::EarlyBinder; +use rustc_middle::ty::{self, ParamTy, PredicateKind, ProjectionPredicate, TraitPredicate, Ty}; use rustc_semver::RustcVersion; use rustc_span::{sym, Symbol}; +use rustc_trait_selection::traits::{query::evaluate_obligation::InferCtxtExt as _, Obligation, ObligationCause}; +use rustc_typeck::check::{FnCtxt, Inherited}; use std::cmp::max; use super::UNNECESSARY_TO_OWNED; @@ -34,7 +38,7 @@ pub fn check<'tcx>( then { if is_cloned_or_copied(cx, method_name, method_def_id) { unnecessary_iter_cloned::check(cx, expr, method_name, receiver); - } else if is_to_owned_like(cx, method_name, method_def_id) { + } else if is_to_owned_like(cx, expr, method_name, method_def_id) { // At this point, we know the call is of a `to_owned`-like function. The functions // `check_addr_of_expr` and `check_call_arg` determine whether the call is unnecessary // based on its context, that is, whether it is a referent in an `AddrOf` expression, an @@ -246,17 +250,12 @@ fn check_other_call_arg<'tcx>( ) -> bool { if_chain! { if let Some((maybe_call, maybe_arg)) = skip_addr_of_ancestors(cx, expr); - if let Some((callee_def_id, call_substs, call_receiver, call_args)) = get_callee_substs_and_args(cx, maybe_call); + if let Some((callee_def_id, _, recv, call_args)) = get_callee_substs_and_args(cx, maybe_call); let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder(); - let index = if let Some(call_receiver) = call_receiver { - std::iter::once(call_receiver).chain(call_args.iter()).position(|arg| arg.hir_id == maybe_arg.hir_id) - } else { - call_args.iter().position(|arg| arg.hir_id == maybe_arg.hir_id) - }; - if let Some(i) = index; + if let Some(i) = recv.into_iter().chain(call_args).position(|arg| arg.hir_id == maybe_arg.hir_id); if let Some(input) = fn_sig.inputs().get(i); let (input, n_refs) = peel_mid_ty_refs(*input); - if let (trait_predicates, projection_predicates) = get_input_traits_and_projections(cx, callee_def_id, input); + if let (trait_predicates, _) = get_input_traits_and_projections(cx, callee_def_id, input); if let Some(sized_def_id) = cx.tcx.lang_items().sized_trait(); if let [trait_predicate] = trait_predicates .iter() @@ -264,52 +263,13 @@ fn check_other_call_arg<'tcx>( .collect::>()[..]; if let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref); if let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef); + if trait_predicate.def_id() == deref_trait_id || trait_predicate.def_id() == as_ref_trait_id; let receiver_ty = cx.typeck_results().expr_ty(receiver); - // If the callee has type parameters, they could appear in `projection_predicate.ty` or the - // types of `trait_predicate.trait_ref.substs`. - if if trait_predicate.def_id() == deref_trait_id { - if let [projection_predicate] = projection_predicates[..] { - let normalized_ty = - cx.tcx - .subst_and_normalize_erasing_regions(call_substs, cx.param_env, projection_predicate.term); - implements_trait(cx, receiver_ty, deref_trait_id, &[]) - && get_associated_type(cx, receiver_ty, deref_trait_id, "Target") - .map_or(false, |ty| ty::TermKind::Ty(ty) == normalized_ty.unpack()) - } else { - false - } - } else if trait_predicate.def_id() == as_ref_trait_id { - let composed_substs = compose_substs( - cx, - &trait_predicate.trait_ref.substs.iter().skip(1).collect::>()[..], - call_substs, - ); - // if `expr` is a `String` and generic target is [u8], skip - // (https://github.com/rust-lang/rust-clippy/issues/9317). - if let [subst] = composed_substs[..] - && let GenericArgKind::Type(arg_ty) = subst.unpack() - && arg_ty.is_slice() - && let inner_ty = arg_ty.builtin_index().unwrap() - && let ty::Uint(ty::UintTy::U8) = inner_ty.kind() - && let self_ty = cx.typeck_results().expr_ty(expr).peel_refs() - && is_type_diagnostic_item(cx, self_ty, sym::String) { - false - } else { - implements_trait(cx, receiver_ty, as_ref_trait_id, &composed_substs) - } - } else { - false - }; + if can_change_type(cx, maybe_arg, receiver_ty); // We can't add an `&` when the trait is `Deref` because `Target = &T` won't match // `Target = T`. if n_refs > 0 || is_copy(cx, receiver_ty) || trait_predicate.def_id() != deref_trait_id; let n_refs = max(n_refs, if is_copy(cx, receiver_ty) { 0 } else { 1 }); - // If the trait is `AsRef` and the input type variable `T` occurs in the output type, then - // `T` must not be instantiated with a reference - // (https://github.com/rust-lang/rust-clippy/issues/8507). - if (n_refs == 0 && !receiver_ty.is_ref()) - || trait_predicate.def_id() != as_ref_trait_id - || !fn_sig.output().contains(input); if let Some(receiver_snippet) = snippet_opt(cx, receiver.span); then { span_lint_and_sugg( @@ -359,11 +319,11 @@ fn get_callee_substs_and_args<'tcx>( } } if_chain! { - if let ExprKind::MethodCall(_, receiver, args, _) = expr.kind; + if let ExprKind::MethodCall(_, recv, args, _) = expr.kind; if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); then { let substs = cx.typeck_results().node_substs(expr.hir_id); - return Some((method_def_id, substs, Some(receiver), args)); + return Some((method_def_id, substs, Some(recv), args)); } } None @@ -395,22 +355,103 @@ fn get_input_traits_and_projections<'tcx>( (trait_predicates, projection_predicates) } -/// Composes two substitutions by applying the latter to the types of the former. -fn compose_substs<'tcx>( - cx: &LateContext<'tcx>, - left: &[GenericArg<'tcx>], - right: SubstsRef<'tcx>, -) -> Vec> { - left.iter() - .map(|arg| { - if let GenericArgKind::Type(arg_ty) = arg.unpack() { - let normalized_ty = cx.tcx.subst_and_normalize_erasing_regions(right, cx.param_env, arg_ty); - GenericArg::from(normalized_ty) - } else { - *arg +fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<'a>) -> bool { + for (_, node) in cx.tcx.hir().parent_iter(expr.hir_id) { + match node { + Node::Stmt(_) => return true, + Node::Block(..) => continue, + Node::Item(item) => { + if let ItemKind::Fn(_, _, body_id) = &item.kind + && let output_ty = return_ty(cx, item.hir_id()) + && let local_def_id = cx.tcx.hir().local_def_id(item.hir_id()) + && Inherited::build(cx.tcx, local_def_id).enter(|inherited| { + let fn_ctxt = FnCtxt::new(&inherited, cx.param_env, item.hir_id()); + fn_ctxt.can_coerce(ty, output_ty) + }) { + if has_lifetime(output_ty) && has_lifetime(ty) { + return false; + } + let body = cx.tcx.hir().body(*body_id); + let body_expr = &body.value; + let mut count = 0; + return find_all_ret_expressions(cx, body_expr, |_| { count += 1; count <= 1 }); + } } - }) - .collect() + Node::Expr(parent_expr) => { + if let Some((callee_def_id, call_substs, recv, call_args)) = get_callee_substs_and_args(cx, parent_expr) + { + let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder(); + if let Some(arg_index) = recv.into_iter().chain(call_args).position(|arg| arg.hir_id == expr.hir_id) + && let Some(param_ty) = fn_sig.inputs().get(arg_index) + && let ty::Param(ParamTy { index: param_index , ..}) = param_ty.kind() + { + if fn_sig + .inputs() + .iter() + .enumerate() + .filter(|(i, _)| *i != arg_index) + .any(|(_, ty)| ty.contains(*param_ty)) + { + return false; + } + + let mut trait_predicates = cx.tcx.param_env(callee_def_id) + .caller_bounds().iter().filter(|predicate| { + if let PredicateKind::Trait(trait_predicate) = predicate.kind().skip_binder() + && trait_predicate.trait_ref.self_ty() == *param_ty { + true + } else { + false + } + }); + + let new_subst = cx.tcx.mk_substs( + call_substs.iter() + .enumerate() + .map(|(i, t)| + if i == (*param_index as usize) { + GenericArg::from(ty) + } else { + t + })); + + if trait_predicates.any(|predicate| { + let predicate = EarlyBinder(predicate).subst(cx.tcx, new_subst); + let obligation = Obligation::new(ObligationCause::dummy(), cx.param_env, predicate); + !cx.tcx + .infer_ctxt() + .enter(|infcx| infcx.predicate_must_hold_modulo_regions(&obligation)) + }) { + return false; + } + + let output_ty = fn_sig.output(); + if output_ty.contains(*param_ty) { + if let Ok(new_ty) = cx.tcx.try_subst_and_normalize_erasing_regions( + new_subst, cx.param_env, output_ty) { + expr = parent_expr; + ty = new_ty; + continue; + } + return false; + } + + return true; + } + } else if let ExprKind::Block(..) = parent_expr.kind { + continue; + } + return false; + }, + _ => return false, + } + } + + false +} + +fn has_lifetime(ty: Ty<'_>) -> bool { + ty.walk().any(|t| matches!(t.unpack(), GenericArgKind::Lifetime(_))) } /// Returns true if the named method is `Iterator::cloned` or `Iterator::copied`. @@ -421,10 +462,10 @@ fn is_cloned_or_copied(cx: &LateContext<'_>, method_name: Symbol, method_def_id: /// Returns true if the named method can be used to convert the receiver to its "owned" /// representation. -fn is_to_owned_like(cx: &LateContext<'_>, method_name: Symbol, method_def_id: DefId) -> bool { +fn is_to_owned_like<'a>(cx: &LateContext<'a>, call_expr: &Expr<'a>, method_name: Symbol, method_def_id: DefId) -> bool { is_clone_like(cx, method_name.as_str(), method_def_id) || is_cow_into_owned(cx, method_name, method_def_id) - || is_to_string(cx, method_name, method_def_id) + || is_to_string_on_string_like(cx, call_expr, method_name, method_def_id) } /// Returns true if the named method is `Cow::into_owned`. @@ -432,7 +473,27 @@ fn is_cow_into_owned(cx: &LateContext<'_>, method_name: Symbol, method_def_id: D method_name.as_str() == "into_owned" && is_diag_item_method(cx, method_def_id, sym::Cow) } -/// Returns true if the named method is `ToString::to_string`. -fn is_to_string(cx: &LateContext<'_>, method_name: Symbol, method_def_id: DefId) -> bool { - method_name == sym::to_string && is_diag_trait_item(cx, method_def_id, sym::ToString) +/// Returns true if the named method is `ToString::to_string` and it's called on a type that +/// is string-like i.e. implements `AsRef` or `Deref`. +fn is_to_string_on_string_like<'a>( + cx: &LateContext<'_>, + call_expr: &'a Expr<'a>, + method_name: Symbol, + method_def_id: DefId, +) -> bool { + if method_name != sym::to_string || !is_diag_trait_item(cx, method_def_id, sym::ToString) { + return false; + } + + if let Some(substs) = cx.typeck_results().node_substs_opt(call_expr.hir_id) + && let [generic_arg] = substs.as_slice() + && let GenericArgKind::Type(ty) = generic_arg.unpack() + && let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref) + && let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef) + && (implements_trait(cx, ty, deref_trait_id, &[cx.tcx.types.str_.into()]) || + implements_trait(cx, ty, as_ref_trait_id, &[cx.tcx.types.str_.into()])) { + true + } else { + false + } } diff --git a/clippy_lints/src/methods/unwrap_or_else_default.rs b/clippy_lints/src/methods/unwrap_or_else_default.rs index f3af281d6cacc..045f739e64ded 100644 --- a/clippy_lints/src/methods/unwrap_or_else_default.rs +++ b/clippy_lints/src/methods/unwrap_or_else_default.rs @@ -5,10 +5,11 @@ use clippy_utils::{ diagnostics::span_lint_and_sugg, is_default_equivalent_call, source::snippet_with_applicability, ty::is_type_diagnostic_item, }; +use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::sym; +use rustc_span::{sym, symbol}; pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, @@ -25,7 +26,7 @@ pub(super) fn check<'tcx>( if_chain! { if is_option || is_result; - if is_default_equivalent_call(cx, u_arg); + if closure_body_returns_empty_to_string(cx, u_arg) || is_default_equivalent_call(cx, u_arg); then { let mut applicability = Applicability::MachineApplicable; @@ -44,3 +45,22 @@ pub(super) fn check<'tcx>( } } } + +fn closure_body_returns_empty_to_string(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> bool { + if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = e.kind { + let body = cx.tcx.hir().body(body); + + if body.params.is_empty() + && let hir::Expr{ kind, .. } = &body.value + && let hir::ExprKind::MethodCall(hir::PathSegment {ident, ..}, self_arg, _, _) = kind + && ident == &symbol::Ident::from_str("to_string") + && let hir::Expr{ kind, .. } = self_arg + && let hir::ExprKind::Lit(lit) = kind + && let LitKind::Str(symbol::kw::Empty, _) = lit.node + { + return true; + } + } + + false +} diff --git a/clippy_lints/src/minmax.rs b/clippy_lints/src/minmax.rs index 44b21e7b080d2..4d8579135fc06 100644 --- a/clippy_lints/src/minmax.rs +++ b/clippy_lints/src/minmax.rs @@ -1,7 +1,6 @@ use clippy_utils::consts::{constant_simple, Constant}; use clippy_utils::diagnostics::span_lint; use clippy_utils::{match_trait_method, paths}; -use if_chain::if_chain; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -84,19 +83,16 @@ fn min_max<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(MinMax, Cons } }, ExprKind::MethodCall(path, receiver, args @ [_], _) => { - if_chain! { - if cx.typeck_results().expr_ty(receiver).is_floating_point() || match_trait_method(cx, expr, &paths::ORD); - then { - if path.ident.name == sym!(max) { - fetch_const(cx, Some(receiver), args, MinMax::Max) - } else if path.ident.name == sym!(min) { - fetch_const(cx, Some(receiver), args, MinMax::Min) - } else { - None - } + if cx.typeck_results().expr_ty(receiver).is_floating_point() || match_trait_method(cx, expr, &paths::ORD) { + if path.ident.name == sym!(max) { + fetch_const(cx, Some(receiver), args, MinMax::Max) + } else if path.ident.name == sym!(min) { + fetch_const(cx, Some(receiver), args, MinMax::Min) } else { None } + } else { + None } }, _ => None, @@ -109,18 +105,18 @@ fn fetch_const<'a>( args: &'a [Expr<'a>], m: MinMax, ) -> Option<(MinMax, Constant, &'a Expr<'a>)> { - let mut args = receiver.into_iter().chain(args.into_iter()); - let arg0 = args.next()?; - let arg1 = args.next()?; + let mut args = receiver.into_iter().chain(args); + let first_arg = args.next()?; + let second_arg = args.next()?; if args.next().is_some() { return None; } - constant_simple(cx, cx.typeck_results(), arg0).map_or_else( - || constant_simple(cx, cx.typeck_results(), arg1).map(|c| (m, c, arg0)), + constant_simple(cx, cx.typeck_results(), first_arg).map_or_else( + || constant_simple(cx, cx.typeck_results(), second_arg).map(|c| (m, c, first_arg)), |c| { - if constant_simple(cx, cx.typeck_results(), arg1).is_none() { + if constant_simple(cx, cx.typeck_results(), second_arg).is_none() { // otherwise ignore - Some((m, c, arg1)) + Some((m, c, second_arg)) } else { None } diff --git a/clippy_lints/src/needless_for_each.rs b/clippy_lints/src/needless_for_each.rs index f8cc3fbb3cdfa..3233d87c07319 100644 --- a/clippy_lints/src/needless_for_each.rs +++ b/clippy_lints/src/needless_for_each.rs @@ -77,7 +77,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach { if let ExprKind::Block(..) = body.value.kind; then { let mut ret_collector = RetCollector::default(); - ret_collector.visit_expr(&body.value); + ret_collector.visit_expr(body.value); // Skip the lint if `return` is used in `Loop` in order not to suggest using `'label`. if ret_collector.ret_in_loop { diff --git a/clippy_lints/src/only_used_in_recursion.rs b/clippy_lints/src/only_used_in_recursion.rs index 17d5fa2152bbf..6217110a1f3ae 100644 --- a/clippy_lints/src/only_used_in_recursion.rs +++ b/clippy_lints/src/only_used_in_recursion.rs @@ -12,6 +12,7 @@ use rustc_middle::ty::{self, ConstKind}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::symbol::{kw, Ident}; use rustc_span::Span; +use std::iter; declare_clippy_lint! { /// ### What it does @@ -234,11 +235,7 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion { })) => ( def_id.to_def_id(), FnKind::TraitFn, - if sig.decl.implicit_self.has_implicit_self() { - 1 - } else { - 0 - }, + usize::from(sig.decl.implicit_self.has_implicit_self()), ), Some(Node::ImplItem(&ImplItem { kind: ImplItemKind::Fn(ref sig, _), @@ -253,11 +250,7 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion { ( trait_item_id, FnKind::ImplTraitFn(cx.tcx.erase_regions(trait_ref.substs) as *const _ as usize), - if sig.decl.implicit_self.has_implicit_self() { - 1 - } else { - 0 - }, + usize::from(sig.decl.implicit_self.has_implicit_self()), ) } else { (def_id.to_def_id(), FnKind::Fn, 0) @@ -310,7 +303,7 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion { && has_matching_substs(param.fn_kind, typeck.node_substs(parent.hir_id)) }) => { - if let Some(idx) = std::iter::once(receiver).chain(args.iter()).position(|arg| arg.hir_id == child_id) { + if let Some(idx) = iter::once(receiver).chain(args).position(|arg| arg.hir_id == child_id) { param.uses.push(Usage::new(span, idx)); } return; diff --git a/clippy_lints/src/operators/arithmetic.rs b/clippy_lints/src/operators/arithmetic.rs deleted file mode 100644 index 800cf249f5c78..0000000000000 --- a/clippy_lints/src/operators/arithmetic.rs +++ /dev/null @@ -1,119 +0,0 @@ -#![allow( - // False positive - clippy::match_same_arms -)] - -use super::ARITHMETIC; -use clippy_utils::{consts::constant_simple, diagnostics::span_lint}; -use rustc_data_structures::fx::FxHashSet; -use rustc_hir as hir; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::impl_lint_pass; -use rustc_span::source_map::Span; - -const HARD_CODED_ALLOWED: &[&str] = &["std::num::Saturating", "std::string::String", "std::num::Wrapping"]; - -#[derive(Debug)] -pub struct Arithmetic { - allowed: FxHashSet, - // Used to check whether expressions are constants, such as in enum discriminants and consts - const_span: Option, - expr_span: Option, -} - -impl_lint_pass!(Arithmetic => [ARITHMETIC]); - -impl Arithmetic { - #[must_use] - pub fn new(mut allowed: FxHashSet) -> Self { - allowed.extend(HARD_CODED_ALLOWED.iter().copied().map(String::from)); - Self { - allowed, - const_span: None, - expr_span: None, - } - } - - /// Checks if the given `expr` has any of the inner `allowed` elements. - fn is_allowed_ty(&self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { - self.allowed.contains( - cx.typeck_results() - .expr_ty(expr) - .to_string() - .split('<') - .next() - .unwrap_or_default(), - ) - } - - fn issue_lint(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) { - span_lint(cx, ARITHMETIC, expr.span, "arithmetic detected"); - self.expr_span = Some(expr.span); - } -} - -impl<'tcx> LateLintPass<'tcx> for Arithmetic { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { - if self.expr_span.is_some() { - return; - } - if let Some(span) = self.const_span && span.contains(expr.span) { - return; - } - match &expr.kind { - hir::ExprKind::Binary(op, lhs, rhs) | hir::ExprKind::AssignOp(op, lhs, rhs) => { - let ( - hir::BinOpKind::Add - | hir::BinOpKind::Sub - | hir::BinOpKind::Mul - | hir::BinOpKind::Div - | hir::BinOpKind::Rem - | hir::BinOpKind::Shl - | hir::BinOpKind::Shr - ) = op.node else { - return; - }; - if self.is_allowed_ty(cx, lhs) || self.is_allowed_ty(cx, rhs) { - return; - } - self.issue_lint(cx, expr); - }, - hir::ExprKind::Unary(hir::UnOp::Neg, _) => { - // CTFE already takes care of things like `-1` that do not overflow. - if constant_simple(cx, cx.typeck_results(), expr).is_none() { - self.issue_lint(cx, expr); - } - }, - _ => {}, - } - } - - fn check_body(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) { - let body_owner = cx.tcx.hir().body_owner_def_id(body.id()); - match cx.tcx.hir().body_owner_kind(body_owner) { - hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => { - let body_span = cx.tcx.def_span(body_owner); - if let Some(span) = self.const_span && span.contains(body_span) { - return; - } - self.const_span = Some(body_span); - }, - hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::Fn => {}, - } - } - - fn check_body_post(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) { - let body_owner = cx.tcx.hir().body_owner(body.id()); - let body_span = cx.tcx.hir().span(body_owner); - if let Some(span) = self.const_span && span.contains(body_span) { - return; - } - self.const_span = None; - } - - fn check_expr_post(&mut self, _: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { - if Some(expr.span) == self.expr_span { - self.expr_span = None; - } - } -} diff --git a/clippy_lints/src/operators/arithmetic_side_effects.rs b/clippy_lints/src/operators/arithmetic_side_effects.rs new file mode 100644 index 0000000000000..83b69fbb31164 --- /dev/null +++ b/clippy_lints/src/operators/arithmetic_side_effects.rs @@ -0,0 +1,173 @@ +#![allow( + // False positive + clippy::match_same_arms +)] + +use super::ARITHMETIC_SIDE_EFFECTS; +use clippy_utils::{consts::constant_simple, diagnostics::span_lint}; +use rustc_ast as ast; +use rustc_data_structures::fx::FxHashSet; +use rustc_hir as hir; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::Ty; +use rustc_session::impl_lint_pass; +use rustc_span::source_map::{Span, Spanned}; + +const HARD_CODED_ALLOWED: &[&str] = &[ + "f32", + "f64", + "std::num::Saturating", + "std::string::String", + "std::num::Wrapping", +]; + +#[derive(Debug)] +pub struct ArithmeticSideEffects { + allowed: FxHashSet, + // Used to check whether expressions are constants, such as in enum discriminants and consts + const_span: Option, + expr_span: Option, +} + +impl_lint_pass!(ArithmeticSideEffects => [ARITHMETIC_SIDE_EFFECTS]); + +impl ArithmeticSideEffects { + #[must_use] + pub fn new(mut allowed: FxHashSet) -> Self { + allowed.extend(HARD_CODED_ALLOWED.iter().copied().map(String::from)); + Self { + allowed, + const_span: None, + expr_span: None, + } + } + + /// Checks assign operators (+=, -=, *=, /=) of integers in a non-constant environment that + /// won't overflow. + fn has_valid_assign_op(op: &Spanned, rhs: &hir::Expr<'_>, rhs_refs: Ty<'_>) -> bool { + if !Self::is_literal_integer(rhs, rhs_refs) { + return false; + } + if let hir::BinOpKind::Div | hir::BinOpKind::Mul = op.node + && let hir::ExprKind::Lit(ref lit) = rhs.kind + && let ast::LitKind::Int(1, _) = lit.node + { + return true; + } + false + } + + /// Checks "raw" binary operators (+, -, *, /) of integers in a non-constant environment + /// already handled by the CTFE. + fn has_valid_bin_op(lhs: &hir::Expr<'_>, lhs_refs: Ty<'_>, rhs: &hir::Expr<'_>, rhs_refs: Ty<'_>) -> bool { + Self::is_literal_integer(lhs, lhs_refs) && Self::is_literal_integer(rhs, rhs_refs) + } + + /// Checks if the given `expr` has any of the inner `allowed` elements. + fn is_allowed_ty(&self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { + self.allowed.contains( + cx.typeck_results() + .expr_ty(expr) + .to_string() + .split('<') + .next() + .unwrap_or_default(), + ) + } + + /// Explicit integers like `1` or `i32::MAX`. Does not take into consideration references. + fn is_literal_integer(expr: &hir::Expr<'_>, expr_refs: Ty<'_>) -> bool { + let is_integral = expr_refs.is_integral(); + let is_literal = matches!(expr.kind, hir::ExprKind::Lit(_)); + is_integral && is_literal + } + + fn issue_lint(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) { + span_lint(cx, ARITHMETIC_SIDE_EFFECTS, expr.span, "arithmetic detected"); + self.expr_span = Some(expr.span); + } + + /// Manages when the lint should be triggered. Operations in constant environments, hard coded + /// types, custom allowed types and non-constant operations that won't overflow are ignored. + fn manage_bin_ops( + &mut self, + cx: &LateContext<'_>, + expr: &hir::Expr<'_>, + op: &Spanned, + lhs: &hir::Expr<'_>, + rhs: &hir::Expr<'_>, + ) { + if constant_simple(cx, cx.typeck_results(), expr).is_some() { + return; + } + if !matches!( + op.node, + hir::BinOpKind::Add + | hir::BinOpKind::Sub + | hir::BinOpKind::Mul + | hir::BinOpKind::Div + | hir::BinOpKind::Rem + | hir::BinOpKind::Shl + | hir::BinOpKind::Shr + ) { + return; + }; + if self.is_allowed_ty(cx, lhs) || self.is_allowed_ty(cx, rhs) { + return; + } + let lhs_refs = cx.typeck_results().expr_ty(lhs).peel_refs(); + let rhs_refs = cx.typeck_results().expr_ty(rhs).peel_refs(); + let has_valid_assign_op = Self::has_valid_assign_op(op, rhs, rhs_refs); + if has_valid_assign_op || Self::has_valid_bin_op(lhs, lhs_refs, rhs, rhs_refs) { + return; + } + self.issue_lint(cx, expr); + } +} + +impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { + if self.expr_span.is_some() || self.const_span.map_or(false, |sp| sp.contains(expr.span)) { + return; + } + match &expr.kind { + hir::ExprKind::Binary(op, lhs, rhs) | hir::ExprKind::AssignOp(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); + } + }, + _ => {}, + } + } + + fn check_body(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) { + let body_owner = cx.tcx.hir().body_owner(body.id()); + let body_owner_def_id = cx.tcx.hir().local_def_id(body_owner); + let body_owner_kind = cx.tcx.hir().body_owner_kind(body_owner_def_id); + if let hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) = body_owner_kind { + let body_span = cx.tcx.hir().span_with_body(body_owner); + if let Some(span) = self.const_span && span.contains(body_span) { + return; + } + self.const_span = Some(body_span); + } + } + + fn check_body_post(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) { + let body_owner = cx.tcx.hir().body_owner(body.id()); + let body_span = cx.tcx.hir().span(body_owner); + if let Some(span) = self.const_span && span.contains(body_span) { + return; + } + self.const_span = None; + } + + fn check_expr_post(&mut self, _: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { + if Some(expr.span) == self.expr_span { + self.expr_span = None; + } + } +} diff --git a/clippy_lints/src/operators/mod.rs b/clippy_lints/src/operators/mod.rs index bb6d99406b493..c32b4df4f75c1 100644 --- a/clippy_lints/src/operators/mod.rs +++ b/clippy_lints/src/operators/mod.rs @@ -21,7 +21,7 @@ mod ptr_eq; mod self_assignment; mod verbose_bit_mask; -pub(crate) mod arithmetic; +pub(crate) mod arithmetic_side_effects; use rustc_hir::{Body, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; @@ -61,25 +61,29 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for any kind of arithmetic operation of any type. + /// Checks any kind of arithmetic operation of any type. /// /// Operators like `+`, `-`, `*` or `<<` are usually capable of overflowing according to the [Rust /// Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow), - /// or can panic (`/`, `%`). Known safe built-in types like `Wrapping` or `Saturing` are filtered - /// away. + /// or can panic (`/`, `%`). + /// + /// Known safe built-in types like `Wrapping` or `Saturing`, floats, operations in constant + /// environments, allowed types and non-constant operations that won't overflow are ignored. /// /// ### Why is this bad? - /// Integer overflow will trigger a panic in debug builds or will wrap in - /// release mode. Division by zero will cause a panic in either mode. In some applications one - /// wants explicitly checked, wrapping or saturating arithmetic. + /// For integers, overflow will trigger a panic in debug builds or wrap the result in + /// release mode; division by zero will cause a panic in either mode. As a result, it is + /// desirable to explicitly call checked, wrapping or saturating arithmetic methods. /// /// #### Example /// ```rust - /// # let a = 0; - /// a + 1; + /// // `n` can be any number, including `i32::MAX`. + /// fn foo(n: i32) -> i32 { + /// n + 1 + /// } /// ``` /// - /// Third-party types also tend to overflow. + /// Third-party types can also overflow or present unwanted side-effects. /// /// #### Example /// ```ignore,rust @@ -88,11 +92,11 @@ declare_clippy_lint! { /// ``` /// /// ### Allowed types - /// Custom allowed types can be specified through the "arithmetic-allowed" filter. + /// Custom allowed types can be specified through the "arithmetic-side-effects-allowed" filter. #[clippy::version = "1.64.0"] - pub ARITHMETIC, + pub ARITHMETIC_SIDE_EFFECTS, restriction, - "any arithmetic expression that could overflow or panic" + "any arithmetic expression that can cause side effects like overflows or panics" } declare_clippy_lint! { @@ -785,7 +789,7 @@ pub struct Operators { } impl_lint_pass!(Operators => [ ABSURD_EXTREME_COMPARISONS, - ARITHMETIC, + ARITHMETIC_SIDE_EFFECTS, INTEGER_ARITHMETIC, FLOAT_ARITHMETIC, ASSIGN_OP_PATTERN, diff --git a/clippy_lints/src/panic_in_result_fn.rs b/clippy_lints/src/panic_in_result_fn.rs index 21acf003d92b2..4aa0d9227abad 100644 --- a/clippy_lints/src/panic_in_result_fn.rs +++ b/clippy_lints/src/panic_in_result_fn.rs @@ -69,7 +69,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, body: &'tcx hir } true }) - .visit_expr(&body.value); + .visit_expr(body.value); if !panics.is_empty() { span_lint_and_then( cx, diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 0028e0bc6c517..41d1baba64f85 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -507,7 +507,7 @@ fn check_mut_from_ref<'tcx>(cx: &LateContext<'tcx>, sig: &FnSig<'_>, body: Optio if let Some(args) = args && !args.is_empty() && body.map_or(true, |body| { - sig.header.unsafety == Unsafety::Unsafe || contains_unsafe_block(cx, &body.value) + sig.header.unsafety == Unsafety::Unsafe || contains_unsafe_block(cx, body.value) }) { span_lint_and_then( @@ -664,7 +664,7 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args: results, skip_count, }; - v.visit_expr(&body.value); + v.visit_expr(body.value); v.results } diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 490f345d29707..918d624eec6fa 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -350,6 +350,7 @@ fn check_range_bounds<'a>(cx: &'a LateContext<'_>, ex: &'a Expr<'_>) -> Option, expr: &Expr<'_>) { if_chain! { + if expr.span.can_be_used_for_suggestions(); if let Some(higher::Range { start, end: Some(end), @@ -357,14 +358,7 @@ fn check_exclusive_range_plus_one(cx: &LateContext<'_>, expr: &Expr<'_>) { }) = higher::Range::hir(expr); if let Some(y) = y_plus_one(cx, end); then { - let span = if expr.span.from_expansion() { - expr.span - .ctxt() - .outer_expn_data() - .call_site - } else { - expr.span - }; + let span = expr.span; span_lint_and_then( cx, RANGE_PLUS_ONE, @@ -399,6 +393,7 @@ fn check_exclusive_range_plus_one(cx: &LateContext<'_>, expr: &Expr<'_>) { // inclusive range minus one: `x..=(y-1)` fn check_inclusive_range_minus_one(cx: &LateContext<'_>, expr: &Expr<'_>) { if_chain! { + if expr.span.can_be_used_for_suggestions(); if let Some(higher::Range { start, end: Some(end), limits: RangeLimits::Closed }) = higher::Range::hir(expr); if let Some(y) = y_minus_one(cx, end); then { diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index 1926661c59603..91553240e3c91 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -139,7 +139,7 @@ impl<'tcx> LateLintPass<'tcx> for Return { } else { RetReplacement::Empty }; - check_final_expr(cx, &body.value, Some(body.value.span), replacement); + check_final_expr(cx, body.value, Some(body.value.span), replacement); }, FnKind::ItemFn(..) | FnKind::Method(..) => { if let ExprKind::Block(block, _) = body.value.kind { diff --git a/clippy_lints/src/suspicious_trait_impl.rs b/clippy_lints/src/suspicious_trait_impl.rs index 4294464dbf61a..6add20c1fb712 100644 --- a/clippy_lints/src/suspicious_trait_impl.rs +++ b/clippy_lints/src/suspicious_trait_impl.rs @@ -78,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for SuspiciousImpl { ] .iter() .find(|&(ts, _)| ts.iter().any(|&t| Ok(trait_id) == cx.tcx.lang_items().require(t))); - if count_binops(&body.value) == 1; + if count_binops(body.value) == 1; then { span_lint( cx, diff --git a/clippy_lints/src/unit_return_expecting_ord.rs b/clippy_lints/src/unit_return_expecting_ord.rs index 851eef7b33241..c0a4f3fbacd64 100644 --- a/clippy_lints/src/unit_return_expecting_ord.rs +++ b/clippy_lints/src/unit_return_expecting_ord.rs @@ -149,7 +149,7 @@ impl<'tcx> LateLintPass<'tcx> for UnitReturnExpectingOrd { let args = std::iter::once(receiver).chain(args.iter()).collect::>(); for (i, trait_name) in arg_indices { if i < args.len() { - match check_arg(cx, &args[i]) { + match check_arg(cx, args[i]) { Some((span, None)) => { span_lint( cx, diff --git a/clippy_lints/src/unit_types/unit_arg.rs b/clippy_lints/src/unit_types/unit_arg.rs index 7ffb53dcf455f..a6f777abc6e94 100644 --- a/clippy_lints/src/unit_types/unit_arg.rs +++ b/clippy_lints/src/unit_types/unit_arg.rs @@ -50,7 +50,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { }) .collect::>(); if !args_to_recover.is_empty() && !is_from_proc_macro(cx, expr) { - lint_unit_args(cx, expr, &args_to_recover.as_slice()); + lint_unit_args(cx, expr, args_to_recover.as_slice()); } } diff --git a/clippy_lints/src/unnecessary_wraps.rs b/clippy_lints/src/unnecessary_wraps.rs index a5afbb8ff9da4..2c40827db0e75 100644 --- a/clippy_lints/src/unnecessary_wraps.rs +++ b/clippy_lints/src/unnecessary_wraps.rs @@ -115,7 +115,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { // Check if all return expression respect the following condition and collect them. let mut suggs = Vec::new(); - let can_sugg = find_all_ret_expressions(cx, &body.value, |ret_expr| { + let can_sugg = find_all_ret_expressions(cx, body.value, |ret_expr| { if_chain! { if !ret_expr.span.from_expansion(); // Check if a function call. diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index 9092156be150a..7e451b7b7a419 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -160,7 +160,7 @@ fn collect_unwrap_info<'tcx>( let name = method_name.ident.as_str(); if is_relevant_option_call(cx, ty, name) || is_relevant_result_call(cx, ty, name); then { - assert!(args.len() == 0); + assert!(args.is_empty()); let unwrappable = match name { "is_some" | "is_ok" => true, "is_err" | "is_none" => false, diff --git a/clippy_lints/src/unwrap_in_result.rs b/clippy_lints/src/unwrap_in_result.rs index b3ca15f7648bc..46020adcaa2ca 100644 --- a/clippy_lints/src/unwrap_in_result.rs +++ b/clippy_lints/src/unwrap_in_result.rs @@ -83,7 +83,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindExpectUnwrap<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { // check for `expect` if let Some(arglists) = method_chain_args(expr, &["expect"]) { - let receiver_ty = self.typeck_results.expr_ty(&arglists[0].0).peel_refs(); + let receiver_ty = self.typeck_results.expr_ty(arglists[0].0).peel_refs(); if is_type_diagnostic_item(self.lcx, receiver_ty, sym::Option) || is_type_diagnostic_item(self.lcx, receiver_ty, sym::Result) { @@ -93,7 +93,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindExpectUnwrap<'a, 'tcx> { // check for `unwrap` if let Some(arglists) = method_chain_args(expr, &["unwrap"]) { - let receiver_ty = self.typeck_results.expr_ty(&arglists[0].0).peel_refs(); + let receiver_ty = self.typeck_results.expr_ty(arglists[0].0).peel_refs(); if is_type_diagnostic_item(self.lcx, receiver_ty, sym::Option) || is_type_diagnostic_item(self.lcx, receiver_ty, sym::Result) { @@ -114,7 +114,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_item: &'tc typeck_results: cx.tcx.typeck(impl_item.def_id), result: Vec::new(), }; - fpu.visit_expr(&body.value); + fpu.visit_expr(body.value); // if we've found one, lint if !fpu.result.is_empty() { diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index 1489c96d9e9b0..4003fff27c006 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -142,7 +142,7 @@ fn check_item(cx: &LateContext<'_>, hir_id: HirId) { let hir = cx.tcx.hir(); if let Some(body_id) = hir.maybe_body_owned_by(hir_id.expect_owner()) { check_node(cx, hir_id, |v| { - v.expr(&v.bind("expr", &hir.body(body_id).value)); + v.expr(&v.bind("expr", hir.body(body_id).value)); }); } } diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 84e65d5fa0b71..a8500beb25747 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -208,7 +208,7 @@ define_Conf! { /// Lint: Arithmetic. /// /// Suppress checking of the passed type names. - (arithmetic_allowed: rustc_data_structures::fx::FxHashSet = <_>::default()), + (arithmetic_side_effects_allowed: rustc_data_structures::fx::FxHashSet = <_>::default()), /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UNUSED_SELF, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX. /// /// Suppress lints whenever the suggested change would cause breakage for other crates. diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index ae1c11ef83c31..17d9a04185767 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -505,7 +505,7 @@ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass { .hir_id(), ), ); - collector.visit_expr(&cx.tcx.hir().body(body_id).value); + collector.visit_expr(cx.tcx.hir().body(body_id).value); } } } @@ -653,7 +653,7 @@ impl<'tcx> LateLintPass<'tcx> for CompilerLintFunctions { } if_chain! { - if let ExprKind::MethodCall(path, [self_arg, ..], _) = &expr.kind; + if let ExprKind::MethodCall(path, self_arg, _, _) = &expr.kind; let fn_name = path.ident; if let Some(sugg) = self.map.get(fn_name.as_str()); let ty = cx.typeck_results().expr_ty(self_arg).peel_refs(); @@ -685,9 +685,8 @@ impl<'tcx> LateLintPass<'tcx> for OuterExpnDataPass { let method_names: Vec<&str> = method_names.iter().map(Symbol::as_str).collect(); if_chain! { if let ["expn_data", "outer_expn"] = method_names.as_slice(); - let args = arg_lists[1]; - if args.len() == 1; - let self_arg = &args.0; + let (self_arg, args)= arg_lists[1]; + if args.is_empty(); let self_ty = cx.typeck_results().expr_ty(self_arg).peel_refs(); if match_type(cx, self_ty, &paths::SYNTAX_CONTEXT); then { @@ -734,30 +733,30 @@ impl<'tcx> LateLintPass<'tcx> for CollapsibleCalls { if and_then_args.len() == 5; if let ExprKind::Closure(&Closure { body, .. }) = &and_then_args[4].kind; let body = cx.tcx.hir().body(body); - let only_expr = peel_blocks_with_stmt(&body.value); - if let ExprKind::MethodCall(ps, span_call_args, _) = &only_expr.kind; - if let ExprKind::Path(..) = span_call_args[0].kind; + let only_expr = peel_blocks_with_stmt(body.value); + if let ExprKind::MethodCall(ps, recv, span_call_args, _) = &only_expr.kind; + if let ExprKind::Path(..) = recv.kind; then { let and_then_snippets = get_and_then_snippets(cx, and_then_args); let mut sle = SpanlessEq::new(cx).deny_side_effects(); match ps.ident.as_str() { - "span_suggestion" if sle.eq_expr(&and_then_args[2], &span_call_args[1]) => { + "span_suggestion" if sle.eq_expr(&and_then_args[2], &span_call_args[0]) => { suggest_suggestion(cx, expr, &and_then_snippets, &span_suggestion_snippets(cx, span_call_args)); }, - "span_help" if sle.eq_expr(&and_then_args[2], &span_call_args[1]) => { - let help_snippet = snippet(cx, span_call_args[2].span, r#""...""#); + "span_help" if sle.eq_expr(&and_then_args[2], &span_call_args[0]) => { + let help_snippet = snippet(cx, span_call_args[1].span, r#""...""#); suggest_help(cx, expr, &and_then_snippets, help_snippet.borrow(), true); }, - "span_note" if sle.eq_expr(&and_then_args[2], &span_call_args[1]) => { - let note_snippet = snippet(cx, span_call_args[2].span, r#""...""#); + "span_note" if sle.eq_expr(&and_then_args[2], &span_call_args[0]) => { + let note_snippet = snippet(cx, span_call_args[1].span, r#""...""#); suggest_note(cx, expr, &and_then_snippets, note_snippet.borrow(), true); }, "help" => { - let help_snippet = snippet(cx, span_call_args[1].span, r#""...""#); + let help_snippet = snippet(cx, span_call_args[0].span, r#""...""#); suggest_help(cx, expr, &and_then_snippets, help_snippet.borrow(), false); } "note" => { - let note_snippet = snippet(cx, span_call_args[1].span, r#""...""#); + let note_snippet = snippet(cx, span_call_args[0].span, r#""...""#); suggest_note(cx, expr, &and_then_snippets, note_snippet.borrow(), false); } _ => (), @@ -798,9 +797,9 @@ fn span_suggestion_snippets<'a, 'hir>( cx: &LateContext<'_>, span_call_args: &'hir [Expr<'hir>], ) -> SpanSuggestionSnippets<'a> { - let help_snippet = snippet(cx, span_call_args[2].span, r#""...""#); - let sugg_snippet = snippet(cx, span_call_args[3].span, ".."); - let applicability_snippet = snippet(cx, span_call_args[4].span, "Applicability::MachineApplicable"); + let help_snippet = snippet(cx, span_call_args[1].span, r#""...""#); + let sugg_snippet = snippet(cx, span_call_args[2].span, ".."); + let applicability_snippet = snippet(cx, span_call_args[3].span, "Applicability::MachineApplicable"); SpanSuggestionSnippets { help: help_snippet, @@ -954,7 +953,7 @@ fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option LateLintPass<'tcx> for InvalidPaths { if el_ty.is_str(); let body = cx.tcx.hir().body(body_id); let typeck_results = cx.tcx.typeck_body(body_id); - if let Some(Constant::Vec(path)) = constant_simple(cx, typeck_results, &body.value); + if let Some(Constant::Vec(path)) = constant_simple(cx, typeck_results, body.value); let path: Vec<&str> = path.iter().map(|x| { if let Constant::Str(s) = x { s.as_str() @@ -1177,7 +1176,7 @@ impl InterningDefinedSymbol { }; if_chain! { // is a method call - if let ExprKind::MethodCall(_, [item], _) = call.kind; + if let ExprKind::MethodCall(_, item, [], _) = call.kind; if let Some(did) = cx.typeck_results().type_dependent_def_id(call.hir_id); let ty = cx.typeck_results().expr_ty(item); // ...on either an Ident or a Symbol diff --git a/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/clippy_lints/src/utils/internal_lints/metadata_collector.rs index b1148bccc2a28..342f627e38275 100644 --- a/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ b/clippy_lints/src/utils/internal_lints/metadata_collector.rs @@ -1145,8 +1145,8 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for IsMultiSpanScanner<'a, 'hir> { self.add_single_span_suggestion(); } }, - ExprKind::MethodCall(path, arg, _arg_span) => { - let (self_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(&arg[0])); + ExprKind::MethodCall(path, recv, _, _arg_span) => { + let (self_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(recv)); if match_type(self.cx, self_ty, &paths::DIAGNOSTIC_BUILDER) { let called_method = path.ident.name.as_str().to_string(); for (method_name, is_multi_part) in &SUGGESTION_DIAGNOSTIC_BUILDER_METHODS { diff --git a/clippy_lints/src/vec_init_then_push.rs b/clippy_lints/src/vec_init_then_push.rs index 8425837fd7336..bd5be0c9d7eda 100644 --- a/clippy_lints/src/vec_init_then_push.rs +++ b/clippy_lints/src/vec_init_then_push.rs @@ -86,7 +86,7 @@ impl VecPushSearcher { }, ExprKind::Unary(UnOp::Deref, _) | ExprKind::Index(..) if !needs_mut => { let mut last_place = parent; - while let Some(parent) = get_parent_expr(cx, parent) { + while let Some(parent) = get_parent_expr(cx, last_place) { if matches!(parent.kind, ExprKind::Unary(UnOp::Deref, _) | ExprKind::Field(..)) || matches!(parent.kind, ExprKind::Index(e, _) if e.hir_id == last_place.hir_id) { diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index 347165d9704a1..640a09a7a9123 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -805,7 +805,11 @@ fn check_newlines(fmtstr: &StrLit) -> bool { let contents = fmtstr.symbol.as_str(); let mut cb = |r: Range, c: Result| { - let c = c.unwrap(); + let c = match c { + Ok(c) => c, + Err(e) if !e.is_fatal() => return, + Err(e) => panic!("{:?}", e), + }; if r.end == contents.len() && c == '\n' && !last_was_cr && !has_internal_newline { should_lint = true; diff --git a/clippy_utils/src/check_proc_macro.rs b/clippy_utils/src/check_proc_macro.rs index e8d2d579f097e..7a8d4e8068ed6 100644 --- a/clippy_utils/src/check_proc_macro.rs +++ b/clippy_utils/src/check_proc_macro.rs @@ -140,7 +140,7 @@ fn expr_search_pat(tcx: TyCtxt<'_>, e: &Expr<'_>) -> (Pat, Pat) { ExprKind::Match(e, _, MatchSource::AwaitDesugar) | ExprKind::Yield(e, YieldSource::Await { .. }) => { (expr_search_pat(tcx, e).0, Pat::Str("await")) }, - ExprKind::Closure(&Closure { body, .. }) => (Pat::Str(""), expr_search_pat(tcx, &tcx.hir().body(body).value).1), + ExprKind::Closure(&Closure { body, .. }) => (Pat::Str(""), expr_search_pat(tcx, tcx.hir().body(body).value).1), ExprKind::Block( Block { rules: BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided), @@ -254,7 +254,7 @@ fn fn_kind_pat(tcx: TyCtxt<'_>, kind: &FnKind<'_>, body: &Body<'_>, hir_id: HirI let (start_pat, end_pat) = match kind { FnKind::ItemFn(.., header) => (fn_header_search_pat(*header), Pat::Str("")), FnKind::Method(.., sig) => (fn_header_search_pat(sig.header), Pat::Str("")), - FnKind::Closure => return (Pat::Str(""), expr_search_pat(tcx, &body.value).1), + FnKind::Closure => return (Pat::Str(""), expr_search_pat(tcx, body.value).1), }; let start_pat = match tcx.hir().get(hir_id) { Node::Item(Item { vis_span, .. }) | Node::ImplItem(ImplItem { vis_span, .. }) => { diff --git a/clippy_utils/src/eager_or_lazy.rs b/clippy_utils/src/eager_or_lazy.rs index 124a00d817847..91c9c382c236b 100644 --- a/clippy_utils/src/eager_or_lazy.rs +++ b/clippy_utils/src/eager_or_lazy.rs @@ -45,7 +45,7 @@ impl ops::BitOrAssign for EagernessSuggestion { } /// Determine the eagerness of the given function call. -fn fn_eagerness<'tcx>(cx: &LateContext<'tcx>, fn_id: DefId, name: Symbol, have_one_arg: bool) -> EagernessSuggestion { +fn fn_eagerness(cx: &LateContext<'_>, fn_id: DefId, name: Symbol, have_one_arg: bool) -> EagernessSuggestion { use EagernessSuggestion::{Eager, Lazy, NoChange}; let name = name.as_str(); diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index f45cec9f0b430..7212d9cd74451 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -201,8 +201,8 @@ impl HirEqInterExpr<'_, '_, '_> { self.inner.cx.tcx.typeck_body(right), )); let res = self.eq_expr( - &self.inner.cx.tcx.hir().body(left).value, - &self.inner.cx.tcx.hir().body(right).value, + self.inner.cx.tcx.hir().body(left).value, + self.inner.cx.tcx.hir().body(right).value, ); self.inner.maybe_typeck_results = old_maybe_typeck_results; res @@ -649,7 +649,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { }) => { std::mem::discriminant(&capture_clause).hash(&mut self.s); // closures inherit TypeckResults - self.hash_expr(&self.cx.tcx.hir().body(body).value); + self.hash_expr(self.cx.tcx.hir().body(body).value); }, ExprKind::Field(e, ref f) => { self.hash_expr(e); @@ -1011,7 +1011,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { pub fn hash_body(&mut self, body_id: BodyId) { // swap out TypeckResults when hashing a body let old_maybe_typeck_results = self.maybe_typeck_results.replace(self.cx.tcx.typeck_body(body_id)); - self.hash_expr(&self.cx.tcx.hir().body(body_id).value); + self.hash_expr(self.cx.tcx.hir().body(body_id).value); self.maybe_typeck_results = old_maybe_typeck_results; } @@ -1019,7 +1019,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { for arg in arg_list { match *arg { GenericArg::Lifetime(l) => self.hash_lifetime(l), - GenericArg::Type(ref ty) => self.hash_ty(ty), + GenericArg::Type(ty) => self.hash_ty(ty), GenericArg::Const(ref ca) => self.hash_body(ca.value.body), GenericArg::Infer(ref inf) => self.hash_ty(&inf.to_ty()), } diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 3cf043f22df5d..bdb858e1f9384 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1031,12 +1031,12 @@ pub fn can_move_expr_to_closure<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<' v.allow_closure.then_some(v.captures) } +/// Arguments of a method: the receiver and all the additional arguments. +pub type MethodArguments<'tcx> = Vec<(&'tcx Expr<'tcx>, &'tcx [Expr<'tcx>])>; + /// Returns the method names and argument list of nested method call expressions that make up /// `expr`. method/span lists are sorted with the most recent call first. -pub fn method_calls<'tcx>( - expr: &'tcx Expr<'tcx>, - max_depth: usize, -) -> (Vec, Vec<(&'tcx Expr<'tcx>, &'tcx [Expr<'tcx>])>, Vec) { +pub fn method_calls<'tcx>(expr: &'tcx Expr<'tcx>, max_depth: usize) -> (Vec, MethodArguments<'tcx>, Vec) { let mut method_names = Vec::with_capacity(max_depth); let mut arg_lists = Vec::with_capacity(max_depth); let mut spans = Vec::with_capacity(max_depth); diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs index 43e53f3feebd3..bd89ff977f877 100644 --- a/clippy_utils/src/macros.rs +++ b/clippy_utils/src/macros.rs @@ -389,8 +389,10 @@ impl FormatString { }; let mut unescaped = String::with_capacity(inner.len()); - unescape_literal(inner, mode, &mut |_, ch| { - unescaped.push(ch.unwrap()); + unescape_literal(inner, mode, &mut |_, ch| match ch { + Ok(ch) => unescaped.push(ch), + Err(e) if !e.is_fatal() => (), + Err(e) => panic!("{:?}", e), }); let mut parts = Vec::new(); diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index b22a9c817460d..d5f64e5118f56 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -6,8 +6,8 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_middle::mir::{ - Body, CastKind, NullOp, Operand, Place, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, - TerminatorKind, NonDivergingIntrinsic + Body, CastKind, NonDivergingIntrinsic, NullOp, Operand, Place, ProjectionElem, Rvalue, Statement, StatementKind, + Terminator, TerminatorKind, }; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, adjustment::PointerCast, Ty, TyCtxt}; @@ -212,9 +212,7 @@ fn check_statement<'tcx>( check_place(tcx, **place, span, body) }, - StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => { - check_operand(tcx, op, span, body) - }, + StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => check_operand(tcx, op, span, body), StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping( rustc_middle::mir::CopyNonOverlapping { dst, src, count }, diff --git a/clippy_utils/src/visitors.rs b/clippy_utils/src/visitors.rs index 6a62002a4d12e..232d571902b6c 100644 --- a/clippy_utils/src/visitors.rs +++ b/clippy_utils/src/visitors.rs @@ -274,7 +274,7 @@ pub fn is_res_used(cx: &LateContext<'_>, res: Res, body: BodyId) -> bool { } !found }) - .visit_expr(&cx.tcx.hir().body(body).value); + .visit_expr(cx.tcx.hir().body(body).value); found } @@ -568,6 +568,7 @@ pub fn for_each_local_use_after_expr<'tcx, B>( // Calls the given function for every unconsumed temporary created by the expression. Note the // function is only guaranteed to be called for types which need to be dropped, but it may be called // for other types. +#[allow(clippy::too_many_lines)] pub fn for_each_unconsumed_temporary<'tcx, B>( cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>, diff --git a/lintcheck/lintcheck_crates.toml b/lintcheck/lintcheck_crates.toml index 4fbae8614ca3d..ebbe9c9ae675f 100644 --- a/lintcheck/lintcheck_crates.toml +++ b/lintcheck/lintcheck_crates.toml @@ -1,6 +1,6 @@ [crates] # some of these are from cargotest -cargo = {name = "cargo", versions = ['0.49.0']} +cargo = {name = "cargo", versions = ['0.64.0']} iron = {name = "iron", versions = ['0.6.1']} ripgrep = {name = "ripgrep", versions = ['12.1.1']} xsv = {name = "xsv", versions = ['0.13.0']} diff --git a/rust-toolchain b/rust-toolchain index 85b60fefd60fc..b6976366dafc9 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2022-08-27" +channel = "nightly-2022-09-08" components = ["cargo", "llvm-tools-preview", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] diff --git a/src/docs.rs b/src/docs.rs new file mode 100644 index 0000000000000..f3a5048e7fa82 --- /dev/null +++ b/src/docs.rs @@ -0,0 +1,596 @@ +// autogenerated. Please look at /clippy_dev/src/update_lints.rs + +macro_rules! include_lint { + ($file_name: expr) => { + include_str!($file_name) + }; +} + +macro_rules! docs { + ($($lint_name: expr,)*) => { + pub fn explain(lint: &str) { + println!("{}", match lint { + $( + $lint_name => include_lint!(concat!("docs/", concat!($lint_name, ".txt"))), + )* + _ => "unknown lint", + }) + } + } +} + +docs! { + "absurd_extreme_comparisons", + "alloc_instead_of_core", + "allow_attributes_without_reason", + "almost_complete_letter_range", + "almost_swapped", + "approx_constant", + "arithmetic_side_effects", + "as_conversions", + "as_underscore", + "assertions_on_constants", + "assertions_on_result_states", + "assign_op_pattern", + "async_yields_async", + "await_holding_invalid_type", + "await_holding_lock", + "await_holding_refcell_ref", + "bad_bit_mask", + "bind_instead_of_map", + "blanket_clippy_restriction_lints", + "blocks_in_if_conditions", + "bool_assert_comparison", + "bool_comparison", + "bool_to_int_with_if", + "borrow_as_ptr", + "borrow_deref_ref", + "borrow_interior_mutable_const", + "borrowed_box", + "box_collection", + "boxed_local", + "branches_sharing_code", + "builtin_type_shadow", + "bytes_count_to_len", + "bytes_nth", + "cargo_common_metadata", + "case_sensitive_file_extension_comparisons", + "cast_abs_to_unsigned", + "cast_enum_constructor", + "cast_enum_truncation", + "cast_lossless", + "cast_possible_truncation", + "cast_possible_wrap", + "cast_precision_loss", + "cast_ptr_alignment", + "cast_ref_to_mut", + "cast_sign_loss", + "cast_slice_different_sizes", + "cast_slice_from_raw_parts", + "char_lit_as_u8", + "chars_last_cmp", + "chars_next_cmp", + "checked_conversions", + "clone_double_ref", + "clone_on_copy", + "clone_on_ref_ptr", + "cloned_instead_of_copied", + "cmp_nan", + "cmp_null", + "cmp_owned", + "cognitive_complexity", + "collapsible_else_if", + "collapsible_if", + "collapsible_match", + "collapsible_str_replace", + "comparison_chain", + "comparison_to_empty", + "copy_iterator", + "crate_in_macro_def", + "create_dir", + "crosspointer_transmute", + "dbg_macro", + "debug_assert_with_mut_call", + "decimal_literal_representation", + "declare_interior_mutable_const", + "default_instead_of_iter_empty", + "default_numeric_fallback", + "default_trait_access", + "default_union_representation", + "deprecated_cfg_attr", + "deprecated_semver", + "deref_addrof", + "deref_by_slicing", + "derivable_impls", + "derive_hash_xor_eq", + "derive_ord_xor_partial_ord", + "derive_partial_eq_without_eq", + "disallowed_methods", + "disallowed_names", + "disallowed_script_idents", + "disallowed_types", + "diverging_sub_expression", + "doc_link_with_quotes", + "doc_markdown", + "double_comparisons", + "double_must_use", + "double_neg", + "double_parens", + "drop_copy", + "drop_non_drop", + "drop_ref", + "duplicate_mod", + "duplicate_underscore_argument", + "duration_subsec", + "else_if_without_else", + "empty_drop", + "empty_enum", + "empty_line_after_outer_attr", + "empty_loop", + "empty_structs_with_brackets", + "enum_clike_unportable_variant", + "enum_glob_use", + "enum_variant_names", + "eq_op", + "equatable_if_let", + "erasing_op", + "err_expect", + "excessive_precision", + "exhaustive_enums", + "exhaustive_structs", + "exit", + "expect_fun_call", + "expect_used", + "expl_impl_clone_on_copy", + "explicit_auto_deref", + "explicit_counter_loop", + "explicit_deref_methods", + "explicit_into_iter_loop", + "explicit_iter_loop", + "explicit_write", + "extend_with_drain", + "extra_unused_lifetimes", + "fallible_impl_from", + "field_reassign_with_default", + "filetype_is_file", + "filter_map_identity", + "filter_map_next", + "filter_next", + "flat_map_identity", + "flat_map_option", + "float_arithmetic", + "float_cmp", + "float_cmp_const", + "float_equality_without_abs", + "fn_address_comparisons", + "fn_params_excessive_bools", + "fn_to_numeric_cast", + "fn_to_numeric_cast_any", + "fn_to_numeric_cast_with_truncation", + "for_kv_map", + "for_loops_over_fallibles", + "forget_copy", + "forget_non_drop", + "forget_ref", + "format_in_format_args", + "format_push_string", + "from_iter_instead_of_collect", + "from_over_into", + "from_str_radix_10", + "future_not_send", + "get_first", + "get_last_with_len", + "get_unwrap", + "identity_op", + "if_let_mutex", + "if_not_else", + "if_same_then_else", + "if_then_some_else_none", + "ifs_same_cond", + "implicit_clone", + "implicit_hasher", + "implicit_return", + "implicit_saturating_sub", + "imprecise_flops", + "inconsistent_digit_grouping", + "inconsistent_struct_constructor", + "index_refutable_slice", + "indexing_slicing", + "ineffective_bit_mask", + "inefficient_to_string", + "infallible_destructuring_match", + "infinite_iter", + "inherent_to_string", + "inherent_to_string_shadow_display", + "init_numbered_fields", + "inline_always", + "inline_asm_x86_att_syntax", + "inline_asm_x86_intel_syntax", + "inline_fn_without_body", + "inspect_for_each", + "int_plus_one", + "integer_arithmetic", + "integer_division", + "into_iter_on_ref", + "invalid_null_ptr_usage", + "invalid_regex", + "invalid_upcast_comparisons", + "invalid_utf8_in_unchecked", + "invisible_characters", + "is_digit_ascii_radix", + "items_after_statements", + "iter_cloned_collect", + "iter_count", + "iter_next_loop", + "iter_next_slice", + "iter_not_returning_iterator", + "iter_nth", + "iter_nth_zero", + "iter_on_empty_collections", + "iter_on_single_items", + "iter_overeager_cloned", + "iter_skip_next", + "iter_with_drain", + "iterator_step_by_zero", + "just_underscores_and_digits", + "large_const_arrays", + "large_digit_groups", + "large_enum_variant", + "large_include_file", + "large_stack_arrays", + "large_types_passed_by_value", + "len_without_is_empty", + "len_zero", + "let_and_return", + "let_underscore_drop", + "let_underscore_lock", + "let_underscore_must_use", + "let_unit_value", + "linkedlist", + "lossy_float_literal", + "macro_use_imports", + "main_recursion", + "manual_assert", + "manual_async_fn", + "manual_bits", + "manual_filter_map", + "manual_find", + "manual_find_map", + "manual_flatten", + "manual_instant_elapsed", + "manual_map", + "manual_memcpy", + "manual_non_exhaustive", + "manual_ok_or", + "manual_range_contains", + "manual_rem_euclid", + "manual_retain", + "manual_saturating_arithmetic", + "manual_split_once", + "manual_str_repeat", + "manual_string_new", + "manual_strip", + "manual_swap", + "manual_unwrap_or", + "many_single_char_names", + "map_clone", + "map_collect_result_unit", + "map_entry", + "map_err_ignore", + "map_flatten", + "map_identity", + "map_unwrap_or", + "match_as_ref", + "match_bool", + "match_like_matches_macro", + "match_on_vec_items", + "match_overlapping_arm", + "match_ref_pats", + "match_result_ok", + "match_same_arms", + "match_single_binding", + "match_str_case_mismatch", + "match_wild_err_arm", + "match_wildcard_for_single_variants", + "maybe_infinite_iter", + "mem_forget", + "mem_replace_option_with_none", + "mem_replace_with_default", + "mem_replace_with_uninit", + "min_max", + "mismatched_target_os", + "mismatching_type_param_order", + "misrefactored_assign_op", + "missing_const_for_fn", + "missing_docs_in_private_items", + "missing_enforced_import_renames", + "missing_errors_doc", + "missing_inline_in_public_items", + "missing_panics_doc", + "missing_safety_doc", + "missing_spin_loop", + "mistyped_literal_suffixes", + "mixed_case_hex_literals", + "mixed_read_write_in_expression", + "mod_module_files", + "module_inception", + "module_name_repetitions", + "modulo_arithmetic", + "modulo_one", + "multi_assignments", + "multiple_crate_versions", + "multiple_inherent_impl", + "must_use_candidate", + "must_use_unit", + "mut_from_ref", + "mut_mut", + "mut_mutex_lock", + "mut_range_bound", + "mutable_key_type", + "mutex_atomic", + "mutex_integer", + "naive_bytecount", + "needless_arbitrary_self_type", + "needless_bitwise_bool", + "needless_bool", + "needless_borrow", + "needless_borrowed_reference", + "needless_collect", + "needless_continue", + "needless_doctest_main", + "needless_for_each", + "needless_late_init", + "needless_lifetimes", + "needless_match", + "needless_option_as_deref", + "needless_option_take", + "needless_parens_on_range_literals", + "needless_pass_by_value", + "needless_question_mark", + "needless_range_loop", + "needless_return", + "needless_splitn", + "needless_update", + "neg_cmp_op_on_partial_ord", + "neg_multiply", + "negative_feature_names", + "never_loop", + "new_ret_no_self", + "new_without_default", + "no_effect", + "no_effect_replace", + "no_effect_underscore_binding", + "non_ascii_literal", + "non_octal_unix_permissions", + "non_send_fields_in_send_ty", + "nonminimal_bool", + "nonsensical_open_options", + "nonstandard_macro_braces", + "not_unsafe_ptr_arg_deref", + "obfuscated_if_else", + "octal_escapes", + "ok_expect", + "only_used_in_recursion", + "op_ref", + "option_as_ref_deref", + "option_env_unwrap", + "option_filter_map", + "option_if_let_else", + "option_map_or_none", + "option_map_unit_fn", + "option_option", + "or_fun_call", + "or_then_unwrap", + "out_of_bounds_indexing", + "overflow_check_conditional", + "overly_complex_bool_expr", + "panic", + "panic_in_result_fn", + "panicking_unwrap", + "partialeq_ne_impl", + "partialeq_to_none", + "path_buf_push_overwrite", + "pattern_type_mismatch", + "positional_named_format_parameters", + "possible_missing_comma", + "precedence", + "print_in_format_impl", + "print_literal", + "print_stderr", + "print_stdout", + "print_with_newline", + "println_empty_string", + "ptr_arg", + "ptr_as_ptr", + "ptr_eq", + "ptr_offset_with_cast", + "pub_use", + "question_mark", + "range_minus_one", + "range_plus_one", + "range_zip_with_len", + "rc_buffer", + "rc_clone_in_vec_init", + "rc_mutex", + "read_zero_byte_vec", + "recursive_format_impl", + "redundant_allocation", + "redundant_clone", + "redundant_closure", + "redundant_closure_call", + "redundant_closure_for_method_calls", + "redundant_else", + "redundant_feature_names", + "redundant_field_names", + "redundant_pattern", + "redundant_pattern_matching", + "redundant_pub_crate", + "redundant_slicing", + "redundant_static_lifetimes", + "ref_binding_to_reference", + "ref_option_ref", + "repeat_once", + "rest_pat_in_fully_bound_structs", + "result_large_err", + "result_map_or_into_option", + "result_map_unit_fn", + "result_unit_err", + "return_self_not_must_use", + "reversed_empty_ranges", + "same_functions_in_if_condition", + "same_item_push", + "same_name_method", + "search_is_some", + "self_assignment", + "self_named_constructors", + "self_named_module_files", + "semicolon_if_nothing_returned", + "separated_literal_suffix", + "serde_api_misuse", + "shadow_reuse", + "shadow_same", + "shadow_unrelated", + "short_circuit_statement", + "should_implement_trait", + "significant_drop_in_scrutinee", + "similar_names", + "single_char_add_str", + "single_char_lifetime_names", + "single_char_pattern", + "single_component_path_imports", + "single_element_loop", + "single_match", + "single_match_else", + "size_of_in_element_count", + "skip_while_next", + "slow_vector_initialization", + "stable_sort_primitive", + "std_instead_of_alloc", + "std_instead_of_core", + "str_to_string", + "string_add", + "string_add_assign", + "string_extend_chars", + "string_from_utf8_as_bytes", + "string_lit_as_bytes", + "string_slice", + "string_to_string", + "strlen_on_c_strings", + "struct_excessive_bools", + "suboptimal_flops", + "suspicious_arithmetic_impl", + "suspicious_assignment_formatting", + "suspicious_else_formatting", + "suspicious_map", + "suspicious_op_assign_impl", + "suspicious_operation_groupings", + "suspicious_splitn", + "suspicious_to_owned", + "suspicious_unary_op_formatting", + "swap_ptr_to_ref", + "tabs_in_doc_comments", + "temporary_assignment", + "to_digit_is_some", + "to_string_in_format_args", + "todo", + "too_many_arguments", + "too_many_lines", + "toplevel_ref_arg", + "trailing_empty_array", + "trait_duplication_in_bounds", + "transmute_bytes_to_str", + "transmute_float_to_int", + "transmute_int_to_bool", + "transmute_int_to_char", + "transmute_int_to_float", + "transmute_num_to_bytes", + "transmute_ptr_to_ptr", + "transmute_ptr_to_ref", + "transmute_undefined_repr", + "transmutes_expressible_as_ptr_casts", + "transmuting_null", + "trim_split_whitespace", + "trivial_regex", + "trivially_copy_pass_by_ref", + "try_err", + "type_complexity", + "type_repetition_in_bounds", + "undocumented_unsafe_blocks", + "undropped_manually_drops", + "unicode_not_nfc", + "unimplemented", + "uninit_assumed_init", + "uninit_vec", + "unit_arg", + "unit_cmp", + "unit_hash", + "unit_return_expecting_ord", + "unnecessary_cast", + "unnecessary_filter_map", + "unnecessary_find_map", + "unnecessary_fold", + "unnecessary_join", + "unnecessary_lazy_evaluations", + "unnecessary_mut_passed", + "unnecessary_operation", + "unnecessary_owned_empty_strings", + "unnecessary_self_imports", + "unnecessary_sort_by", + "unnecessary_to_owned", + "unnecessary_unwrap", + "unnecessary_wraps", + "unneeded_field_pattern", + "unneeded_wildcard_pattern", + "unnested_or_patterns", + "unreachable", + "unreadable_literal", + "unsafe_derive_deserialize", + "unsafe_removed_from_name", + "unseparated_literal_suffix", + "unsound_collection_transmute", + "unused_async", + "unused_io_amount", + "unused_peekable", + "unused_rounding", + "unused_self", + "unused_unit", + "unusual_byte_groupings", + "unwrap_in_result", + "unwrap_or_else_default", + "unwrap_used", + "upper_case_acronyms", + "use_debug", + "use_self", + "used_underscore_binding", + "useless_asref", + "useless_attribute", + "useless_conversion", + "useless_format", + "useless_let_if_seq", + "useless_transmute", + "useless_vec", + "vec_box", + "vec_init_then_push", + "vec_resize_to_zero", + "verbose_bit_mask", + "verbose_file_reads", + "vtable_address_comparisons", + "while_immutable_condition", + "while_let_loop", + "while_let_on_iterator", + "wildcard_dependencies", + "wildcard_enum_match_arm", + "wildcard_imports", + "wildcard_in_or_patterns", + "write_literal", + "write_with_newline", + "writeln_empty_string", + "wrong_self_convention", + "wrong_transmute", + "zero_divided_by_zero", + "zero_prefixed_literal", + "zero_ptr", + "zero_sized_map_values", + "zst_offset", + +} diff --git a/src/docs/absurd_extreme_comparisons.txt b/src/docs/absurd_extreme_comparisons.txt new file mode 100644 index 0000000000000..590bee28aa237 --- /dev/null +++ b/src/docs/absurd_extreme_comparisons.txt @@ -0,0 +1,25 @@ +### What it does +Checks for comparisons where one side of the relation is +either the minimum or maximum value for its type and warns if it involves a +case that is always true or always false. Only integer and boolean types are +checked. + +### Why is this bad? +An expression like `min <= x` may misleadingly imply +that it is possible for `x` to be less than the minimum. Expressions like +`max < x` are probably mistakes. + +### Known problems +For `usize` the size of the current compile target will +be assumed (e.g., 64 bits on 64 bit systems). This means code that uses such +a comparison to detect target pointer width will trigger this lint. One can +use `mem::sizeof` and compare its value or conditional compilation +attributes +like `#[cfg(target_pointer_width = "64")] ..` instead. + +### Example +``` +let vec: Vec = Vec::new(); +if vec.len() <= 0 {} +if 100 > i32::MAX {} +``` \ No newline at end of file diff --git a/src/docs/alloc_instead_of_core.txt b/src/docs/alloc_instead_of_core.txt new file mode 100644 index 0000000000000..488a36e9276c2 --- /dev/null +++ b/src/docs/alloc_instead_of_core.txt @@ -0,0 +1,18 @@ +### What it does + +Finds items imported through `alloc` when available through `core`. + +### Why is this bad? + +Crates which have `no_std` compatibility and may optionally require alloc may wish to ensure types are +imported from core to ensure disabling `alloc` does not cause the crate to fail to compile. This lint +is also useful for crates migrating to become `no_std` compatible. + +### Example +``` +use alloc::slice::from_ref; +``` +Use instead: +``` +use core::slice::from_ref; +``` \ No newline at end of file diff --git a/src/docs/allow_attributes_without_reason.txt b/src/docs/allow_attributes_without_reason.txt new file mode 100644 index 0000000000000..fcc4f49b08b37 --- /dev/null +++ b/src/docs/allow_attributes_without_reason.txt @@ -0,0 +1,22 @@ +### What it does +Checks for attributes that allow lints without a reason. + +(This requires the `lint_reasons` feature) + +### Why is this bad? +Allowing a lint should always have a reason. This reason should be documented to +ensure that others understand the reasoning + +### Example +``` +#![feature(lint_reasons)] + +#![allow(clippy::some_lint)] +``` + +Use instead: +``` +#![feature(lint_reasons)] + +#![allow(clippy::some_lint, reason = "False positive rust-lang/rust-clippy#1002020")] +``` \ No newline at end of file diff --git a/src/docs/almost_complete_letter_range.txt b/src/docs/almost_complete_letter_range.txt new file mode 100644 index 0000000000000..01cbaf9eae259 --- /dev/null +++ b/src/docs/almost_complete_letter_range.txt @@ -0,0 +1,15 @@ +### What it does +Checks for ranges which almost include the entire range of letters from 'a' to 'z', but +don't because they're a half open range. + +### Why is this bad? +This (`'a'..'z'`) is almost certainly a typo meant to include all letters. + +### Example +``` +let _ = 'a'..'z'; +``` +Use instead: +``` +let _ = 'a'..='z'; +``` \ No newline at end of file diff --git a/src/docs/almost_swapped.txt b/src/docs/almost_swapped.txt new file mode 100644 index 0000000000000..cd10a8d5409b1 --- /dev/null +++ b/src/docs/almost_swapped.txt @@ -0,0 +1,15 @@ +### What it does +Checks for `foo = bar; bar = foo` sequences. + +### Why is this bad? +This looks like a failed attempt to swap. + +### Example +``` +a = b; +b = a; +``` +If swapping is intended, use `swap()` instead: +``` +std::mem::swap(&mut a, &mut b); +``` \ No newline at end of file diff --git a/src/docs/approx_constant.txt b/src/docs/approx_constant.txt new file mode 100644 index 0000000000000..393fa4b5ef7ec --- /dev/null +++ b/src/docs/approx_constant.txt @@ -0,0 +1,24 @@ +### What it does +Checks for floating point literals that approximate +constants which are defined in +[`std::f32::consts`](https://doc.rust-lang.org/stable/std/f32/consts/#constants) +or +[`std::f64::consts`](https://doc.rust-lang.org/stable/std/f64/consts/#constants), +respectively, suggesting to use the predefined constant. + +### Why is this bad? +Usually, the definition in the standard library is more +precise than what people come up with. If you find that your definition is +actually more precise, please [file a Rust +issue](https://github.com/rust-lang/rust/issues). + +### Example +``` +let x = 3.14; +let y = 1_f64 / x; +``` +Use instead: +``` +let x = std::f32::consts::PI; +let y = std::f64::consts::FRAC_1_PI; +``` \ No newline at end of file diff --git a/src/docs/arithmetic_side_effects.txt b/src/docs/arithmetic_side_effects.txt new file mode 100644 index 0000000000000..6c7d51a4989e0 --- /dev/null +++ b/src/docs/arithmetic_side_effects.txt @@ -0,0 +1,33 @@ +### What it does +Checks any kind of arithmetic operation of any type. + +Operators like `+`, `-`, `*` or `<<` are usually capable of overflowing according to the [Rust +Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow), +or can panic (`/`, `%`). + +Known safe built-in types like `Wrapping` or `Saturing`, floats, operations in constant +environments, allowed types and non-constant operations that won't overflow are ignored. + +### Why is this bad? +For integers, overflow will trigger a panic in debug builds or wrap the result in +release mode; division by zero will cause a panic in either mode. As a result, it is +desirable to explicitly call checked, wrapping or saturating arithmetic methods. + +#### Example +``` +// `n` can be any number, including `i32::MAX`. +fn foo(n: i32) -> i32 { + n + 1 +} +``` + +Third-party types can also overflow or present unwanted side-effects. + +#### Example +``` +use rust_decimal::Decimal; +let _n = Decimal::MAX + Decimal::MAX; +``` + +### Allowed types +Custom allowed types can be specified through the "arithmetic-side-effects-allowed" filter. \ No newline at end of file diff --git a/src/docs/as_conversions.txt b/src/docs/as_conversions.txt new file mode 100644 index 0000000000000..4af479bd8111c --- /dev/null +++ b/src/docs/as_conversions.txt @@ -0,0 +1,32 @@ +### What it does +Checks for usage of `as` conversions. + +Note that this lint is specialized in linting *every single* use of `as` +regardless of whether good alternatives exist or not. +If you want more precise lints for `as`, please consider using these separate lints: +`unnecessary_cast`, `cast_lossless/cast_possible_truncation/cast_possible_wrap/cast_precision_loss/cast_sign_loss`, +`fn_to_numeric_cast(_with_truncation)`, `char_lit_as_u8`, `ref_to_mut` and `ptr_as_ptr`. +There is a good explanation the reason why this lint should work in this way and how it is useful +[in this issue](https://github.com/rust-lang/rust-clippy/issues/5122). + +### Why is this bad? +`as` conversions will perform many kinds of +conversions, including silently lossy conversions and dangerous coercions. +There are cases when it makes sense to use `as`, so the lint is +Allow by default. + +### Example +``` +let a: u32; +... +f(a as u16); +``` + +Use instead: +``` +f(a.try_into()?); + +// or + +f(a.try_into().expect("Unexpected u16 overflow in f")); +``` \ No newline at end of file diff --git a/src/docs/as_underscore.txt b/src/docs/as_underscore.txt new file mode 100644 index 0000000000000..2d9b0c358936b --- /dev/null +++ b/src/docs/as_underscore.txt @@ -0,0 +1,21 @@ +### What it does +Check for the usage of `as _` conversion using inferred type. + +### Why is this bad? +The conversion might include lossy conversion and dangerous cast that might go +undetected due to the type being inferred. + +The lint is allowed by default as using `_` is less wordy than always specifying the type. + +### Example +``` +fn foo(n: usize) {} +let n: u16 = 256; +foo(n as _); +``` +Use instead: +``` +fn foo(n: usize) {} +let n: u16 = 256; +foo(n as usize); +``` \ No newline at end of file diff --git a/src/docs/assertions_on_constants.txt b/src/docs/assertions_on_constants.txt new file mode 100644 index 0000000000000..270c1e3b639d9 --- /dev/null +++ b/src/docs/assertions_on_constants.txt @@ -0,0 +1,14 @@ +### What it does +Checks for `assert!(true)` and `assert!(false)` calls. + +### Why is this bad? +Will be optimized out by the compiler or should probably be replaced by a +`panic!()` or `unreachable!()` + +### Example +``` +assert!(false) +assert!(true) +const B: bool = false; +assert!(B) +``` \ No newline at end of file diff --git a/src/docs/assertions_on_result_states.txt b/src/docs/assertions_on_result_states.txt new file mode 100644 index 0000000000000..0889084fd3ad6 --- /dev/null +++ b/src/docs/assertions_on_result_states.txt @@ -0,0 +1,14 @@ +### What it does +Checks for `assert!(r.is_ok())` or `assert!(r.is_err())` calls. + +### Why is this bad? +An assertion failure cannot output an useful message of the error. + +### Known problems +The suggested replacement decreases the readability of code and log output. + +### Example +``` +assert!(r.is_ok()); +assert!(r.is_err()); +``` \ No newline at end of file diff --git a/src/docs/assign_op_pattern.txt b/src/docs/assign_op_pattern.txt new file mode 100644 index 0000000000000..f355c0cc18d37 --- /dev/null +++ b/src/docs/assign_op_pattern.txt @@ -0,0 +1,28 @@ +### What it does +Checks for `a = a op b` or `a = b commutative_op a` +patterns. + +### Why is this bad? +These can be written as the shorter `a op= b`. + +### Known problems +While forbidden by the spec, `OpAssign` traits may have +implementations that differ from the regular `Op` impl. + +### Example +``` +let mut a = 5; +let b = 0; +// ... + +a = a + b; +``` + +Use instead: +``` +let mut a = 5; +let b = 0; +// ... + +a += b; +``` \ No newline at end of file diff --git a/src/docs/async_yields_async.txt b/src/docs/async_yields_async.txt new file mode 100644 index 0000000000000..a40de6d2e4736 --- /dev/null +++ b/src/docs/async_yields_async.txt @@ -0,0 +1,28 @@ +### What it does +Checks for async blocks that yield values of types +that can themselves be awaited. + +### Why is this bad? +An await is likely missing. + +### Example +``` +async fn foo() {} + +fn bar() { + let x = async { + foo() + }; +} +``` + +Use instead: +``` +async fn foo() {} + +fn bar() { + let x = async { + foo().await + }; +} +``` \ No newline at end of file diff --git a/src/docs/await_holding_invalid_type.txt b/src/docs/await_holding_invalid_type.txt new file mode 100644 index 0000000000000..e9c768772ff6b --- /dev/null +++ b/src/docs/await_holding_invalid_type.txt @@ -0,0 +1,29 @@ +### What it does +Allows users to configure types which should not be held across `await` +suspension points. + +### Why is this bad? +There are some types which are perfectly "safe" to be used concurrently +from a memory access perspective but will cause bugs at runtime if they +are held in such a way. + +### Example + +``` +await-holding-invalid-types = [ + # You can specify a type name + "CustomLockType", + # You can (optionally) specify a reason + { path = "OtherCustomLockType", reason = "Relies on a thread local" } +] +``` + +``` +struct CustomLockType; +struct OtherCustomLockType; +async fn foo() { + let _x = CustomLockType; + let _y = OtherCustomLockType; + baz().await; // Lint violation +} +``` \ No newline at end of file diff --git a/src/docs/await_holding_lock.txt b/src/docs/await_holding_lock.txt new file mode 100644 index 0000000000000..0f450a11160cc --- /dev/null +++ b/src/docs/await_holding_lock.txt @@ -0,0 +1,51 @@ +### What it does +Checks for calls to await while holding a non-async-aware MutexGuard. + +### Why is this bad? +The Mutex types found in std::sync and parking_lot +are not designed to operate in an async context across await points. + +There are two potential solutions. One is to use an async-aware Mutex +type. Many asynchronous foundation crates provide such a Mutex type. The +other solution is to ensure the mutex is unlocked before calling await, +either by introducing a scope or an explicit call to Drop::drop. + +### Known problems +Will report false positive for explicitly dropped guards +([#6446](https://github.com/rust-lang/rust-clippy/issues/6446)). A workaround for this is +to wrap the `.lock()` call in a block instead of explicitly dropping the guard. + +### Example +``` +async fn foo(x: &Mutex) { + let mut guard = x.lock().unwrap(); + *guard += 1; + baz().await; +} + +async fn bar(x: &Mutex) { + let mut guard = x.lock().unwrap(); + *guard += 1; + drop(guard); // explicit drop + baz().await; +} +``` + +Use instead: +``` +async fn foo(x: &Mutex) { + { + let mut guard = x.lock().unwrap(); + *guard += 1; + } + baz().await; +} + +async fn bar(x: &Mutex) { + { + let mut guard = x.lock().unwrap(); + *guard += 1; + } // guard dropped here at end of scope + baz().await; +} +``` \ No newline at end of file diff --git a/src/docs/await_holding_refcell_ref.txt b/src/docs/await_holding_refcell_ref.txt new file mode 100644 index 0000000000000..226a261b9cc52 --- /dev/null +++ b/src/docs/await_holding_refcell_ref.txt @@ -0,0 +1,47 @@ +### What it does +Checks for calls to await while holding a `RefCell` `Ref` or `RefMut`. + +### Why is this bad? +`RefCell` refs only check for exclusive mutable access +at runtime. Holding onto a `RefCell` ref across an `await` suspension point +risks panics from a mutable ref shared while other refs are outstanding. + +### Known problems +Will report false positive for explicitly dropped refs +([#6353](https://github.com/rust-lang/rust-clippy/issues/6353)). A workaround for this is +to wrap the `.borrow[_mut]()` call in a block instead of explicitly dropping the ref. + +### Example +``` +async fn foo(x: &RefCell) { + let mut y = x.borrow_mut(); + *y += 1; + baz().await; +} + +async fn bar(x: &RefCell) { + let mut y = x.borrow_mut(); + *y += 1; + drop(y); // explicit drop + baz().await; +} +``` + +Use instead: +``` +async fn foo(x: &RefCell) { + { + let mut y = x.borrow_mut(); + *y += 1; + } + baz().await; +} + +async fn bar(x: &RefCell) { + { + let mut y = x.borrow_mut(); + *y += 1; + } // y dropped here at end of scope + baz().await; +} +``` \ No newline at end of file diff --git a/src/docs/bad_bit_mask.txt b/src/docs/bad_bit_mask.txt new file mode 100644 index 0000000000000..d40024ee56209 --- /dev/null +++ b/src/docs/bad_bit_mask.txt @@ -0,0 +1,30 @@ +### What it does +Checks for incompatible bit masks in comparisons. + +The formula for detecting if an expression of the type `_ m + c` (where `` is one of {`&`, `|`} and `` is one of +{`!=`, `>=`, `>`, `!=`, `>=`, `>`}) can be determined from the following +table: + +|Comparison |Bit Op|Example |is always|Formula | +|------------|------|-------------|---------|----------------------| +|`==` or `!=`| `&` |`x & 2 == 3` |`false` |`c & m != c` | +|`<` or `>=`| `&` |`x & 2 < 3` |`true` |`m < c` | +|`>` or `<=`| `&` |`x & 1 > 1` |`false` |`m <= c` | +|`==` or `!=`| `\|` |`x \| 1 == 0`|`false` |`c \| m != c` | +|`<` or `>=`| `\|` |`x \| 1 < 1` |`false` |`m >= c` | +|`<=` or `>` | `\|` |`x \| 1 > 0` |`true` |`m > c` | + +### Why is this bad? +If the bits that the comparison cares about are always +set to zero or one by the bit mask, the comparison is constant `true` or +`false` (depending on mask, compared value, and operators). + +So the code is actively misleading, and the only reason someone would write +this intentionally is to win an underhanded Rust contest or create a +test-case for this lint. + +### Example +``` +if (x & 1 == 2) { } +``` \ No newline at end of file diff --git a/src/docs/bind_instead_of_map.txt b/src/docs/bind_instead_of_map.txt new file mode 100644 index 0000000000000..148575803d389 --- /dev/null +++ b/src/docs/bind_instead_of_map.txt @@ -0,0 +1,22 @@ +### What it does +Checks for usage of `_.and_then(|x| Some(y))`, `_.and_then(|x| Ok(y))` or +`_.or_else(|x| Err(y))`. + +### Why is this bad? +Readability, this can be written more concisely as +`_.map(|x| y)` or `_.map_err(|x| y)`. + +### Example +``` +let _ = opt().and_then(|s| Some(s.len())); +let _ = res().and_then(|s| if s.len() == 42 { Ok(10) } else { Ok(20) }); +let _ = res().or_else(|s| if s.len() == 42 { Err(10) } else { Err(20) }); +``` + +The correct use would be: + +``` +let _ = opt().map(|s| s.len()); +let _ = res().map(|s| if s.len() == 42 { 10 } else { 20 }); +let _ = res().map_err(|s| if s.len() == 42 { 10 } else { 20 }); +``` \ No newline at end of file diff --git a/src/docs/blanket_clippy_restriction_lints.txt b/src/docs/blanket_clippy_restriction_lints.txt new file mode 100644 index 0000000000000..28a4ebf7169bf --- /dev/null +++ b/src/docs/blanket_clippy_restriction_lints.txt @@ -0,0 +1,16 @@ +### What it does +Checks for `warn`/`deny`/`forbid` attributes targeting the whole clippy::restriction category. + +### Why is this bad? +Restriction lints sometimes are in contrast with other lints or even go against idiomatic rust. +These lints should only be enabled on a lint-by-lint basis and with careful consideration. + +### Example +``` +#![deny(clippy::restriction)] +``` + +Use instead: +``` +#![deny(clippy::as_conversions)] +``` \ No newline at end of file diff --git a/src/docs/blocks_in_if_conditions.txt b/src/docs/blocks_in_if_conditions.txt new file mode 100644 index 0000000000000..3afa14853fd21 --- /dev/null +++ b/src/docs/blocks_in_if_conditions.txt @@ -0,0 +1,21 @@ +### What it does +Checks for `if` conditions that use blocks containing an +expression, statements or conditions that use closures with blocks. + +### Why is this bad? +Style, using blocks in the condition makes it hard to read. + +### Examples +``` +if { true } { /* ... */ } + +if { let x = somefunc(); x } { /* ... */ } +``` + +Use instead: +``` +if true { /* ... */ } + +let res = { let x = somefunc(); x }; +if res { /* ... */ } +``` \ No newline at end of file diff --git a/src/docs/bool_assert_comparison.txt b/src/docs/bool_assert_comparison.txt new file mode 100644 index 0000000000000..df7ca00cc2ba4 --- /dev/null +++ b/src/docs/bool_assert_comparison.txt @@ -0,0 +1,16 @@ +### What it does +This lint warns about boolean comparisons in assert-like macros. + +### Why is this bad? +It is shorter to use the equivalent. + +### Example +``` +assert_eq!("a".is_empty(), false); +assert_ne!("a".is_empty(), true); +``` + +Use instead: +``` +assert!(!"a".is_empty()); +``` \ No newline at end of file diff --git a/src/docs/bool_comparison.txt b/src/docs/bool_comparison.txt new file mode 100644 index 0000000000000..0996f60cec44c --- /dev/null +++ b/src/docs/bool_comparison.txt @@ -0,0 +1,18 @@ +### What it does +Checks for expressions of the form `x == true`, +`x != true` and order comparisons such as `x < true` (or vice versa) and +suggest using the variable directly. + +### Why is this bad? +Unnecessary code. + +### Example +``` +if x == true {} +if y == false {} +``` +use `x` directly: +``` +if x {} +if !y {} +``` \ No newline at end of file diff --git a/src/docs/bool_to_int_with_if.txt b/src/docs/bool_to_int_with_if.txt new file mode 100644 index 0000000000000..63535b454c9f1 --- /dev/null +++ b/src/docs/bool_to_int_with_if.txt @@ -0,0 +1,26 @@ +### What it does +Instead of using an if statement to convert a bool to an int, +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. +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 + +### Example +``` +if condition { + 1_i64 +} else { + 0 +}; +``` +Use instead: +``` +i64::from(condition); +``` +or +``` +condition as i64; +``` \ No newline at end of file diff --git a/src/docs/borrow_as_ptr.txt b/src/docs/borrow_as_ptr.txt new file mode 100644 index 0000000000000..0be865abd5780 --- /dev/null +++ b/src/docs/borrow_as_ptr.txt @@ -0,0 +1,26 @@ +### What it does +Checks for the usage of `&expr as *const T` or +`&mut expr as *mut T`, and suggest using `ptr::addr_of` or +`ptr::addr_of_mut` instead. + +### Why is this bad? +This would improve readability and avoid creating a reference +that points to an uninitialized value or unaligned place. +Read the `ptr::addr_of` docs for more information. + +### Example +``` +let val = 1; +let p = &val as *const i32; + +let mut val_mut = 1; +let p_mut = &mut val_mut as *mut i32; +``` +Use instead: +``` +let val = 1; +let p = std::ptr::addr_of!(val); + +let mut val_mut = 1; +let p_mut = std::ptr::addr_of_mut!(val_mut); +``` \ No newline at end of file diff --git a/src/docs/borrow_deref_ref.txt b/src/docs/borrow_deref_ref.txt new file mode 100644 index 0000000000000..352480d3f26a7 --- /dev/null +++ b/src/docs/borrow_deref_ref.txt @@ -0,0 +1,27 @@ +### What it does +Checks for `&*(&T)`. + +### Why is this bad? +Dereferencing and then borrowing a reference value has no effect in most cases. + +### Known problems +False negative on such code: +``` +let x = &12; +let addr_x = &x as *const _ as usize; +let addr_y = &&*x as *const _ as usize; // assert ok now, and lint triggered. + // But if we fix it, assert will fail. +assert_ne!(addr_x, addr_y); +``` + +### Example +``` +let s = &String::new(); + +let a: &String = &* s; +``` + +Use instead: +``` +let a: &String = s; +``` \ No newline at end of file diff --git a/src/docs/borrow_interior_mutable_const.txt b/src/docs/borrow_interior_mutable_const.txt new file mode 100644 index 0000000000000..e55b6a77e6667 --- /dev/null +++ b/src/docs/borrow_interior_mutable_const.txt @@ -0,0 +1,40 @@ +### What it does +Checks if `const` items which is interior mutable (e.g., +contains a `Cell`, `Mutex`, `AtomicXxxx`, etc.) has been borrowed directly. + +### Why is this bad? +Consts are copied everywhere they are referenced, i.e., +every time you refer to the const a fresh instance of the `Cell` or `Mutex` +or `AtomicXxxx` will be created, which defeats the whole purpose of using +these types in the first place. + +The `const` value should be stored inside a `static` item. + +### Known problems +When an enum has variants with interior mutability, use of its non +interior mutable variants can generate false positives. See issue +[#3962](https://github.com/rust-lang/rust-clippy/issues/3962) + +Types that have underlying or potential interior mutability trigger the lint whether +the interior mutable field is used or not. See issues +[#5812](https://github.com/rust-lang/rust-clippy/issues/5812) and +[#3825](https://github.com/rust-lang/rust-clippy/issues/3825) + +### Example +``` +use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; +const CONST_ATOM: AtomicUsize = AtomicUsize::new(12); + +CONST_ATOM.store(6, SeqCst); // the content of the atomic is unchanged +assert_eq!(CONST_ATOM.load(SeqCst), 12); // because the CONST_ATOM in these lines are distinct +``` + +Use instead: +``` +use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; +const CONST_ATOM: AtomicUsize = AtomicUsize::new(12); + +static STATIC_ATOM: AtomicUsize = CONST_ATOM; +STATIC_ATOM.store(9, SeqCst); +assert_eq!(STATIC_ATOM.load(SeqCst), 9); // use a `static` item to refer to the same instance +``` \ No newline at end of file diff --git a/src/docs/borrowed_box.txt b/src/docs/borrowed_box.txt new file mode 100644 index 0000000000000..d7089be662a58 --- /dev/null +++ b/src/docs/borrowed_box.txt @@ -0,0 +1,19 @@ +### What it does +Checks for use of `&Box` anywhere in the code. +Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information. + +### Why is this bad? +A `&Box` parameter requires the function caller to box `T` first before passing it to a function. +Using `&T` defines a concrete type for the parameter and generalizes the function, this would also +auto-deref to `&T` at the function call site if passed a `&Box`. + +### Example +``` +fn foo(bar: &Box) { ... } +``` + +Better: + +``` +fn foo(bar: &T) { ... } +``` \ No newline at end of file diff --git a/src/docs/box_collection.txt b/src/docs/box_collection.txt new file mode 100644 index 0000000000000..053f24c46281d --- /dev/null +++ b/src/docs/box_collection.txt @@ -0,0 +1,23 @@ +### What it does +Checks for use of `Box` where T is a collection such as Vec anywhere in the code. +Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information. + +### Why is this bad? +Collections already keeps their contents in a separate area on +the heap. So if you `Box` them, you just add another level of indirection +without any benefit whatsoever. + +### Example +``` +struct X { + values: Box>, +} +``` + +Better: + +``` +struct X { + values: Vec, +} +``` \ No newline at end of file diff --git a/src/docs/boxed_local.txt b/src/docs/boxed_local.txt new file mode 100644 index 0000000000000..8b1febf1455fd --- /dev/null +++ b/src/docs/boxed_local.txt @@ -0,0 +1,18 @@ +### What it does +Checks for usage of `Box` where an unboxed `T` would +work fine. + +### Why is this bad? +This is an unnecessary allocation, and bad for +performance. It is only necessary to allocate if you wish to move the box +into something. + +### Example +``` +fn foo(x: Box) {} +``` + +Use instead: +``` +fn foo(x: u32) {} +``` \ No newline at end of file diff --git a/src/docs/branches_sharing_code.txt b/src/docs/branches_sharing_code.txt new file mode 100644 index 0000000000000..79be6124798a2 --- /dev/null +++ b/src/docs/branches_sharing_code.txt @@ -0,0 +1,32 @@ +### What it does +Checks if the `if` and `else` block contain shared code that can be +moved out of the blocks. + +### Why is this bad? +Duplicate code is less maintainable. + +### Known problems +* The lint doesn't check if the moved expressions modify values that are being used in + the if condition. The suggestion can in that case modify the behavior of the program. + See [rust-clippy#7452](https://github.com/rust-lang/rust-clippy/issues/7452) + +### Example +``` +let foo = if … { + println!("Hello World"); + 13 +} else { + println!("Hello World"); + 42 +}; +``` + +Use instead: +``` +println!("Hello World"); +let foo = if … { + 13 +} else { + 42 +}; +``` \ No newline at end of file diff --git a/src/docs/builtin_type_shadow.txt b/src/docs/builtin_type_shadow.txt new file mode 100644 index 0000000000000..15b1c9df7baab --- /dev/null +++ b/src/docs/builtin_type_shadow.txt @@ -0,0 +1,15 @@ +### What it does +Warns if a generic shadows a built-in type. + +### Why is this bad? +This gives surprising type errors. + +### Example + +``` +impl Foo { + fn impl_func(&self) -> u32 { + 42 + } +} +``` \ No newline at end of file diff --git a/src/docs/bytes_count_to_len.txt b/src/docs/bytes_count_to_len.txt new file mode 100644 index 0000000000000..ca7bf9a38da8e --- /dev/null +++ b/src/docs/bytes_count_to_len.txt @@ -0,0 +1,18 @@ +### What it does +It checks for `str::bytes().count()` and suggests replacing it with +`str::len()`. + +### Why is this bad? +`str::bytes().count()` is longer and may not be as performant as using +`str::len()`. + +### Example +``` +"hello".bytes().count(); +String::from("hello").bytes().count(); +``` +Use instead: +``` +"hello".len(); +String::from("hello").len(); +``` \ No newline at end of file diff --git a/src/docs/bytes_nth.txt b/src/docs/bytes_nth.txt new file mode 100644 index 0000000000000..260de343353d8 --- /dev/null +++ b/src/docs/bytes_nth.txt @@ -0,0 +1,16 @@ +### What it does +Checks for the use of `.bytes().nth()`. + +### Why is this bad? +`.as_bytes().get()` is more efficient and more +readable. + +### Example +``` +"Hello".bytes().nth(3); +``` + +Use instead: +``` +"Hello".as_bytes().get(3); +``` \ No newline at end of file diff --git a/src/docs/cargo_common_metadata.txt b/src/docs/cargo_common_metadata.txt new file mode 100644 index 0000000000000..1998647a92740 --- /dev/null +++ b/src/docs/cargo_common_metadata.txt @@ -0,0 +1,33 @@ +### What it does +Checks to see if all common metadata is defined in +`Cargo.toml`. See: https://rust-lang-nursery.github.io/api-guidelines/documentation.html#cargotoml-includes-all-common-metadata-c-metadata + +### Why is this bad? +It will be more difficult for users to discover the +purpose of the crate, and key information related to it. + +### Example +``` +[package] +name = "clippy" +version = "0.0.212" +repository = "https://github.com/rust-lang/rust-clippy" +readme = "README.md" +license = "MIT OR Apache-2.0" +keywords = ["clippy", "lint", "plugin"] +categories = ["development-tools", "development-tools::cargo-plugins"] +``` + +Should include a description field like: + +``` +[package] +name = "clippy" +version = "0.0.212" +description = "A bunch of helpful lints to avoid common pitfalls in Rust" +repository = "https://github.com/rust-lang/rust-clippy" +readme = "README.md" +license = "MIT OR Apache-2.0" +keywords = ["clippy", "lint", "plugin"] +categories = ["development-tools", "development-tools::cargo-plugins"] +``` \ No newline at end of file diff --git a/src/docs/case_sensitive_file_extension_comparisons.txt b/src/docs/case_sensitive_file_extension_comparisons.txt new file mode 100644 index 0000000000000..8e6e18ed4e23a --- /dev/null +++ b/src/docs/case_sensitive_file_extension_comparisons.txt @@ -0,0 +1,21 @@ +### What it does +Checks for calls to `ends_with` with possible file extensions +and suggests to use a case-insensitive approach instead. + +### Why is this bad? +`ends_with` is case-sensitive and may not detect files with a valid extension. + +### Example +``` +fn is_rust_file(filename: &str) -> bool { + filename.ends_with(".rs") +} +``` +Use instead: +``` +fn is_rust_file(filename: &str) -> bool { + let filename = std::path::Path::new(filename); + filename.extension() + .map_or(false, |ext| ext.eq_ignore_ascii_case("rs")) +} +``` \ No newline at end of file diff --git a/src/docs/cast_abs_to_unsigned.txt b/src/docs/cast_abs_to_unsigned.txt new file mode 100644 index 0000000000000..c5d8ee034ce59 --- /dev/null +++ b/src/docs/cast_abs_to_unsigned.txt @@ -0,0 +1,16 @@ +### What it does +Checks for uses of the `abs()` method that cast the result to unsigned. + +### Why is this bad? +The `unsigned_abs()` method avoids panic when called on the MIN value. + +### Example +``` +let x: i32 = -42; +let y: u32 = x.abs() as u32; +``` +Use instead: +``` +let x: i32 = -42; +let y: u32 = x.unsigned_abs(); +``` \ No newline at end of file diff --git a/src/docs/cast_enum_constructor.txt b/src/docs/cast_enum_constructor.txt new file mode 100644 index 0000000000000..675c03a42bc23 --- /dev/null +++ b/src/docs/cast_enum_constructor.txt @@ -0,0 +1,11 @@ +### What it does +Checks for casts from an enum tuple constructor to an integer. + +### Why is this bad? +The cast is easily confused with casting a c-like enum value to an integer. + +### Example +``` +enum E { X(i32) }; +let _ = E::X as usize; +``` \ No newline at end of file diff --git a/src/docs/cast_enum_truncation.txt b/src/docs/cast_enum_truncation.txt new file mode 100644 index 0000000000000..abe32a8296da2 --- /dev/null +++ b/src/docs/cast_enum_truncation.txt @@ -0,0 +1,12 @@ +### What it does +Checks for casts from an enum type to an integral type which will definitely truncate the +value. + +### Why is this bad? +The resulting integral value will not match the value of the variant it came from. + +### Example +``` +enum E { X = 256 }; +let _ = E::X as u8; +``` \ No newline at end of file diff --git a/src/docs/cast_lossless.txt b/src/docs/cast_lossless.txt new file mode 100644 index 0000000000000..c3a61dd470fc9 --- /dev/null +++ b/src/docs/cast_lossless.txt @@ -0,0 +1,26 @@ +### What it does +Checks for casts between numerical types that may +be replaced by safe conversion functions. + +### Why is this bad? +Rust's `as` keyword will perform many kinds of +conversions, including silently lossy conversions. Conversion functions such +as `i32::from` will only perform lossless conversions. Using the conversion +functions prevents conversions from turning into silent lossy conversions if +the types of the input expressions ever change, and make it easier for +people reading the code to know that the conversion is lossless. + +### Example +``` +fn as_u64(x: u8) -> u64 { + x as u64 +} +``` + +Using `::from` would look like this: + +``` +fn as_u64(x: u8) -> u64 { + u64::from(x) +} +``` \ No newline at end of file diff --git a/src/docs/cast_possible_truncation.txt b/src/docs/cast_possible_truncation.txt new file mode 100644 index 0000000000000..0b164848cc7c2 --- /dev/null +++ b/src/docs/cast_possible_truncation.txt @@ -0,0 +1,16 @@ +### What it does +Checks for casts between numerical types that may +truncate large values. This is expected behavior, so the cast is `Allow` by +default. + +### Why is this bad? +In some problem domains, it is good practice to avoid +truncation. This lint can be activated to help assess where additional +checks could be beneficial. + +### Example +``` +fn as_u8(x: u64) -> u8 { + x as u8 +} +``` \ No newline at end of file diff --git a/src/docs/cast_possible_wrap.txt b/src/docs/cast_possible_wrap.txt new file mode 100644 index 0000000000000..f883fc9cfb994 --- /dev/null +++ b/src/docs/cast_possible_wrap.txt @@ -0,0 +1,17 @@ +### What it does +Checks for casts from an unsigned type to a signed type of +the same size. Performing such a cast is a 'no-op' for the compiler, +i.e., nothing is changed at the bit level, and the binary representation of +the value is reinterpreted. This can cause wrapping if the value is too big +for the target signed type. However, the cast works as defined, so this lint +is `Allow` by default. + +### Why is this bad? +While such a cast is not bad in itself, the results can +be surprising when this is not the intended behavior, as demonstrated by the +example below. + +### Example +``` +u32::MAX as i32; // will yield a value of `-1` +``` \ No newline at end of file diff --git a/src/docs/cast_precision_loss.txt b/src/docs/cast_precision_loss.txt new file mode 100644 index 0000000000000..f915d9f8a6d0d --- /dev/null +++ b/src/docs/cast_precision_loss.txt @@ -0,0 +1,19 @@ +### What it does +Checks for casts from any numerical to a float type where +the receiving type cannot store all values from the original type without +rounding errors. This possible rounding is to be expected, so this lint is +`Allow` by default. + +Basically, this warns on casting any integer with 32 or more bits to `f32` +or any 64-bit integer to `f64`. + +### Why is this bad? +It's not bad at all. But in some applications it can be +helpful to know where precision loss can take place. This lint can help find +those places in the code. + +### Example +``` +let x = u64::MAX; +x as f64; +``` \ No newline at end of file diff --git a/src/docs/cast_ptr_alignment.txt b/src/docs/cast_ptr_alignment.txt new file mode 100644 index 0000000000000..6a6d4dcaa2ae5 --- /dev/null +++ b/src/docs/cast_ptr_alignment.txt @@ -0,0 +1,21 @@ +### What it does +Checks for casts, using `as` or `pointer::cast`, +from a less-strictly-aligned pointer to a more-strictly-aligned pointer + +### Why is this bad? +Dereferencing the resulting pointer may be undefined +behavior. + +### Known problems +Using `std::ptr::read_unaligned` and `std::ptr::write_unaligned` or similar +on the resulting pointer is fine. Is over-zealous: Casts with manual alignment checks or casts like +u64-> u8 -> u16 can be fine. Miri is able to do a more in-depth analysis. + +### Example +``` +let _ = (&1u8 as *const u8) as *const u16; +let _ = (&mut 1u8 as *mut u8) as *mut u16; + +(&1u8 as *const u8).cast::(); +(&mut 1u8 as *mut u8).cast::(); +``` \ No newline at end of file diff --git a/src/docs/cast_ref_to_mut.txt b/src/docs/cast_ref_to_mut.txt new file mode 100644 index 0000000000000..fb5b4dbb62d82 --- /dev/null +++ b/src/docs/cast_ref_to_mut.txt @@ -0,0 +1,28 @@ +### What it does +Checks for casts of `&T` to `&mut T` anywhere in the code. + +### Why is this bad? +It’s basically guaranteed to be undefined behavior. +`UnsafeCell` is the only way to obtain aliasable data that is considered +mutable. + +### Example +``` +fn x(r: &i32) { + unsafe { + *(r as *const _ as *mut _) += 1; + } +} +``` + +Instead consider using interior mutability types. + +``` +use std::cell::UnsafeCell; + +fn x(r: &UnsafeCell) { + unsafe { + *r.get() += 1; + } +} +``` \ No newline at end of file diff --git a/src/docs/cast_sign_loss.txt b/src/docs/cast_sign_loss.txt new file mode 100644 index 0000000000000..d64fe1b07f469 --- /dev/null +++ b/src/docs/cast_sign_loss.txt @@ -0,0 +1,15 @@ +### What it does +Checks for casts from a signed to an unsigned numerical +type. In this case, negative values wrap around to large positive values, +which can be quite surprising in practice. However, as the cast works as +defined, this lint is `Allow` by default. + +### Why is this bad? +Possibly surprising results. You can activate this lint +as a one-time check to see where numerical wrapping can arise. + +### Example +``` +let y: i8 = -1; +y as u128; // will return 18446744073709551615 +``` \ No newline at end of file diff --git a/src/docs/cast_slice_different_sizes.txt b/src/docs/cast_slice_different_sizes.txt new file mode 100644 index 0000000000000..c01ef0ba92c03 --- /dev/null +++ b/src/docs/cast_slice_different_sizes.txt @@ -0,0 +1,38 @@ +### What it does +Checks for `as` casts between raw pointers to slices with differently sized elements. + +### Why is this bad? +The produced raw pointer to a slice does not update its length metadata. The produced +pointer will point to a different number of bytes than the original pointer because the +length metadata of a raw slice pointer is in elements rather than bytes. +Producing a slice reference from the raw pointer will either create a slice with +less data (which can be surprising) or create a slice with more data and cause Undefined Behavior. + +### Example +// Missing data +``` +let a = [1_i32, 2, 3, 4]; +let p = &a as *const [i32] as *const [u8]; +unsafe { + println!("{:?}", &*p); +} +``` +// Undefined Behavior (note: also potential alignment issues) +``` +let a = [1_u8, 2, 3, 4]; +let p = &a as *const [u8] as *const [u32]; +unsafe { + println!("{:?}", &*p); +} +``` +Instead use `ptr::slice_from_raw_parts` to construct a slice from a data pointer and the correct length +``` +let a = [1_i32, 2, 3, 4]; +let old_ptr = &a as *const [i32]; +// The data pointer is cast to a pointer to the target `u8` not `[u8]` +// The length comes from the known length of 4 i32s times the 4 bytes per i32 +let new_ptr = core::ptr::slice_from_raw_parts(old_ptr as *const u8, 16); +unsafe { + println!("{:?}", &*new_ptr); +} +``` \ No newline at end of file diff --git a/src/docs/cast_slice_from_raw_parts.txt b/src/docs/cast_slice_from_raw_parts.txt new file mode 100644 index 0000000000000..b58c739766aab --- /dev/null +++ b/src/docs/cast_slice_from_raw_parts.txt @@ -0,0 +1,20 @@ +### What it does +Checks for a raw slice being cast to a slice pointer + +### Why is this bad? +This can result in multiple `&mut` references to the same location when only a pointer is +required. +`ptr::slice_from_raw_parts` is a safe alternative that doesn't require +the same [safety requirements] to be upheld. + +### Example +``` +let _: *const [u8] = std::slice::from_raw_parts(ptr, len) as *const _; +let _: *mut [u8] = std::slice::from_raw_parts_mut(ptr, len) as *mut _; +``` +Use instead: +``` +let _: *const [u8] = std::ptr::slice_from_raw_parts(ptr, len); +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 \ No newline at end of file diff --git a/src/docs/char_lit_as_u8.txt b/src/docs/char_lit_as_u8.txt new file mode 100644 index 0000000000000..00d60b9a451b9 --- /dev/null +++ b/src/docs/char_lit_as_u8.txt @@ -0,0 +1,21 @@ +### What it does +Checks for expressions where a character literal is cast +to `u8` and suggests using a byte literal instead. + +### Why is this bad? +In general, casting values to smaller types is +error-prone and should be avoided where possible. In the particular case of +converting a character literal to u8, it is easy to avoid by just using a +byte literal instead. As an added bonus, `b'a'` is even slightly shorter +than `'a' as u8`. + +### Example +``` +'x' as u8 +``` + +A better version, using the byte literal: + +``` +b'x' +``` \ No newline at end of file diff --git a/src/docs/chars_last_cmp.txt b/src/docs/chars_last_cmp.txt new file mode 100644 index 0000000000000..4c1d8838973a7 --- /dev/null +++ b/src/docs/chars_last_cmp.txt @@ -0,0 +1,17 @@ +### What it does +Checks for usage of `_.chars().last()` or +`_.chars().next_back()` on a `str` to check if it ends with a given char. + +### Why is this bad? +Readability, this can be written more concisely as +`_.ends_with(_)`. + +### Example +``` +name.chars().last() == Some('_') || name.chars().next_back() == Some('-'); +``` + +Use instead: +``` +name.ends_with('_') || name.ends_with('-'); +``` \ No newline at end of file diff --git a/src/docs/chars_next_cmp.txt b/src/docs/chars_next_cmp.txt new file mode 100644 index 0000000000000..77cbce2de00f9 --- /dev/null +++ b/src/docs/chars_next_cmp.txt @@ -0,0 +1,19 @@ +### What it does +Checks for usage of `.chars().next()` on a `str` to check +if it starts with a given char. + +### Why is this bad? +Readability, this can be written more concisely as +`_.starts_with(_)`. + +### Example +``` +let name = "foo"; +if name.chars().next() == Some('_') {}; +``` + +Use instead: +``` +let name = "foo"; +if name.starts_with('_') {}; +``` \ No newline at end of file diff --git a/src/docs/checked_conversions.txt b/src/docs/checked_conversions.txt new file mode 100644 index 0000000000000..536b01294ee17 --- /dev/null +++ b/src/docs/checked_conversions.txt @@ -0,0 +1,15 @@ +### What it does +Checks for explicit bounds checking when casting. + +### Why is this bad? +Reduces the readability of statements & is error prone. + +### Example +``` +foo <= i32::MAX as u32; +``` + +Use instead: +``` +i32::try_from(foo).is_ok(); +``` \ No newline at end of file diff --git a/src/docs/clone_double_ref.txt b/src/docs/clone_double_ref.txt new file mode 100644 index 0000000000000..2729635bd246f --- /dev/null +++ b/src/docs/clone_double_ref.txt @@ -0,0 +1,16 @@ +### What it does +Checks for usage of `.clone()` on an `&&T`. + +### Why is this bad? +Cloning an `&&T` copies the inner `&T`, instead of +cloning the underlying `T`. + +### Example +``` +fn main() { + let x = vec![1]; + let y = &&x; + let z = y.clone(); + println!("{:p} {:p}", *y, z); // prints out the same pointer +} +``` \ No newline at end of file diff --git a/src/docs/clone_on_copy.txt b/src/docs/clone_on_copy.txt new file mode 100644 index 0000000000000..99a0bdb4c4ac0 --- /dev/null +++ b/src/docs/clone_on_copy.txt @@ -0,0 +1,11 @@ +### What it does +Checks for usage of `.clone()` on a `Copy` type. + +### Why is this bad? +The only reason `Copy` types implement `Clone` is for +generics, not for using the `clone` method on a concrete type. + +### Example +``` +42u64.clone(); +``` \ No newline at end of file diff --git a/src/docs/clone_on_ref_ptr.txt b/src/docs/clone_on_ref_ptr.txt new file mode 100644 index 0000000000000..2d83f8fefc122 --- /dev/null +++ b/src/docs/clone_on_ref_ptr.txt @@ -0,0 +1,21 @@ +### What it does +Checks for usage of `.clone()` on a ref-counted pointer, +(`Rc`, `Arc`, `rc::Weak`, or `sync::Weak`), and suggests calling Clone via unified +function syntax instead (e.g., `Rc::clone(foo)`). + +### Why is this bad? +Calling '.clone()' on an Rc, Arc, or Weak +can obscure the fact that only the pointer is being cloned, not the underlying +data. + +### Example +``` +let x = Rc::new(1); + +x.clone(); +``` + +Use instead: +``` +Rc::clone(&x); +``` \ No newline at end of file diff --git a/src/docs/cloned_instead_of_copied.txt b/src/docs/cloned_instead_of_copied.txt new file mode 100644 index 0000000000000..2f2014d5fd299 --- /dev/null +++ b/src/docs/cloned_instead_of_copied.txt @@ -0,0 +1,16 @@ +### What it does +Checks for usages of `cloned()` on an `Iterator` or `Option` where +`copied()` could be used instead. + +### Why is this bad? +`copied()` is better because it guarantees that the type being cloned +implements `Copy`. + +### Example +``` +[1, 2, 3].iter().cloned(); +``` +Use instead: +``` +[1, 2, 3].iter().copied(); +``` \ No newline at end of file diff --git a/src/docs/cmp_nan.txt b/src/docs/cmp_nan.txt new file mode 100644 index 0000000000000..e2ad04d932359 --- /dev/null +++ b/src/docs/cmp_nan.txt @@ -0,0 +1,16 @@ +### What it does +Checks for comparisons to NaN. + +### Why is this bad? +NaN does not compare meaningfully to anything – not +even itself – so those comparisons are simply wrong. + +### Example +``` +if x == f32::NAN { } +``` + +Use instead: +``` +if x.is_nan() { } +``` \ No newline at end of file diff --git a/src/docs/cmp_null.txt b/src/docs/cmp_null.txt new file mode 100644 index 0000000000000..02fd15124f038 --- /dev/null +++ b/src/docs/cmp_null.txt @@ -0,0 +1,23 @@ +### What it does +This lint checks for equality comparisons with `ptr::null` + +### Why is this bad? +It's easier and more readable to use the inherent +`.is_null()` +method instead + +### Example +``` +use std::ptr; + +if x == ptr::null { + // .. +} +``` + +Use instead: +``` +if x.is_null() { + // .. +} +``` \ No newline at end of file diff --git a/src/docs/cmp_owned.txt b/src/docs/cmp_owned.txt new file mode 100644 index 0000000000000..f8d4956ff1d4b --- /dev/null +++ b/src/docs/cmp_owned.txt @@ -0,0 +1,18 @@ +### What it does +Checks for conversions to owned values just for the sake +of a comparison. + +### Why is this bad? +The comparison can operate on a reference, so creating +an owned value effectively throws it away directly afterwards, which is +needlessly consuming code and heap space. + +### Example +``` +if x.to_owned() == y {} +``` + +Use instead: +``` +if x == y {} +``` \ No newline at end of file diff --git a/src/docs/cognitive_complexity.txt b/src/docs/cognitive_complexity.txt new file mode 100644 index 0000000000000..fdd75f6479cd0 --- /dev/null +++ b/src/docs/cognitive_complexity.txt @@ -0,0 +1,13 @@ +### What it does +Checks for methods with high cognitive complexity. + +### Why is this bad? +Methods of high cognitive complexity tend to be hard to +both read and maintain. Also LLVM will tend to optimize small methods better. + +### Known problems +Sometimes it's hard to find a way to reduce the +complexity. + +### Example +You'll see it when you get the warning. \ No newline at end of file diff --git a/src/docs/collapsible_else_if.txt b/src/docs/collapsible_else_if.txt new file mode 100644 index 0000000000000..4ddfca17731f7 --- /dev/null +++ b/src/docs/collapsible_else_if.txt @@ -0,0 +1,29 @@ +### What it does +Checks for collapsible `else { if ... }` expressions +that can be collapsed to `else if ...`. + +### Why is this bad? +Each `if`-statement adds one level of nesting, which +makes code look more complex than it really is. + +### Example +``` + +if x { + … +} else { + if y { + … + } +} +``` + +Should be written: + +``` +if x { + … +} else if y { + … +} +``` \ No newline at end of file diff --git a/src/docs/collapsible_if.txt b/src/docs/collapsible_if.txt new file mode 100644 index 0000000000000..e1264ee062e95 --- /dev/null +++ b/src/docs/collapsible_if.txt @@ -0,0 +1,23 @@ +### What it does +Checks for nested `if` statements which can be collapsed +by `&&`-combining their conditions. + +### Why is this bad? +Each `if`-statement adds one level of nesting, which +makes code look more complex than it really is. + +### Example +``` +if x { + if y { + // … + } +} +``` + +Use instead: +``` +if x && y { + // … +} +``` \ No newline at end of file diff --git a/src/docs/collapsible_match.txt b/src/docs/collapsible_match.txt new file mode 100644 index 0000000000000..0d59594a03a27 --- /dev/null +++ b/src/docs/collapsible_match.txt @@ -0,0 +1,31 @@ +### What it does +Finds nested `match` or `if let` expressions where the patterns may be "collapsed" together +without adding any branches. + +Note that this lint is not intended to find _all_ cases where nested match patterns can be merged, but only +cases where merging would most likely make the code more readable. + +### Why is this bad? +It is unnecessarily verbose and complex. + +### Example +``` +fn func(opt: Option>) { + let n = match opt { + Some(n) => match n { + Ok(n) => n, + _ => return, + } + None => return, + }; +} +``` +Use instead: +``` +fn func(opt: Option>) { + let n = match opt { + Some(Ok(n)) => n, + _ => return, + }; +} +``` \ No newline at end of file diff --git a/src/docs/collapsible_str_replace.txt b/src/docs/collapsible_str_replace.txt new file mode 100644 index 0000000000000..c24c25a3028a5 --- /dev/null +++ b/src/docs/collapsible_str_replace.txt @@ -0,0 +1,19 @@ +### What it does +Checks for consecutive calls to `str::replace` (2 or more) +that can be collapsed into a single call. + +### Why is this bad? +Consecutive `str::replace` calls scan the string multiple times +with repetitive code. + +### Example +``` +let hello = "hesuo worpd" + .replace('s', "l") + .replace("u", "l") + .replace('p', "l"); +``` +Use instead: +``` +let hello = "hesuo worpd".replace(&['s', 'u', 'p'], "l"); +``` \ No newline at end of file diff --git a/src/docs/comparison_chain.txt b/src/docs/comparison_chain.txt new file mode 100644 index 0000000000000..43b09f31ff4aa --- /dev/null +++ b/src/docs/comparison_chain.txt @@ -0,0 +1,36 @@ +### What it does +Checks comparison chains written with `if` that can be +rewritten with `match` and `cmp`. + +### Why is this bad? +`if` is not guaranteed to be exhaustive and conditionals can get +repetitive + +### Known problems +The match statement may be slower due to the compiler +not inlining the call to cmp. See issue [#5354](https://github.com/rust-lang/rust-clippy/issues/5354) + +### Example +``` +fn f(x: u8, y: u8) { + if x > y { + a() + } else if x < y { + b() + } else { + c() + } +} +``` + +Use instead: +``` +use std::cmp::Ordering; +fn f(x: u8, y: u8) { + match x.cmp(&y) { + Ordering::Greater => a(), + Ordering::Less => b(), + Ordering::Equal => c() + } +} +``` \ No newline at end of file diff --git a/src/docs/comparison_to_empty.txt b/src/docs/comparison_to_empty.txt new file mode 100644 index 0000000000000..db6f74fe2706b --- /dev/null +++ b/src/docs/comparison_to_empty.txt @@ -0,0 +1,31 @@ +### What it does +Checks for comparing to an empty slice such as `""` or `[]`, +and suggests using `.is_empty()` where applicable. + +### Why is this bad? +Some structures can answer `.is_empty()` much faster +than checking for equality. So it is good to get into the habit of using +`.is_empty()`, and having it is cheap. +Besides, it makes the intent clearer than a manual comparison in some contexts. + +### Example + +``` +if s == "" { + .. +} + +if arr == [] { + .. +} +``` +Use instead: +``` +if s.is_empty() { + .. +} + +if arr.is_empty() { + .. +} +``` \ No newline at end of file diff --git a/src/docs/copy_iterator.txt b/src/docs/copy_iterator.txt new file mode 100644 index 0000000000000..5f9a2a015b86c --- /dev/null +++ b/src/docs/copy_iterator.txt @@ -0,0 +1,20 @@ +### What it does +Checks for types that implement `Copy` as well as +`Iterator`. + +### Why is this bad? +Implicit copies can be confusing when working with +iterator combinators. + +### Example +``` +#[derive(Copy, Clone)] +struct Countdown(u8); + +impl Iterator for Countdown { + // ... +} + +let a: Vec<_> = my_iterator.take(1).collect(); +let b: Vec<_> = my_iterator.collect(); +``` \ No newline at end of file diff --git a/src/docs/crate_in_macro_def.txt b/src/docs/crate_in_macro_def.txt new file mode 100644 index 0000000000000..047e986dee71f --- /dev/null +++ b/src/docs/crate_in_macro_def.txt @@ -0,0 +1,35 @@ +### What it does +Checks for use of `crate` as opposed to `$crate` in a macro definition. + +### Why is this bad? +`crate` refers to the macro call's crate, whereas `$crate` refers to the macro definition's +crate. Rarely is the former intended. See: +https://doc.rust-lang.org/reference/macros-by-example.html#hygiene + +### Example +``` +#[macro_export] +macro_rules! print_message { + () => { + println!("{}", crate::MESSAGE); + }; +} +pub const MESSAGE: &str = "Hello!"; +``` +Use instead: +``` +#[macro_export] +macro_rules! print_message { + () => { + println!("{}", $crate::MESSAGE); + }; +} +pub const MESSAGE: &str = "Hello!"; +``` + +Note that if the use of `crate` is intentional, an `allow` attribute can be applied to the +macro definition, e.g.: +``` +#[allow(clippy::crate_in_macro_def)] +macro_rules! ok { ... crate::foo ... } +``` \ No newline at end of file diff --git a/src/docs/create_dir.txt b/src/docs/create_dir.txt new file mode 100644 index 0000000000000..e4e7937684e6e --- /dev/null +++ b/src/docs/create_dir.txt @@ -0,0 +1,15 @@ +### What it does +Checks usage of `std::fs::create_dir` and suggest using `std::fs::create_dir_all` instead. + +### Why is this bad? +Sometimes `std::fs::create_dir` is mistakenly chosen over `std::fs::create_dir_all`. + +### Example +``` +std::fs::create_dir("foo"); +``` + +Use instead: +``` +std::fs::create_dir_all("foo"); +``` \ No newline at end of file diff --git a/src/docs/crosspointer_transmute.txt b/src/docs/crosspointer_transmute.txt new file mode 100644 index 0000000000000..49dea154970e5 --- /dev/null +++ b/src/docs/crosspointer_transmute.txt @@ -0,0 +1,12 @@ +### What it does +Checks for transmutes between a type `T` and `*T`. + +### Why is this bad? +It's easy to mistakenly transmute between a type and a +pointer to that type. + +### Example +``` +core::intrinsics::transmute(t) // where the result type is the same as + // `*t` or `&t`'s +``` \ No newline at end of file diff --git a/src/docs/dbg_macro.txt b/src/docs/dbg_macro.txt new file mode 100644 index 0000000000000..3e1a9a043f9f4 --- /dev/null +++ b/src/docs/dbg_macro.txt @@ -0,0 +1,16 @@ +### What it does +Checks for usage of dbg!() macro. + +### Why is this bad? +`dbg!` macro is intended as a debugging tool. It +should not be in version control. + +### Example +``` +dbg!(true) +``` + +Use instead: +``` +true +``` \ No newline at end of file diff --git a/src/docs/debug_assert_with_mut_call.txt b/src/docs/debug_assert_with_mut_call.txt new file mode 100644 index 0000000000000..2c44abe1f05c8 --- /dev/null +++ b/src/docs/debug_assert_with_mut_call.txt @@ -0,0 +1,18 @@ +### What it does +Checks for function/method calls with a mutable +parameter in `debug_assert!`, `debug_assert_eq!` and `debug_assert_ne!` macros. + +### Why is this bad? +In release builds `debug_assert!` macros are optimized out by the +compiler. +Therefore mutating something in a `debug_assert!` macro results in different behavior +between a release and debug build. + +### Example +``` +debug_assert_eq!(vec![3].pop(), Some(3)); + +// or + +debug_assert!(takes_a_mut_parameter(&mut x)); +``` \ No newline at end of file diff --git a/src/docs/decimal_literal_representation.txt b/src/docs/decimal_literal_representation.txt new file mode 100644 index 0000000000000..daca9bbb3a848 --- /dev/null +++ b/src/docs/decimal_literal_representation.txt @@ -0,0 +1,13 @@ +### What it does +Warns if there is a better representation for a numeric literal. + +### Why is this bad? +Especially for big powers of 2 a hexadecimal representation is more +readable than a decimal representation. + +### Example +``` +`255` => `0xFF` +`65_535` => `0xFFFF` +`4_042_322_160` => `0xF0F0_F0F0` +``` \ No newline at end of file diff --git a/src/docs/declare_interior_mutable_const.txt b/src/docs/declare_interior_mutable_const.txt new file mode 100644 index 0000000000000..2801b5ccff802 --- /dev/null +++ b/src/docs/declare_interior_mutable_const.txt @@ -0,0 +1,46 @@ +### What it does +Checks for declaration of `const` items which is interior +mutable (e.g., contains a `Cell`, `Mutex`, `AtomicXxxx`, etc.). + +### Why is this bad? +Consts are copied everywhere they are referenced, i.e., +every time you refer to the const a fresh instance of the `Cell` or `Mutex` +or `AtomicXxxx` will be created, which defeats the whole purpose of using +these types in the first place. + +The `const` should better be replaced by a `static` item if a global +variable is wanted, or replaced by a `const fn` if a constructor is wanted. + +### Known problems +A "non-constant" const item is a legacy way to supply an +initialized value to downstream `static` items (e.g., the +`std::sync::ONCE_INIT` constant). In this case the use of `const` is legit, +and this lint should be suppressed. + +Even though the lint avoids triggering on a constant whose type has enums that have variants +with interior mutability, and its value uses non interior mutable variants (see +[#3962](https://github.com/rust-lang/rust-clippy/issues/3962) and +[#3825](https://github.com/rust-lang/rust-clippy/issues/3825) for examples); +it complains about associated constants without default values only based on its types; +which might not be preferable. +There're other enums plus associated constants cases that the lint cannot handle. + +Types that have underlying or potential interior mutability trigger the lint whether +the interior mutable field is used or not. See issues +[#5812](https://github.com/rust-lang/rust-clippy/issues/5812) and + +### Example +``` +use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; + +const CONST_ATOM: AtomicUsize = AtomicUsize::new(12); +CONST_ATOM.store(6, SeqCst); // the content of the atomic is unchanged +assert_eq!(CONST_ATOM.load(SeqCst), 12); // because the CONST_ATOM in these lines are distinct +``` + +Use instead: +``` +static STATIC_ATOM: AtomicUsize = AtomicUsize::new(15); +STATIC_ATOM.store(9, SeqCst); +assert_eq!(STATIC_ATOM.load(SeqCst), 9); // use a `static` item to refer to the same instance +``` \ No newline at end of file diff --git a/src/docs/default_instead_of_iter_empty.txt b/src/docs/default_instead_of_iter_empty.txt new file mode 100644 index 0000000000000..b63ef3d18fc41 --- /dev/null +++ b/src/docs/default_instead_of_iter_empty.txt @@ -0,0 +1,15 @@ +### What it does +It checks for `std::iter::Empty::default()` and suggests replacing it with +`std::iter::empty()`. +### Why is this bad? +`std::iter::empty()` is the more idiomatic way. +### Example +``` +let _ = std::iter::Empty::::default(); +let iter: std::iter::Empty = std::iter::Empty::default(); +``` +Use instead: +``` +let _ = std::iter::empty::(); +let iter: std::iter::Empty = std::iter::empty(); +``` \ No newline at end of file diff --git a/src/docs/default_numeric_fallback.txt b/src/docs/default_numeric_fallback.txt new file mode 100644 index 0000000000000..15076a0a68bf6 --- /dev/null +++ b/src/docs/default_numeric_fallback.txt @@ -0,0 +1,28 @@ +### What it does +Checks for usage of unconstrained numeric literals which may cause default numeric fallback in type +inference. + +Default numeric fallback means that if numeric types have not yet been bound to concrete +types at the end of type inference, then integer type is bound to `i32`, and similarly +floating type is bound to `f64`. + +See [RFC0212](https://github.com/rust-lang/rfcs/blob/master/text/0212-restore-int-fallback.md) for more information about the fallback. + +### Why is this bad? +For those who are very careful about types, default numeric fallback +can be a pitfall that cause unexpected runtime behavior. + +### Known problems +This lint can only be allowed at the function level or above. + +### Example +``` +let i = 10; +let f = 1.23; +``` + +Use instead: +``` +let i = 10i32; +let f = 1.23f64; +``` \ No newline at end of file diff --git a/src/docs/default_trait_access.txt b/src/docs/default_trait_access.txt new file mode 100644 index 0000000000000..e69298969c8ed --- /dev/null +++ b/src/docs/default_trait_access.txt @@ -0,0 +1,16 @@ +### What it does +Checks for literal calls to `Default::default()`. + +### Why is this bad? +It's easier for the reader if the name of the type is used, rather than the +generic `Default`. + +### Example +``` +let s: String = Default::default(); +``` + +Use instead: +``` +let s = String::default(); +``` \ No newline at end of file diff --git a/src/docs/default_union_representation.txt b/src/docs/default_union_representation.txt new file mode 100644 index 0000000000000..f79ff9760e57e --- /dev/null +++ b/src/docs/default_union_representation.txt @@ -0,0 +1,36 @@ +### What it does +Displays a warning when a union is declared with the default representation (without a `#[repr(C)]` attribute). + +### Why is this bad? +Unions in Rust have unspecified layout by default, despite many people thinking that they +lay out each field at the start of the union (like C does). That is, there are no guarantees +about the offset of the fields for unions with multiple non-ZST fields without an explicitly +specified layout. These cases may lead to undefined behavior in unsafe blocks. + +### Example +``` +union Foo { + a: i32, + b: u32, +} + +fn main() { + let _x: u32 = unsafe { + Foo { a: 0_i32 }.b // Undefined behavior: `b` is allowed to be padding + }; +} +``` +Use instead: +``` +#[repr(C)] +union Foo { + a: i32, + b: u32, +} + +fn main() { + let _x: u32 = unsafe { + Foo { a: 0_i32 }.b // Now defined behavior, this is just an i32 -> u32 transmute + }; +} +``` \ No newline at end of file diff --git a/src/docs/deprecated_cfg_attr.txt b/src/docs/deprecated_cfg_attr.txt new file mode 100644 index 0000000000000..9f264887a057e --- /dev/null +++ b/src/docs/deprecated_cfg_attr.txt @@ -0,0 +1,24 @@ +### What it does +Checks for `#[cfg_attr(rustfmt, rustfmt_skip)]` and suggests to replace it +with `#[rustfmt::skip]`. + +### Why is this bad? +Since tool_attributes ([rust-lang/rust#44690](https://github.com/rust-lang/rust/issues/44690)) +are stable now, they should be used instead of the old `cfg_attr(rustfmt)` attributes. + +### Known problems +This lint doesn't detect crate level inner attributes, because they get +processed before the PreExpansionPass lints get executed. See +[#3123](https://github.com/rust-lang/rust-clippy/pull/3123#issuecomment-422321765) + +### Example +``` +#[cfg_attr(rustfmt, rustfmt_skip)] +fn main() { } +``` + +Use instead: +``` +#[rustfmt::skip] +fn main() { } +``` \ No newline at end of file diff --git a/src/docs/deprecated_semver.txt b/src/docs/deprecated_semver.txt new file mode 100644 index 0000000000000..c9574a99b2bec --- /dev/null +++ b/src/docs/deprecated_semver.txt @@ -0,0 +1,13 @@ +### What it does +Checks for `#[deprecated]` annotations with a `since` +field that is not a valid semantic version. + +### Why is this bad? +For checking the version of the deprecation, it must be +a valid semver. Failing that, the contained information is useless. + +### Example +``` +#[deprecated(since = "forever")] +fn something_else() { /* ... */ } +``` \ No newline at end of file diff --git a/src/docs/deref_addrof.txt b/src/docs/deref_addrof.txt new file mode 100644 index 0000000000000..fa711b924d480 --- /dev/null +++ b/src/docs/deref_addrof.txt @@ -0,0 +1,22 @@ +### What it does +Checks for usage of `*&` and `*&mut` in expressions. + +### Why is this bad? +Immediately dereferencing a reference is no-op and +makes the code less clear. + +### Known problems +Multiple dereference/addrof pairs are not handled so +the suggested fix for `x = **&&y` is `x = *&y`, which is still incorrect. + +### Example +``` +let a = f(*&mut b); +let c = *&d; +``` + +Use instead: +``` +let a = f(b); +let c = d; +``` \ No newline at end of file diff --git a/src/docs/deref_by_slicing.txt b/src/docs/deref_by_slicing.txt new file mode 100644 index 0000000000000..4dad24ac00cad --- /dev/null +++ b/src/docs/deref_by_slicing.txt @@ -0,0 +1,17 @@ +### What it does +Checks for slicing expressions which are equivalent to dereferencing the +value. + +### Why is this bad? +Some people may prefer to dereference rather than slice. + +### Example +``` +let vec = vec![1, 2, 3]; +let slice = &vec[..]; +``` +Use instead: +``` +let vec = vec![1, 2, 3]; +let slice = &*vec; +``` \ No newline at end of file diff --git a/src/docs/derivable_impls.txt b/src/docs/derivable_impls.txt new file mode 100644 index 0000000000000..5cee43956cc36 --- /dev/null +++ b/src/docs/derivable_impls.txt @@ -0,0 +1,35 @@ +### What it does +Detects manual `std::default::Default` implementations that are identical to a derived implementation. + +### Why is this bad? +It is less concise. + +### Example +``` +struct Foo { + bar: bool +} + +impl Default for Foo { + fn default() -> Self { + Self { + bar: false + } + } +} +``` + +Use instead: +``` +#[derive(Default)] +struct Foo { + bar: bool +} +``` + +### Known problems +Derive macros [sometimes use incorrect bounds](https://github.com/rust-lang/rust/issues/26925) +in generic types and the user defined `impl` may be more generalized or +specialized than what derive will produce. This lint can't detect the manual `impl` +has exactly equal bounds, and therefore this lint is disabled for types with +generic parameters. \ No newline at end of file diff --git a/src/docs/derive_hash_xor_eq.txt b/src/docs/derive_hash_xor_eq.txt new file mode 100644 index 0000000000000..fbf623d5adbc1 --- /dev/null +++ b/src/docs/derive_hash_xor_eq.txt @@ -0,0 +1,23 @@ +### What it does +Checks for deriving `Hash` but implementing `PartialEq` +explicitly or vice versa. + +### Why is this bad? +The implementation of these traits must agree (for +example for use with `HashMap`) so it’s probably a bad idea to use a +default-generated `Hash` implementation with an explicitly defined +`PartialEq`. In particular, the following must hold for any type: + +``` +k1 == k2 ⇒ hash(k1) == hash(k2) +``` + +### Example +``` +#[derive(Hash)] +struct Foo; + +impl PartialEq for Foo { + ... +} +``` \ No newline at end of file diff --git a/src/docs/derive_ord_xor_partial_ord.txt b/src/docs/derive_ord_xor_partial_ord.txt new file mode 100644 index 0000000000000..f2107a5f69eea --- /dev/null +++ b/src/docs/derive_ord_xor_partial_ord.txt @@ -0,0 +1,44 @@ +### What it does +Checks for deriving `Ord` but implementing `PartialOrd` +explicitly or vice versa. + +### Why is this bad? +The implementation of these traits must agree (for +example for use with `sort`) so it’s probably a bad idea to use a +default-generated `Ord` implementation with an explicitly defined +`PartialOrd`. In particular, the following must hold for any type +implementing `Ord`: + +``` +k1.cmp(&k2) == k1.partial_cmp(&k2).unwrap() +``` + +### Example +``` +#[derive(Ord, PartialEq, Eq)] +struct Foo; + +impl PartialOrd for Foo { + ... +} +``` +Use instead: +``` +#[derive(PartialEq, Eq)] +struct Foo; + +impl PartialOrd for Foo { + fn partial_cmp(&self, other: &Foo) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for Foo { + ... +} +``` +or, if you don't need a custom ordering: +``` +#[derive(Ord, PartialOrd, PartialEq, Eq)] +struct Foo; +``` \ No newline at end of file diff --git a/src/docs/derive_partial_eq_without_eq.txt b/src/docs/derive_partial_eq_without_eq.txt new file mode 100644 index 0000000000000..932fabad666c3 --- /dev/null +++ b/src/docs/derive_partial_eq_without_eq.txt @@ -0,0 +1,25 @@ +### What it does +Checks for types that derive `PartialEq` and could implement `Eq`. + +### Why is this bad? +If a type `T` derives `PartialEq` and all of its members implement `Eq`, +then `T` can always implement `Eq`. Implementing `Eq` allows `T` to be used +in APIs that require `Eq` types. It also allows structs containing `T` to derive +`Eq` themselves. + +### Example +``` +#[derive(PartialEq)] +struct Foo { + i_am_eq: i32, + i_am_eq_too: Vec, +} +``` +Use instead: +``` +#[derive(PartialEq, Eq)] +struct Foo { + i_am_eq: i32, + i_am_eq_too: Vec, +} +``` \ No newline at end of file diff --git a/src/docs/disallowed_methods.txt b/src/docs/disallowed_methods.txt new file mode 100644 index 0000000000000..d8ad5b6a6674c --- /dev/null +++ b/src/docs/disallowed_methods.txt @@ -0,0 +1,41 @@ +### What it does +Denies the configured methods and functions in clippy.toml + +Note: Even though this lint is warn-by-default, it will only trigger if +methods are defined in the clippy.toml file. + +### Why is this bad? +Some methods are undesirable in certain contexts, and it's beneficial to +lint for them as needed. + +### Example +An example clippy.toml configuration: +``` +disallowed-methods = [ + # Can use a string as the path of the disallowed method. + "std::boxed::Box::new", + # Can also use an inline table with a `path` key. + { path = "std::time::Instant::now" }, + # When using an inline table, can add a `reason` for why the method + # is disallowed. + { path = "std::vec::Vec::leak", reason = "no leaking memory" }, +] +``` + +``` +// Example code where clippy issues a warning +let xs = vec![1, 2, 3, 4]; +xs.leak(); // Vec::leak is disallowed in the config. +// The diagnostic contains the message "no leaking memory". + +let _now = Instant::now(); // Instant::now is disallowed in the config. + +let _box = Box::new(3); // Box::new is disallowed in the config. +``` + +Use instead: +``` +// Example code which does not raise clippy warning +let mut xs = Vec::new(); // Vec::new is _not_ disallowed in the config. +xs.push(123); // Vec::push is _not_ disallowed in the config. +``` \ No newline at end of file diff --git a/src/docs/disallowed_names.txt b/src/docs/disallowed_names.txt new file mode 100644 index 0000000000000..f4aaee9c77b7b --- /dev/null +++ b/src/docs/disallowed_names.txt @@ -0,0 +1,12 @@ +### What it does +Checks for usage of disallowed names for variables, such +as `foo`. + +### Why is this bad? +These names are usually placeholder names and should be +avoided. + +### Example +``` +let foo = 3.14; +``` \ No newline at end of file diff --git a/src/docs/disallowed_script_idents.txt b/src/docs/disallowed_script_idents.txt new file mode 100644 index 0000000000000..2151b7a20dedc --- /dev/null +++ b/src/docs/disallowed_script_idents.txt @@ -0,0 +1,32 @@ +### What it does +Checks for usage of unicode scripts other than those explicitly allowed +by the lint config. + +This lint doesn't take into account non-text scripts such as `Unknown` and `Linear_A`. +It also ignores the `Common` script type. +While configuring, be sure to use official script name [aliases] from +[the list of supported scripts][supported_scripts]. + +See also: [`non_ascii_idents`]. + +[aliases]: http://www.unicode.org/reports/tr24/tr24-31.html#Script_Value_Aliases +[supported_scripts]: https://www.unicode.org/iso15924/iso15924-codes.html + +### Why is this bad? +It may be not desired to have many different scripts for +identifiers in the codebase. + +Note that if you only want to allow plain English, you might want to use +built-in [`non_ascii_idents`] lint instead. + +[`non_ascii_idents`]: https://doc.rust-lang.org/rustc/lints/listing/allowed-by-default.html#non-ascii-idents + +### Example +``` +// Assuming that `clippy.toml` contains the following line: +// allowed-locales = ["Latin", "Cyrillic"] +let counter = 10; // OK, latin is allowed. +let счётчик = 10; // OK, cyrillic is allowed. +let zähler = 10; // OK, it's still latin. +let カウンタ = 10; // Will spawn the lint. +``` \ No newline at end of file diff --git a/src/docs/disallowed_types.txt b/src/docs/disallowed_types.txt new file mode 100644 index 0000000000000..2bcbcddee5666 --- /dev/null +++ b/src/docs/disallowed_types.txt @@ -0,0 +1,33 @@ +### What it does +Denies the configured types in clippy.toml. + +Note: Even though this lint is warn-by-default, it will only trigger if +types are defined in the clippy.toml file. + +### Why is this bad? +Some types are undesirable in certain contexts. + +### Example: +An example clippy.toml configuration: +``` +disallowed-types = [ + # Can use a string as the path of the disallowed type. + "std::collections::BTreeMap", + # Can also use an inline table with a `path` key. + { path = "std::net::TcpListener" }, + # When using an inline table, can add a `reason` for why the type + # is disallowed. + { path = "std::net::Ipv4Addr", reason = "no IPv4 allowed" }, +] +``` + +``` +use std::collections::BTreeMap; +// or its use +let x = std::collections::BTreeMap::new(); +``` +Use instead: +``` +// A similar type that is allowed by the config +use std::collections::HashMap; +``` \ No newline at end of file diff --git a/src/docs/diverging_sub_expression.txt b/src/docs/diverging_sub_expression.txt new file mode 100644 index 0000000000000..1943622180251 --- /dev/null +++ b/src/docs/diverging_sub_expression.txt @@ -0,0 +1,19 @@ +### What it does +Checks for diverging calls that are not match arms or +statements. + +### Why is this bad? +It is often confusing to read. In addition, the +sub-expression evaluation order for Rust is not well documented. + +### Known problems +Someone might want to use `some_bool || panic!()` as a +shorthand. + +### Example +``` +let a = b() || panic!() || c(); +// `c()` is dead, `panic!()` is only called if `b()` returns `false` +let x = (a, b, c, panic!()); +// can simply be replaced by `panic!()` +``` \ No newline at end of file diff --git a/src/docs/doc_link_with_quotes.txt b/src/docs/doc_link_with_quotes.txt new file mode 100644 index 0000000000000..107c8ac116d93 --- /dev/null +++ b/src/docs/doc_link_with_quotes.txt @@ -0,0 +1,16 @@ +### What it does +Detects the syntax `['foo']` in documentation comments (notice quotes instead of backticks) +outside of code blocks +### Why is this bad? +It is likely a typo when defining an intra-doc link + +### Example +``` +/// See also: ['foo'] +fn bar() {} +``` +Use instead: +``` +/// See also: [`foo`] +fn bar() {} +``` \ No newline at end of file diff --git a/src/docs/doc_markdown.txt b/src/docs/doc_markdown.txt new file mode 100644 index 0000000000000..94f54c587e302 --- /dev/null +++ b/src/docs/doc_markdown.txt @@ -0,0 +1,35 @@ +### What it does +Checks for the presence of `_`, `::` or camel-case words +outside ticks in documentation. + +### Why is this bad? +*Rustdoc* supports markdown formatting, `_`, `::` and +camel-case probably indicates some code which should be included between +ticks. `_` can also be used for emphasis in markdown, this lint tries to +consider that. + +### Known problems +Lots of bad docs won’t be fixed, what the lint checks +for is limited, and there are still false positives. HTML elements and their +content are not linted. + +In addition, when writing documentation comments, including `[]` brackets +inside a link text would trip the parser. Therefore, documenting link with +`[`SmallVec<[T; INLINE_CAPACITY]>`]` and then [`SmallVec<[T; INLINE_CAPACITY]>`]: SmallVec +would fail. + +### Examples +``` +/// Do something with the foo_bar parameter. See also +/// that::other::module::foo. +// ^ `foo_bar` and `that::other::module::foo` should be ticked. +fn doit(foo_bar: usize) {} +``` + +``` +// Link text with `[]` brackets should be written as following: +/// Consume the array and return the inner +/// [`SmallVec<[T; INLINE_CAPACITY]>`][SmallVec]. +/// [SmallVec]: SmallVec +fn main() {} +``` \ No newline at end of file diff --git a/src/docs/double_comparisons.txt b/src/docs/double_comparisons.txt new file mode 100644 index 0000000000000..7dc6818779f4b --- /dev/null +++ b/src/docs/double_comparisons.txt @@ -0,0 +1,17 @@ +### What it does +Checks for double comparisons that could be simplified to a single expression. + + +### Why is this bad? +Readability. + +### Example +``` +if x == y || x < y {} +``` + +Use instead: + +``` +if x <= y {} +``` \ No newline at end of file diff --git a/src/docs/double_must_use.txt b/src/docs/double_must_use.txt new file mode 100644 index 0000000000000..0017d10d40d33 --- /dev/null +++ b/src/docs/double_must_use.txt @@ -0,0 +1,17 @@ +### What it does +Checks for a `#[must_use]` attribute without +further information on functions and methods that return a type already +marked as `#[must_use]`. + +### Why is this bad? +The attribute isn't needed. Not using the result +will already be reported. Alternatively, one can add some text to the +attribute to improve the lint message. + +### Examples +``` +#[must_use] +fn double_must_use() -> Result<(), ()> { + unimplemented!(); +} +``` \ No newline at end of file diff --git a/src/docs/double_neg.txt b/src/docs/double_neg.txt new file mode 100644 index 0000000000000..a07f67496d7cc --- /dev/null +++ b/src/docs/double_neg.txt @@ -0,0 +1,12 @@ +### What it does +Detects expressions of the form `--x`. + +### Why is this bad? +It can mislead C/C++ programmers to think `x` was +decremented. + +### Example +``` +let mut x = 3; +--x; +``` \ No newline at end of file diff --git a/src/docs/double_parens.txt b/src/docs/double_parens.txt new file mode 100644 index 0000000000000..260d7dd575e55 --- /dev/null +++ b/src/docs/double_parens.txt @@ -0,0 +1,24 @@ +### What it does +Checks for unnecessary double parentheses. + +### Why is this bad? +This makes code harder to read and might indicate a +mistake. + +### Example +``` +fn simple_double_parens() -> i32 { + ((0)) +} + +foo((0)); +``` + +Use instead: +``` +fn simple_no_parens() -> i32 { + 0 +} + +foo(0); +``` \ No newline at end of file diff --git a/src/docs/drop_copy.txt b/src/docs/drop_copy.txt new file mode 100644 index 0000000000000..f917ca8ed21a6 --- /dev/null +++ b/src/docs/drop_copy.txt @@ -0,0 +1,15 @@ +### What it does +Checks for calls to `std::mem::drop` with a value +that derives the Copy trait + +### Why is this bad? +Calling `std::mem::drop` [does nothing for types that +implement Copy](https://doc.rust-lang.org/std/mem/fn.drop.html), since the +value will be copied and moved into the function on invocation. + +### Example +``` +let x: i32 = 42; // i32 implements Copy +std::mem::drop(x) // A copy of x is passed to the function, leaving the + // original unaffected +``` \ No newline at end of file diff --git a/src/docs/drop_non_drop.txt b/src/docs/drop_non_drop.txt new file mode 100644 index 0000000000000..ee1e3a6c216ef --- /dev/null +++ b/src/docs/drop_non_drop.txt @@ -0,0 +1,13 @@ +### What it does +Checks for calls to `std::mem::drop` with a value that does not implement `Drop`. + +### Why is this bad? +Calling `std::mem::drop` is no different than dropping such a type. A different value may +have been intended. + +### Example +``` +struct Foo; +let x = Foo; +std::mem::drop(x); +``` \ No newline at end of file diff --git a/src/docs/drop_ref.txt b/src/docs/drop_ref.txt new file mode 100644 index 0000000000000..c4f7adf0cfa33 --- /dev/null +++ b/src/docs/drop_ref.txt @@ -0,0 +1,17 @@ +### What it does +Checks for calls to `std::mem::drop` with a reference +instead of an owned value. + +### Why is this bad? +Calling `drop` on a reference will only drop the +reference itself, which is a no-op. It will not call the `drop` method (from +the `Drop` trait implementation) on the underlying referenced value, which +is likely what was intended. + +### Example +``` +let mut lock_guard = mutex.lock(); +std::mem::drop(&lock_guard) // Should have been drop(lock_guard), mutex +// still locked +operation_that_requires_mutex_to_be_unlocked(); +``` \ No newline at end of file diff --git a/src/docs/duplicate_mod.txt b/src/docs/duplicate_mod.txt new file mode 100644 index 0000000000000..709a9aba03ad2 --- /dev/null +++ b/src/docs/duplicate_mod.txt @@ -0,0 +1,31 @@ +### What it does +Checks for files that are included as modules multiple times. + +### Why is this bad? +Loading a file as a module more than once causes it to be compiled +multiple times, taking longer and putting duplicate content into the +module tree. + +### Example +``` +// lib.rs +mod a; +mod b; +``` +``` +// a.rs +#[path = "./b.rs"] +mod b; +``` + +Use instead: + +``` +// lib.rs +mod a; +mod b; +``` +``` +// a.rs +use crate::b; +``` \ No newline at end of file diff --git a/src/docs/duplicate_underscore_argument.txt b/src/docs/duplicate_underscore_argument.txt new file mode 100644 index 0000000000000..a8fcd6a9fbe68 --- /dev/null +++ b/src/docs/duplicate_underscore_argument.txt @@ -0,0 +1,16 @@ +### What it does +Checks for function arguments having the similar names +differing by an underscore. + +### Why is this bad? +It affects code readability. + +### Example +``` +fn foo(a: i32, _a: i32) {} +``` + +Use instead: +``` +fn bar(a: i32, _b: i32) {} +``` \ No newline at end of file diff --git a/src/docs/duration_subsec.txt b/src/docs/duration_subsec.txt new file mode 100644 index 0000000000000..e7e0ca88745ee --- /dev/null +++ b/src/docs/duration_subsec.txt @@ -0,0 +1,19 @@ +### What it does +Checks for calculation of subsecond microseconds or milliseconds +from other `Duration` methods. + +### Why is this bad? +It's more concise to call `Duration::subsec_micros()` or +`Duration::subsec_millis()` than to calculate them. + +### Example +``` +let micros = duration.subsec_nanos() / 1_000; +let millis = duration.subsec_nanos() / 1_000_000; +``` + +Use instead: +``` +let micros = duration.subsec_micros(); +let millis = duration.subsec_millis(); +``` \ No newline at end of file diff --git a/src/docs/else_if_without_else.txt b/src/docs/else_if_without_else.txt new file mode 100644 index 0000000000000..33f5d0f918592 --- /dev/null +++ b/src/docs/else_if_without_else.txt @@ -0,0 +1,27 @@ +### What it does +Checks for usage of if expressions with an `else if` branch, +but without a final `else` branch. + +### Why is this bad? +Some coding guidelines require this (e.g., MISRA-C:2004 Rule 14.10). + +### Example +``` +if x.is_positive() { + a(); +} else if x.is_negative() { + b(); +} +``` + +Use instead: + +``` +if x.is_positive() { + a(); +} else if x.is_negative() { + b(); +} else { + // We don't care about zero. +} +``` \ No newline at end of file diff --git a/src/docs/empty_drop.txt b/src/docs/empty_drop.txt new file mode 100644 index 0000000000000..d0c0c24a9c880 --- /dev/null +++ b/src/docs/empty_drop.txt @@ -0,0 +1,20 @@ +### What it does +Checks for empty `Drop` implementations. + +### Why is this bad? +Empty `Drop` implementations have no effect when dropping an instance of the type. They are +most likely useless. However, an empty `Drop` implementation prevents a type from being +destructured, which might be the intention behind adding the implementation as a marker. + +### Example +``` +struct S; + +impl Drop for S { + fn drop(&mut self) {} +} +``` +Use instead: +``` +struct S; +``` \ No newline at end of file diff --git a/src/docs/empty_enum.txt b/src/docs/empty_enum.txt new file mode 100644 index 0000000000000..f7b41c41ee5a1 --- /dev/null +++ b/src/docs/empty_enum.txt @@ -0,0 +1,27 @@ +### What it does +Checks for `enum`s with no variants. + +As of this writing, the `never_type` is still a +nightly-only experimental API. Therefore, this lint is only triggered +if the `never_type` is enabled. + +### Why is this bad? +If you want to introduce a type which +can't be instantiated, you should use `!` (the primitive type "never"), +or a wrapper around it, because `!` has more extensive +compiler support (type inference, etc...) and wrappers +around it are the conventional way to define an uninhabited type. +For further information visit [never type documentation](https://doc.rust-lang.org/std/primitive.never.html) + + +### Example +``` +enum Test {} +``` + +Use instead: +``` +#![feature(never_type)] + +struct Test(!); +``` \ No newline at end of file diff --git a/src/docs/empty_line_after_outer_attr.txt b/src/docs/empty_line_after_outer_attr.txt new file mode 100644 index 0000000000000..c85242bbee0ec --- /dev/null +++ b/src/docs/empty_line_after_outer_attr.txt @@ -0,0 +1,35 @@ +### What it does +Checks for empty lines after outer attributes + +### Why is this bad? +Most likely the attribute was meant to be an inner attribute using a '!'. +If it was meant to be an outer attribute, then the following item +should not be separated by empty lines. + +### Known problems +Can cause false positives. + +From the clippy side it's difficult to detect empty lines between an attributes and the +following item because empty lines and comments are not part of the AST. The parsing +currently works for basic cases but is not perfect. + +### Example +``` +#[allow(dead_code)] + +fn not_quite_good_code() { } +``` + +Use instead: +``` +// Good (as inner attribute) +#![allow(dead_code)] + +fn this_is_fine() { } + +// or + +// Good (as outer attribute) +#[allow(dead_code)] +fn this_is_fine_too() { } +``` \ No newline at end of file diff --git a/src/docs/empty_loop.txt b/src/docs/empty_loop.txt new file mode 100644 index 0000000000000..fea49a74d04e0 --- /dev/null +++ b/src/docs/empty_loop.txt @@ -0,0 +1,27 @@ +### What it does +Checks for empty `loop` expressions. + +### Why is this bad? +These busy loops burn CPU cycles without doing +anything. It is _almost always_ a better idea to `panic!` than to have +a busy loop. + +If panicking isn't possible, think of the environment and either: + - block on something + - sleep the thread for some microseconds + - yield or pause the thread + +For `std` targets, this can be done with +[`std::thread::sleep`](https://doc.rust-lang.org/std/thread/fn.sleep.html) +or [`std::thread::yield_now`](https://doc.rust-lang.org/std/thread/fn.yield_now.html). + +For `no_std` targets, doing this is more complicated, especially because +`#[panic_handler]`s can't panic. To stop/pause the thread, you will +probably need to invoke some target-specific intrinsic. Examples include: + - [`x86_64::instructions::hlt`](https://docs.rs/x86_64/0.12.2/x86_64/instructions/fn.hlt.html) + - [`cortex_m::asm::wfi`](https://docs.rs/cortex-m/0.6.3/cortex_m/asm/fn.wfi.html) + +### Example +``` +loop {} +``` \ No newline at end of file diff --git a/src/docs/empty_structs_with_brackets.txt b/src/docs/empty_structs_with_brackets.txt new file mode 100644 index 0000000000000..ab5e35ae2ada8 --- /dev/null +++ b/src/docs/empty_structs_with_brackets.txt @@ -0,0 +1,14 @@ +### What it does +Finds structs without fields (a so-called "empty struct") that are declared with brackets. + +### Why is this bad? +Empty brackets after a struct declaration can be omitted. + +### Example +``` +struct Cookie {} +``` +Use instead: +``` +struct Cookie; +``` \ No newline at end of file diff --git a/src/docs/enum_clike_unportable_variant.txt b/src/docs/enum_clike_unportable_variant.txt new file mode 100644 index 0000000000000..d30a973a5a135 --- /dev/null +++ b/src/docs/enum_clike_unportable_variant.txt @@ -0,0 +1,16 @@ +### What it does +Checks for C-like enumerations that are +`repr(isize/usize)` and have values that don't fit into an `i32`. + +### Why is this bad? +This will truncate the variant value on 32 bit +architectures, but works fine on 64 bit. + +### Example +``` +#[repr(usize)] +enum NonPortable { + X = 0x1_0000_0000, + Y = 0, +} +``` \ No newline at end of file diff --git a/src/docs/enum_glob_use.txt b/src/docs/enum_glob_use.txt new file mode 100644 index 0000000000000..3776822c35b0c --- /dev/null +++ b/src/docs/enum_glob_use.txt @@ -0,0 +1,24 @@ +### What it does +Checks for `use Enum::*`. + +### Why is this bad? +It is usually better style to use the prefixed name of +an enumeration variant, rather than importing variants. + +### Known problems +Old-style enumerations that prefix the variants are +still around. + +### Example +``` +use std::cmp::Ordering::*; + +foo(Less); +``` + +Use instead: +``` +use std::cmp::Ordering; + +foo(Ordering::Less) +``` \ No newline at end of file diff --git a/src/docs/enum_variant_names.txt b/src/docs/enum_variant_names.txt new file mode 100644 index 0000000000000..e726925edda82 --- /dev/null +++ b/src/docs/enum_variant_names.txt @@ -0,0 +1,30 @@ +### What it does +Detects enumeration variants that are prefixed or suffixed +by the same characters. + +### Why is this bad? +Enumeration variant names should specify their variant, +not repeat the enumeration name. + +### Limitations +Characters with no casing will be considered when comparing prefixes/suffixes +This applies to numbers and non-ascii characters without casing +e.g. `Foo1` and `Foo2` is considered to have different prefixes +(the prefixes are `Foo1` and `Foo2` respectively), as also `Bar螃`, `Bar蟹` + +### Example +``` +enum Cake { + BlackForestCake, + HummingbirdCake, + BattenbergCake, +} +``` +Use instead: +``` +enum Cake { + BlackForest, + Hummingbird, + Battenberg, +} +``` \ No newline at end of file diff --git a/src/docs/eq_op.txt b/src/docs/eq_op.txt new file mode 100644 index 0000000000000..2d75a0ec546e7 --- /dev/null +++ b/src/docs/eq_op.txt @@ -0,0 +1,22 @@ +### What it does +Checks for equal operands to comparison, logical and +bitwise, difference and division binary operators (`==`, `>`, etc., `&&`, +`||`, `&`, `|`, `^`, `-` and `/`). + +### Why is this bad? +This is usually just a typo or a copy and paste error. + +### Known problems +False negatives: We had some false positives regarding +calls (notably [racer](https://github.com/phildawes/racer) had one instance +of `x.pop() && x.pop()`), so we removed matching any function or method +calls. We may introduce a list of known pure functions in the future. + +### Example +``` +if x + 1 == x + 1 {} + +// or + +assert_eq!(a, a); +``` \ No newline at end of file diff --git a/src/docs/equatable_if_let.txt b/src/docs/equatable_if_let.txt new file mode 100644 index 0000000000000..9997046954c20 --- /dev/null +++ b/src/docs/equatable_if_let.txt @@ -0,0 +1,23 @@ +### What it does +Checks for pattern matchings that can be expressed using equality. + +### Why is this bad? + +* It reads better and has less cognitive load because equality won't cause binding. +* It is a [Yoda condition](https://en.wikipedia.org/wiki/Yoda_conditions). Yoda conditions are widely +criticized for increasing the cognitive load of reading the code. +* Equality is a simple bool expression and can be merged with `&&` and `||` and +reuse if blocks + +### Example +``` +if let Some(2) = x { + do_thing(); +} +``` +Use instead: +``` +if x == Some(2) { + do_thing(); +} +``` \ No newline at end of file diff --git a/src/docs/erasing_op.txt b/src/docs/erasing_op.txt new file mode 100644 index 0000000000000..3d285a6d86e48 --- /dev/null +++ b/src/docs/erasing_op.txt @@ -0,0 +1,15 @@ +### What it does +Checks for erasing operations, e.g., `x * 0`. + +### Why is this bad? +The whole expression can be replaced by zero. +This is most likely not the intended outcome and should probably be +corrected + +### Example +``` +let x = 1; +0 / x; +0 * x; +x & 0; +``` \ No newline at end of file diff --git a/src/docs/err_expect.txt b/src/docs/err_expect.txt new file mode 100644 index 0000000000000..1dc83c5ce0ee0 --- /dev/null +++ b/src/docs/err_expect.txt @@ -0,0 +1,16 @@ +### What it does +Checks for `.err().expect()` calls on the `Result` type. + +### Why is this bad? +`.expect_err()` can be called directly to avoid the extra type conversion from `err()`. + +### Example +``` +let x: Result = Ok(10); +x.err().expect("Testing err().expect()"); +``` +Use instead: +``` +let x: Result = Ok(10); +x.expect_err("Testing expect_err"); +``` \ No newline at end of file diff --git a/src/docs/excessive_precision.txt b/src/docs/excessive_precision.txt new file mode 100644 index 0000000000000..517879c47152b --- /dev/null +++ b/src/docs/excessive_precision.txt @@ -0,0 +1,18 @@ +### What it does +Checks for float literals with a precision greater +than that supported by the underlying type. + +### Why is this bad? +Rust will truncate the literal silently. + +### Example +``` +let v: f32 = 0.123_456_789_9; +println!("{}", v); // 0.123_456_789 +``` + +Use instead: +``` +let v: f64 = 0.123_456_789_9; +println!("{}", v); // 0.123_456_789_9 +``` \ No newline at end of file diff --git a/src/docs/exhaustive_enums.txt b/src/docs/exhaustive_enums.txt new file mode 100644 index 0000000000000..d1032a7a29aa0 --- /dev/null +++ b/src/docs/exhaustive_enums.txt @@ -0,0 +1,23 @@ +### What it does +Warns on any exported `enum`s that are not tagged `#[non_exhaustive]` + +### Why is this bad? +Exhaustive enums are typically fine, but a project which does +not wish to make a stability commitment around exported enums may wish to +disable them by default. + +### Example +``` +enum Foo { + Bar, + Baz +} +``` +Use instead: +``` +#[non_exhaustive] +enum Foo { + Bar, + Baz +} +``` \ No newline at end of file diff --git a/src/docs/exhaustive_structs.txt b/src/docs/exhaustive_structs.txt new file mode 100644 index 0000000000000..fd6e4f5caf1f2 --- /dev/null +++ b/src/docs/exhaustive_structs.txt @@ -0,0 +1,23 @@ +### What it does +Warns on any exported `structs`s that are not tagged `#[non_exhaustive]` + +### Why is this bad? +Exhaustive structs are typically fine, but a project which does +not wish to make a stability commitment around exported structs may wish to +disable them by default. + +### Example +``` +struct Foo { + bar: u8, + baz: String, +} +``` +Use instead: +``` +#[non_exhaustive] +struct Foo { + bar: u8, + baz: String, +} +``` \ No newline at end of file diff --git a/src/docs/exit.txt b/src/docs/exit.txt new file mode 100644 index 0000000000000..1e6154d43e053 --- /dev/null +++ b/src/docs/exit.txt @@ -0,0 +1,12 @@ +### What it does +`exit()` terminates the program and doesn't provide a +stack trace. + +### Why is this bad? +Ideally a program is terminated by finishing +the main function. + +### Example +``` +std::process::exit(0) +``` \ No newline at end of file diff --git a/src/docs/expect_fun_call.txt b/src/docs/expect_fun_call.txt new file mode 100644 index 0000000000000..d82d9aa9baff2 --- /dev/null +++ b/src/docs/expect_fun_call.txt @@ -0,0 +1,24 @@ +### What it does +Checks for calls to `.expect(&format!(...))`, `.expect(foo(..))`, +etc., and suggests to use `unwrap_or_else` instead + +### Why is this bad? +The function will always be called. + +### Known problems +If the function has side-effects, not calling it will +change the semantics of the program, but you shouldn't rely on that anyway. + +### Example +``` +foo.expect(&format!("Err {}: {}", err_code, err_msg)); + +// or + +foo.expect(format!("Err {}: {}", err_code, err_msg).as_str()); +``` + +Use instead: +``` +foo.unwrap_or_else(|| panic!("Err {}: {}", err_code, err_msg)); +``` \ No newline at end of file diff --git a/src/docs/expect_used.txt b/src/docs/expect_used.txt new file mode 100644 index 0000000000000..4a6981e334fd3 --- /dev/null +++ b/src/docs/expect_used.txt @@ -0,0 +1,26 @@ +### What it does +Checks for `.expect()` or `.expect_err()` calls on `Result`s and `.expect()` call on `Option`s. + +### Why is this bad? +Usually it is better to handle the `None` or `Err` case. +Still, for a lot of quick-and-dirty code, `expect` is a good choice, which is why +this lint is `Allow` by default. + +`result.expect()` will let the thread panic on `Err` +values. Normally, you want to implement more sophisticated error handling, +and propagate errors upwards with `?` operator. + +### Examples +``` +option.expect("one"); +result.expect("one"); +``` + +Use instead: +``` +option?; + +// or + +result?; +``` \ No newline at end of file diff --git a/src/docs/expl_impl_clone_on_copy.txt b/src/docs/expl_impl_clone_on_copy.txt new file mode 100644 index 0000000000000..391d93b6713cc --- /dev/null +++ b/src/docs/expl_impl_clone_on_copy.txt @@ -0,0 +1,20 @@ +### What it does +Checks for explicit `Clone` implementations for `Copy` +types. + +### Why is this bad? +To avoid surprising behavior, these traits should +agree and the behavior of `Copy` cannot be overridden. In almost all +situations a `Copy` type should have a `Clone` implementation that does +nothing more than copy the object, which is what `#[derive(Copy, Clone)]` +gets you. + +### Example +``` +#[derive(Copy)] +struct Foo; + +impl Clone for Foo { + // .. +} +``` \ No newline at end of file diff --git a/src/docs/explicit_auto_deref.txt b/src/docs/explicit_auto_deref.txt new file mode 100644 index 0000000000000..65b2563177252 --- /dev/null +++ b/src/docs/explicit_auto_deref.txt @@ -0,0 +1,16 @@ +### What it does +Checks for dereferencing expressions which would be covered by auto-deref. + +### Why is this bad? +This unnecessarily complicates the code. + +### Example +``` +let x = String::new(); +let y: &str = &*x; +``` +Use instead: +``` +let x = String::new(); +let y: &str = &x; +``` \ No newline at end of file diff --git a/src/docs/explicit_counter_loop.txt b/src/docs/explicit_counter_loop.txt new file mode 100644 index 0000000000000..2661a43e10341 --- /dev/null +++ b/src/docs/explicit_counter_loop.txt @@ -0,0 +1,21 @@ +### What it does +Checks `for` loops over slices with an explicit counter +and suggests the use of `.enumerate()`. + +### Why is this bad? +Using `.enumerate()` makes the intent more clear, +declutters the code and may be faster in some instances. + +### Example +``` +let mut i = 0; +for item in &v { + bar(i, *item); + i += 1; +} +``` + +Use instead: +``` +for (i, item) in v.iter().enumerate() { bar(i, *item); } +``` \ No newline at end of file diff --git a/src/docs/explicit_deref_methods.txt b/src/docs/explicit_deref_methods.txt new file mode 100644 index 0000000000000..e14e981c7073b --- /dev/null +++ b/src/docs/explicit_deref_methods.txt @@ -0,0 +1,24 @@ +### What it does +Checks for explicit `deref()` or `deref_mut()` method calls. + +### Why is this bad? +Dereferencing by `&*x` or `&mut *x` is clearer and more concise, +when not part of a method chain. + +### Example +``` +use std::ops::Deref; +let a: &mut String = &mut String::from("foo"); +let b: &str = a.deref(); +``` + +Use instead: +``` +let a: &mut String = &mut String::from("foo"); +let b = &*a; +``` + +This lint excludes: +``` +let _ = d.unwrap().deref(); +``` \ No newline at end of file diff --git a/src/docs/explicit_into_iter_loop.txt b/src/docs/explicit_into_iter_loop.txt new file mode 100644 index 0000000000000..3931dfd69a318 --- /dev/null +++ b/src/docs/explicit_into_iter_loop.txt @@ -0,0 +1,20 @@ +### What it does +Checks for loops on `y.into_iter()` where `y` will do, and +suggests the latter. + +### Why is this bad? +Readability. + +### Example +``` +// with `y` a `Vec` or slice: +for x in y.into_iter() { + // .. +} +``` +can be rewritten to +``` +for x in y { + // .. +} +``` \ No newline at end of file diff --git a/src/docs/explicit_iter_loop.txt b/src/docs/explicit_iter_loop.txt new file mode 100644 index 0000000000000..cabe72e91d04f --- /dev/null +++ b/src/docs/explicit_iter_loop.txt @@ -0,0 +1,25 @@ +### What it does +Checks for loops on `x.iter()` where `&x` will do, and +suggests the latter. + +### Why is this bad? +Readability. + +### Known problems +False negatives. We currently only warn on some known +types. + +### Example +``` +// with `y` a `Vec` or slice: +for x in y.iter() { + // .. +} +``` + +Use instead: +``` +for x in &y { + // .. +} +``` \ No newline at end of file diff --git a/src/docs/explicit_write.txt b/src/docs/explicit_write.txt new file mode 100644 index 0000000000000..eafed5d39e5c6 --- /dev/null +++ b/src/docs/explicit_write.txt @@ -0,0 +1,18 @@ +### What it does +Checks for usage of `write!()` / `writeln()!` which can be +replaced with `(e)print!()` / `(e)println!()` + +### Why is this bad? +Using `(e)println! is clearer and more concise + +### Example +``` +writeln!(&mut std::io::stderr(), "foo: {:?}", bar).unwrap(); +writeln!(&mut std::io::stdout(), "foo: {:?}", bar).unwrap(); +``` + +Use instead: +``` +eprintln!("foo: {:?}", bar); +println!("foo: {:?}", bar); +``` \ No newline at end of file diff --git a/src/docs/extend_with_drain.txt b/src/docs/extend_with_drain.txt new file mode 100644 index 0000000000000..2f31dcf5f7401 --- /dev/null +++ b/src/docs/extend_with_drain.txt @@ -0,0 +1,21 @@ +### What it does +Checks for occurrences where one vector gets extended instead of append + +### Why is this bad? +Using `append` instead of `extend` is more concise and faster + +### Example +``` +let mut a = vec![1, 2, 3]; +let mut b = vec![4, 5, 6]; + +a.extend(b.drain(..)); +``` + +Use instead: +``` +let mut a = vec![1, 2, 3]; +let mut b = vec![4, 5, 6]; + +a.append(&mut b); +``` \ No newline at end of file diff --git a/src/docs/extra_unused_lifetimes.txt b/src/docs/extra_unused_lifetimes.txt new file mode 100644 index 0000000000000..bc1814aa4752d --- /dev/null +++ b/src/docs/extra_unused_lifetimes.txt @@ -0,0 +1,23 @@ +### What it does +Checks for lifetimes in generics that are never used +anywhere else. + +### Why is this bad? +The additional lifetimes make the code look more +complicated, while there is nothing out of the ordinary going on. Removing +them leads to more readable code. + +### Example +``` +// unnecessary lifetimes +fn unused_lifetime<'a>(x: u8) { + // .. +} +``` + +Use instead: +``` +fn no_lifetime(x: u8) { + // ... +} +``` \ No newline at end of file diff --git a/src/docs/fallible_impl_from.txt b/src/docs/fallible_impl_from.txt new file mode 100644 index 0000000000000..588a5bb103d46 --- /dev/null +++ b/src/docs/fallible_impl_from.txt @@ -0,0 +1,32 @@ +### What it does +Checks for impls of `From<..>` that contain `panic!()` or `unwrap()` + +### Why is this bad? +`TryFrom` should be used if there's a possibility of failure. + +### Example +``` +struct Foo(i32); + +impl From for Foo { + fn from(s: String) -> Self { + Foo(s.parse().unwrap()) + } +} +``` + +Use instead: +``` +struct Foo(i32); + +impl TryFrom for Foo { + type Error = (); + fn try_from(s: String) -> Result { + if let Ok(parsed) = s.parse() { + Ok(Foo(parsed)) + } else { + Err(()) + } + } +} +``` \ No newline at end of file diff --git a/src/docs/field_reassign_with_default.txt b/src/docs/field_reassign_with_default.txt new file mode 100644 index 0000000000000..e58b7239fde9e --- /dev/null +++ b/src/docs/field_reassign_with_default.txt @@ -0,0 +1,23 @@ +### What it does +Checks for immediate reassignment of fields initialized +with Default::default(). + +### Why is this bad? +It's more idiomatic to use the [functional update syntax](https://doc.rust-lang.org/reference/expressions/struct-expr.html#functional-update-syntax). + +### Known problems +Assignments to patterns that are of tuple type are not linted. + +### Example +``` +let mut a: A = Default::default(); +a.i = 42; +``` + +Use instead: +``` +let a = A { + i: 42, + .. Default::default() +}; +``` \ No newline at end of file diff --git a/src/docs/filetype_is_file.txt b/src/docs/filetype_is_file.txt new file mode 100644 index 0000000000000..ad14bd62c4de4 --- /dev/null +++ b/src/docs/filetype_is_file.txt @@ -0,0 +1,29 @@ +### What it does +Checks for `FileType::is_file()`. + +### Why is this bad? +When people testing a file type with `FileType::is_file` +they are testing whether a path is something they can get bytes from. But +`is_file` doesn't cover special file types in unix-like systems, and doesn't cover +symlink in windows. Using `!FileType::is_dir()` is a better way to that intention. + +### Example +``` +let metadata = std::fs::metadata("foo.txt")?; +let filetype = metadata.file_type(); + +if filetype.is_file() { + // read file +} +``` + +should be written as: + +``` +let metadata = std::fs::metadata("foo.txt")?; +let filetype = metadata.file_type(); + +if !filetype.is_dir() { + // read file +} +``` \ No newline at end of file diff --git a/src/docs/filter_map_identity.txt b/src/docs/filter_map_identity.txt new file mode 100644 index 0000000000000..83b666f2e2782 --- /dev/null +++ b/src/docs/filter_map_identity.txt @@ -0,0 +1,14 @@ +### What it does +Checks for usage of `filter_map(|x| x)`. + +### Why is this bad? +Readability, this can be written more concisely by using `flatten`. + +### Example +``` +iter.filter_map(|x| x); +``` +Use instead: +``` +iter.flatten(); +``` \ No newline at end of file diff --git a/src/docs/filter_map_next.txt b/src/docs/filter_map_next.txt new file mode 100644 index 0000000000000..b38620b56a50f --- /dev/null +++ b/src/docs/filter_map_next.txt @@ -0,0 +1,16 @@ +### What it does +Checks for usage of `_.filter_map(_).next()`. + +### Why is this bad? +Readability, this can be written more concisely as +`_.find_map(_)`. + +### Example +``` + (0..3).filter_map(|x| if x == 2 { Some(x) } else { None }).next(); +``` +Can be written as + +``` + (0..3).find_map(|x| if x == 2 { Some(x) } else { None }); +``` \ No newline at end of file diff --git a/src/docs/filter_next.txt b/src/docs/filter_next.txt new file mode 100644 index 0000000000000..898a74166dc14 --- /dev/null +++ b/src/docs/filter_next.txt @@ -0,0 +1,16 @@ +### What it does +Checks for usage of `_.filter(_).next()`. + +### Why is this bad? +Readability, this can be written more concisely as +`_.find(_)`. + +### Example +``` +vec.iter().filter(|x| **x == 0).next(); +``` + +Use instead: +``` +vec.iter().find(|x| **x == 0); +``` \ No newline at end of file diff --git a/src/docs/flat_map_identity.txt b/src/docs/flat_map_identity.txt new file mode 100644 index 0000000000000..a5ee79b4982fb --- /dev/null +++ b/src/docs/flat_map_identity.txt @@ -0,0 +1,14 @@ +### What it does +Checks for usage of `flat_map(|x| x)`. + +### Why is this bad? +Readability, this can be written more concisely by using `flatten`. + +### Example +``` +iter.flat_map(|x| x); +``` +Can be written as +``` +iter.flatten(); +``` \ No newline at end of file diff --git a/src/docs/flat_map_option.txt b/src/docs/flat_map_option.txt new file mode 100644 index 0000000000000..d50b9156d3654 --- /dev/null +++ b/src/docs/flat_map_option.txt @@ -0,0 +1,16 @@ +### What it does +Checks for usages of `Iterator::flat_map()` where `filter_map()` could be +used instead. + +### Why is this bad? +When applicable, `filter_map()` is more clear since it shows that +`Option` is used to produce 0 or 1 items. + +### Example +``` +let nums: Vec = ["1", "2", "whee!"].iter().flat_map(|x| x.parse().ok()).collect(); +``` +Use instead: +``` +let nums: Vec = ["1", "2", "whee!"].iter().filter_map(|x| x.parse().ok()).collect(); +``` \ No newline at end of file diff --git a/src/docs/float_arithmetic.txt b/src/docs/float_arithmetic.txt new file mode 100644 index 0000000000000..1f9bce5abd59f --- /dev/null +++ b/src/docs/float_arithmetic.txt @@ -0,0 +1,11 @@ +### What it does +Checks for float arithmetic. + +### Why is this bad? +For some embedded systems or kernel development, it +can be useful to rule out floating-point numbers. + +### Example +``` +a + 1.0; +``` \ No newline at end of file diff --git a/src/docs/float_cmp.txt b/src/docs/float_cmp.txt new file mode 100644 index 0000000000000..c19907c903e9d --- /dev/null +++ b/src/docs/float_cmp.txt @@ -0,0 +1,28 @@ +### What it does +Checks for (in-)equality comparisons on floating-point +values (apart from zero), except in functions called `*eq*` (which probably +implement equality for a type involving floats). + +### Why is this bad? +Floating point calculations are usually imprecise, so +asking if two values are *exactly* equal is asking for trouble. For a good +guide on what to do, see [the floating point +guide](http://www.floating-point-gui.de/errors/comparison). + +### Example +``` +let x = 1.2331f64; +let y = 1.2332f64; + +if y == 1.23f64 { } +if y != x {} // where both are floats +``` + +Use instead: +``` +let error_margin = f64::EPSILON; // Use an epsilon for comparison +// Or, if Rust <= 1.42, use `std::f64::EPSILON` constant instead. +// let error_margin = std::f64::EPSILON; +if (y - 1.23f64).abs() < error_margin { } +if (y - x).abs() > error_margin { } +``` \ No newline at end of file diff --git a/src/docs/float_cmp_const.txt b/src/docs/float_cmp_const.txt new file mode 100644 index 0000000000000..9208feaacd810 --- /dev/null +++ b/src/docs/float_cmp_const.txt @@ -0,0 +1,26 @@ +### What it does +Checks for (in-)equality comparisons on floating-point +value and constant, except in functions called `*eq*` (which probably +implement equality for a type involving floats). + +### Why is this bad? +Floating point calculations are usually imprecise, so +asking if two values are *exactly* equal is asking for trouble. For a good +guide on what to do, see [the floating point +guide](http://www.floating-point-gui.de/errors/comparison). + +### Example +``` +let x: f64 = 1.0; +const ONE: f64 = 1.00; + +if x == ONE { } // where both are floats +``` + +Use instead: +``` +let error_margin = f64::EPSILON; // Use an epsilon for comparison +// Or, if Rust <= 1.42, use `std::f64::EPSILON` constant instead. +// let error_margin = std::f64::EPSILON; +if (x - ONE).abs() < error_margin { } +``` \ No newline at end of file diff --git a/src/docs/float_equality_without_abs.txt b/src/docs/float_equality_without_abs.txt new file mode 100644 index 0000000000000..556b574e15d30 --- /dev/null +++ b/src/docs/float_equality_without_abs.txt @@ -0,0 +1,26 @@ +### What it does +Checks for statements of the form `(a - b) < f32::EPSILON` or +`(a - b) < f64::EPSILON`. Notes the missing `.abs()`. + +### Why is this bad? +The code without `.abs()` is more likely to have a bug. + +### Known problems +If the user can ensure that b is larger than a, the `.abs()` is +technically unnecessary. However, it will make the code more robust and doesn't have any +large performance implications. If the abs call was deliberately left out for performance +reasons, it is probably better to state this explicitly in the code, which then can be done +with an allow. + +### Example +``` +pub fn is_roughly_equal(a: f32, b: f32) -> bool { + (a - b) < f32::EPSILON +} +``` +Use instead: +``` +pub fn is_roughly_equal(a: f32, b: f32) -> bool { + (a - b).abs() < f32::EPSILON +} +``` \ No newline at end of file diff --git a/src/docs/fn_address_comparisons.txt b/src/docs/fn_address_comparisons.txt new file mode 100644 index 0000000000000..7d2b7b681deb1 --- /dev/null +++ b/src/docs/fn_address_comparisons.txt @@ -0,0 +1,17 @@ +### What it does +Checks for comparisons with an address of a function item. + +### Why is this bad? +Function item address is not guaranteed to be unique and could vary +between different code generation units. Furthermore different function items could have +the same address after being merged together. + +### Example +``` +type F = fn(); +fn a() {} +let f: F = a; +if f == a { + // ... +} +``` \ No newline at end of file diff --git a/src/docs/fn_params_excessive_bools.txt b/src/docs/fn_params_excessive_bools.txt new file mode 100644 index 0000000000000..2eae0563368c1 --- /dev/null +++ b/src/docs/fn_params_excessive_bools.txt @@ -0,0 +1,31 @@ +### What it does +Checks for excessive use of +bools in function definitions. + +### Why is this bad? +Calls to such functions +are confusing and error prone, because it's +hard to remember argument order and you have +no type system support to back you up. Using +two-variant enums instead of bools often makes +API easier to use. + +### Example +``` +fn f(is_round: bool, is_hot: bool) { ... } +``` + +Use instead: +``` +enum Shape { + Round, + Spiky, +} + +enum Temperature { + Hot, + IceCold, +} + +fn f(shape: Shape, temperature: Temperature) { ... } +``` \ No newline at end of file diff --git a/src/docs/fn_to_numeric_cast.txt b/src/docs/fn_to_numeric_cast.txt new file mode 100644 index 0000000000000..1f587f6d71768 --- /dev/null +++ b/src/docs/fn_to_numeric_cast.txt @@ -0,0 +1,21 @@ +### What it does +Checks for casts of function pointers to something other than usize + +### Why is this bad? +Casting a function pointer to anything other than usize/isize is not portable across +architectures, because you end up losing bits if the target type is too small or end up with a +bunch of extra bits that waste space and add more instructions to the final binary than +strictly necessary for the problem + +Casting to isize also doesn't make sense since there are no signed addresses. + +### Example +``` +fn fun() -> i32 { 1 } +let _ = fun as i64; +``` + +Use instead: +``` +let _ = fun as usize; +``` \ No newline at end of file diff --git a/src/docs/fn_to_numeric_cast_any.txt b/src/docs/fn_to_numeric_cast_any.txt new file mode 100644 index 0000000000000..ee3c33d237255 --- /dev/null +++ b/src/docs/fn_to_numeric_cast_any.txt @@ -0,0 +1,35 @@ +### What it does +Checks for casts of a function pointer to any integer type. + +### Why is this bad? +Casting a function pointer to an integer can have surprising results and can occur +accidentally if parentheses are omitted from a function call. If you aren't doing anything +low-level with function pointers then you can opt-out of casting functions to integers in +order to avoid mistakes. Alternatively, you can use this lint to audit all uses of function +pointer casts in your code. + +### Example +``` +// fn1 is cast as `usize` +fn fn1() -> u16 { + 1 +}; +let _ = fn1 as usize; +``` + +Use instead: +``` +// maybe you intended to call the function? +fn fn2() -> u16 { + 1 +}; +let _ = fn2() as usize; + +// or + +// maybe you intended to cast it to a function type? +fn fn3() -> u16 { + 1 +} +let _ = fn3 as fn() -> u16; +``` \ No newline at end of file diff --git a/src/docs/fn_to_numeric_cast_with_truncation.txt b/src/docs/fn_to_numeric_cast_with_truncation.txt new file mode 100644 index 0000000000000..69f12fa319f18 --- /dev/null +++ b/src/docs/fn_to_numeric_cast_with_truncation.txt @@ -0,0 +1,26 @@ +### What it does +Checks for casts of a function pointer to a numeric type not wide enough to +store address. + +### Why is this bad? +Such a cast discards some bits of the function's address. If this is intended, it would be more +clearly expressed by casting to usize first, then casting the usize to the intended type (with +a comment) to perform the truncation. + +### Example +``` +fn fn1() -> i16 { + 1 +}; +let _ = fn1 as i32; +``` + +Use instead: +``` +// Cast to usize first, then comment with the reason for the truncation +fn fn1() -> i16 { + 1 +}; +let fn_ptr = fn1 as usize; +let fn_ptr_truncated = fn_ptr as i32; +``` \ No newline at end of file diff --git a/src/docs/for_kv_map.txt b/src/docs/for_kv_map.txt new file mode 100644 index 0000000000000..a9a2ffee9c743 --- /dev/null +++ b/src/docs/for_kv_map.txt @@ -0,0 +1,22 @@ +### What it does +Checks for iterating a map (`HashMap` or `BTreeMap`) and +ignoring either the keys or values. + +### Why is this bad? +Readability. There are `keys` and `values` methods that +can be used to express that don't need the values or keys. + +### Example +``` +for (k, _) in &map { + .. +} +``` + +could be replaced by + +``` +for k in map.keys() { + .. +} +``` \ No newline at end of file diff --git a/src/docs/for_loops_over_fallibles.txt b/src/docs/for_loops_over_fallibles.txt new file mode 100644 index 0000000000000..c5a7508e45d40 --- /dev/null +++ b/src/docs/for_loops_over_fallibles.txt @@ -0,0 +1,32 @@ +### What it does +Checks for `for` loops over `Option` or `Result` values. + +### Why is this bad? +Readability. This is more clearly expressed as an `if +let`. + +### Example +``` +for x in opt { + // .. +} + +for x in &res { + // .. +} + +for x in res.iter() { + // .. +} +``` + +Use instead: +``` +if let Some(x) = opt { + // .. +} + +if let Ok(x) = res { + // .. +} +``` \ No newline at end of file diff --git a/src/docs/forget_copy.txt b/src/docs/forget_copy.txt new file mode 100644 index 0000000000000..1d100912e9a48 --- /dev/null +++ b/src/docs/forget_copy.txt @@ -0,0 +1,21 @@ +### What it does +Checks for calls to `std::mem::forget` with a value that +derives the Copy trait + +### Why is this bad? +Calling `std::mem::forget` [does nothing for types that +implement Copy](https://doc.rust-lang.org/std/mem/fn.drop.html) since the +value will be copied and moved into the function on invocation. + +An alternative, but also valid, explanation is that Copy types do not +implement +the Drop trait, which means they have no destructors. Without a destructor, +there +is nothing for `std::mem::forget` to ignore. + +### Example +``` +let x: i32 = 42; // i32 implements Copy +std::mem::forget(x) // A copy of x is passed to the function, leaving the + // original unaffected +``` \ No newline at end of file diff --git a/src/docs/forget_non_drop.txt b/src/docs/forget_non_drop.txt new file mode 100644 index 0000000000000..3307d654c17f2 --- /dev/null +++ b/src/docs/forget_non_drop.txt @@ -0,0 +1,13 @@ +### What it does +Checks for calls to `std::mem::forget` with a value that does not implement `Drop`. + +### Why is this bad? +Calling `std::mem::forget` is no different than dropping such a type. A different value may +have been intended. + +### Example +``` +struct Foo; +let x = Foo; +std::mem::forget(x); +``` \ No newline at end of file diff --git a/src/docs/forget_ref.txt b/src/docs/forget_ref.txt new file mode 100644 index 0000000000000..874fb8786068d --- /dev/null +++ b/src/docs/forget_ref.txt @@ -0,0 +1,15 @@ +### What it does +Checks for calls to `std::mem::forget` with a reference +instead of an owned value. + +### Why is this bad? +Calling `forget` on a reference will only forget the +reference itself, which is a no-op. It will not forget the underlying +referenced +value, which is likely what was intended. + +### Example +``` +let x = Box::new(1); +std::mem::forget(&x) // Should have been forget(x), x will still be dropped +``` \ No newline at end of file diff --git a/src/docs/format_in_format_args.txt b/src/docs/format_in_format_args.txt new file mode 100644 index 0000000000000..ac498472f017f --- /dev/null +++ b/src/docs/format_in_format_args.txt @@ -0,0 +1,16 @@ +### What it does +Detects `format!` within the arguments of another macro that does +formatting such as `format!` itself, `write!` or `println!`. Suggests +inlining the `format!` call. + +### Why is this bad? +The recommended code is both shorter and avoids a temporary allocation. + +### Example +``` +println!("error: {}", format!("something failed at {}", Location::caller())); +``` +Use instead: +``` +println!("error: something failed at {}", Location::caller()); +``` \ No newline at end of file diff --git a/src/docs/format_push_string.txt b/src/docs/format_push_string.txt new file mode 100644 index 0000000000000..ca409ebc7ec26 --- /dev/null +++ b/src/docs/format_push_string.txt @@ -0,0 +1,26 @@ +### What it does +Detects cases where the result of a `format!` call is +appended to an existing `String`. + +### Why is this bad? +Introduces an extra, avoidable heap allocation. + +### Known problems +`format!` returns a `String` but `write!` returns a `Result`. +Thus you are forced to ignore the `Err` variant to achieve the same API. + +While using `write!` in the suggested way should never fail, this isn't necessarily clear to the programmer. + +### Example +``` +let mut s = String::new(); +s += &format!("0x{:X}", 1024); +s.push_str(&format!("0x{:X}", 1024)); +``` +Use instead: +``` +use std::fmt::Write as _; // import without risk of name clashing + +let mut s = String::new(); +let _ = write!(s, "0x{:X}", 1024); +``` \ No newline at end of file diff --git a/src/docs/from_iter_instead_of_collect.txt b/src/docs/from_iter_instead_of_collect.txt new file mode 100644 index 0000000000000..f3fd275972645 --- /dev/null +++ b/src/docs/from_iter_instead_of_collect.txt @@ -0,0 +1,24 @@ +### What it does +Checks for `from_iter()` function calls on types that implement the `FromIterator` +trait. + +### Why is this bad? +It is recommended style to use collect. See +[FromIterator documentation](https://doc.rust-lang.org/std/iter/trait.FromIterator.html) + +### Example +``` +let five_fives = std::iter::repeat(5).take(5); + +let v = Vec::from_iter(five_fives); + +assert_eq!(v, vec![5, 5, 5, 5, 5]); +``` +Use instead: +``` +let five_fives = std::iter::repeat(5).take(5); + +let v: Vec = five_fives.collect(); + +assert_eq!(v, vec![5, 5, 5, 5, 5]); +``` \ No newline at end of file diff --git a/src/docs/from_over_into.txt b/src/docs/from_over_into.txt new file mode 100644 index 0000000000000..0770bcc42c270 --- /dev/null +++ b/src/docs/from_over_into.txt @@ -0,0 +1,26 @@ +### What it does +Searches for implementations of the `Into<..>` trait and suggests to implement `From<..>` instead. + +### Why is this bad? +According the std docs implementing `From<..>` is preferred since it gives you `Into<..>` for free where the reverse isn't true. + +### Example +``` +struct StringWrapper(String); + +impl Into for String { + fn into(self) -> StringWrapper { + StringWrapper(self) + } +} +``` +Use instead: +``` +struct StringWrapper(String); + +impl From for StringWrapper { + fn from(s: String) -> StringWrapper { + StringWrapper(s) + } +} +``` \ No newline at end of file diff --git a/src/docs/from_str_radix_10.txt b/src/docs/from_str_radix_10.txt new file mode 100644 index 0000000000000..f6f319d3eaa18 --- /dev/null +++ b/src/docs/from_str_radix_10.txt @@ -0,0 +1,25 @@ +### What it does + +Checks for function invocations of the form `primitive::from_str_radix(s, 10)` + +### Why is this bad? + +This specific common use case can be rewritten as `s.parse::()` +(and in most cases, the turbofish can be removed), which reduces code length +and complexity. + +### Known problems + +This lint may suggest using (&).parse() instead of .parse() directly +in some cases, which is correct but adds unnecessary complexity to the code. + +### Example +``` +let input: &str = get_input(); +let num = u16::from_str_radix(input, 10)?; +``` +Use instead: +``` +let input: &str = get_input(); +let num: u16 = input.parse()?; +``` \ No newline at end of file diff --git a/src/docs/future_not_send.txt b/src/docs/future_not_send.txt new file mode 100644 index 0000000000000..0aa048d273551 --- /dev/null +++ b/src/docs/future_not_send.txt @@ -0,0 +1,29 @@ +### What it does +This lint requires Future implementations returned from +functions and methods to implement the `Send` marker trait. It is mostly +used by library authors (public and internal) that target an audience where +multithreaded executors are likely to be used for running these Futures. + +### Why is this bad? +A Future implementation captures some state that it +needs to eventually produce its final value. When targeting a multithreaded +executor (which is the norm on non-embedded devices) this means that this +state may need to be transported to other threads, in other words the +whole Future needs to implement the `Send` marker trait. If it does not, +then the resulting Future cannot be submitted to a thread pool in the +end user’s code. + +Especially for generic functions it can be confusing to leave the +discovery of this problem to the end user: the reported error location +will be far from its cause and can in many cases not even be fixed without +modifying the library where the offending Future implementation is +produced. + +### Example +``` +async fn not_send(bytes: std::rc::Rc<[u8]>) {} +``` +Use instead: +``` +async fn is_send(bytes: std::sync::Arc<[u8]>) {} +``` \ No newline at end of file diff --git a/src/docs/get_first.txt b/src/docs/get_first.txt new file mode 100644 index 0000000000000..c905a737ddf3f --- /dev/null +++ b/src/docs/get_first.txt @@ -0,0 +1,19 @@ +### What it does +Checks for using `x.get(0)` instead of +`x.first()`. + +### Why is this bad? +Using `x.first()` is easier to read and has the same +result. + +### Example +``` +let x = vec![2, 3, 5]; +let first_element = x.get(0); +``` + +Use instead: +``` +let x = vec![2, 3, 5]; +let first_element = x.first(); +``` \ No newline at end of file diff --git a/src/docs/get_last_with_len.txt b/src/docs/get_last_with_len.txt new file mode 100644 index 0000000000000..31c7f269586ab --- /dev/null +++ b/src/docs/get_last_with_len.txt @@ -0,0 +1,26 @@ +### What it does +Checks for using `x.get(x.len() - 1)` instead of +`x.last()`. + +### Why is this bad? +Using `x.last()` is easier to read and has the same +result. + +Note that using `x[x.len() - 1]` is semantically different from +`x.last()`. Indexing into the array will panic on out-of-bounds +accesses, while `x.get()` and `x.last()` will return `None`. + +There is another lint (get_unwrap) that covers the case of using +`x.get(index).unwrap()` instead of `x[index]`. + +### Example +``` +let x = vec![2, 3, 5]; +let last_element = x.get(x.len() - 1); +``` + +Use instead: +``` +let x = vec![2, 3, 5]; +let last_element = x.last(); +``` \ No newline at end of file diff --git a/src/docs/get_unwrap.txt b/src/docs/get_unwrap.txt new file mode 100644 index 0000000000000..8defc22244169 --- /dev/null +++ b/src/docs/get_unwrap.txt @@ -0,0 +1,30 @@ +### What it does +Checks for use of `.get().unwrap()` (or +`.get_mut().unwrap`) on a standard library type which implements `Index` + +### Why is this bad? +Using the Index trait (`[]`) is more clear and more +concise. + +### Known problems +Not a replacement for error handling: Using either +`.unwrap()` or the Index trait (`[]`) carries the risk of causing a `panic` +if the value being accessed is `None`. If the use of `.get().unwrap()` is a +temporary placeholder for dealing with the `Option` type, then this does +not mitigate the need for error handling. If there is a chance that `.get()` +will be `None` in your program, then it is advisable that the `None` case +is handled in a future refactor instead of using `.unwrap()` or the Index +trait. + +### Example +``` +let mut some_vec = vec![0, 1, 2, 3]; +let last = some_vec.get(3).unwrap(); +*some_vec.get_mut(0).unwrap() = 1; +``` +The correct use would be: +``` +let mut some_vec = vec![0, 1, 2, 3]; +let last = some_vec[3]; +some_vec[0] = 1; +``` \ No newline at end of file diff --git a/src/docs/identity_op.txt b/src/docs/identity_op.txt new file mode 100644 index 0000000000000..a8e40bb43e9d5 --- /dev/null +++ b/src/docs/identity_op.txt @@ -0,0 +1,11 @@ +### What it does +Checks for identity operations, e.g., `x + 0`. + +### Why is this bad? +This code can be removed without changing the +meaning. So it just obscures what's going on. Delete it mercilessly. + +### Example +``` +x / 1 + 0 * 1 - 0 | 0; +``` \ No newline at end of file diff --git a/src/docs/if_let_mutex.txt b/src/docs/if_let_mutex.txt new file mode 100644 index 0000000000000..4d873ade9ace3 --- /dev/null +++ b/src/docs/if_let_mutex.txt @@ -0,0 +1,25 @@ +### What it does +Checks for `Mutex::lock` calls in `if let` expression +with lock calls in any of the else blocks. + +### Why is this bad? +The Mutex lock remains held for the whole +`if let ... else` block and deadlocks. + +### Example +``` +if let Ok(thing) = mutex.lock() { + do_thing(); +} else { + mutex.lock(); +} +``` +Should be written +``` +let locked = mutex.lock(); +if let Ok(thing) = locked { + do_thing(thing); +} else { + use_locked(locked); +} +``` \ No newline at end of file diff --git a/src/docs/if_not_else.txt b/src/docs/if_not_else.txt new file mode 100644 index 0000000000000..0e5ac4ce6bb80 --- /dev/null +++ b/src/docs/if_not_else.txt @@ -0,0 +1,25 @@ +### What it does +Checks for usage of `!` or `!=` in an if condition with an +else branch. + +### Why is this bad? +Negations reduce the readability of statements. + +### Example +``` +if !v.is_empty() { + a() +} else { + b() +} +``` + +Could be written: + +``` +if v.is_empty() { + b() +} else { + a() +} +``` \ No newline at end of file diff --git a/src/docs/if_same_then_else.txt b/src/docs/if_same_then_else.txt new file mode 100644 index 0000000000000..75127016bb8c1 --- /dev/null +++ b/src/docs/if_same_then_else.txt @@ -0,0 +1,15 @@ +### What it does +Checks for `if/else` with the same body as the *then* part +and the *else* part. + +### Why is this bad? +This is probably a copy & paste error. + +### Example +``` +let foo = if … { + 42 +} else { + 42 +}; +``` \ No newline at end of file diff --git a/src/docs/if_then_some_else_none.txt b/src/docs/if_then_some_else_none.txt new file mode 100644 index 0000000000000..13744f920e362 --- /dev/null +++ b/src/docs/if_then_some_else_none.txt @@ -0,0 +1,26 @@ +### What it does +Checks for if-else that could be written using either `bool::then` or `bool::then_some`. + +### Why is this bad? +Looks a little redundant. Using `bool::then` is more concise and incurs no loss of clarity. +For simple calculations and known values, use `bool::then_some`, which is eagerly evaluated +in comparison to `bool::then`. + +### Example +``` +let a = if v.is_empty() { + println!("true!"); + Some(42) +} else { + None +}; +``` + +Could be written: + +``` +let a = v.is_empty().then(|| { + println!("true!"); + 42 +}); +``` \ No newline at end of file diff --git a/src/docs/ifs_same_cond.txt b/src/docs/ifs_same_cond.txt new file mode 100644 index 0000000000000..024ba5df93a63 --- /dev/null +++ b/src/docs/ifs_same_cond.txt @@ -0,0 +1,25 @@ +### What it does +Checks for consecutive `if`s with the same condition. + +### Why is this bad? +This is probably a copy & paste error. + +### Example +``` +if a == b { + … +} else if a == b { + … +} +``` + +Note that this lint ignores all conditions with a function call as it could +have side effects: + +``` +if foo() { + … +} else if foo() { // not linted + … +} +``` \ No newline at end of file diff --git a/src/docs/implicit_clone.txt b/src/docs/implicit_clone.txt new file mode 100644 index 0000000000000..f5aa112c52c36 --- /dev/null +++ b/src/docs/implicit_clone.txt @@ -0,0 +1,19 @@ +### What it does +Checks for the usage of `_.to_owned()`, `vec.to_vec()`, or similar when calling `_.clone()` would be clearer. + +### Why is this bad? +These methods do the same thing as `_.clone()` but may be confusing as +to why we are calling `to_vec` on something that is already a `Vec` or calling `to_owned` on something that is already owned. + +### Example +``` +let a = vec![1, 2, 3]; +let b = a.to_vec(); +let c = a.to_owned(); +``` +Use instead: +``` +let a = vec![1, 2, 3]; +let b = a.clone(); +let c = a.clone(); +``` \ No newline at end of file diff --git a/src/docs/implicit_hasher.txt b/src/docs/implicit_hasher.txt new file mode 100644 index 0000000000000..0c1f76620f51d --- /dev/null +++ b/src/docs/implicit_hasher.txt @@ -0,0 +1,26 @@ +### What it does +Checks for public `impl` or `fn` missing generalization +over different hashers and implicitly defaulting to the default hashing +algorithm (`SipHash`). + +### Why is this bad? +`HashMap` or `HashSet` with custom hashers cannot be +used with them. + +### Known problems +Suggestions for replacing constructors can contain +false-positives. Also applying suggestions can require modification of other +pieces of code, possibly including external crates. + +### Example +``` +impl Serialize for HashMap { } + +pub fn foo(map: &mut HashMap) { } +``` +could be rewritten as +``` +impl Serialize for HashMap { } + +pub fn foo(map: &mut HashMap) { } +``` \ No newline at end of file diff --git a/src/docs/implicit_return.txt b/src/docs/implicit_return.txt new file mode 100644 index 0000000000000..ee65a636b38c5 --- /dev/null +++ b/src/docs/implicit_return.txt @@ -0,0 +1,22 @@ +### What it does +Checks for missing return statements at the end of a block. + +### Why is this bad? +Actually omitting the return keyword is idiomatic Rust code. Programmers +coming from other languages might prefer the expressiveness of `return`. It's possible to miss +the last returning statement because the only difference is a missing `;`. Especially in bigger +code with multiple return paths having a `return` keyword makes it easier to find the +corresponding statements. + +### Example +``` +fn foo(x: usize) -> usize { + x +} +``` +add return +``` +fn foo(x: usize) -> usize { + return x; +} +``` \ No newline at end of file diff --git a/src/docs/implicit_saturating_sub.txt b/src/docs/implicit_saturating_sub.txt new file mode 100644 index 0000000000000..03b47905a2118 --- /dev/null +++ b/src/docs/implicit_saturating_sub.txt @@ -0,0 +1,21 @@ +### What it does +Checks for implicit saturating subtraction. + +### Why is this bad? +Simplicity and readability. Instead we can easily use an builtin function. + +### Example +``` +let mut i: u32 = end - start; + +if i != 0 { + i -= 1; +} +``` + +Use instead: +``` +let mut i: u32 = end - start; + +i = i.saturating_sub(1); +``` \ No newline at end of file diff --git a/src/docs/imprecise_flops.txt b/src/docs/imprecise_flops.txt new file mode 100644 index 0000000000000..e84d81cea98e0 --- /dev/null +++ b/src/docs/imprecise_flops.txt @@ -0,0 +1,23 @@ +### What it does +Looks for floating-point expressions that +can be expressed using built-in methods to improve accuracy +at the cost of performance. + +### Why is this bad? +Negatively impacts accuracy. + +### Example +``` +let a = 3f32; +let _ = a.powf(1.0 / 3.0); +let _ = (1.0 + a).ln(); +let _ = a.exp() - 1.0; +``` + +Use instead: +``` +let a = 3f32; +let _ = a.cbrt(); +let _ = a.ln_1p(); +let _ = a.exp_m1(); +``` \ No newline at end of file diff --git a/src/docs/inconsistent_digit_grouping.txt b/src/docs/inconsistent_digit_grouping.txt new file mode 100644 index 0000000000000..aa0b072de1c40 --- /dev/null +++ b/src/docs/inconsistent_digit_grouping.txt @@ -0,0 +1,17 @@ +### What it does +Warns if an integral or floating-point constant is +grouped inconsistently with underscores. + +### Why is this bad? +Readers may incorrectly interpret inconsistently +grouped digits. + +### Example +``` +618_64_9189_73_511 +``` + +Use instead: +``` +61_864_918_973_511 +``` \ No newline at end of file diff --git a/src/docs/inconsistent_struct_constructor.txt b/src/docs/inconsistent_struct_constructor.txt new file mode 100644 index 0000000000000..eb682109a54ee --- /dev/null +++ b/src/docs/inconsistent_struct_constructor.txt @@ -0,0 +1,40 @@ +### What it does +Checks for struct constructors where all fields are shorthand and +the order of the field init shorthand in the constructor is inconsistent +with the order in the struct definition. + +### Why is this bad? +Since the order of fields in a constructor doesn't affect the +resulted instance as the below example indicates, + +``` +#[derive(Debug, PartialEq, Eq)] +struct Foo { + x: i32, + y: i32, +} +let x = 1; +let y = 2; + +// This assertion never fails: +assert_eq!(Foo { x, y }, Foo { y, x }); +``` + +inconsistent order can be confusing and decreases readability and consistency. + +### Example +``` +struct Foo { + x: i32, + y: i32, +} +let x = 1; +let y = 2; + +Foo { y, x }; +``` + +Use instead: +``` +Foo { x, y }; +``` \ No newline at end of file diff --git a/src/docs/index_refutable_slice.txt b/src/docs/index_refutable_slice.txt new file mode 100644 index 0000000000000..8a7d52761af81 --- /dev/null +++ b/src/docs/index_refutable_slice.txt @@ -0,0 +1,29 @@ +### What it does +The lint checks for slice bindings in patterns that are only used to +access individual slice values. + +### Why is this bad? +Accessing slice values using indices can lead to panics. Using refutable +patterns can avoid these. Binding to individual values also improves the +readability as they can be named. + +### Limitations +This lint currently only checks for immutable access inside `if let` +patterns. + +### Example +``` +let slice: Option<&[u32]> = Some(&[1, 2, 3]); + +if let Some(slice) = slice { + println!("{}", slice[0]); +} +``` +Use instead: +``` +let slice: Option<&[u32]> = Some(&[1, 2, 3]); + +if let Some(&[first, ..]) = slice { + println!("{}", first); +} +``` \ No newline at end of file diff --git a/src/docs/indexing_slicing.txt b/src/docs/indexing_slicing.txt new file mode 100644 index 0000000000000..76ca6ed318b38 --- /dev/null +++ b/src/docs/indexing_slicing.txt @@ -0,0 +1,33 @@ +### What it does +Checks for usage of indexing or slicing. Arrays are special cases, this lint +does report on arrays if we can tell that slicing operations are in bounds and does not +lint on constant `usize` indexing on arrays because that is handled by rustc's `const_err` lint. + +### Why is this bad? +Indexing and slicing can panic at runtime and there are +safe alternatives. + +### Example +``` +// Vector +let x = vec![0; 5]; + +x[2]; +&x[2..100]; + +// Array +let y = [0, 1, 2, 3]; + +&y[10..100]; +&y[10..]; +``` + +Use instead: +``` + +x.get(2); +x.get(2..100); + +y.get(10); +y.get(10..100); +``` \ No newline at end of file diff --git a/src/docs/ineffective_bit_mask.txt b/src/docs/ineffective_bit_mask.txt new file mode 100644 index 0000000000000..f6e7ef556215b --- /dev/null +++ b/src/docs/ineffective_bit_mask.txt @@ -0,0 +1,25 @@ +### What it does +Checks for bit masks in comparisons which can be removed +without changing the outcome. The basic structure can be seen in the +following table: + +|Comparison| Bit Op |Example |equals | +|----------|----------|------------|-------| +|`>` / `<=`|`\|` / `^`|`x \| 2 > 3`|`x > 3`| +|`<` / `>=`|`\|` / `^`|`x ^ 1 < 4` |`x < 4`| + +### Why is this bad? +Not equally evil as [`bad_bit_mask`](#bad_bit_mask), +but still a bit misleading, because the bit mask is ineffective. + +### Known problems +False negatives: This lint will only match instances +where we have figured out the math (which is for a power-of-two compared +value). This means things like `x | 1 >= 7` (which would be better written +as `x >= 6`) will not be reported (but bit masks like this are fairly +uncommon). + +### Example +``` +if (x | 1 > 3) { } +``` \ No newline at end of file diff --git a/src/docs/inefficient_to_string.txt b/src/docs/inefficient_to_string.txt new file mode 100644 index 0000000000000..f7061d1ce7b08 --- /dev/null +++ b/src/docs/inefficient_to_string.txt @@ -0,0 +1,17 @@ +### What it does +Checks for usage of `.to_string()` on an `&&T` where +`T` implements `ToString` directly (like `&&str` or `&&String`). + +### Why is this bad? +This bypasses the specialized implementation of +`ToString` and instead goes through the more expensive string formatting +facilities. + +### Example +``` +// Generic implementation for `T: Display` is used (slow) +["foo", "bar"].iter().map(|s| s.to_string()); + +// OK, the specialized impl is used +["foo", "bar"].iter().map(|&s| s.to_string()); +``` \ No newline at end of file diff --git a/src/docs/infallible_destructuring_match.txt b/src/docs/infallible_destructuring_match.txt new file mode 100644 index 0000000000000..4b5d3c4ba6c40 --- /dev/null +++ b/src/docs/infallible_destructuring_match.txt @@ -0,0 +1,29 @@ +### What it does +Checks for matches being used to destructure a single-variant enum +or tuple struct where a `let` will suffice. + +### Why is this bad? +Just readability – `let` doesn't nest, whereas a `match` does. + +### Example +``` +enum Wrapper { + Data(i32), +} + +let wrapper = Wrapper::Data(42); + +let data = match wrapper { + Wrapper::Data(i) => i, +}; +``` + +The correct use would be: +``` +enum Wrapper { + Data(i32), +} + +let wrapper = Wrapper::Data(42); +let Wrapper::Data(data) = wrapper; +``` \ No newline at end of file diff --git a/src/docs/infinite_iter.txt b/src/docs/infinite_iter.txt new file mode 100644 index 0000000000000..8a22fabc5492c --- /dev/null +++ b/src/docs/infinite_iter.txt @@ -0,0 +1,13 @@ +### What it does +Checks for iteration that is guaranteed to be infinite. + +### Why is this bad? +While there may be places where this is acceptable +(e.g., in event streams), in most cases this is simply an error. + +### Example +``` +use std::iter; + +iter::repeat(1_u8).collect::>(); +``` \ No newline at end of file diff --git a/src/docs/inherent_to_string.txt b/src/docs/inherent_to_string.txt new file mode 100644 index 0000000000000..b18e600e9e67b --- /dev/null +++ b/src/docs/inherent_to_string.txt @@ -0,0 +1,29 @@ +### What it does +Checks for the definition of inherent methods with a signature of `to_string(&self) -> String`. + +### Why is this bad? +This method is also implicitly defined if a type implements the `Display` trait. As the functionality of `Display` is much more versatile, it should be preferred. + +### Example +``` +pub struct A; + +impl A { + pub fn to_string(&self) -> String { + "I am A".to_string() + } +} +``` + +Use instead: +``` +use std::fmt; + +pub struct A; + +impl fmt::Display for A { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "I am A") + } +} +``` \ No newline at end of file diff --git a/src/docs/inherent_to_string_shadow_display.txt b/src/docs/inherent_to_string_shadow_display.txt new file mode 100644 index 0000000000000..a4bd0b622c4f5 --- /dev/null +++ b/src/docs/inherent_to_string_shadow_display.txt @@ -0,0 +1,37 @@ +### What it does +Checks for the definition of inherent methods with a signature of `to_string(&self) -> String` and if the type implementing this method also implements the `Display` trait. + +### Why is this bad? +This method is also implicitly defined if a type implements the `Display` trait. The less versatile inherent method will then shadow the implementation introduced by `Display`. + +### Example +``` +use std::fmt; + +pub struct A; + +impl A { + pub fn to_string(&self) -> String { + "I am A".to_string() + } +} + +impl fmt::Display for A { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "I am A, too") + } +} +``` + +Use instead: +``` +use std::fmt; + +pub struct A; + +impl fmt::Display for A { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "I am A") + } +} +``` \ No newline at end of file diff --git a/src/docs/init_numbered_fields.txt b/src/docs/init_numbered_fields.txt new file mode 100644 index 0000000000000..ba40af6a5fa55 --- /dev/null +++ b/src/docs/init_numbered_fields.txt @@ -0,0 +1,24 @@ +### What it does +Checks for tuple structs initialized with field syntax. +It will however not lint if a base initializer is present. +The lint will also ignore code in macros. + +### Why is this bad? +This may be confusing to the uninitiated and adds no +benefit as opposed to tuple initializers + +### Example +``` +struct TupleStruct(u8, u16); + +let _ = TupleStruct { + 0: 1, + 1: 23, +}; + +// should be written as +let base = TupleStruct(1, 23); + +// This is OK however +let _ = TupleStruct { 0: 42, ..base }; +``` \ No newline at end of file diff --git a/src/docs/inline_always.txt b/src/docs/inline_always.txt new file mode 100644 index 0000000000000..7721da4c4cc71 --- /dev/null +++ b/src/docs/inline_always.txt @@ -0,0 +1,23 @@ +### What it does +Checks for items annotated with `#[inline(always)]`, +unless the annotated function is empty or simply panics. + +### Why is this bad? +While there are valid uses of this annotation (and once +you know when to use it, by all means `allow` this lint), it's a common +newbie-mistake to pepper one's code with it. + +As a rule of thumb, before slapping `#[inline(always)]` on a function, +measure if that additional function call really affects your runtime profile +sufficiently to make up for the increase in compile time. + +### Known problems +False positives, big time. This lint is meant to be +deactivated by everyone doing serious performance work. This means having +done the measurement. + +### Example +``` +#[inline(always)] +fn not_quite_hot_code(..) { ... } +``` \ No newline at end of file diff --git a/src/docs/inline_asm_x86_att_syntax.txt b/src/docs/inline_asm_x86_att_syntax.txt new file mode 100644 index 0000000000000..8eb49d122d899 --- /dev/null +++ b/src/docs/inline_asm_x86_att_syntax.txt @@ -0,0 +1,16 @@ +### What it does +Checks for usage of AT&T x86 assembly syntax. + +### Why is this bad? +The lint has been enabled to indicate a preference +for Intel x86 assembly syntax. + +### Example + +``` +asm!("lea ({}), {}", in(reg) ptr, lateout(reg) _, options(att_syntax)); +``` +Use instead: +``` +asm!("lea {}, [{}]", lateout(reg) _, in(reg) ptr); +``` \ No newline at end of file diff --git a/src/docs/inline_asm_x86_intel_syntax.txt b/src/docs/inline_asm_x86_intel_syntax.txt new file mode 100644 index 0000000000000..5aa22c8ed2357 --- /dev/null +++ b/src/docs/inline_asm_x86_intel_syntax.txt @@ -0,0 +1,16 @@ +### What it does +Checks for usage of Intel x86 assembly syntax. + +### Why is this bad? +The lint has been enabled to indicate a preference +for AT&T x86 assembly syntax. + +### Example + +``` +asm!("lea {}, [{}]", lateout(reg) _, in(reg) ptr); +``` +Use instead: +``` +asm!("lea ({}), {}", in(reg) ptr, lateout(reg) _, options(att_syntax)); +``` \ No newline at end of file diff --git a/src/docs/inline_fn_without_body.txt b/src/docs/inline_fn_without_body.txt new file mode 100644 index 0000000000000..127c161aaa250 --- /dev/null +++ b/src/docs/inline_fn_without_body.txt @@ -0,0 +1,14 @@ +### What it does +Checks for `#[inline]` on trait methods without bodies + +### Why is this bad? +Only implementations of trait methods may be inlined. +The inline attribute is ignored for trait methods without bodies. + +### Example +``` +trait Animal { + #[inline] + fn name(&self) -> &'static str; +} +``` \ No newline at end of file diff --git a/src/docs/inspect_for_each.txt b/src/docs/inspect_for_each.txt new file mode 100644 index 0000000000000..01a46d6c451f4 --- /dev/null +++ b/src/docs/inspect_for_each.txt @@ -0,0 +1,23 @@ +### What it does +Checks for usage of `inspect().for_each()`. + +### Why is this bad? +It is the same as performing the computation +inside `inspect` at the beginning of the closure in `for_each`. + +### Example +``` +[1,2,3,4,5].iter() +.inspect(|&x| println!("inspect the number: {}", x)) +.for_each(|&x| { + assert!(x >= 0); +}); +``` +Can be written as +``` +[1,2,3,4,5].iter() +.for_each(|&x| { + println!("inspect the number: {}", x); + assert!(x >= 0); +}); +``` \ No newline at end of file diff --git a/src/docs/int_plus_one.txt b/src/docs/int_plus_one.txt new file mode 100644 index 0000000000000..1b68f3eeb64b4 --- /dev/null +++ b/src/docs/int_plus_one.txt @@ -0,0 +1,15 @@ +### What it does +Checks for usage of `x >= y + 1` or `x - 1 >= y` (and `<=`) in a block + +### Why is this bad? +Readability -- better to use `> y` instead of `>= y + 1`. + +### Example +``` +if x >= y + 1 {} +``` + +Use instead: +``` +if x > y {} +``` \ No newline at end of file diff --git a/src/docs/integer_arithmetic.txt b/src/docs/integer_arithmetic.txt new file mode 100644 index 0000000000000..ea57a2ef97bf5 --- /dev/null +++ b/src/docs/integer_arithmetic.txt @@ -0,0 +1,18 @@ +### What it does +Checks for integer arithmetic operations which could overflow or panic. + +Specifically, checks for any operators (`+`, `-`, `*`, `<<`, etc) which are capable +of overflowing according to the [Rust +Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow), +or which can panic (`/`, `%`). No bounds analysis or sophisticated reasoning is +attempted. + +### Why is this bad? +Integer overflow will trigger a panic in debug builds or will wrap in +release mode. Division by zero will cause a panic in either mode. In some applications one +wants explicitly checked, wrapping or saturating arithmetic. + +### Example +``` +a + 1; +``` \ No newline at end of file diff --git a/src/docs/integer_division.txt b/src/docs/integer_division.txt new file mode 100644 index 0000000000000..f6d3349810ed8 --- /dev/null +++ b/src/docs/integer_division.txt @@ -0,0 +1,19 @@ +### What it does +Checks for division of integers + +### Why is this bad? +When outside of some very specific algorithms, +integer division is very often a mistake because it discards the +remainder. + +### Example +``` +let x = 3 / 2; +println!("{}", x); +``` + +Use instead: +``` +let x = 3f32 / 2f32; +println!("{}", x); +``` \ No newline at end of file diff --git a/src/docs/into_iter_on_ref.txt b/src/docs/into_iter_on_ref.txt new file mode 100644 index 0000000000000..acb6bd474ebf3 --- /dev/null +++ b/src/docs/into_iter_on_ref.txt @@ -0,0 +1,18 @@ +### What it does +Checks for `into_iter` calls on references which should be replaced by `iter` +or `iter_mut`. + +### Why is this bad? +Readability. Calling `into_iter` on a reference will not move out its +content into the resulting iterator, which is confusing. It is better just call `iter` or +`iter_mut` directly. + +### Example +``` +(&vec).into_iter(); +``` + +Use instead: +``` +(&vec).iter(); +``` \ No newline at end of file diff --git a/src/docs/invalid_null_ptr_usage.txt b/src/docs/invalid_null_ptr_usage.txt new file mode 100644 index 0000000000000..6fb3fa3f83d66 --- /dev/null +++ b/src/docs/invalid_null_ptr_usage.txt @@ -0,0 +1,16 @@ +### What it does +This lint checks for invalid usages of `ptr::null`. + +### Why is this bad? +This causes undefined behavior. + +### Example +``` +// Undefined behavior +unsafe { std::slice::from_raw_parts(ptr::null(), 0); } +``` + +Use instead: +``` +unsafe { std::slice::from_raw_parts(NonNull::dangling().as_ptr(), 0); } +``` \ No newline at end of file diff --git a/src/docs/invalid_regex.txt b/src/docs/invalid_regex.txt new file mode 100644 index 0000000000000..6c9969b6e1a33 --- /dev/null +++ b/src/docs/invalid_regex.txt @@ -0,0 +1,12 @@ +### What it does +Checks [regex](https://crates.io/crates/regex) creation +(with `Regex::new`, `RegexBuilder::new`, or `RegexSet::new`) for correct +regex syntax. + +### Why is this bad? +This will lead to a runtime panic. + +### Example +``` +Regex::new("(") +``` \ No newline at end of file diff --git a/src/docs/invalid_upcast_comparisons.txt b/src/docs/invalid_upcast_comparisons.txt new file mode 100644 index 0000000000000..77cb033080372 --- /dev/null +++ b/src/docs/invalid_upcast_comparisons.txt @@ -0,0 +1,18 @@ +### What it does +Checks for comparisons where the relation is always either +true or false, but where one side has been upcast so that the comparison is +necessary. Only integer types are checked. + +### Why is this bad? +An expression like `let x : u8 = ...; (x as u32) > 300` +will mistakenly imply that it is possible for `x` to be outside the range of +`u8`. + +### Known problems +https://github.com/rust-lang/rust-clippy/issues/886 + +### Example +``` +let x: u8 = 1; +(x as u32) > 300; +``` \ No newline at end of file diff --git a/src/docs/invalid_utf8_in_unchecked.txt b/src/docs/invalid_utf8_in_unchecked.txt new file mode 100644 index 0000000000000..afb5acbe9c51c --- /dev/null +++ b/src/docs/invalid_utf8_in_unchecked.txt @@ -0,0 +1,12 @@ +### What it does +Checks for `std::str::from_utf8_unchecked` with an invalid UTF-8 literal + +### Why is this bad? +Creating such a `str` would result in undefined behavior + +### Example +``` +unsafe { + std::str::from_utf8_unchecked(b"cl\x82ippy"); +} +``` \ No newline at end of file diff --git a/src/docs/invisible_characters.txt b/src/docs/invisible_characters.txt new file mode 100644 index 0000000000000..3dda380911f91 --- /dev/null +++ b/src/docs/invisible_characters.txt @@ -0,0 +1,10 @@ +### What it does +Checks for invisible Unicode characters in the code. + +### Why is this bad? +Having an invisible character in the code makes for all +sorts of April fools, but otherwise is very much frowned upon. + +### Example +You don't see it, but there may be a zero-width space or soft hyphen +some­where in this text. \ No newline at end of file diff --git a/src/docs/is_digit_ascii_radix.txt b/src/docs/is_digit_ascii_radix.txt new file mode 100644 index 0000000000000..9f11cf43054fe --- /dev/null +++ b/src/docs/is_digit_ascii_radix.txt @@ -0,0 +1,20 @@ +### What it does +Finds usages of [`char::is_digit`](https://doc.rust-lang.org/stable/std/primitive.char.html#method.is_digit) that +can be replaced with [`is_ascii_digit`](https://doc.rust-lang.org/stable/std/primitive.char.html#method.is_ascii_digit) or +[`is_ascii_hexdigit`](https://doc.rust-lang.org/stable/std/primitive.char.html#method.is_ascii_hexdigit). + +### Why is this bad? +`is_digit(..)` is slower and requires specifying the radix. + +### Example +``` +let c: char = '6'; +c.is_digit(10); +c.is_digit(16); +``` +Use instead: +``` +let c: char = '6'; +c.is_ascii_digit(); +c.is_ascii_hexdigit(); +``` \ No newline at end of file diff --git a/src/docs/items_after_statements.txt b/src/docs/items_after_statements.txt new file mode 100644 index 0000000000000..6fdfff50d20e4 --- /dev/null +++ b/src/docs/items_after_statements.txt @@ -0,0 +1,37 @@ +### What it does +Checks for items declared after some statement in a block. + +### Why is this bad? +Items live for the entire scope they are declared +in. But statements are processed in order. This might cause confusion as +it's hard to figure out which item is meant in a statement. + +### Example +``` +fn foo() { + println!("cake"); +} + +fn main() { + foo(); // prints "foo" + fn foo() { + println!("foo"); + } + foo(); // prints "foo" +} +``` + +Use instead: +``` +fn foo() { + println!("cake"); +} + +fn main() { + fn foo() { + println!("foo"); + } + foo(); // prints "foo" + foo(); // prints "foo" +} +``` \ No newline at end of file diff --git a/src/docs/iter_cloned_collect.txt b/src/docs/iter_cloned_collect.txt new file mode 100644 index 0000000000000..90dc9ebb40f0b --- /dev/null +++ b/src/docs/iter_cloned_collect.txt @@ -0,0 +1,17 @@ +### What it does +Checks for the use of `.cloned().collect()` on slice to +create a `Vec`. + +### Why is this bad? +`.to_vec()` is clearer + +### Example +``` +let s = [1, 2, 3, 4, 5]; +let s2: Vec = s[..].iter().cloned().collect(); +``` +The better use would be: +``` +let s = [1, 2, 3, 4, 5]; +let s2: Vec = s.to_vec(); +``` \ No newline at end of file diff --git a/src/docs/iter_count.txt b/src/docs/iter_count.txt new file mode 100644 index 0000000000000..f3db4a26c2997 --- /dev/null +++ b/src/docs/iter_count.txt @@ -0,0 +1,22 @@ +### What it does +Checks for the use of `.iter().count()`. + +### Why is this bad? +`.len()` is more efficient and more +readable. + +### Example +``` +let some_vec = vec![0, 1, 2, 3]; + +some_vec.iter().count(); +&some_vec[..].iter().count(); +``` + +Use instead: +``` +let some_vec = vec![0, 1, 2, 3]; + +some_vec.len(); +&some_vec[..].len(); +``` \ No newline at end of file diff --git a/src/docs/iter_next_loop.txt b/src/docs/iter_next_loop.txt new file mode 100644 index 0000000000000..b33eb39d6e1d3 --- /dev/null +++ b/src/docs/iter_next_loop.txt @@ -0,0 +1,17 @@ +### What it does +Checks for loops on `x.next()`. + +### Why is this bad? +`next()` returns either `Some(value)` if there was a +value, or `None` otherwise. The insidious thing is that `Option<_>` +implements `IntoIterator`, so that possibly one value will be iterated, +leading to some hard to find bugs. No one will want to write such code +[except to win an Underhanded Rust +Contest](https://www.reddit.com/r/rust/comments/3hb0wm/underhanded_rust_contest/cu5yuhr). + +### Example +``` +for x in y.next() { + .. +} +``` \ No newline at end of file diff --git a/src/docs/iter_next_slice.txt b/src/docs/iter_next_slice.txt new file mode 100644 index 0000000000000..1cea25eaf3017 --- /dev/null +++ b/src/docs/iter_next_slice.txt @@ -0,0 +1,16 @@ +### What it does +Checks for usage of `iter().next()` on a Slice or an Array + +### Why is this bad? +These can be shortened into `.get()` + +### Example +``` +a[2..].iter().next(); +b.iter().next(); +``` +should be written as: +``` +a.get(2); +b.get(0); +``` \ No newline at end of file diff --git a/src/docs/iter_not_returning_iterator.txt b/src/docs/iter_not_returning_iterator.txt new file mode 100644 index 0000000000000..0ca862910a6f0 --- /dev/null +++ b/src/docs/iter_not_returning_iterator.txt @@ -0,0 +1,26 @@ +### What it does +Detects methods named `iter` or `iter_mut` that do not have a return type that implements `Iterator`. + +### Why is this bad? +Methods named `iter` or `iter_mut` conventionally return an `Iterator`. + +### Example +``` +// `String` does not implement `Iterator` +struct Data {} +impl Data { + fn iter(&self) -> String { + todo!() + } +} +``` +Use instead: +``` +use std::str::Chars; +struct Data {} +impl Data { + fn iter(&self) -> Chars<'static> { + todo!() + } +} +``` \ No newline at end of file diff --git a/src/docs/iter_nth.txt b/src/docs/iter_nth.txt new file mode 100644 index 0000000000000..3d67d583ffde3 --- /dev/null +++ b/src/docs/iter_nth.txt @@ -0,0 +1,20 @@ +### What it does +Checks for use of `.iter().nth()` (and the related +`.iter_mut().nth()`) on standard library types with *O*(1) element access. + +### Why is this bad? +`.get()` and `.get_mut()` are more efficient and more +readable. + +### Example +``` +let some_vec = vec![0, 1, 2, 3]; +let bad_vec = some_vec.iter().nth(3); +let bad_slice = &some_vec[..].iter().nth(3); +``` +The correct use would be: +``` +let some_vec = vec![0, 1, 2, 3]; +let bad_vec = some_vec.get(3); +let bad_slice = &some_vec[..].get(3); +``` \ No newline at end of file diff --git a/src/docs/iter_nth_zero.txt b/src/docs/iter_nth_zero.txt new file mode 100644 index 0000000000000..8efe47a16a100 --- /dev/null +++ b/src/docs/iter_nth_zero.txt @@ -0,0 +1,17 @@ +### What it does +Checks for the use of `iter.nth(0)`. + +### Why is this bad? +`iter.next()` is equivalent to +`iter.nth(0)`, as they both consume the next element, + but is more readable. + +### Example +``` +let x = s.iter().nth(0); +``` + +Use instead: +``` +let x = s.iter().next(); +``` \ No newline at end of file diff --git a/src/docs/iter_on_empty_collections.txt b/src/docs/iter_on_empty_collections.txt new file mode 100644 index 0000000000000..87c4ec12afae7 --- /dev/null +++ b/src/docs/iter_on_empty_collections.txt @@ -0,0 +1,25 @@ +### What it does + +Checks for calls to `iter`, `iter_mut` or `into_iter` on empty collections + +### Why is this bad? + +It is simpler to use the empty function from the standard library: + +### Example + +``` +use std::{slice, option}; +let a: slice::Iter = [].iter(); +let f: option::IntoIter = None.into_iter(); +``` +Use instead: +``` +use std::iter; +let a: iter::Empty = iter::empty(); +let b: iter::Empty = iter::empty(); +``` + +### Known problems + +The type of the resulting iterator might become incompatible with its usage \ No newline at end of file diff --git a/src/docs/iter_on_single_items.txt b/src/docs/iter_on_single_items.txt new file mode 100644 index 0000000000000..d0388f25d045e --- /dev/null +++ b/src/docs/iter_on_single_items.txt @@ -0,0 +1,24 @@ +### What it does + +Checks for calls to `iter`, `iter_mut` or `into_iter` on collections containing a single item + +### Why is this bad? + +It is simpler to use the once function from the standard library: + +### Example + +``` +let a = [123].iter(); +let b = Some(123).into_iter(); +``` +Use instead: +``` +use std::iter; +let a = iter::once(&123); +let b = iter::once(123); +``` + +### Known problems + +The type of the resulting iterator might become incompatible with its usage \ No newline at end of file diff --git a/src/docs/iter_overeager_cloned.txt b/src/docs/iter_overeager_cloned.txt new file mode 100644 index 0000000000000..2f902a0c2db4d --- /dev/null +++ b/src/docs/iter_overeager_cloned.txt @@ -0,0 +1,22 @@ +### What it does +Checks for usage of `_.cloned().()` where call to `.cloned()` can be postponed. + +### Why is this bad? +It's often inefficient to clone all elements of an iterator, when eventually, only some +of them will be consumed. + +### Known Problems +This `lint` removes the side of effect of cloning items in the iterator. +A code that relies on that side-effect could fail. + +### Examples +``` +vec.iter().cloned().take(10); +vec.iter().cloned().last(); +``` + +Use instead: +``` +vec.iter().take(10).cloned(); +vec.iter().last().cloned(); +``` \ No newline at end of file diff --git a/src/docs/iter_skip_next.txt b/src/docs/iter_skip_next.txt new file mode 100644 index 0000000000000..da226b041cf23 --- /dev/null +++ b/src/docs/iter_skip_next.txt @@ -0,0 +1,18 @@ +### What it does +Checks for use of `.skip(x).next()` on iterators. + +### Why is this bad? +`.nth(x)` is cleaner + +### Example +``` +let some_vec = vec![0, 1, 2, 3]; +let bad_vec = some_vec.iter().skip(3).next(); +let bad_slice = &some_vec[..].iter().skip(3).next(); +``` +The correct use would be: +``` +let some_vec = vec![0, 1, 2, 3]; +let bad_vec = some_vec.iter().nth(3); +let bad_slice = &some_vec[..].iter().nth(3); +``` \ No newline at end of file diff --git a/src/docs/iter_with_drain.txt b/src/docs/iter_with_drain.txt new file mode 100644 index 0000000000000..2c52b99f7a5c5 --- /dev/null +++ b/src/docs/iter_with_drain.txt @@ -0,0 +1,16 @@ +### What it does +Checks for use of `.drain(..)` on `Vec` and `VecDeque` for iteration. + +### Why is this bad? +`.into_iter()` is simpler with better performance. + +### Example +``` +let mut foo = vec![0, 1, 2, 3]; +let bar: HashSet = foo.drain(..).collect(); +``` +Use instead: +``` +let foo = vec![0, 1, 2, 3]; +let bar: HashSet = foo.into_iter().collect(); +``` \ No newline at end of file diff --git a/src/docs/iterator_step_by_zero.txt b/src/docs/iterator_step_by_zero.txt new file mode 100644 index 0000000000000..73ecc99acfcbc --- /dev/null +++ b/src/docs/iterator_step_by_zero.txt @@ -0,0 +1,13 @@ +### What it does +Checks for calling `.step_by(0)` on iterators which panics. + +### Why is this bad? +This very much looks like an oversight. Use `panic!()` instead if you +actually intend to panic. + +### Example +``` +for x in (0..100).step_by(0) { + //.. +} +``` \ No newline at end of file diff --git a/src/docs/just_underscores_and_digits.txt b/src/docs/just_underscores_and_digits.txt new file mode 100644 index 0000000000000..a8790bcf25be6 --- /dev/null +++ b/src/docs/just_underscores_and_digits.txt @@ -0,0 +1,14 @@ +### What it does +Checks if you have variables whose name consists of just +underscores and digits. + +### Why is this bad? +It's hard to memorize what a variable means without a +descriptive name. + +### Example +``` +let _1 = 1; +let ___1 = 1; +let __1___2 = 11; +``` \ No newline at end of file diff --git a/src/docs/large_const_arrays.txt b/src/docs/large_const_arrays.txt new file mode 100644 index 0000000000000..71f67854f2a1a --- /dev/null +++ b/src/docs/large_const_arrays.txt @@ -0,0 +1,17 @@ +### What it does +Checks for large `const` arrays that should +be defined as `static` instead. + +### Why is this bad? +Performance: const variables are inlined upon use. +Static items result in only one instance and has a fixed location in memory. + +### Example +``` +pub const a = [0u32; 1_000_000]; +``` + +Use instead: +``` +pub static a = [0u32; 1_000_000]; +``` \ No newline at end of file diff --git a/src/docs/large_digit_groups.txt b/src/docs/large_digit_groups.txt new file mode 100644 index 0000000000000..f60b19345af44 --- /dev/null +++ b/src/docs/large_digit_groups.txt @@ -0,0 +1,12 @@ +### What it does +Warns if the digits of an integral or floating-point +constant are grouped into groups that +are too large. + +### Why is this bad? +Negatively impacts readability. + +### Example +``` +let x: u64 = 6186491_8973511; +``` \ No newline at end of file diff --git a/src/docs/large_enum_variant.txt b/src/docs/large_enum_variant.txt new file mode 100644 index 0000000000000..1f95430790d29 --- /dev/null +++ b/src/docs/large_enum_variant.txt @@ -0,0 +1,41 @@ +### What it does +Checks for large size differences between variants on +`enum`s. + +### Why is this bad? +Enum size is bounded by the largest variant. Having one +large variant can penalize the memory layout of that enum. + +### Known problems +This lint obviously cannot take the distribution of +variants in your running program into account. It is possible that the +smaller variants make up less than 1% of all instances, in which case +the overhead is negligible and the boxing is counter-productive. Always +measure the change this lint suggests. + +For types that implement `Copy`, the suggestion to `Box` a variant's +data would require removing the trait impl. The types can of course +still be `Clone`, but that is worse ergonomically. Depending on the +use case it may be possible to store the large data in an auxiliary +structure (e.g. Arena or ECS). + +The lint will ignore the impact of generic types to the type layout by +assuming every type parameter is zero-sized. Depending on your use case, +this may lead to a false positive. + +### Example +``` +enum Test { + A(i32), + B([i32; 8000]), +} +``` + +Use instead: +``` +// Possibly better +enum Test2 { + A(i32), + B(Box<[i32; 8000]>), +} +``` \ No newline at end of file diff --git a/src/docs/large_include_file.txt b/src/docs/large_include_file.txt new file mode 100644 index 0000000000000..b2a54bd2eb5ca --- /dev/null +++ b/src/docs/large_include_file.txt @@ -0,0 +1,21 @@ +### What it does +Checks for the inclusion of large files via `include_bytes!()` +and `include_str!()` + +### Why is this bad? +Including large files can increase the size of the binary + +### Example +``` +let included_str = include_str!("very_large_file.txt"); +let included_bytes = include_bytes!("very_large_file.txt"); +``` + +Use instead: +``` +use std::fs; + +// You can load the file at runtime +let string = fs::read_to_string("very_large_file.txt")?; +let bytes = fs::read("very_large_file.txt")?; +``` \ No newline at end of file diff --git a/src/docs/large_stack_arrays.txt b/src/docs/large_stack_arrays.txt new file mode 100644 index 0000000000000..4a6f34785b0ef --- /dev/null +++ b/src/docs/large_stack_arrays.txt @@ -0,0 +1,10 @@ +### What it does +Checks for local arrays that may be too large. + +### Why is this bad? +Large local arrays may cause stack overflow. + +### Example +``` +let a = [0u32; 1_000_000]; +``` \ No newline at end of file diff --git a/src/docs/large_types_passed_by_value.txt b/src/docs/large_types_passed_by_value.txt new file mode 100644 index 0000000000000..bca07f3ac61bb --- /dev/null +++ b/src/docs/large_types_passed_by_value.txt @@ -0,0 +1,24 @@ +### What it does +Checks for functions taking arguments by value, where +the argument type is `Copy` and large enough to be worth considering +passing by reference. Does not trigger if the function is being exported, +because that might induce API breakage, if the parameter is declared as mutable, +or if the argument is a `self`. + +### Why is this bad? +Arguments passed by value might result in an unnecessary +shallow copy, taking up more space in the stack and requiring a call to +`memcpy`, which can be expensive. + +### Example +``` +#[derive(Clone, Copy)] +struct TooLarge([u8; 2048]); + +fn foo(v: TooLarge) {} +``` + +Use instead: +``` +fn foo(v: &TooLarge) {} +``` \ No newline at end of file diff --git a/src/docs/len_without_is_empty.txt b/src/docs/len_without_is_empty.txt new file mode 100644 index 0000000000000..47a2e85752285 --- /dev/null +++ b/src/docs/len_without_is_empty.txt @@ -0,0 +1,19 @@ +### What it does +Checks for items that implement `.len()` but not +`.is_empty()`. + +### Why is this bad? +It is good custom to have both methods, because for +some data structures, asking about the length will be a costly operation, +whereas `.is_empty()` can usually answer in constant time. Also it used to +lead to false positives on the [`len_zero`](#len_zero) lint – currently that +lint will ignore such entities. + +### Example +``` +impl X { + pub fn len(&self) -> usize { + .. + } +} +``` \ No newline at end of file diff --git a/src/docs/len_zero.txt b/src/docs/len_zero.txt new file mode 100644 index 0000000000000..664124bd391df --- /dev/null +++ b/src/docs/len_zero.txt @@ -0,0 +1,28 @@ +### What it does +Checks for getting the length of something via `.len()` +just to compare to zero, and suggests using `.is_empty()` where applicable. + +### Why is this bad? +Some structures can answer `.is_empty()` much faster +than calculating their length. So it is good to get into the habit of using +`.is_empty()`, and having it is cheap. +Besides, it makes the intent clearer than a manual comparison in some contexts. + +### Example +``` +if x.len() == 0 { + .. +} +if y.len() != 0 { + .. +} +``` +instead use +``` +if x.is_empty() { + .. +} +if !y.is_empty() { + .. +} +``` \ No newline at end of file diff --git a/src/docs/let_and_return.txt b/src/docs/let_and_return.txt new file mode 100644 index 0000000000000..eba5a90ddd66c --- /dev/null +++ b/src/docs/let_and_return.txt @@ -0,0 +1,21 @@ +### What it does +Checks for `let`-bindings, which are subsequently +returned. + +### Why is this bad? +It is just extraneous code. Remove it to make your code +more rusty. + +### Example +``` +fn foo() -> String { + let x = String::new(); + x +} +``` +instead, use +``` +fn foo() -> String { + String::new() +} +``` \ No newline at end of file diff --git a/src/docs/let_underscore_drop.txt b/src/docs/let_underscore_drop.txt new file mode 100644 index 0000000000000..29ce9bf50ce6a --- /dev/null +++ b/src/docs/let_underscore_drop.txt @@ -0,0 +1,29 @@ +### What it does +Checks for `let _ = ` +where expr has a type that implements `Drop` + +### 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. + +### Example +``` +{ + let _ = DroppableItem; + // ^ dropped here + /* more code */ +} +``` + +Use instead: +``` +{ + let _droppable = DroppableItem; + /* more code */ + // dropped at end of scope +} +``` \ No newline at end of file diff --git a/src/docs/let_underscore_lock.txt b/src/docs/let_underscore_lock.txt new file mode 100644 index 0000000000000..bd8217fb58b3c --- /dev/null +++ b/src/docs/let_underscore_lock.txt @@ -0,0 +1,20 @@ +### What it does +Checks for `let _ = sync_lock`. +This supports `mutex` and `rwlock` in `std::sync` and `parking_lot`. + +### Why is this bad? +This statement immediately drops the lock instead of +extending its lifetime to the end of the scope, which is often not intended. +To extend lock lifetime to the end of the scope, use an underscore-prefixed +name instead (i.e. _lock). If you want to explicitly drop the lock, +`std::mem::drop` conveys your intention better and is less error-prone. + +### Example +``` +let _ = mutex.lock(); +``` + +Use instead: +``` +let _lock = mutex.lock(); +``` \ No newline at end of file diff --git a/src/docs/let_underscore_must_use.txt b/src/docs/let_underscore_must_use.txt new file mode 100644 index 0000000000000..270b81d9a4c41 --- /dev/null +++ b/src/docs/let_underscore_must_use.txt @@ -0,0 +1,17 @@ +### What it does +Checks for `let _ = ` where expr is `#[must_use]` + +### Why is this bad? +It's better to explicitly handle the value of a `#[must_use]` +expr + +### Example +``` +fn f() -> Result { + Ok(0) +} + +let _ = f(); +// is_ok() is marked #[must_use] +let _ = f().is_ok(); +``` \ No newline at end of file diff --git a/src/docs/let_unit_value.txt b/src/docs/let_unit_value.txt new file mode 100644 index 0000000000000..bc16d5b3d81be --- /dev/null +++ b/src/docs/let_unit_value.txt @@ -0,0 +1,13 @@ +### What it does +Checks for binding a unit value. + +### Why is this bad? +A unit value cannot usefully be used anywhere. So +binding one is kind of pointless. + +### Example +``` +let x = { + 1; +}; +``` \ No newline at end of file diff --git a/src/docs/linkedlist.txt b/src/docs/linkedlist.txt new file mode 100644 index 0000000000000..986ff1369e3c1 --- /dev/null +++ b/src/docs/linkedlist.txt @@ -0,0 +1,32 @@ +### What it does +Checks for usage of any `LinkedList`, suggesting to use a +`Vec` or a `VecDeque` (formerly called `RingBuf`). + +### Why is this bad? +Gankro says: + +> The TL;DR of `LinkedList` is that it's built on a massive amount of +pointers and indirection. +> It wastes memory, it has terrible cache locality, and is all-around slow. +`RingBuf`, while +> "only" amortized for push/pop, should be faster in the general case for +almost every possible +> workload, and isn't even amortized at all if you can predict the capacity +you need. +> +> `LinkedList`s are only really good if you're doing a lot of merging or +splitting of lists. +> This is because they can just mangle some pointers instead of actually +copying the data. Even +> if you're doing a lot of insertion in the middle of the list, `RingBuf` +can still be better +> because of how expensive it is to seek to the middle of a `LinkedList`. + +### Known problems +False positives – the instances where using a +`LinkedList` makes sense are few and far between, but they can still happen. + +### Example +``` +let x: LinkedList = LinkedList::new(); +``` \ No newline at end of file diff --git a/src/docs/lossy_float_literal.txt b/src/docs/lossy_float_literal.txt new file mode 100644 index 0000000000000..bbcb9115ea62a --- /dev/null +++ b/src/docs/lossy_float_literal.txt @@ -0,0 +1,18 @@ +### What it does +Checks for whole number float literals that +cannot be represented as the underlying type without loss. + +### Why is this bad? +Rust will silently lose precision during +conversion to a float. + +### Example +``` +let _: f32 = 16_777_217.0; // 16_777_216.0 +``` + +Use instead: +``` +let _: f32 = 16_777_216.0; +let _: f64 = 16_777_217.0; +``` \ No newline at end of file diff --git a/src/docs/macro_use_imports.txt b/src/docs/macro_use_imports.txt new file mode 100644 index 0000000000000..6a8180a60bc6f --- /dev/null +++ b/src/docs/macro_use_imports.txt @@ -0,0 +1,12 @@ +### What it does +Checks for `#[macro_use] use...`. + +### Why is this bad? +Since the Rust 2018 edition you can import +macro's directly, this is considered idiomatic. + +### Example +``` +#[macro_use] +use some_macro; +``` \ No newline at end of file diff --git a/src/docs/main_recursion.txt b/src/docs/main_recursion.txt new file mode 100644 index 0000000000000..e49becd15bbdb --- /dev/null +++ b/src/docs/main_recursion.txt @@ -0,0 +1,13 @@ +### What it does +Checks for recursion using the entrypoint. + +### Why is this bad? +Apart from special setups (which we could detect following attributes like #![no_std]), +recursing into main() seems like an unintuitive anti-pattern we should be able to detect. + +### Example +``` +fn main() { + main(); +} +``` \ No newline at end of file diff --git a/src/docs/manual_assert.txt b/src/docs/manual_assert.txt new file mode 100644 index 0000000000000..93653081a2ce0 --- /dev/null +++ b/src/docs/manual_assert.txt @@ -0,0 +1,18 @@ +### What it does +Detects `if`-then-`panic!` that can be replaced with `assert!`. + +### Why is this bad? +`assert!` is simpler than `if`-then-`panic!`. + +### Example +``` +let sad_people: Vec<&str> = vec![]; +if !sad_people.is_empty() { + panic!("there are sad people: {:?}", sad_people); +} +``` +Use instead: +``` +let sad_people: Vec<&str> = vec![]; +assert!(sad_people.is_empty(), "there are sad people: {:?}", sad_people); +``` \ No newline at end of file diff --git a/src/docs/manual_async_fn.txt b/src/docs/manual_async_fn.txt new file mode 100644 index 0000000000000..d01ac402e0d21 --- /dev/null +++ b/src/docs/manual_async_fn.txt @@ -0,0 +1,16 @@ +### What it does +It checks for manual implementations of `async` functions. + +### Why is this bad? +It's more idiomatic to use the dedicated syntax. + +### Example +``` +use std::future::Future; + +fn foo() -> impl Future { async { 42 } } +``` +Use instead: +``` +async fn foo() -> i32 { 42 } +``` \ No newline at end of file diff --git a/src/docs/manual_bits.txt b/src/docs/manual_bits.txt new file mode 100644 index 0000000000000..b96c2eb151d41 --- /dev/null +++ b/src/docs/manual_bits.txt @@ -0,0 +1,15 @@ +### What it does +Checks for uses of `std::mem::size_of::() * 8` when +`T::BITS` is available. + +### Why is this bad? +Can be written as the shorter `T::BITS`. + +### Example +``` +std::mem::size_of::() * 8; +``` +Use instead: +``` +usize::BITS as usize; +``` \ No newline at end of file diff --git a/src/docs/manual_filter_map.txt b/src/docs/manual_filter_map.txt new file mode 100644 index 0000000000000..3b6860798ff58 --- /dev/null +++ b/src/docs/manual_filter_map.txt @@ -0,0 +1,19 @@ +### What it does +Checks for usage of `_.filter(_).map(_)` that can be written more simply +as `filter_map(_)`. + +### Why is this bad? +Redundant code in the `filter` and `map` operations is poor style and +less performant. + +### Example +``` +(0_i32..10) + .filter(|n| n.checked_add(1).is_some()) + .map(|n| n.checked_add(1).unwrap()); +``` + +Use instead: +``` +(0_i32..10).filter_map(|n| n.checked_add(1)); +``` \ No newline at end of file diff --git a/src/docs/manual_find.txt b/src/docs/manual_find.txt new file mode 100644 index 0000000000000..e3e07a2771f95 --- /dev/null +++ b/src/docs/manual_find.txt @@ -0,0 +1,24 @@ +### What it does +Check for manual implementations of Iterator::find + +### Why is this bad? +It doesn't affect performance, but using `find` is shorter and easier to read. + +### Example + +``` +fn example(arr: Vec) -> Option { + for el in arr { + if el == 1 { + return Some(el); + } + } + None +} +``` +Use instead: +``` +fn example(arr: Vec) -> Option { + arr.into_iter().find(|&el| el == 1) +} +``` \ No newline at end of file diff --git a/src/docs/manual_find_map.txt b/src/docs/manual_find_map.txt new file mode 100644 index 0000000000000..83b22060c0e19 --- /dev/null +++ b/src/docs/manual_find_map.txt @@ -0,0 +1,19 @@ +### What it does +Checks for usage of `_.find(_).map(_)` that can be written more simply +as `find_map(_)`. + +### Why is this bad? +Redundant code in the `find` and `map` operations is poor style and +less performant. + +### Example +``` +(0_i32..10) + .find(|n| n.checked_add(1).is_some()) + .map(|n| n.checked_add(1).unwrap()); +``` + +Use instead: +``` +(0_i32..10).find_map(|n| n.checked_add(1)); +``` \ No newline at end of file diff --git a/src/docs/manual_flatten.txt b/src/docs/manual_flatten.txt new file mode 100644 index 0000000000000..62d5f3ec93576 --- /dev/null +++ b/src/docs/manual_flatten.txt @@ -0,0 +1,25 @@ +### What it does +Check for unnecessary `if let` usage in a for loop +where only the `Some` or `Ok` variant of the iterator element is used. + +### Why is this bad? +It is verbose and can be simplified +by first calling the `flatten` method on the `Iterator`. + +### Example + +``` +let x = vec![Some(1), Some(2), Some(3)]; +for n in x { + if let Some(n) = n { + println!("{}", n); + } +} +``` +Use instead: +``` +let x = vec![Some(1), Some(2), Some(3)]; +for n in x.into_iter().flatten() { + println!("{}", n); +} +``` \ No newline at end of file diff --git a/src/docs/manual_instant_elapsed.txt b/src/docs/manual_instant_elapsed.txt new file mode 100644 index 0000000000000..dde3d493c70d3 --- /dev/null +++ b/src/docs/manual_instant_elapsed.txt @@ -0,0 +1,21 @@ +### 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 +``` +use std::time::Instant; +let prev_instant = Instant::now(); +let duration = Instant::now() - prev_instant; +``` +Use instead: +``` +use std::time::Instant; +let prev_instant = Instant::now(); +let duration = prev_instant.elapsed(); +``` \ No newline at end of file diff --git a/src/docs/manual_map.txt b/src/docs/manual_map.txt new file mode 100644 index 0000000000000..7f68ccd1037e3 --- /dev/null +++ b/src/docs/manual_map.txt @@ -0,0 +1,17 @@ +### What it does +Checks for usages of `match` which could be implemented using `map` + +### Why is this bad? +Using the `map` method is clearer and more concise. + +### Example +``` +match Some(0) { + Some(x) => Some(x + 1), + None => None, +}; +``` +Use instead: +``` +Some(0).map(|x| x + 1); +``` \ No newline at end of file diff --git a/src/docs/manual_memcpy.txt b/src/docs/manual_memcpy.txt new file mode 100644 index 0000000000000..d7690bf258669 --- /dev/null +++ b/src/docs/manual_memcpy.txt @@ -0,0 +1,18 @@ +### What it does +Checks for for-loops that manually copy items between +slices that could be optimized by having a memcpy. + +### Why is this bad? +It is not as fast as a memcpy. + +### Example +``` +for i in 0..src.len() { + dst[i + 64] = src[i]; +} +``` + +Use instead: +``` +dst[64..(src.len() + 64)].clone_from_slice(&src[..]); +``` \ No newline at end of file diff --git a/src/docs/manual_non_exhaustive.txt b/src/docs/manual_non_exhaustive.txt new file mode 100644 index 0000000000000..fb021393bd7c9 --- /dev/null +++ b/src/docs/manual_non_exhaustive.txt @@ -0,0 +1,41 @@ +### What it does +Checks for manual implementations of the non-exhaustive pattern. + +### Why is this bad? +Using the #[non_exhaustive] attribute expresses better the intent +and allows possible optimizations when applied to enums. + +### Example +``` +struct S { + pub a: i32, + pub b: i32, + _c: (), +} + +enum E { + A, + B, + #[doc(hidden)] + _C, +} + +struct T(pub i32, pub i32, ()); +``` +Use instead: +``` +#[non_exhaustive] +struct S { + pub a: i32, + pub b: i32, +} + +#[non_exhaustive] +enum E { + A, + B, +} + +#[non_exhaustive] +struct T(pub i32, pub i32); +``` \ No newline at end of file diff --git a/src/docs/manual_ok_or.txt b/src/docs/manual_ok_or.txt new file mode 100644 index 0000000000000..5accdf25965ab --- /dev/null +++ b/src/docs/manual_ok_or.txt @@ -0,0 +1,19 @@ +### What it does + +Finds patterns that reimplement `Option::ok_or`. + +### Why is this bad? + +Concise code helps focusing on behavior instead of boilerplate. + +### Examples +``` +let foo: Option = None; +foo.map_or(Err("error"), |v| Ok(v)); +``` + +Use instead: +``` +let foo: Option = None; +foo.ok_or("error"); +``` \ No newline at end of file diff --git a/src/docs/manual_range_contains.txt b/src/docs/manual_range_contains.txt new file mode 100644 index 0000000000000..0ade26951d385 --- /dev/null +++ b/src/docs/manual_range_contains.txt @@ -0,0 +1,19 @@ +### What it does +Checks for expressions like `x >= 3 && x < 8` that could +be more readably expressed as `(3..8).contains(x)`. + +### Why is this bad? +`contains` expresses the intent better and has less +failure modes (such as fencepost errors or using `||` instead of `&&`). + +### Example +``` +// given +let x = 6; + +assert!(x >= 3 && x < 8); +``` +Use instead: +``` +assert!((3..8).contains(&x)); +``` \ No newline at end of file diff --git a/src/docs/manual_rem_euclid.txt b/src/docs/manual_rem_euclid.txt new file mode 100644 index 0000000000000..d3bb8c61304e1 --- /dev/null +++ b/src/docs/manual_rem_euclid.txt @@ -0,0 +1,17 @@ +### What it does +Checks for an expression like `((x % 4) + 4) % 4` which is a common manual reimplementation +of `x.rem_euclid(4)`. + +### Why is this bad? +It's simpler and more readable. + +### Example +``` +let x: i32 = 24; +let rem = ((x % 4) + 4) % 4; +``` +Use instead: +``` +let x: i32 = 24; +let rem = x.rem_euclid(4); +``` \ No newline at end of file diff --git a/src/docs/manual_retain.txt b/src/docs/manual_retain.txt new file mode 100644 index 0000000000000..cd4f65a93fc33 --- /dev/null +++ b/src/docs/manual_retain.txt @@ -0,0 +1,15 @@ +### What it does +Checks for code to be replaced by `.retain()`. +### Why is this bad? +`.retain()` is simpler and avoids needless allocation. +### Example +``` +let mut vec = vec![0, 1, 2]; +vec = vec.iter().filter(|&x| x % 2 == 0).copied().collect(); +vec = vec.into_iter().filter(|x| x % 2 == 0).collect(); +``` +Use instead: +``` +let mut vec = vec![0, 1, 2]; +vec.retain(|x| x % 2 == 0); +``` \ No newline at end of file diff --git a/src/docs/manual_saturating_arithmetic.txt b/src/docs/manual_saturating_arithmetic.txt new file mode 100644 index 0000000000000..d9f5d3d118712 --- /dev/null +++ b/src/docs/manual_saturating_arithmetic.txt @@ -0,0 +1,18 @@ +### What it does +Checks for `.checked_add/sub(x).unwrap_or(MAX/MIN)`. + +### Why is this bad? +These can be written simply with `saturating_add/sub` methods. + +### Example +``` +let add = x.checked_add(y).unwrap_or(u32::MAX); +let sub = x.checked_sub(y).unwrap_or(u32::MIN); +``` + +can be written using dedicated methods for saturating addition/subtraction as: + +``` +let add = x.saturating_add(y); +let sub = x.saturating_sub(y); +``` \ No newline at end of file diff --git a/src/docs/manual_split_once.txt b/src/docs/manual_split_once.txt new file mode 100644 index 0000000000000..291ae447de08a --- /dev/null +++ b/src/docs/manual_split_once.txt @@ -0,0 +1,29 @@ +### What it does +Checks for usages of `str::splitn(2, _)` + +### Why is this bad? +`split_once` is both clearer in intent and slightly more efficient. + +### Example +``` +let s = "key=value=add"; +let (key, value) = s.splitn(2, '=').next_tuple()?; +let value = s.splitn(2, '=').nth(1)?; + +let mut parts = s.splitn(2, '='); +let key = parts.next()?; +let value = parts.next()?; +``` + +Use instead: +``` +let s = "key=value=add"; +let (key, value) = s.split_once('=')?; +let value = s.split_once('=')?.1; + +let (key, value) = s.split_once('=')?; +``` + +### Limitations +The multiple statement variant currently only detects `iter.next()?`/`iter.next().unwrap()` +in two separate `let` statements that immediately follow the `splitn()` \ No newline at end of file diff --git a/src/docs/manual_str_repeat.txt b/src/docs/manual_str_repeat.txt new file mode 100644 index 0000000000000..1d4a7a48e2033 --- /dev/null +++ b/src/docs/manual_str_repeat.txt @@ -0,0 +1,15 @@ +### What it does +Checks for manual implementations of `str::repeat` + +### Why is this bad? +These are both harder to read, as well as less performant. + +### Example +``` +let x: String = std::iter::repeat('x').take(10).collect(); +``` + +Use instead: +``` +let x: String = "x".repeat(10); +``` \ No newline at end of file diff --git a/src/docs/manual_string_new.txt b/src/docs/manual_string_new.txt new file mode 100644 index 0000000000000..4cbc43f8f8439 --- /dev/null +++ b/src/docs/manual_string_new.txt @@ -0,0 +1,20 @@ +### What it does + +Checks for usage of `""` to create a `String`, such as `"".to_string()`, `"".to_owned()`, +`String::from("")` and others. + +### Why is this bad? + +Different ways of creating an empty string makes your code less standardized, which can +be confusing. + +### Example +``` +let a = "".to_string(); +let b: String = "".into(); +``` +Use instead: +``` +let a = String::new(); +let b = String::new(); +``` \ No newline at end of file diff --git a/src/docs/manual_strip.txt b/src/docs/manual_strip.txt new file mode 100644 index 0000000000000..f32d8e7a09bb3 --- /dev/null +++ b/src/docs/manual_strip.txt @@ -0,0 +1,24 @@ +### What it does +Suggests using `strip_{prefix,suffix}` over `str::{starts,ends}_with` and slicing using +the pattern's length. + +### Why is this bad? +Using `str:strip_{prefix,suffix}` is safer and may have better performance as there is no +slicing which may panic and the compiler does not need to insert this panic code. It is +also sometimes more readable as it removes the need for duplicating or storing the pattern +used by `str::{starts,ends}_with` and in the slicing. + +### Example +``` +let s = "hello, world!"; +if s.starts_with("hello, ") { + assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!"); +} +``` +Use instead: +``` +let s = "hello, world!"; +if let Some(end) = s.strip_prefix("hello, ") { + assert_eq!(end.to_uppercase(), "WORLD!"); +} +``` \ No newline at end of file diff --git a/src/docs/manual_swap.txt b/src/docs/manual_swap.txt new file mode 100644 index 0000000000000..bd9526288e35b --- /dev/null +++ b/src/docs/manual_swap.txt @@ -0,0 +1,22 @@ +### What it does +Checks for manual swapping. + +### Why is this bad? +The `std::mem::swap` function exposes the intent better +without deinitializing or copying either variable. + +### Example +``` +let mut a = 42; +let mut b = 1337; + +let t = b; +b = a; +a = t; +``` +Use std::mem::swap(): +``` +let mut a = 1; +let mut b = 2; +std::mem::swap(&mut a, &mut b); +``` \ No newline at end of file diff --git a/src/docs/manual_unwrap_or.txt b/src/docs/manual_unwrap_or.txt new file mode 100644 index 0000000000000..1fd7d831bfca2 --- /dev/null +++ b/src/docs/manual_unwrap_or.txt @@ -0,0 +1,20 @@ +### What it does +Finds patterns that reimplement `Option::unwrap_or` or `Result::unwrap_or`. + +### Why is this bad? +Concise code helps focusing on behavior instead of boilerplate. + +### Example +``` +let foo: Option = None; +match foo { + Some(v) => v, + None => 1, +}; +``` + +Use instead: +``` +let foo: Option = None; +foo.unwrap_or(1); +``` \ No newline at end of file diff --git a/src/docs/many_single_char_names.txt b/src/docs/many_single_char_names.txt new file mode 100644 index 0000000000000..55ee5da555744 --- /dev/null +++ b/src/docs/many_single_char_names.txt @@ -0,0 +1,12 @@ +### What it does +Checks for too many variables whose name consists of a +single character. + +### Why is this bad? +It's hard to memorize what a variable means without a +descriptive name. + +### Example +``` +let (a, b, c, d, e, f, g) = (...); +``` \ No newline at end of file diff --git a/src/docs/map_clone.txt b/src/docs/map_clone.txt new file mode 100644 index 0000000000000..3ee27f072ef3d --- /dev/null +++ b/src/docs/map_clone.txt @@ -0,0 +1,22 @@ +### What it does +Checks for usage of `map(|x| x.clone())` or +dereferencing closures for `Copy` types, on `Iterator` or `Option`, +and suggests `cloned()` or `copied()` instead + +### Why is this bad? +Readability, this can be written more concisely + +### Example +``` +let x = vec![42, 43]; +let y = x.iter(); +let z = y.map(|i| *i); +``` + +The correct use would be: + +``` +let x = vec![42, 43]; +let y = x.iter(); +let z = y.cloned(); +``` \ No newline at end of file diff --git a/src/docs/map_collect_result_unit.txt b/src/docs/map_collect_result_unit.txt new file mode 100644 index 0000000000000..9b720612495ce --- /dev/null +++ b/src/docs/map_collect_result_unit.txt @@ -0,0 +1,14 @@ +### What it does +Checks for usage of `_.map(_).collect::()`. + +### Why is this bad? +Using `try_for_each` instead is more readable and idiomatic. + +### Example +``` +(0..3).map(|t| Err(t)).collect::>(); +``` +Use instead: +``` +(0..3).try_for_each(|t| Err(t)); +``` \ No newline at end of file diff --git a/src/docs/map_entry.txt b/src/docs/map_entry.txt new file mode 100644 index 0000000000000..20dba1798d0d5 --- /dev/null +++ b/src/docs/map_entry.txt @@ -0,0 +1,28 @@ +### What it does +Checks for uses of `contains_key` + `insert` on `HashMap` +or `BTreeMap`. + +### Why is this bad? +Using `entry` is more efficient. + +### Known problems +The suggestion may have type inference errors in some cases. e.g. +``` +let mut map = std::collections::HashMap::new(); +let _ = if !map.contains_key(&0) { + map.insert(0, 0) +} else { + None +}; +``` + +### Example +``` +if !map.contains_key(&k) { + map.insert(k, v); +} +``` +Use instead: +``` +map.entry(k).or_insert(v); +``` \ No newline at end of file diff --git a/src/docs/map_err_ignore.txt b/src/docs/map_err_ignore.txt new file mode 100644 index 0000000000000..2606c13a7afd9 --- /dev/null +++ b/src/docs/map_err_ignore.txt @@ -0,0 +1,93 @@ +### What it does +Checks for instances of `map_err(|_| Some::Enum)` + +### Why is this bad? +This `map_err` throws away the original error rather than allowing the enum to contain and report the cause of the error + +### Example +Before: +``` +use std::fmt; + +#[derive(Debug)] +enum Error { + Indivisible, + Remainder(u8), +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Error::Indivisible => write!(f, "could not divide input by three"), + Error::Remainder(remainder) => write!( + f, + "input is not divisible by three, remainder = {}", + remainder + ), + } + } +} + +impl std::error::Error for Error {} + +fn divisible_by_3(input: &str) -> Result<(), Error> { + input + .parse::() + .map_err(|_| Error::Indivisible) + .map(|v| v % 3) + .and_then(|remainder| { + if remainder == 0 { + Ok(()) + } else { + Err(Error::Remainder(remainder as u8)) + } + }) +} + ``` + + After: + ```rust +use std::{fmt, num::ParseIntError}; + +#[derive(Debug)] +enum Error { + Indivisible(ParseIntError), + Remainder(u8), +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Error::Indivisible(_) => write!(f, "could not divide input by three"), + Error::Remainder(remainder) => write!( + f, + "input is not divisible by three, remainder = {}", + remainder + ), + } + } +} + +impl std::error::Error for Error { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + Error::Indivisible(source) => Some(source), + _ => None, + } + } +} + +fn divisible_by_3(input: &str) -> Result<(), Error> { + input + .parse::() + .map_err(Error::Indivisible) + .map(|v| v % 3) + .and_then(|remainder| { + if remainder == 0 { + Ok(()) + } else { + Err(Error::Remainder(remainder as u8)) + } + }) +} +``` \ No newline at end of file diff --git a/src/docs/map_flatten.txt b/src/docs/map_flatten.txt new file mode 100644 index 0000000000000..73c0e51407f28 --- /dev/null +++ b/src/docs/map_flatten.txt @@ -0,0 +1,21 @@ +### What it does +Checks for usage of `_.map(_).flatten(_)` on `Iterator` and `Option` + +### Why is this bad? +Readability, this can be written more concisely as +`_.flat_map(_)` for `Iterator` or `_.and_then(_)` for `Option` + +### Example +``` +let vec = vec![vec![1]]; +let opt = Some(5); + +vec.iter().map(|x| x.iter()).flatten(); +opt.map(|x| Some(x * 2)).flatten(); +``` + +Use instead: +``` +vec.iter().flat_map(|x| x.iter()); +opt.and_then(|x| Some(x * 2)); +``` \ No newline at end of file diff --git a/src/docs/map_identity.txt b/src/docs/map_identity.txt new file mode 100644 index 0000000000000..e2e7af0bed9b1 --- /dev/null +++ b/src/docs/map_identity.txt @@ -0,0 +1,16 @@ +### What it does +Checks for instances of `map(f)` where `f` is the identity function. + +### Why is this bad? +It can be written more concisely without the call to `map`. + +### Example +``` +let x = [1, 2, 3]; +let y: Vec<_> = x.iter().map(|x| x).map(|x| 2*x).collect(); +``` +Use instead: +``` +let x = [1, 2, 3]; +let y: Vec<_> = x.iter().map(|x| 2*x).collect(); +``` \ No newline at end of file diff --git a/src/docs/map_unwrap_or.txt b/src/docs/map_unwrap_or.txt new file mode 100644 index 0000000000000..485b29f01b103 --- /dev/null +++ b/src/docs/map_unwrap_or.txt @@ -0,0 +1,22 @@ +### What it does +Checks for usage of `option.map(_).unwrap_or(_)` or `option.map(_).unwrap_or_else(_)` or +`result.map(_).unwrap_or_else(_)`. + +### Why is this bad? +Readability, these can be written more concisely (resp.) as +`option.map_or(_, _)`, `option.map_or_else(_, _)` and `result.map_or_else(_, _)`. + +### Known problems +The order of the arguments is not in execution order + +### Examples +``` +option.map(|a| a + 1).unwrap_or(0); +result.map(|a| a + 1).unwrap_or_else(some_function); +``` + +Use instead: +``` +option.map_or(0, |a| a + 1); +result.map_or_else(some_function, |a| a + 1); +``` \ No newline at end of file diff --git a/src/docs/match_as_ref.txt b/src/docs/match_as_ref.txt new file mode 100644 index 0000000000000..5e5f3d645a4e4 --- /dev/null +++ b/src/docs/match_as_ref.txt @@ -0,0 +1,23 @@ +### What it does +Checks for match which is used to add a reference to an +`Option` value. + +### Why is this bad? +Using `as_ref()` or `as_mut()` instead is shorter. + +### Example +``` +let x: Option<()> = None; + +let r: Option<&()> = match x { + None => None, + Some(ref v) => Some(v), +}; +``` + +Use instead: +``` +let x: Option<()> = None; + +let r: Option<&()> = x.as_ref(); +``` \ No newline at end of file diff --git a/src/docs/match_bool.txt b/src/docs/match_bool.txt new file mode 100644 index 0000000000000..96f9e1f8b7d1b --- /dev/null +++ b/src/docs/match_bool.txt @@ -0,0 +1,24 @@ +### What it does +Checks for matches where match expression is a `bool`. It +suggests to replace the expression with an `if...else` block. + +### Why is this bad? +It makes the code less readable. + +### Example +``` +let condition: bool = true; +match condition { + true => foo(), + false => bar(), +} +``` +Use if/else instead: +``` +let condition: bool = true; +if condition { + foo(); +} else { + bar(); +} +``` \ No newline at end of file diff --git a/src/docs/match_like_matches_macro.txt b/src/docs/match_like_matches_macro.txt new file mode 100644 index 0000000000000..643e2ddc97ba0 --- /dev/null +++ b/src/docs/match_like_matches_macro.txt @@ -0,0 +1,32 @@ +### What it does +Checks for `match` or `if let` expressions producing a +`bool` that could be written using `matches!` + +### Why is this bad? +Readability and needless complexity. + +### Known problems +This lint falsely triggers, if there are arms with +`cfg` attributes that remove an arm evaluating to `false`. + +### Example +``` +let x = Some(5); + +let a = match x { + Some(0) => true, + _ => false, +}; + +let a = if let Some(0) = x { + true +} else { + false +}; +``` + +Use instead: +``` +let x = Some(5); +let a = matches!(x, Some(0)); +``` \ No newline at end of file diff --git a/src/docs/match_on_vec_items.txt b/src/docs/match_on_vec_items.txt new file mode 100644 index 0000000000000..981d18d0f9ed5 --- /dev/null +++ b/src/docs/match_on_vec_items.txt @@ -0,0 +1,29 @@ +### What it does +Checks for `match vec[idx]` or `match vec[n..m]`. + +### Why is this bad? +This can panic at runtime. + +### Example +``` +let arr = vec![0, 1, 2, 3]; +let idx = 1; + +match arr[idx] { + 0 => println!("{}", 0), + 1 => println!("{}", 3), + _ => {}, +} +``` + +Use instead: +``` +let arr = vec![0, 1, 2, 3]; +let idx = 1; + +match arr.get(idx) { + Some(0) => println!("{}", 0), + Some(1) => println!("{}", 3), + _ => {}, +} +``` \ No newline at end of file diff --git a/src/docs/match_overlapping_arm.txt b/src/docs/match_overlapping_arm.txt new file mode 100644 index 0000000000000..841c091bd5cad --- /dev/null +++ b/src/docs/match_overlapping_arm.txt @@ -0,0 +1,16 @@ +### What it does +Checks for overlapping match arms. + +### Why is this bad? +It is likely to be an error and if not, makes the code +less obvious. + +### Example +``` +let x = 5; +match x { + 1..=10 => println!("1 ... 10"), + 5..=15 => println!("5 ... 15"), + _ => (), +} +``` \ No newline at end of file diff --git a/src/docs/match_ref_pats.txt b/src/docs/match_ref_pats.txt new file mode 100644 index 0000000000000..b1d9029950972 --- /dev/null +++ b/src/docs/match_ref_pats.txt @@ -0,0 +1,26 @@ +### What it does +Checks for matches where all arms match a reference, +suggesting to remove the reference and deref the matched expression +instead. It also checks for `if let &foo = bar` blocks. + +### Why is this bad? +It just makes the code less readable. That reference +destructuring adds nothing to the code. + +### Example +``` +match x { + &A(ref y) => foo(y), + &B => bar(), + _ => frob(&x), +} +``` + +Use instead: +``` +match *x { + A(ref y) => foo(y), + B => bar(), + _ => frob(x), +} +``` \ No newline at end of file diff --git a/src/docs/match_result_ok.txt b/src/docs/match_result_ok.txt new file mode 100644 index 0000000000000..eea7c8e00f1bb --- /dev/null +++ b/src/docs/match_result_ok.txt @@ -0,0 +1,27 @@ +### What it does +Checks for unnecessary `ok()` in `while let`. + +### Why is this bad? +Calling `ok()` in `while let` is unnecessary, instead match +on `Ok(pat)` + +### Example +``` +while let Some(value) = iter.next().ok() { + vec.push(value) +} + +if let Some(value) = iter.next().ok() { + vec.push(value) +} +``` +Use instead: +``` +while let Ok(value) = iter.next() { + vec.push(value) +} + +if let Ok(value) = iter.next() { + vec.push(value) +} +``` \ No newline at end of file diff --git a/src/docs/match_same_arms.txt b/src/docs/match_same_arms.txt new file mode 100644 index 0000000000000..14edf12032e0d --- /dev/null +++ b/src/docs/match_same_arms.txt @@ -0,0 +1,38 @@ +### What it does +Checks for `match` with identical arm bodies. + +### Why is this bad? +This is probably a copy & paste error. If arm bodies +are the same on purpose, you can factor them +[using `|`](https://doc.rust-lang.org/book/patterns.html#multiple-patterns). + +### Known problems +False positive possible with order dependent `match` +(see issue +[#860](https://github.com/rust-lang/rust-clippy/issues/860)). + +### Example +``` +match foo { + Bar => bar(), + Quz => quz(), + Baz => bar(), // <= oops +} +``` + +This should probably be +``` +match foo { + Bar => bar(), + Quz => quz(), + Baz => baz(), // <= fixed +} +``` + +or if the original code was not a typo: +``` +match foo { + Bar | Baz => bar(), // <= shows the intent better + Quz => quz(), +} +``` \ No newline at end of file diff --git a/src/docs/match_single_binding.txt b/src/docs/match_single_binding.txt new file mode 100644 index 0000000000000..67ded0bbd5534 --- /dev/null +++ b/src/docs/match_single_binding.txt @@ -0,0 +1,23 @@ +### What it does +Checks for useless match that binds to only one value. + +### Why is this bad? +Readability and needless complexity. + +### Known problems + Suggested replacements may be incorrect when `match` +is actually binding temporary value, bringing a 'dropped while borrowed' error. + +### Example +``` +match (a, b) { + (c, d) => { + // useless match + } +} +``` + +Use instead: +``` +let (c, d) = (a, b); +``` \ No newline at end of file diff --git a/src/docs/match_str_case_mismatch.txt b/src/docs/match_str_case_mismatch.txt new file mode 100644 index 0000000000000..19e74c2084eae --- /dev/null +++ b/src/docs/match_str_case_mismatch.txt @@ -0,0 +1,22 @@ +### What it does +Checks for `match` expressions modifying the case of a string with non-compliant arms + +### Why is this bad? +The arm is unreachable, which is likely a mistake + +### Example +``` +match &*text.to_ascii_lowercase() { + "foo" => {}, + "Bar" => {}, + _ => {}, +} +``` +Use instead: +``` +match &*text.to_ascii_lowercase() { + "foo" => {}, + "bar" => {}, + _ => {}, +} +``` \ No newline at end of file diff --git a/src/docs/match_wild_err_arm.txt b/src/docs/match_wild_err_arm.txt new file mode 100644 index 0000000000000..f89b3a23a1ca2 --- /dev/null +++ b/src/docs/match_wild_err_arm.txt @@ -0,0 +1,16 @@ +### What it does +Checks for arm which matches all errors with `Err(_)` +and take drastic actions like `panic!`. + +### Why is this bad? +It is generally a bad practice, similar to +catching all exceptions in java with `catch(Exception)` + +### Example +``` +let x: Result = Ok(3); +match x { + Ok(_) => println!("ok"), + Err(_) => panic!("err"), +} +``` \ No newline at end of file diff --git a/src/docs/match_wildcard_for_single_variants.txt b/src/docs/match_wildcard_for_single_variants.txt new file mode 100644 index 0000000000000..25559b9ecdcff --- /dev/null +++ b/src/docs/match_wildcard_for_single_variants.txt @@ -0,0 +1,27 @@ +### What it does +Checks for wildcard enum matches for a single variant. + +### Why is this bad? +New enum variants added by library updates can be missed. + +### Known problems +Suggested replacements may not use correct path to enum +if it's not present in the current scope. + +### Example +``` +match x { + Foo::A => {}, + Foo::B => {}, + _ => {}, +} +``` + +Use instead: +``` +match x { + Foo::A => {}, + Foo::B => {}, + Foo::C => {}, +} +``` \ No newline at end of file diff --git a/src/docs/maybe_infinite_iter.txt b/src/docs/maybe_infinite_iter.txt new file mode 100644 index 0000000000000..1204a49b46681 --- /dev/null +++ b/src/docs/maybe_infinite_iter.txt @@ -0,0 +1,16 @@ +### What it does +Checks for iteration that may be infinite. + +### Why is this bad? +While there may be places where this is acceptable +(e.g., in event streams), in most cases this is simply an error. + +### Known problems +The code may have a condition to stop iteration, but +this lint is not clever enough to analyze it. + +### Example +``` +let infinite_iter = 0..; +[0..].iter().zip(infinite_iter.take_while(|x| *x > 5)); +``` \ No newline at end of file diff --git a/src/docs/mem_forget.txt b/src/docs/mem_forget.txt new file mode 100644 index 0000000000000..a6888c48fc33b --- /dev/null +++ b/src/docs/mem_forget.txt @@ -0,0 +1,12 @@ +### What it does +Checks for usage of `std::mem::forget(t)` where `t` is +`Drop`. + +### Why is this bad? +`std::mem::forget(t)` prevents `t` from running its +destructor, possibly causing leaks. + +### Example +``` +mem::forget(Rc::new(55)) +``` \ No newline at end of file diff --git a/src/docs/mem_replace_option_with_none.txt b/src/docs/mem_replace_option_with_none.txt new file mode 100644 index 0000000000000..7f243d1c16565 --- /dev/null +++ b/src/docs/mem_replace_option_with_none.txt @@ -0,0 +1,21 @@ +### What it does +Checks for `mem::replace()` on an `Option` with +`None`. + +### Why is this bad? +`Option` already has the method `take()` for +taking its current value (Some(..) or None) and replacing it with +`None`. + +### Example +``` +use std::mem; + +let mut an_option = Some(0); +let replaced = mem::replace(&mut an_option, None); +``` +Is better expressed with: +``` +let mut an_option = Some(0); +let taken = an_option.take(); +``` \ No newline at end of file diff --git a/src/docs/mem_replace_with_default.txt b/src/docs/mem_replace_with_default.txt new file mode 100644 index 0000000000000..24e0913a30c92 --- /dev/null +++ b/src/docs/mem_replace_with_default.txt @@ -0,0 +1,18 @@ +### What it does +Checks for `std::mem::replace` on a value of type +`T` with `T::default()`. + +### Why is this bad? +`std::mem` module already has the method `take` to +take the current value and replace it with the default value of that type. + +### Example +``` +let mut text = String::from("foo"); +let replaced = std::mem::replace(&mut text, String::default()); +``` +Is better expressed with: +``` +let mut text = String::from("foo"); +let taken = std::mem::take(&mut text); +``` \ No newline at end of file diff --git a/src/docs/mem_replace_with_uninit.txt b/src/docs/mem_replace_with_uninit.txt new file mode 100644 index 0000000000000..0bb483668abc1 --- /dev/null +++ b/src/docs/mem_replace_with_uninit.txt @@ -0,0 +1,24 @@ +### What it does +Checks for `mem::replace(&mut _, mem::uninitialized())` +and `mem::replace(&mut _, mem::zeroed())`. + +### Why is this bad? +This will lead to undefined behavior even if the +value is overwritten later, because the uninitialized value may be +observed in the case of a panic. + +### Example +``` +use std::mem; + +#[allow(deprecated, invalid_value)] +fn myfunc (v: &mut Vec) { + let taken_v = unsafe { mem::replace(v, mem::uninitialized()) }; + let new_v = may_panic(taken_v); // undefined behavior on panic + mem::forget(mem::replace(v, new_v)); +} +``` + +The [take_mut](https://docs.rs/take_mut) crate offers a sound solution, +at the cost of either lazily creating a replacement value or aborting +on panic, to ensure that the uninitialized value cannot be observed. \ No newline at end of file diff --git a/src/docs/min_max.txt b/src/docs/min_max.txt new file mode 100644 index 0000000000000..6acf0f932e986 --- /dev/null +++ b/src/docs/min_max.txt @@ -0,0 +1,18 @@ +### What it does +Checks for expressions where `std::cmp::min` and `max` are +used to clamp values, but switched so that the result is constant. + +### Why is this bad? +This is in all probability not the intended outcome. At +the least it hurts readability of the code. + +### Example +``` +min(0, max(100, x)) + +// or + +x.max(100).min(0) +``` +It will always be equal to `0`. Probably the author meant to clamp the value +between 0 and 100, but has erroneously swapped `min` and `max`. \ No newline at end of file diff --git a/src/docs/mismatched_target_os.txt b/src/docs/mismatched_target_os.txt new file mode 100644 index 0000000000000..51e5ec6e7c5c4 --- /dev/null +++ b/src/docs/mismatched_target_os.txt @@ -0,0 +1,24 @@ +### What it does +Checks for cfg attributes having operating systems used in target family position. + +### Why is this bad? +The configuration option will not be recognised and the related item will not be included +by the conditional compilation engine. + +### Example +``` +#[cfg(linux)] +fn conditional() { } +``` + +Use instead: +``` +#[cfg(target_os = "linux")] +fn conditional() { } + +// or + +#[cfg(unix)] +fn conditional() { } +``` +Check the [Rust Reference](https://doc.rust-lang.org/reference/conditional-compilation.html#target_os) for more details. \ No newline at end of file diff --git a/src/docs/mismatching_type_param_order.txt b/src/docs/mismatching_type_param_order.txt new file mode 100644 index 0000000000000..ffc7f32d0aad8 --- /dev/null +++ b/src/docs/mismatching_type_param_order.txt @@ -0,0 +1,33 @@ +### What it does +Checks for type parameters which are positioned inconsistently between +a type definition and impl block. Specifically, a parameter in an impl +block which has the same name as a parameter in the type def, but is in +a different place. + +### Why is this bad? +Type parameters are determined by their position rather than name. +Naming type parameters inconsistently may cause you to refer to the +wrong type parameter. + +### Limitations +This lint only applies to impl blocks with simple generic params, e.g. +`A`. If there is anything more complicated, such as a tuple, it will be +ignored. + +### Example +``` +struct Foo { + x: A, + y: B, +} +// inside the impl, B refers to Foo::A +impl Foo {} +``` +Use instead: +``` +struct Foo { + x: A, + y: B, +} +impl Foo {} +``` \ No newline at end of file diff --git a/src/docs/misrefactored_assign_op.txt b/src/docs/misrefactored_assign_op.txt new file mode 100644 index 0000000000000..3d691fe4178b5 --- /dev/null +++ b/src/docs/misrefactored_assign_op.txt @@ -0,0 +1,20 @@ +### What it does +Checks for `a op= a op b` or `a op= b op a` patterns. + +### Why is this bad? +Most likely these are bugs where one meant to write `a +op= b`. + +### Known problems +Clippy cannot know for sure if `a op= a op b` should have +been `a = a op a op b` or `a = a op b`/`a op= b`. Therefore, it suggests both. +If `a op= a op b` is really the correct behavior it should be +written as `a = a op a op b` as it's less confusing. + +### Example +``` +let mut a = 5; +let b = 2; +// ... +a += a + b; +``` \ No newline at end of file diff --git a/src/docs/missing_const_for_fn.txt b/src/docs/missing_const_for_fn.txt new file mode 100644 index 0000000000000..067614d4c46bf --- /dev/null +++ b/src/docs/missing_const_for_fn.txt @@ -0,0 +1,40 @@ +### What it does +Suggests the use of `const` in functions and methods where possible. + +### Why is this bad? +Not having the function const prevents callers of the function from being const as well. + +### Known problems +Const functions are currently still being worked on, with some features only being available +on nightly. This lint does not consider all edge cases currently and the suggestions may be +incorrect if you are using this lint on stable. + +Also, the lint only runs one pass over the code. Consider these two non-const functions: + +``` +fn a() -> i32 { + 0 +} +fn b() -> i32 { + a() +} +``` + +When running Clippy, the lint will only suggest to make `a` const, because `b` at this time +can't be const as it calls a non-const function. Making `a` const and running Clippy again, +will suggest to make `b` const, too. + +### Example +``` +fn new() -> Self { + Self { random_number: 42 } +} +``` + +Could be a const fn: + +``` +const fn new() -> Self { + Self { random_number: 42 } +} +``` \ No newline at end of file diff --git a/src/docs/missing_docs_in_private_items.txt b/src/docs/missing_docs_in_private_items.txt new file mode 100644 index 0000000000000..5d37505bb1716 --- /dev/null +++ b/src/docs/missing_docs_in_private_items.txt @@ -0,0 +1,9 @@ +### What it does +Warns if there is missing doc for any documentable item +(public or private). + +### Why is this bad? +Doc is good. *rustc* has a `MISSING_DOCS` +allowed-by-default lint for +public members, but has no way to enforce documentation of private items. +This lint fixes that. \ No newline at end of file diff --git a/src/docs/missing_enforced_import_renames.txt b/src/docs/missing_enforced_import_renames.txt new file mode 100644 index 0000000000000..8f4649bd5923d --- /dev/null +++ b/src/docs/missing_enforced_import_renames.txt @@ -0,0 +1,22 @@ +### What it does +Checks for imports that do not rename the item as specified +in the `enforce-import-renames` config option. + +### Why is this bad? +Consistency is important, if a project has defined import +renames they should be followed. More practically, some item names are too +vague outside of their defining scope this can enforce a more meaningful naming. + +### Example +An example clippy.toml configuration: +``` +enforced-import-renames = [ { path = "serde_json::Value", rename = "JsonValue" }] +``` + +``` +use serde_json::Value; +``` +Use instead: +``` +use serde_json::Value as JsonValue; +``` \ No newline at end of file diff --git a/src/docs/missing_errors_doc.txt b/src/docs/missing_errors_doc.txt new file mode 100644 index 0000000000000..028778d85aeba --- /dev/null +++ b/src/docs/missing_errors_doc.txt @@ -0,0 +1,21 @@ +### What it does +Checks the doc comments of publicly visible functions that +return a `Result` type and warns if there is no `# Errors` section. + +### Why is this bad? +Documenting the type of errors that can be returned from a +function can help callers write code to handle the errors appropriately. + +### Examples +Since the following function returns a `Result` it has an `# Errors` section in +its doc comment: + +``` +/// # Errors +/// +/// Will return `Err` if `filename` does not exist or the user does not have +/// permission to read it. +pub fn read(filename: String) -> io::Result { + unimplemented!(); +} +``` \ No newline at end of file diff --git a/src/docs/missing_inline_in_public_items.txt b/src/docs/missing_inline_in_public_items.txt new file mode 100644 index 0000000000000..d90c50fe7f9e8 --- /dev/null +++ b/src/docs/missing_inline_in_public_items.txt @@ -0,0 +1,45 @@ +### What it does +It lints if an exported function, method, trait method with default impl, +or trait method impl is not `#[inline]`. + +### Why is this bad? +In general, it is not. Functions can be inlined across +crates when that's profitable as long as any form of LTO is used. When LTO is disabled, +functions that are not `#[inline]` cannot be inlined across crates. Certain types of crates +might intend for most of the methods in their public API to be able to be inlined across +crates even when LTO is disabled. For these types of crates, enabling this lint might make +sense. It allows the crate to require all exported methods to be `#[inline]` by default, and +then opt out for specific methods where this might not make sense. + +### Example +``` +pub fn foo() {} // missing #[inline] +fn ok() {} // ok +#[inline] pub fn bar() {} // ok +#[inline(always)] pub fn baz() {} // ok + +pub trait Bar { + fn bar(); // ok + fn def_bar() {} // missing #[inline] +} + +struct Baz; +impl Baz { + fn private() {} // ok +} + +impl Bar for Baz { + fn bar() {} // ok - Baz is not exported +} + +pub struct PubBaz; +impl PubBaz { + fn private() {} // ok + pub fn not_private() {} // missing #[inline] +} + +impl Bar for PubBaz { + fn bar() {} // missing #[inline] + fn def_bar() {} // missing #[inline] +} +``` \ No newline at end of file diff --git a/src/docs/missing_panics_doc.txt b/src/docs/missing_panics_doc.txt new file mode 100644 index 0000000000000..e5e39a824519b --- /dev/null +++ b/src/docs/missing_panics_doc.txt @@ -0,0 +1,24 @@ +### What it does +Checks the doc comments of publicly visible functions that +may panic and warns if there is no `# Panics` section. + +### Why is this bad? +Documenting the scenarios in which panicking occurs +can help callers who do not want to panic to avoid those situations. + +### Examples +Since the following function may panic it has a `# Panics` section in +its doc comment: + +``` +/// # Panics +/// +/// Will panic if y is 0 +pub fn divide_by(x: i32, y: i32) -> i32 { + if y == 0 { + panic!("Cannot divide by 0") + } else { + x / y + } +} +``` \ No newline at end of file diff --git a/src/docs/missing_safety_doc.txt b/src/docs/missing_safety_doc.txt new file mode 100644 index 0000000000000..6492eb84f63bf --- /dev/null +++ b/src/docs/missing_safety_doc.txt @@ -0,0 +1,26 @@ +### What it does +Checks for the doc comments of publicly visible +unsafe functions and warns if there is no `# Safety` section. + +### Why is this bad? +Unsafe functions should document their safety +preconditions, so that users can be sure they are using them safely. + +### Examples +``` +/// This function should really be documented +pub unsafe fn start_apocalypse(u: &mut Universe) { + unimplemented!(); +} +``` + +At least write a line about safety: + +``` +/// # Safety +/// +/// This function should not be called before the horsemen are ready. +pub unsafe fn start_apocalypse(u: &mut Universe) { + unimplemented!(); +} +``` \ No newline at end of file diff --git a/src/docs/missing_spin_loop.txt b/src/docs/missing_spin_loop.txt new file mode 100644 index 0000000000000..3a06a91d71835 --- /dev/null +++ b/src/docs/missing_spin_loop.txt @@ -0,0 +1,27 @@ +### What it does +Check for empty spin loops + +### Why is this bad? +The loop body should have something like `thread::park()` or at least +`std::hint::spin_loop()` to avoid needlessly burning cycles and conserve +energy. Perhaps even better use an actual lock, if possible. + +### Known problems +This lint doesn't currently trigger on `while let` or +`loop { match .. { .. } }` loops, which would be considered idiomatic in +combination with e.g. `AtomicBool::compare_exchange_weak`. + +### Example + +``` +use core::sync::atomic::{AtomicBool, Ordering}; +let b = AtomicBool::new(true); +// give a ref to `b` to another thread,wait for it to become false +while b.load(Ordering::Acquire) {}; +``` +Use instead: +``` +while b.load(Ordering::Acquire) { + std::hint::spin_loop() +} +``` \ No newline at end of file diff --git a/src/docs/mistyped_literal_suffixes.txt b/src/docs/mistyped_literal_suffixes.txt new file mode 100644 index 0000000000000..1760fcbfeacc4 --- /dev/null +++ b/src/docs/mistyped_literal_suffixes.txt @@ -0,0 +1,15 @@ +### What it does +Warns for mistyped suffix in literals + +### Why is this bad? +This is most probably a typo + +### Known problems +- Does not match on integers too large to fit in the corresponding unsigned type +- Does not match on `_127` since that is a valid grouping for decimal and octal numbers + +### Example +``` +`2_32` => `2_i32` +`250_8 => `250_u8` +``` \ No newline at end of file diff --git a/src/docs/mixed_case_hex_literals.txt b/src/docs/mixed_case_hex_literals.txt new file mode 100644 index 0000000000000..d2d01e0c98eb4 --- /dev/null +++ b/src/docs/mixed_case_hex_literals.txt @@ -0,0 +1,16 @@ +### What it does +Warns on hexadecimal literals with mixed-case letter +digits. + +### Why is this bad? +It looks confusing. + +### Example +``` +0x1a9BAcD +``` + +Use instead: +``` +0x1A9BACD +``` \ No newline at end of file diff --git a/src/docs/mixed_read_write_in_expression.txt b/src/docs/mixed_read_write_in_expression.txt new file mode 100644 index 0000000000000..02d1c5d052524 --- /dev/null +++ b/src/docs/mixed_read_write_in_expression.txt @@ -0,0 +1,32 @@ +### What it does +Checks for a read and a write to the same variable where +whether the read occurs before or after the write depends on the evaluation +order of sub-expressions. + +### Why is this bad? +It is often confusing to read. As described [here](https://doc.rust-lang.org/reference/expressions.html?highlight=subexpression#evaluation-order-of-operands), +the operands of these expressions are evaluated before applying the effects of the expression. + +### Known problems +Code which intentionally depends on the evaluation +order, or which is correct for any evaluation order. + +### Example +``` +let mut x = 0; + +let a = { + x = 1; + 1 +} + x; +// Unclear whether a is 1 or 2. +``` + +Use instead: +``` +let tmp = { + x = 1; + 1 +}; +let a = tmp + x; +``` \ No newline at end of file diff --git a/src/docs/mod_module_files.txt b/src/docs/mod_module_files.txt new file mode 100644 index 0000000000000..95bca583afd3c --- /dev/null +++ b/src/docs/mod_module_files.txt @@ -0,0 +1,22 @@ +### What it does +Checks that module layout uses only self named module files, bans `mod.rs` files. + +### Why is this bad? +Having multiple module layout styles in a project can be confusing. + +### Example +``` +src/ + stuff/ + stuff_files.rs + mod.rs + lib.rs +``` +Use instead: +``` +src/ + stuff/ + stuff_files.rs + stuff.rs + lib.rs +``` \ No newline at end of file diff --git a/src/docs/module_inception.txt b/src/docs/module_inception.txt new file mode 100644 index 0000000000000..d80a1b8d8fe57 --- /dev/null +++ b/src/docs/module_inception.txt @@ -0,0 +1,24 @@ +### What it does +Checks for modules that have the same name as their +parent module + +### Why is this bad? +A typical beginner mistake is to have `mod foo;` and +again `mod foo { .. +}` in `foo.rs`. +The expectation is that items inside the inner `mod foo { .. }` are then +available +through `foo::x`, but they are only available through +`foo::foo::x`. +If this is done on purpose, it would be better to choose a more +representative module name. + +### Example +``` +// lib.rs +mod foo; +// foo.rs +mod foo { + ... +} +``` \ No newline at end of file diff --git a/src/docs/module_name_repetitions.txt b/src/docs/module_name_repetitions.txt new file mode 100644 index 0000000000000..3bc05d02780ca --- /dev/null +++ b/src/docs/module_name_repetitions.txt @@ -0,0 +1,20 @@ +### What it does +Detects type names that are prefixed or suffixed by the +containing module's name. + +### Why is this bad? +It requires the user to type the module name twice. + +### Example +``` +mod cake { + struct BlackForestCake; +} +``` + +Use instead: +``` +mod cake { + struct BlackForest; +} +``` \ No newline at end of file diff --git a/src/docs/modulo_arithmetic.txt b/src/docs/modulo_arithmetic.txt new file mode 100644 index 0000000000000..ff7296f3c5b8d --- /dev/null +++ b/src/docs/modulo_arithmetic.txt @@ -0,0 +1,15 @@ +### What it does +Checks for modulo arithmetic. + +### Why is this bad? +The results of modulo (%) operation might differ +depending on the language, when negative numbers are involved. +If you interop with different languages it might be beneficial +to double check all places that use modulo arithmetic. + +For example, in Rust `17 % -3 = 2`, but in Python `17 % -3 = -1`. + +### Example +``` +let x = -17 % 3; +``` \ No newline at end of file diff --git a/src/docs/modulo_one.txt b/src/docs/modulo_one.txt new file mode 100644 index 0000000000000..bc8f95b0be693 --- /dev/null +++ b/src/docs/modulo_one.txt @@ -0,0 +1,16 @@ +### What it does +Checks for getting the remainder of a division by one or minus +one. + +### Why is this bad? +The result for a divisor of one can only ever be zero; for +minus one it can cause panic/overflow (if the left operand is the minimal value of +the respective integer type) or results in zero. No one will write such code +deliberately, unless trying to win an Underhanded Rust Contest. Even for that +contest, it's probably a bad idea. Use something more underhanded. + +### Example +``` +let a = x % 1; +let a = x % -1; +``` \ No newline at end of file diff --git a/src/docs/multi_assignments.txt b/src/docs/multi_assignments.txt new file mode 100644 index 0000000000000..ed1f1b420cbd3 --- /dev/null +++ b/src/docs/multi_assignments.txt @@ -0,0 +1,17 @@ +### What it does +Checks for nested assignments. + +### Why is this bad? +While this is in most cases already a type mismatch, +the result of an assignment being `()` can throw off people coming from languages like python or C, +where such assignments return a copy of the assigned value. + +### Example +``` +a = b = 42; +``` +Use instead: +``` +b = 42; +a = b; +``` \ No newline at end of file diff --git a/src/docs/multiple_crate_versions.txt b/src/docs/multiple_crate_versions.txt new file mode 100644 index 0000000000000..cf2d2c6abee3e --- /dev/null +++ b/src/docs/multiple_crate_versions.txt @@ -0,0 +1,19 @@ +### What it does +Checks to see if multiple versions of a crate are being +used. + +### Why is this bad? +This bloats the size of targets, and can lead to +confusing error messages when structs or traits are used interchangeably +between different versions of a crate. + +### Known problems +Because this can be caused purely by the dependencies +themselves, it's not always possible to fix this issue. + +### Example +``` +[dependencies] +ctrlc = "=3.1.0" +ansi_term = "=0.11.0" +``` \ No newline at end of file diff --git a/src/docs/multiple_inherent_impl.txt b/src/docs/multiple_inherent_impl.txt new file mode 100644 index 0000000000000..9d42286560cef --- /dev/null +++ b/src/docs/multiple_inherent_impl.txt @@ -0,0 +1,26 @@ +### What it does +Checks for multiple inherent implementations of a struct + +### Why is this bad? +Splitting the implementation of a type makes the code harder to navigate. + +### Example +``` +struct X; +impl X { + fn one() {} +} +impl X { + fn other() {} +} +``` + +Could be written: + +``` +struct X; +impl X { + fn one() {} + fn other() {} +} +``` \ No newline at end of file diff --git a/src/docs/must_use_candidate.txt b/src/docs/must_use_candidate.txt new file mode 100644 index 0000000000000..70890346fe6b8 --- /dev/null +++ b/src/docs/must_use_candidate.txt @@ -0,0 +1,23 @@ +### What it does +Checks for public functions that have no +`#[must_use]` attribute, but return something not already marked +must-use, have no mutable arg and mutate no statics. + +### Why is this bad? +Not bad at all, this lint just shows places where +you could add the attribute. + +### Known problems +The lint only checks the arguments for mutable +types without looking if they are actually changed. On the other hand, +it also ignores a broad range of potentially interesting side effects, +because we cannot decide whether the programmer intends the function to +be called for the side effect or the result. Expect many false +positives. At least we don't lint if the result type is unit or already +`#[must_use]`. + +### Examples +``` +// this could be annotated with `#[must_use]`. +fn id(t: T) -> T { t } +``` \ No newline at end of file diff --git a/src/docs/must_use_unit.txt b/src/docs/must_use_unit.txt new file mode 100644 index 0000000000000..cabbb23f8651e --- /dev/null +++ b/src/docs/must_use_unit.txt @@ -0,0 +1,13 @@ +### What it does +Checks for a `#[must_use]` attribute on +unit-returning functions and methods. + +### Why is this bad? +Unit values are useless. The attribute is likely +a remnant of a refactoring that removed the return type. + +### Examples +``` +#[must_use] +fn useless() { } +``` \ No newline at end of file diff --git a/src/docs/mut_from_ref.txt b/src/docs/mut_from_ref.txt new file mode 100644 index 0000000000000..cc1da12549a5d --- /dev/null +++ b/src/docs/mut_from_ref.txt @@ -0,0 +1,26 @@ +### What it does +This lint checks for functions that take immutable references and return +mutable ones. This will not trigger if no unsafe code exists as there +are multiple safe functions which will do this transformation + +To be on the conservative side, if there's at least one mutable +reference with the output lifetime, this lint will not trigger. + +### Why is this bad? +Creating a mutable reference which can be repeatably derived from an +immutable reference is unsound as it allows creating multiple live +mutable references to the same object. + +This [error](https://github.com/rust-lang/rust/issues/39465) actually +lead to an interim Rust release 1.15.1. + +### Known problems +This pattern is used by memory allocators to allow allocating multiple +objects while returning mutable references to each one. So long as +different mutable references are returned each time such a function may +be safe. + +### Example +``` +fn foo(&Foo) -> &mut Bar { .. } +``` \ No newline at end of file diff --git a/src/docs/mut_mut.txt b/src/docs/mut_mut.txt new file mode 100644 index 0000000000000..0bd34dd24b26a --- /dev/null +++ b/src/docs/mut_mut.txt @@ -0,0 +1,12 @@ +### What it does +Checks for instances of `mut mut` references. + +### Why is this bad? +Multiple `mut`s don't add anything meaningful to the +source. This is either a copy'n'paste error, or it shows a fundamental +misunderstanding of references. + +### Example +``` +let x = &mut &mut y; +``` \ No newline at end of file diff --git a/src/docs/mut_mutex_lock.txt b/src/docs/mut_mutex_lock.txt new file mode 100644 index 0000000000000..5e9ad8a3f176a --- /dev/null +++ b/src/docs/mut_mutex_lock.txt @@ -0,0 +1,29 @@ +### What it does +Checks for `&mut Mutex::lock` calls + +### Why is this bad? +`Mutex::lock` is less efficient than +calling `Mutex::get_mut`. In addition you also have a statically +guarantee that the mutex isn't locked, instead of just a runtime +guarantee. + +### Example +``` +use std::sync::{Arc, Mutex}; + +let mut value_rc = Arc::new(Mutex::new(42_u8)); +let value_mutex = Arc::get_mut(&mut value_rc).unwrap(); + +let mut value = value_mutex.lock().unwrap(); +*value += 1; +``` +Use instead: +``` +use std::sync::{Arc, Mutex}; + +let mut value_rc = Arc::new(Mutex::new(42_u8)); +let value_mutex = Arc::get_mut(&mut value_rc).unwrap(); + +let value = value_mutex.get_mut().unwrap(); +*value += 1; +``` \ No newline at end of file diff --git a/src/docs/mut_range_bound.txt b/src/docs/mut_range_bound.txt new file mode 100644 index 0000000000000..e9c38a543b146 --- /dev/null +++ b/src/docs/mut_range_bound.txt @@ -0,0 +1,29 @@ +### What it does +Checks for loops which have a range bound that is a mutable variable + +### Why is this bad? +One might think that modifying the mutable variable changes the loop bounds + +### Known problems +False positive when mutation is followed by a `break`, but the `break` is not immediately +after the mutation: + +``` +let mut x = 5; +for _ in 0..x { + x += 1; // x is a range bound that is mutated + ..; // some other expression + break; // leaves the loop, so mutation is not an issue +} +``` + +False positive on nested loops ([#6072](https://github.com/rust-lang/rust-clippy/issues/6072)) + +### Example +``` +let mut foo = 42; +for i in 0..foo { + foo -= 1; + println!("{}", i); // prints numbers from 0 to 42, not 0 to 21 +} +``` \ No newline at end of file diff --git a/src/docs/mutable_key_type.txt b/src/docs/mutable_key_type.txt new file mode 100644 index 0000000000000..15fe34f2bb5ec --- /dev/null +++ b/src/docs/mutable_key_type.txt @@ -0,0 +1,61 @@ +### What it does +Checks for sets/maps with mutable key types. + +### Why is this bad? +All of `HashMap`, `HashSet`, `BTreeMap` and +`BtreeSet` rely on either the hash or the order of keys be unchanging, +so having types with interior mutability is a bad idea. + +### Known problems + +#### False Positives +It's correct to use a struct that contains interior mutability as a key, when its +implementation of `Hash` or `Ord` doesn't access any of the interior mutable types. +However, this lint is unable to recognize this, so it will often cause false positives in +theses cases. The `bytes` crate is a great example of this. + +#### False Negatives +For custom `struct`s/`enum`s, this lint is unable to check for interior mutability behind +indirection. For example, `struct BadKey<'a>(&'a Cell)` will be seen as immutable +and cause a false negative if its implementation of `Hash`/`Ord` accesses the `Cell`. + +This lint does check a few cases for indirection. Firstly, using some standard library +types (`Option`, `Result`, `Box`, `Rc`, `Arc`, `Vec`, `VecDeque`, `BTreeMap` and +`BTreeSet`) directly as keys (e.g. in `HashMap>, ()>`) **will** trigger the +lint, because the impls of `Hash`/`Ord` for these types directly call `Hash`/`Ord` on their +contained type. + +Secondly, the implementations of `Hash` and `Ord` for raw pointers (`*const T` or `*mut T`) +apply only to the **address** of the contained value. Therefore, interior mutability +behind raw pointers (e.g. in `HashSet<*mut Cell>`) can't impact the value of `Hash` +or `Ord`, and therefore will not trigger this link. For more info, see issue +[#6745](https://github.com/rust-lang/rust-clippy/issues/6745). + +### Example +``` +use std::cmp::{PartialEq, Eq}; +use std::collections::HashSet; +use std::hash::{Hash, Hasher}; +use std::sync::atomic::AtomicUsize; + +struct Bad(AtomicUsize); +impl PartialEq for Bad { + fn eq(&self, rhs: &Self) -> bool { + .. +; unimplemented!(); + } +} + +impl Eq for Bad {} + +impl Hash for Bad { + fn hash(&self, h: &mut H) { + .. +; unimplemented!(); + } +} + +fn main() { + let _: HashSet = HashSet::new(); +} +``` \ No newline at end of file diff --git a/src/docs/mutex_atomic.txt b/src/docs/mutex_atomic.txt new file mode 100644 index 0000000000000..062ac8b323b74 --- /dev/null +++ b/src/docs/mutex_atomic.txt @@ -0,0 +1,22 @@ +### What it does +Checks for usages of `Mutex` where an atomic will do. + +### Why is this bad? +Using a mutex just to make access to a plain bool or +reference sequential is shooting flies with cannons. +`std::sync::atomic::AtomicBool` and `std::sync::atomic::AtomicPtr` are leaner and +faster. + +### Known problems +This lint cannot detect if the mutex is actually used +for waiting before a critical section. + +### Example +``` +let x = Mutex::new(&y); +``` + +Use instead: +``` +let x = AtomicBool::new(y); +``` \ No newline at end of file diff --git a/src/docs/mutex_integer.txt b/src/docs/mutex_integer.txt new file mode 100644 index 0000000000000..f9dbdfb904c9a --- /dev/null +++ b/src/docs/mutex_integer.txt @@ -0,0 +1,22 @@ +### What it does +Checks for usages of `Mutex` where `X` is an integral +type. + +### Why is this bad? +Using a mutex just to make access to a plain integer +sequential is +shooting flies with cannons. `std::sync::atomic::AtomicUsize` is leaner and faster. + +### Known problems +This lint cannot detect if the mutex is actually used +for waiting before a critical section. + +### Example +``` +let x = Mutex::new(0usize); +``` + +Use instead: +``` +let x = AtomicUsize::new(0usize); +``` \ No newline at end of file diff --git a/src/docs/naive_bytecount.txt b/src/docs/naive_bytecount.txt new file mode 100644 index 0000000000000..24659dc79ae71 --- /dev/null +++ b/src/docs/naive_bytecount.txt @@ -0,0 +1,22 @@ +### What it does +Checks for naive byte counts + +### Why is this bad? +The [`bytecount`](https://crates.io/crates/bytecount) +crate has methods to count your bytes faster, especially for large slices. + +### Known problems +If you have predominantly small slices, the +`bytecount::count(..)` method may actually be slower. However, if you can +ensure that less than 2³²-1 matches arise, the `naive_count_32(..)` can be +faster in those cases. + +### Example +``` +let count = vec.iter().filter(|x| **x == 0u8).count(); +``` + +Use instead: +``` +let count = bytecount::count(&vec, 0u8); +``` \ No newline at end of file diff --git a/src/docs/needless_arbitrary_self_type.txt b/src/docs/needless_arbitrary_self_type.txt new file mode 100644 index 0000000000000..8216a3a3fb6e5 --- /dev/null +++ b/src/docs/needless_arbitrary_self_type.txt @@ -0,0 +1,44 @@ +### What it does +The lint checks for `self` in fn parameters that +specify the `Self`-type explicitly +### Why is this bad? +Increases the amount and decreases the readability of code + +### Example +``` +enum ValType { + I32, + I64, + F32, + F64, +} + +impl ValType { + pub fn bytes(self: Self) -> usize { + match self { + Self::I32 | Self::F32 => 4, + Self::I64 | Self::F64 => 8, + } + } +} +``` + +Could be rewritten as + +``` +enum ValType { + I32, + I64, + F32, + F64, +} + +impl ValType { + pub fn bytes(self) -> usize { + match self { + Self::I32 | Self::F32 => 4, + Self::I64 | Self::F64 => 8, + } + } +} +``` \ No newline at end of file diff --git a/src/docs/needless_bitwise_bool.txt b/src/docs/needless_bitwise_bool.txt new file mode 100644 index 0000000000000..fcd7b730aaae0 --- /dev/null +++ b/src/docs/needless_bitwise_bool.txt @@ -0,0 +1,22 @@ +### What it does +Checks for uses of bitwise and/or operators between booleans, where performance may be improved by using +a lazy and. + +### Why is this bad? +The bitwise operators do not support short-circuiting, so it may hinder code performance. +Additionally, boolean logic "masked" as bitwise logic is not caught by lints like `unnecessary_fold` + +### Known problems +This lint evaluates only when the right side is determined to have no side effects. At this time, that +determination is quite conservative. + +### Example +``` +let (x,y) = (true, false); +if x & !y {} // where both x and y are booleans +``` +Use instead: +``` +let (x,y) = (true, false); +if x && !y {} +``` \ No newline at end of file diff --git a/src/docs/needless_bool.txt b/src/docs/needless_bool.txt new file mode 100644 index 0000000000000..b5c78871f14f6 --- /dev/null +++ b/src/docs/needless_bool.txt @@ -0,0 +1,26 @@ +### What it does +Checks for expressions of the form `if c { true } else { +false }` (or vice versa) and suggests using the condition directly. + +### Why is this bad? +Redundant code. + +### Known problems +Maybe false positives: Sometimes, the two branches are +painstakingly documented (which we, of course, do not detect), so they *may* +have some value. Even then, the documentation can be rewritten to match the +shorter code. + +### Example +``` +if x { + false +} else { + true +} +``` + +Use instead: +``` +!x +``` \ No newline at end of file diff --git a/src/docs/needless_borrow.txt b/src/docs/needless_borrow.txt new file mode 100644 index 0000000000000..4debcf473723a --- /dev/null +++ b/src/docs/needless_borrow.txt @@ -0,0 +1,21 @@ +### What it does +Checks for address of operations (`&`) that are going to +be dereferenced immediately by the compiler. + +### Why is this bad? +Suggests that the receiver of the expression borrows +the expression. + +### Example +``` +fn fun(_a: &i32) {} + +let x: &i32 = &&&&&&5; +fun(&x); +``` + +Use instead: +``` +let x: &i32 = &5; +fun(x); +``` \ No newline at end of file diff --git a/src/docs/needless_borrowed_reference.txt b/src/docs/needless_borrowed_reference.txt new file mode 100644 index 0000000000000..55faa0cf57195 --- /dev/null +++ b/src/docs/needless_borrowed_reference.txt @@ -0,0 +1,30 @@ +### What it does +Checks for bindings that destructure a reference and borrow the inner +value with `&ref`. + +### Why is this bad? +This pattern has no effect in almost all cases. + +### Known problems +In some cases, `&ref` is needed to avoid a lifetime mismatch error. +Example: +``` +fn foo(a: &Option, b: &Option) { + match (a, b) { + (None, &ref c) | (&ref c, None) => (), + (&Some(ref c), _) => (), + }; +} +``` + +### Example +``` +let mut v = Vec::::new(); +v.iter_mut().filter(|&ref a| a.is_empty()); +``` + +Use instead: +``` +let mut v = Vec::::new(); +v.iter_mut().filter(|a| a.is_empty()); +``` \ No newline at end of file diff --git a/src/docs/needless_collect.txt b/src/docs/needless_collect.txt new file mode 100644 index 0000000000000..275c39afc9df1 --- /dev/null +++ b/src/docs/needless_collect.txt @@ -0,0 +1,14 @@ +### 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 +``` +let len = iterator.clone().collect::>().len(); +// should be +let len = iterator.count(); +``` \ No newline at end of file diff --git a/src/docs/needless_continue.txt b/src/docs/needless_continue.txt new file mode 100644 index 0000000000000..2cee621c1af03 --- /dev/null +++ b/src/docs/needless_continue.txt @@ -0,0 +1,61 @@ +### What it does +The lint checks for `if`-statements appearing in loops +that contain a `continue` statement in either their main blocks or their +`else`-blocks, when omitting the `else`-block possibly with some +rearrangement of code can make the code easier to understand. + +### Why is this bad? +Having explicit `else` blocks for `if` statements +containing `continue` in their THEN branch adds unnecessary branching and +nesting to the code. Having an else block containing just `continue` can +also be better written by grouping the statements following the whole `if` +statement within the THEN block and omitting the else block completely. + +### Example +``` +while condition() { + update_condition(); + if x { + // ... + } else { + continue; + } + println!("Hello, world"); +} +``` + +Could be rewritten as + +``` +while condition() { + update_condition(); + if x { + // ... + println!("Hello, world"); + } +} +``` + +As another example, the following code + +``` +loop { + if waiting() { + continue; + } else { + // Do something useful + } + # break; +} +``` +Could be rewritten as + +``` +loop { + if waiting() { + continue; + } + // Do something useful + # break; +} +``` \ No newline at end of file diff --git a/src/docs/needless_doctest_main.txt b/src/docs/needless_doctest_main.txt new file mode 100644 index 0000000000000..8f91a7baa7151 --- /dev/null +++ b/src/docs/needless_doctest_main.txt @@ -0,0 +1,22 @@ +### What it does +Checks for `fn main() { .. }` in doctests + +### Why is this bad? +The test can be shorter (and likely more readable) +if the `fn main()` is left implicit. + +### Examples +``` +/// An example of a doctest with a `main()` function +/// +/// # Examples +/// +/// ``` +/// fn main() { +/// // this needs not be in an `fn` +/// } +/// ``` +fn needless_main() { + unimplemented!(); +} +``` \ No newline at end of file diff --git a/src/docs/needless_for_each.txt b/src/docs/needless_for_each.txt new file mode 100644 index 0000000000000..9ae6dd360c8f7 --- /dev/null +++ b/src/docs/needless_for_each.txt @@ -0,0 +1,24 @@ +### What it does +Checks for usage of `for_each` that would be more simply written as a +`for` loop. + +### Why is this bad? +`for_each` may be used after applying iterator transformers like +`filter` for better readability and performance. It may also be used to fit a simple +operation on one line. +But when none of these apply, a simple `for` loop is more idiomatic. + +### Example +``` +let v = vec![0, 1, 2]; +v.iter().for_each(|elem| { + println!("{}", elem); +}) +``` +Use instead: +``` +let v = vec![0, 1, 2]; +for elem in v.iter() { + println!("{}", elem); +} +``` \ No newline at end of file diff --git a/src/docs/needless_late_init.txt b/src/docs/needless_late_init.txt new file mode 100644 index 0000000000000..9e7bbcea99825 --- /dev/null +++ b/src/docs/needless_late_init.txt @@ -0,0 +1,42 @@ +### What it does +Checks for late initializations that can be replaced by a `let` statement +with an initializer. + +### Why is this bad? +Assigning in the `let` statement is less repetitive. + +### Example +``` +let a; +a = 1; + +let b; +match 3 { + 0 => b = "zero", + 1 => b = "one", + _ => b = "many", +} + +let c; +if true { + c = 1; +} else { + c = -1; +} +``` +Use instead: +``` +let a = 1; + +let b = match 3 { + 0 => "zero", + 1 => "one", + _ => "many", +}; + +let c = if true { + 1 +} else { + -1 +}; +``` \ No newline at end of file diff --git a/src/docs/needless_lifetimes.txt b/src/docs/needless_lifetimes.txt new file mode 100644 index 0000000000000..b280caa66b583 --- /dev/null +++ b/src/docs/needless_lifetimes.txt @@ -0,0 +1,29 @@ +### What it does +Checks for lifetime annotations which can be removed by +relying on lifetime elision. + +### Why is this bad? +The additional lifetimes make the code look more +complicated, while there is nothing out of the ordinary going on. Removing +them leads to more readable code. + +### Known problems +- We bail out if the function has a `where` clause where lifetimes +are mentioned due to potential false positives. +- Lifetime bounds such as `impl Foo + 'a` and `T: 'a` must be elided with the +placeholder notation `'_` because the fully elided notation leaves the type bound to `'static`. + +### Example +``` +// Unnecessary lifetime annotations +fn in_and_out<'a>(x: &'a u8, y: u8) -> &'a u8 { + x +} +``` + +Use instead: +``` +fn elided(x: &u8, y: u8) -> &u8 { + x +} +``` \ No newline at end of file diff --git a/src/docs/needless_match.txt b/src/docs/needless_match.txt new file mode 100644 index 0000000000000..92b40a5df6488 --- /dev/null +++ b/src/docs/needless_match.txt @@ -0,0 +1,36 @@ +### What it does +Checks for unnecessary `match` or match-like `if let` returns for `Option` and `Result` +when function signatures are the same. + +### Why is this bad? +This `match` block does nothing and might not be what the coder intended. + +### Example +``` +fn foo() -> Result<(), i32> { + match result { + Ok(val) => Ok(val), + Err(err) => Err(err), + } +} + +fn bar() -> Option { + if let Some(val) = option { + Some(val) + } else { + None + } +} +``` + +Could be replaced as + +``` +fn foo() -> Result<(), i32> { + result +} + +fn bar() -> Option { + option +} +``` \ No newline at end of file diff --git a/src/docs/needless_option_as_deref.txt b/src/docs/needless_option_as_deref.txt new file mode 100644 index 0000000000000..226396c97ac49 --- /dev/null +++ b/src/docs/needless_option_as_deref.txt @@ -0,0 +1,18 @@ +### What it does +Checks for no-op uses of `Option::{as_deref, as_deref_mut}`, +for example, `Option<&T>::as_deref()` returns the same type. + +### Why is this bad? +Redundant code and improving readability. + +### Example +``` +let a = Some(&1); +let b = a.as_deref(); // goes from Option<&i32> to Option<&i32> +``` + +Use instead: +``` +let a = Some(&1); +let b = a; +``` \ No newline at end of file diff --git a/src/docs/needless_option_take.txt b/src/docs/needless_option_take.txt new file mode 100644 index 0000000000000..6bac65a13b5b8 --- /dev/null +++ b/src/docs/needless_option_take.txt @@ -0,0 +1,17 @@ +### What it does +Checks for calling `take` function after `as_ref`. + +### Why is this bad? +Redundant code. `take` writes `None` to its argument. +In this case the modification is useless as it's a temporary that cannot be read from afterwards. + +### Example +``` +let x = Some(3); +x.as_ref().take(); +``` +Use instead: +``` +let x = Some(3); +x.as_ref(); +``` \ No newline at end of file diff --git a/src/docs/needless_parens_on_range_literals.txt b/src/docs/needless_parens_on_range_literals.txt new file mode 100644 index 0000000000000..85fab10cb5f65 --- /dev/null +++ b/src/docs/needless_parens_on_range_literals.txt @@ -0,0 +1,23 @@ +### What it does +The lint checks for parenthesis on literals in range statements that are +superfluous. + +### Why is this bad? +Having superfluous parenthesis makes the code less readable +overhead when reading. + +### Example + +``` +for i in (0)..10 { + println!("{i}"); +} +``` + +Use instead: + +``` +for i in 0..10 { + println!("{i}"); +} +``` \ No newline at end of file diff --git a/src/docs/needless_pass_by_value.txt b/src/docs/needless_pass_by_value.txt new file mode 100644 index 0000000000000..58c420b19f628 --- /dev/null +++ b/src/docs/needless_pass_by_value.txt @@ -0,0 +1,27 @@ +### What it does +Checks for functions taking arguments by value, but not +consuming them in its +body. + +### Why is this bad? +Taking arguments by reference is more flexible and can +sometimes avoid +unnecessary allocations. + +### Known problems +* This lint suggests taking an argument by reference, +however sometimes it is better to let users decide the argument type +(by using `Borrow` trait, for example), depending on how the function is used. + +### Example +``` +fn foo(v: Vec) { + assert_eq!(v.len(), 42); +} +``` +should be +``` +fn foo(v: &[i32]) { + assert_eq!(v.len(), 42); +} +``` \ No newline at end of file diff --git a/src/docs/needless_question_mark.txt b/src/docs/needless_question_mark.txt new file mode 100644 index 0000000000000..540739fd45fae --- /dev/null +++ b/src/docs/needless_question_mark.txt @@ -0,0 +1,43 @@ +### What it does +Suggests alternatives for useless applications of `?` in terminating expressions + +### Why is this bad? +There's no reason to use `?` to short-circuit when execution of the body will end there anyway. + +### Example +``` +struct TO { + magic: Option, +} + +fn f(to: TO) -> Option { + Some(to.magic?) +} + +struct TR { + magic: Result, +} + +fn g(tr: Result) -> Result { + tr.and_then(|t| Ok(t.magic?)) +} + +``` +Use instead: +``` +struct TO { + magic: Option, +} + +fn f(to: TO) -> Option { + to.magic +} + +struct TR { + magic: Result, +} + +fn g(tr: Result) -> Result { + tr.and_then(|t| t.magic) +} +``` \ No newline at end of file diff --git a/src/docs/needless_range_loop.txt b/src/docs/needless_range_loop.txt new file mode 100644 index 0000000000000..583c09b284976 --- /dev/null +++ b/src/docs/needless_range_loop.txt @@ -0,0 +1,23 @@ +### What it does +Checks for looping over the range of `0..len` of some +collection just to get the values by index. + +### Why is this bad? +Just iterating the collection itself makes the intent +more clear and is probably faster. + +### Example +``` +let vec = vec!['a', 'b', 'c']; +for i in 0..vec.len() { + println!("{}", vec[i]); +} +``` + +Use instead: +``` +let vec = vec!['a', 'b', 'c']; +for i in vec { + println!("{}", i); +} +``` \ No newline at end of file diff --git a/src/docs/needless_return.txt b/src/docs/needless_return.txt new file mode 100644 index 0000000000000..48782cb0ca84d --- /dev/null +++ b/src/docs/needless_return.txt @@ -0,0 +1,19 @@ +### What it does +Checks for return statements at the end of a block. + +### Why is this bad? +Removing the `return` and semicolon will make the code +more rusty. + +### Example +``` +fn foo(x: usize) -> usize { + return x; +} +``` +simplify to +``` +fn foo(x: usize) -> usize { + x +} +``` \ No newline at end of file diff --git a/src/docs/needless_splitn.txt b/src/docs/needless_splitn.txt new file mode 100644 index 0000000000000..b10a84fbc42d4 --- /dev/null +++ b/src/docs/needless_splitn.txt @@ -0,0 +1,16 @@ +### What it does +Checks for usages of `str::splitn` (or `str::rsplitn`) where using `str::split` would be the same. +### Why is this bad? +The function `split` is simpler and there is no performance difference in these cases, considering +that both functions return a lazy iterator. +### Example +``` +let str = "key=value=add"; +let _ = str.splitn(3, '=').next().unwrap(); +``` + +Use instead: +``` +let str = "key=value=add"; +let _ = str.split('=').next().unwrap(); +``` \ No newline at end of file diff --git a/src/docs/needless_update.txt b/src/docs/needless_update.txt new file mode 100644 index 0000000000000..82adabf6482c3 --- /dev/null +++ b/src/docs/needless_update.txt @@ -0,0 +1,30 @@ +### What it does +Checks for needlessly including a base struct on update +when all fields are changed anyway. + +This lint is not applied to structs marked with +[non_exhaustive](https://doc.rust-lang.org/reference/attributes/type_system.html). + +### Why is this bad? +This will cost resources (because the base has to be +somewhere), and make the code less readable. + +### Example +``` +Point { + x: 1, + y: 1, + z: 1, + ..zero_point +}; +``` + +Use instead: +``` +// Missing field `z` +Point { + x: 1, + y: 1, + ..zero_point +}; +``` \ No newline at end of file diff --git a/src/docs/neg_cmp_op_on_partial_ord.txt b/src/docs/neg_cmp_op_on_partial_ord.txt new file mode 100644 index 0000000000000..fa55c6cfd74b3 --- /dev/null +++ b/src/docs/neg_cmp_op_on_partial_ord.txt @@ -0,0 +1,26 @@ +### What it does +Checks for the usage of negated comparison operators on types which only implement +`PartialOrd` (e.g., `f64`). + +### Why is this bad? +These operators make it easy to forget that the underlying types actually allow not only three +potential Orderings (Less, Equal, Greater) but also a fourth one (Uncomparable). This is +especially easy to miss if the operator based comparison result is negated. + +### Example +``` +let a = 1.0; +let b = f64::NAN; + +let not_less_or_equal = !(a <= b); +``` + +Use instead: +``` +use std::cmp::Ordering; + +let _not_less_or_equal = match a.partial_cmp(&b) { + None | Some(Ordering::Greater) => true, + _ => false, +}; +``` \ No newline at end of file diff --git a/src/docs/neg_multiply.txt b/src/docs/neg_multiply.txt new file mode 100644 index 0000000000000..4e8b096eb9cc7 --- /dev/null +++ b/src/docs/neg_multiply.txt @@ -0,0 +1,18 @@ +### What it does +Checks for multiplication by -1 as a form of negation. + +### Why is this bad? +It's more readable to just negate. + +### Known problems +This only catches integers (for now). + +### Example +``` +let a = x * -1; +``` + +Use instead: +``` +let a = -x; +``` \ No newline at end of file diff --git a/src/docs/negative_feature_names.txt b/src/docs/negative_feature_names.txt new file mode 100644 index 0000000000000..01ee9efb318be --- /dev/null +++ b/src/docs/negative_feature_names.txt @@ -0,0 +1,22 @@ +### What it does +Checks for negative feature names with prefix `no-` or `not-` + +### Why is this bad? +Features are supposed to be additive, and negatively-named features violate it. + +### Example +``` +[features] +default = [] +no-abc = [] +not-def = [] + +``` +Use instead: +``` +[features] +default = ["abc", "def"] +abc = [] +def = [] + +``` \ No newline at end of file diff --git a/src/docs/never_loop.txt b/src/docs/never_loop.txt new file mode 100644 index 0000000000000..737ccf415cb98 --- /dev/null +++ b/src/docs/never_loop.txt @@ -0,0 +1,15 @@ +### What it does +Checks for loops that will always `break`, `return` or +`continue` an outer loop. + +### Why is this bad? +This loop never loops, all it does is obfuscating the +code. + +### Example +``` +loop { + ..; + break; +} +``` \ No newline at end of file diff --git a/src/docs/new_ret_no_self.txt b/src/docs/new_ret_no_self.txt new file mode 100644 index 0000000000000..291bad24a643b --- /dev/null +++ b/src/docs/new_ret_no_self.txt @@ -0,0 +1,47 @@ +### What it does +Checks for `new` not returning a type that contains `Self`. + +### Why is this bad? +As a convention, `new` methods are used to make a new +instance of a type. + +### Example +In an impl block: +``` +impl Foo { + fn new() -> NotAFoo { + } +} +``` + +``` +struct Bar(Foo); +impl Foo { + // Bad. The type name must contain `Self` + fn new() -> Bar { + } +} +``` + +``` +impl Foo { + // Good. Return type contains `Self` + fn new() -> Result { + } +} +``` + +Or in a trait definition: +``` +pub trait Trait { + // Bad. The type name must contain `Self` + fn new(); +} +``` + +``` +pub trait Trait { + // Good. Return type contains `Self` + fn new() -> Self; +} +``` \ No newline at end of file diff --git a/src/docs/new_without_default.txt b/src/docs/new_without_default.txt new file mode 100644 index 0000000000000..662d39c8efdd2 --- /dev/null +++ b/src/docs/new_without_default.txt @@ -0,0 +1,32 @@ +### What it does +Checks for public types with a `pub fn new() -> Self` method and no +implementation of +[`Default`](https://doc.rust-lang.org/std/default/trait.Default.html). + +### Why is this bad? +The user might expect to be able to use +[`Default`](https://doc.rust-lang.org/std/default/trait.Default.html) as the +type can be constructed without arguments. + +### Example +``` +pub struct Foo(Bar); + +impl Foo { + pub fn new() -> Self { + Foo(Bar::new()) + } +} +``` + +To fix the lint, add a `Default` implementation that delegates to `new`: + +``` +pub struct Foo(Bar); + +impl Default for Foo { + fn default() -> Self { + Foo::new() + } +} +``` \ No newline at end of file diff --git a/src/docs/no_effect.txt b/src/docs/no_effect.txt new file mode 100644 index 0000000000000..d4cc08fa8a7d8 --- /dev/null +++ b/src/docs/no_effect.txt @@ -0,0 +1,12 @@ +### What it does +Checks for statements which have no effect. + +### Why is this bad? +Unlike dead code, these statements are actually +executed. However, as they have no effect, all they do is make the code less +readable. + +### Example +``` +0; +``` \ No newline at end of file diff --git a/src/docs/no_effect_replace.txt b/src/docs/no_effect_replace.txt new file mode 100644 index 0000000000000..646d45287ef50 --- /dev/null +++ b/src/docs/no_effect_replace.txt @@ -0,0 +1,11 @@ +### What it does +Checks for `replace` statements which have no effect. + +### Why is this bad? +It's either a mistake or confusing. + +### Example +``` +"1234".replace("12", "12"); +"1234".replacen("12", "12", 1); +``` \ No newline at end of file diff --git a/src/docs/no_effect_underscore_binding.txt b/src/docs/no_effect_underscore_binding.txt new file mode 100644 index 0000000000000..972f60dd01e92 --- /dev/null +++ b/src/docs/no_effect_underscore_binding.txt @@ -0,0 +1,16 @@ +### What it does +Checks for binding to underscore prefixed variable without side-effects. + +### Why is this bad? +Unlike dead code, these bindings are actually +executed. However, as they have no effect and shouldn't be used further on, all they +do is make the code less readable. + +### Known problems +Further usage of this variable is not checked, which can lead to false positives if it is +used later in the code. + +### Example +``` +let _i_serve_no_purpose = 1; +``` \ No newline at end of file diff --git a/src/docs/non_ascii_literal.txt b/src/docs/non_ascii_literal.txt new file mode 100644 index 0000000000000..164902b4726e1 --- /dev/null +++ b/src/docs/non_ascii_literal.txt @@ -0,0 +1,19 @@ +### What it does +Checks for non-ASCII characters in string and char literals. + +### Why is this bad? +Yeah, we know, the 90's called and wanted their charset +back. Even so, there still are editors and other programs out there that +don't work well with Unicode. So if the code is meant to be used +internationally, on multiple operating systems, or has other portability +requirements, activating this lint could be useful. + +### Example +``` +let x = String::from("€"); +``` + +Use instead: +``` +let x = String::from("\u{20ac}"); +``` \ No newline at end of file diff --git a/src/docs/non_octal_unix_permissions.txt b/src/docs/non_octal_unix_permissions.txt new file mode 100644 index 0000000000000..4a468e94db164 --- /dev/null +++ b/src/docs/non_octal_unix_permissions.txt @@ -0,0 +1,23 @@ +### What it does +Checks for non-octal values used to set Unix file permissions. + +### Why is this bad? +They will be converted into octal, creating potentially +unintended file permissions. + +### Example +``` +use std::fs::OpenOptions; +use std::os::unix::fs::OpenOptionsExt; + +let mut options = OpenOptions::new(); +options.mode(644); +``` +Use instead: +``` +use std::fs::OpenOptions; +use std::os::unix::fs::OpenOptionsExt; + +let mut options = OpenOptions::new(); +options.mode(0o644); +``` \ No newline at end of file diff --git a/src/docs/non_send_fields_in_send_ty.txt b/src/docs/non_send_fields_in_send_ty.txt new file mode 100644 index 0000000000000..11e6f6e162cf0 --- /dev/null +++ b/src/docs/non_send_fields_in_send_ty.txt @@ -0,0 +1,36 @@ +### What it does +This lint warns about a `Send` implementation for a type that +contains fields that are not safe to be sent across threads. +It tries to detect fields that can cause a soundness issue +when sent to another thread (e.g., `Rc`) while allowing `!Send` fields +that are expected to exist in a `Send` type, such as raw pointers. + +### Why is this bad? +Sending the struct to another thread effectively sends all of its fields, +and the fields that do not implement `Send` can lead to soundness bugs +such as data races when accessed in a thread +that is different from the thread that created it. + +See: +* [*The Rustonomicon* about *Send and Sync*](https://doc.rust-lang.org/nomicon/send-and-sync.html) +* [The documentation of `Send`](https://doc.rust-lang.org/std/marker/trait.Send.html) + +### Known Problems +This lint relies on heuristics to distinguish types that are actually +unsafe to be sent across threads and `!Send` types that are expected to +exist in `Send` type. Its rule can filter out basic cases such as +`Vec<*const T>`, but it's not perfect. Feel free to create an issue if +you have a suggestion on how this heuristic can be improved. + +### Example +``` +struct ExampleStruct { + rc_is_not_send: Rc, + unbounded_generic_field: T, +} + +// This impl is unsound because it allows sending `!Send` types through `ExampleStruct` +unsafe impl Send for ExampleStruct {} +``` +Use thread-safe types like [`std::sync::Arc`](https://doc.rust-lang.org/std/sync/struct.Arc.html) +or specify correct bounds on generic type parameters (`T: Send`). \ No newline at end of file diff --git a/src/docs/nonminimal_bool.txt b/src/docs/nonminimal_bool.txt new file mode 100644 index 0000000000000..488980ddf0239 --- /dev/null +++ b/src/docs/nonminimal_bool.txt @@ -0,0 +1,23 @@ +### What it does +Checks for boolean expressions that can be written more +concisely. + +### Why is this bad? +Readability of boolean expressions suffers from +unnecessary duplication. + +### Known problems +Ignores short circuiting behavior of `||` and +`&&`. Ignores `|`, `&` and `^`. + +### Example +``` +if a && true {} +if !(a == b) {} +``` + +Use instead: +``` +if a {} +if a != b {} +``` \ No newline at end of file diff --git a/src/docs/nonsensical_open_options.txt b/src/docs/nonsensical_open_options.txt new file mode 100644 index 0000000000000..7a95443b51a50 --- /dev/null +++ b/src/docs/nonsensical_open_options.txt @@ -0,0 +1,14 @@ +### What it does +Checks for duplicate open options as well as combinations +that make no sense. + +### Why is this bad? +In the best case, the code will be harder to read than +necessary. I don't know the worst case. + +### Example +``` +use std::fs::OpenOptions; + +OpenOptions::new().read(true).truncate(true); +``` \ No newline at end of file diff --git a/src/docs/nonstandard_macro_braces.txt b/src/docs/nonstandard_macro_braces.txt new file mode 100644 index 0000000000000..7e8d0d2d33bf1 --- /dev/null +++ b/src/docs/nonstandard_macro_braces.txt @@ -0,0 +1,15 @@ +### What it does +Checks that common macros are used with consistent bracing. + +### Why is this bad? +This is mostly a consistency lint although using () or [] +doesn't give you a semicolon in item position, which can be unexpected. + +### Example +``` +vec!{1, 2, 3}; +``` +Use instead: +``` +vec![1, 2, 3]; +``` \ No newline at end of file diff --git a/src/docs/not_unsafe_ptr_arg_deref.txt b/src/docs/not_unsafe_ptr_arg_deref.txt new file mode 100644 index 0000000000000..31355fbb7b666 --- /dev/null +++ b/src/docs/not_unsafe_ptr_arg_deref.txt @@ -0,0 +1,30 @@ +### What it does +Checks for public functions that dereference raw pointer +arguments but are not marked `unsafe`. + +### Why is this bad? +The function should probably be marked `unsafe`, since +for an arbitrary raw pointer, there is no way of telling for sure if it is +valid. + +### Known problems +* It does not check functions recursively so if the pointer is passed to a +private non-`unsafe` function which does the dereferencing, the lint won't +trigger. +* It only checks for arguments whose type are raw pointers, not raw pointers +got from an argument in some other way (`fn foo(bar: &[*const u8])` or +`some_argument.get_raw_ptr()`). + +### Example +``` +pub fn foo(x: *const u8) { + println!("{}", unsafe { *x }); +} +``` + +Use instead: +``` +pub unsafe fn foo(x: *const u8) { + println!("{}", unsafe { *x }); +} +``` \ No newline at end of file diff --git a/src/docs/obfuscated_if_else.txt b/src/docs/obfuscated_if_else.txt new file mode 100644 index 0000000000000..638f63b0db5e4 --- /dev/null +++ b/src/docs/obfuscated_if_else.txt @@ -0,0 +1,21 @@ +### What it does +Checks for usages of `.then_some(..).unwrap_or(..)` + +### Why is this bad? +This can be written more clearly with `if .. else ..` + +### Limitations +This lint currently only looks for usages of +`.then_some(..).unwrap_or(..)`, but will be expanded +to account for similar patterns. + +### Example +``` +let x = true; +x.then_some("a").unwrap_or("b"); +``` +Use instead: +``` +let x = true; +if x { "a" } else { "b" }; +``` \ No newline at end of file diff --git a/src/docs/octal_escapes.txt b/src/docs/octal_escapes.txt new file mode 100644 index 0000000000000..eee820587158c --- /dev/null +++ b/src/docs/octal_escapes.txt @@ -0,0 +1,33 @@ +### What it does +Checks for `\0` escapes in string and byte literals that look like octal +character escapes in C. + +### Why is this bad? + +C and other languages support octal character escapes in strings, where +a backslash is followed by up to three octal digits. For example, `\033` +stands for the ASCII character 27 (ESC). Rust does not support this +notation, but has the escape code `\0` which stands for a null +byte/character, and any following digits do not form part of the escape +sequence. Therefore, `\033` is not a compiler error but the result may +be surprising. + +### Known problems +The actual meaning can be the intended one. `\x00` can be used in these +cases to be unambiguous. + +The lint does not trigger for format strings in `print!()`, `write!()` +and friends since the string is already preprocessed when Clippy lints +can see it. + +### Example +``` +let one = "\033[1m Bold? \033[0m"; // \033 intended as escape +let two = "\033\0"; // \033 intended as null-3-3 +``` + +Use instead: +``` +let one = "\x1b[1mWill this be bold?\x1b[0m"; +let two = "\x0033\x00"; +``` \ No newline at end of file diff --git a/src/docs/ok_expect.txt b/src/docs/ok_expect.txt new file mode 100644 index 0000000000000..fd5205d49dc0e --- /dev/null +++ b/src/docs/ok_expect.txt @@ -0,0 +1,19 @@ +### What it does +Checks for usage of `ok().expect(..)`. + +### Why is this bad? +Because you usually call `expect()` on the `Result` +directly to get a better error message. + +### Known problems +The error type needs to implement `Debug` + +### Example +``` +x.ok().expect("why did I do this again?"); +``` + +Use instead: +``` +x.expect("why did I do this again?"); +``` \ No newline at end of file diff --git a/src/docs/only_used_in_recursion.txt b/src/docs/only_used_in_recursion.txt new file mode 100644 index 0000000000000..f19f47ff9eb50 --- /dev/null +++ b/src/docs/only_used_in_recursion.txt @@ -0,0 +1,58 @@ +### What it does +Checks for arguments that are only used in recursion with no side-effects. + +### Why is this bad? +It could contain a useless calculation and can make function simpler. + +The arguments can be involved in calculations and assignments but as long as +the calculations have no side-effects (function calls or mutating dereference) +and the assigned variables are also only in recursion, it is useless. + +### Known problems +Too many code paths in the linting code are currently untested and prone to produce false +positives or are prone to have performance implications. + +In some cases, this would not catch all useless arguments. + +``` +fn foo(a: usize, b: usize) -> usize { + let f = |x| x + 1; + + if a == 0 { + 1 + } else { + foo(a - 1, f(b)) + } +} +``` + +For example, the argument `b` is only used in recursion, but the lint would not catch it. + +List of some examples that can not be caught: +- binary operation of non-primitive types +- closure usage +- some `break` relative operations +- struct pattern binding + +Also, when you recurse the function name with path segments, it is not possible to detect. + +### Example +``` +fn f(a: usize, b: usize) -> usize { + if a == 0 { + 1 + } else { + f(a - 1, b + 1) + } +} +``` +Use instead: +``` +fn f(a: usize) -> usize { + if a == 0 { + 1 + } else { + f(a - 1) + } +} +``` \ No newline at end of file diff --git a/src/docs/op_ref.txt b/src/docs/op_ref.txt new file mode 100644 index 0000000000000..7a7ed1bc9badc --- /dev/null +++ b/src/docs/op_ref.txt @@ -0,0 +1,17 @@ +### What it does +Checks for arguments to `==` which have their address +taken to satisfy a bound +and suggests to dereference the other argument instead + +### Why is this bad? +It is more idiomatic to dereference the other argument. + +### Example +``` +&x == y +``` + +Use instead: +``` +x == *y +``` \ No newline at end of file diff --git a/src/docs/option_as_ref_deref.txt b/src/docs/option_as_ref_deref.txt new file mode 100644 index 0000000000000..ad7411d3d4bd9 --- /dev/null +++ b/src/docs/option_as_ref_deref.txt @@ -0,0 +1,15 @@ +### What it does +Checks for usage of `_.as_ref().map(Deref::deref)` or it's aliases (such as String::as_str). + +### Why is this bad? +Readability, this can be written more concisely as +`_.as_deref()`. + +### Example +``` +opt.as_ref().map(String::as_str) +``` +Can be written as +``` +opt.as_deref() +``` \ No newline at end of file diff --git a/src/docs/option_env_unwrap.txt b/src/docs/option_env_unwrap.txt new file mode 100644 index 0000000000000..c952cba8e2615 --- /dev/null +++ b/src/docs/option_env_unwrap.txt @@ -0,0 +1,19 @@ +### What it does +Checks for usage of `option_env!(...).unwrap()` and +suggests usage of the `env!` macro. + +### Why is this bad? +Unwrapping the result of `option_env!` will panic +at run-time if the environment variable doesn't exist, whereas `env!` +catches it at compile-time. + +### Example +``` +let _ = option_env!("HOME").unwrap(); +``` + +Is better expressed as: + +``` +let _ = env!("HOME"); +``` \ No newline at end of file diff --git a/src/docs/option_filter_map.txt b/src/docs/option_filter_map.txt new file mode 100644 index 0000000000000..25f7bde7b4d04 --- /dev/null +++ b/src/docs/option_filter_map.txt @@ -0,0 +1,15 @@ +### What it does +Checks for indirect collection of populated `Option` + +### Why is this bad? +`Option` is like a collection of 0-1 things, so `flatten` +automatically does this without suspicious-looking `unwrap` calls. + +### Example +``` +let _ = std::iter::empty::>().filter(Option::is_some).map(Option::unwrap); +``` +Use instead: +``` +let _ = std::iter::empty::>().flatten(); +``` \ No newline at end of file diff --git a/src/docs/option_if_let_else.txt b/src/docs/option_if_let_else.txt new file mode 100644 index 0000000000000..43652db513b4c --- /dev/null +++ b/src/docs/option_if_let_else.txt @@ -0,0 +1,46 @@ +### What it does +Lints usage of `if let Some(v) = ... { y } else { x }` and +`match .. { Some(v) => y, None/_ => x }` which are more +idiomatically done with `Option::map_or` (if the else bit is a pure +expression) or `Option::map_or_else` (if the else bit is an impure +expression). + +### Why is this bad? +Using the dedicated functions of the `Option` type is clearer and +more concise than an `if let` expression. + +### Known problems +This lint uses a deliberately conservative metric for checking +if the inside of either body contains breaks or continues which will +cause it to not suggest a fix if either block contains a loop with +continues or breaks contained within the loop. + +### Example +``` +let _ = if let Some(foo) = optional { + foo +} else { + 5 +}; +let _ = match optional { + Some(val) => val + 1, + None => 5 +}; +let _ = if let Some(foo) = optional { + foo +} else { + let y = do_complicated_function(); + y*y +}; +``` + +should be + +``` +let _ = optional.map_or(5, |foo| foo); +let _ = optional.map_or(5, |val| val + 1); +let _ = optional.map_or_else(||{ + let y = do_complicated_function(); + y*y +}, |foo| foo); +``` \ No newline at end of file diff --git a/src/docs/option_map_or_none.txt b/src/docs/option_map_or_none.txt new file mode 100644 index 0000000000000..c86c65215f01c --- /dev/null +++ b/src/docs/option_map_or_none.txt @@ -0,0 +1,19 @@ +### What it does +Checks for usage of `_.map_or(None, _)`. + +### Why is this bad? +Readability, this can be written more concisely as +`_.and_then(_)`. + +### Known problems +The order of the arguments is not in execution order. + +### Example +``` +opt.map_or(None, |a| Some(a + 1)); +``` + +Use instead: +``` +opt.and_then(|a| Some(a + 1)); +``` \ No newline at end of file diff --git a/src/docs/option_map_unit_fn.txt b/src/docs/option_map_unit_fn.txt new file mode 100644 index 0000000000000..fc4b528f0923e --- /dev/null +++ b/src/docs/option_map_unit_fn.txt @@ -0,0 +1,27 @@ +### What it does +Checks for usage of `option.map(f)` where f is a function +or closure that returns the unit type `()`. + +### Why is this bad? +Readability, this can be written more clearly with +an if let statement + +### Example +``` +let x: Option = do_stuff(); +x.map(log_err_msg); +x.map(|msg| log_err_msg(format_msg(msg))); +``` + +The correct use would be: + +``` +let x: Option = do_stuff(); +if let Some(msg) = x { + log_err_msg(msg); +} + +if let Some(msg) = x { + log_err_msg(format_msg(msg)); +} +``` \ No newline at end of file diff --git a/src/docs/option_option.txt b/src/docs/option_option.txt new file mode 100644 index 0000000000000..b4324bd83990a --- /dev/null +++ b/src/docs/option_option.txt @@ -0,0 +1,32 @@ +### What it does +Checks for use of `Option>` in function signatures and type +definitions + +### Why is this bad? +`Option<_>` represents an optional value. `Option>` +represents an optional optional value which is logically the same thing as an optional +value but has an unneeded extra level of wrapping. + +If you have a case where `Some(Some(_))`, `Some(None)` and `None` are distinct cases, +consider a custom `enum` instead, with clear names for each case. + +### Example +``` +fn get_data() -> Option> { + None +} +``` + +Better: + +``` +pub enum Contents { + Data(Vec), // Was Some(Some(Vec)) + NotYetFetched, // Was Some(None) + None, // Was None +} + +fn get_data() -> Contents { + Contents::None +} +``` \ No newline at end of file diff --git a/src/docs/or_fun_call.txt b/src/docs/or_fun_call.txt new file mode 100644 index 0000000000000..6ce77cc268c51 --- /dev/null +++ b/src/docs/or_fun_call.txt @@ -0,0 +1,27 @@ +### What it does +Checks for calls to `.or(foo(..))`, `.unwrap_or(foo(..))`, +`.or_insert(foo(..))` etc., and suggests to use `.or_else(|| foo(..))`, +`.unwrap_or_else(|| foo(..))`, `.unwrap_or_default()` or `.or_default()` +etc. instead. + +### Why is this bad? +The function will always be called and potentially +allocate an object acting as the default. + +### 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. + +### Example +``` +foo.unwrap_or(String::new()); +``` + +Use instead: +``` +foo.unwrap_or_else(String::new); + +// or + +foo.unwrap_or_default(); +``` \ No newline at end of file diff --git a/src/docs/or_then_unwrap.txt b/src/docs/or_then_unwrap.txt new file mode 100644 index 0000000000000..64ac53749e8ad --- /dev/null +++ b/src/docs/or_then_unwrap.txt @@ -0,0 +1,22 @@ +### What it does +Checks for `.or(…).unwrap()` calls to Options and Results. + +### Why is this bad? +You should use `.unwrap_or(…)` instead for clarity. + +### Example +``` +// Result +let value = result.or::(Ok(fallback)).unwrap(); + +// Option +let value = option.or(Some(fallback)).unwrap(); +``` +Use instead: +``` +// Result +let value = result.unwrap_or(fallback); + +// Option +let value = option.unwrap_or(fallback); +``` \ No newline at end of file diff --git a/src/docs/out_of_bounds_indexing.txt b/src/docs/out_of_bounds_indexing.txt new file mode 100644 index 0000000000000..5802eea29966f --- /dev/null +++ b/src/docs/out_of_bounds_indexing.txt @@ -0,0 +1,22 @@ +### What it does +Checks for out of bounds array indexing with a constant +index. + +### Why is this bad? +This will always panic at runtime. + +### Example +``` +let x = [1, 2, 3, 4]; + +x[9]; +&x[2..9]; +``` + +Use instead: +``` +// Index within bounds + +x[0]; +x[3]; +``` \ No newline at end of file diff --git a/src/docs/overflow_check_conditional.txt b/src/docs/overflow_check_conditional.txt new file mode 100644 index 0000000000000..a09cc18a0bcc5 --- /dev/null +++ b/src/docs/overflow_check_conditional.txt @@ -0,0 +1,11 @@ +### What it does +Detects classic underflow/overflow checks. + +### Why is this bad? +Most classic C underflow/overflow checks will fail in +Rust. Users can use functions like `overflowing_*` and `wrapping_*` instead. + +### Example +``` +a + b < a; +``` \ No newline at end of file diff --git a/src/docs/overly_complex_bool_expr.txt b/src/docs/overly_complex_bool_expr.txt new file mode 100644 index 0000000000000..65ca18392e756 --- /dev/null +++ b/src/docs/overly_complex_bool_expr.txt @@ -0,0 +1,20 @@ +### What it does +Checks for boolean expressions that contain terminals that +can be eliminated. + +### Why is this bad? +This is most likely a logic bug. + +### Known problems +Ignores short circuiting behavior. + +### Example +``` +// The `b` is unnecessary, the expression is equivalent to `if a`. +if a && b || a { ... } +``` + +Use instead: +``` +if a {} +``` \ No newline at end of file diff --git a/src/docs/panic.txt b/src/docs/panic.txt new file mode 100644 index 0000000000000..f9bdc6e87ccf9 --- /dev/null +++ b/src/docs/panic.txt @@ -0,0 +1,10 @@ +### What it does +Checks for usage of `panic!`. + +### Why is this bad? +`panic!` will stop the execution of the executable + +### Example +``` +panic!("even with a good reason"); +``` \ No newline at end of file diff --git a/src/docs/panic_in_result_fn.txt b/src/docs/panic_in_result_fn.txt new file mode 100644 index 0000000000000..51c2f8ae5a30e --- /dev/null +++ b/src/docs/panic_in_result_fn.txt @@ -0,0 +1,22 @@ +### What it does +Checks for usage of `panic!`, `unimplemented!`, `todo!`, `unreachable!` or assertions in a function of type result. + +### Why is this bad? +For some codebases, it is desirable for functions of type result to return an error instead of crashing. Hence panicking macros should be avoided. + +### Known problems +Functions called from a function returning a `Result` may invoke a panicking macro. This is not checked. + +### Example +``` +fn result_with_panic() -> Result +{ + panic!("error"); +} +``` +Use instead: +``` +fn result_without_panic() -> Result { + Err(String::from("error")) +} +``` \ No newline at end of file diff --git a/src/docs/panicking_unwrap.txt b/src/docs/panicking_unwrap.txt new file mode 100644 index 0000000000000..1fbc245c8ec38 --- /dev/null +++ b/src/docs/panicking_unwrap.txt @@ -0,0 +1,18 @@ +### What it does +Checks for calls of `unwrap[_err]()` that will always fail. + +### Why is this bad? +If panicking is desired, an explicit `panic!()` should be used. + +### Known problems +This lint only checks `if` conditions not assignments. +So something like `let x: Option<()> = None; x.unwrap();` will not be recognized. + +### Example +``` +if option.is_none() { + do_something_with(option.unwrap()) +} +``` + +This code will always panic. The if condition should probably be inverted. \ No newline at end of file diff --git a/src/docs/partialeq_ne_impl.txt b/src/docs/partialeq_ne_impl.txt new file mode 100644 index 0000000000000..78f55188bab81 --- /dev/null +++ b/src/docs/partialeq_ne_impl.txt @@ -0,0 +1,18 @@ +### What it does +Checks for manual re-implementations of `PartialEq::ne`. + +### Why is this bad? +`PartialEq::ne` is required to always return the +negated result of `PartialEq::eq`, which is exactly what the default +implementation does. Therefore, there should never be any need to +re-implement it. + +### Example +``` +struct Foo; + +impl PartialEq for Foo { + fn eq(&self, other: &Foo) -> bool { true } + fn ne(&self, other: &Foo) -> bool { !(self == other) } +} +``` \ No newline at end of file diff --git a/src/docs/partialeq_to_none.txt b/src/docs/partialeq_to_none.txt new file mode 100644 index 0000000000000..5cc07bf88435c --- /dev/null +++ b/src/docs/partialeq_to_none.txt @@ -0,0 +1,24 @@ +### What it does + +Checks for binary comparisons to a literal `Option::None`. + +### Why is this bad? + +A programmer checking if some `foo` is `None` via a comparison `foo == None` +is usually inspired from other programming languages (e.g. `foo is None` +in Python). +Checking if a value of type `Option` is (not) equal to `None` in that +way relies on `T: PartialEq` to do the comparison, which is unneeded. + +### Example +``` +fn foo(f: Option) -> &'static str { + if f != None { "yay" } else { "nay" } +} +``` +Use instead: +``` +fn foo(f: Option) -> &'static str { + if f.is_some() { "yay" } else { "nay" } +} +``` \ No newline at end of file diff --git a/src/docs/path_buf_push_overwrite.txt b/src/docs/path_buf_push_overwrite.txt new file mode 100644 index 0000000000000..34f8901da2396 --- /dev/null +++ b/src/docs/path_buf_push_overwrite.txt @@ -0,0 +1,25 @@ +### What it does +* Checks for [push](https://doc.rust-lang.org/std/path/struct.PathBuf.html#method.push) +calls on `PathBuf` that can cause overwrites. + +### Why is this bad? +Calling `push` with a root path at the start can overwrite the +previous defined path. + +### Example +``` +use std::path::PathBuf; + +let mut x = PathBuf::from("/foo"); +x.push("/bar"); +assert_eq!(x, PathBuf::from("/bar")); +``` +Could be written: + +``` +use std::path::PathBuf; + +let mut x = PathBuf::from("/foo"); +x.push("bar"); +assert_eq!(x, PathBuf::from("/foo/bar")); +``` \ No newline at end of file diff --git a/src/docs/pattern_type_mismatch.txt b/src/docs/pattern_type_mismatch.txt new file mode 100644 index 0000000000000..64da881d592a8 --- /dev/null +++ b/src/docs/pattern_type_mismatch.txt @@ -0,0 +1,64 @@ +### What it does +Checks for patterns that aren't exact representations of the types +they are applied to. + +To satisfy this lint, you will have to adjust either the expression that is matched +against or the pattern itself, as well as the bindings that are introduced by the +adjusted patterns. For matching you will have to either dereference the expression +with the `*` operator, or amend the patterns to explicitly match against `&` +or `&mut ` depending on the reference mutability. For the bindings you need +to use the inverse. You can leave them as plain bindings if you wish for the value +to be copied, but you must use `ref mut ` or `ref ` to construct +a reference into the matched structure. + +If you are looking for a way to learn about ownership semantics in more detail, it +is recommended to look at IDE options available to you to highlight types, lifetimes +and reference semantics in your code. The available tooling would expose these things +in a general way even outside of the various pattern matching mechanics. Of course +this lint can still be used to highlight areas of interest and ensure a good understanding +of ownership semantics. + +### Why is this bad? +It isn't bad in general. But in some contexts it can be desirable +because it increases ownership hints in the code, and will guard against some changes +in ownership. + +### Example +This example shows the basic adjustments necessary to satisfy the lint. Note how +the matched expression is explicitly dereferenced with `*` and the `inner` variable +is bound to a shared borrow via `ref inner`. + +``` +// Bad +let value = &Some(Box::new(23)); +match value { + Some(inner) => println!("{}", inner), + None => println!("none"), +} + +// Good +let value = &Some(Box::new(23)); +match *value { + Some(ref inner) => println!("{}", inner), + None => println!("none"), +} +``` + +The following example demonstrates one of the advantages of the more verbose style. +Note how the second version uses `ref mut a` to explicitly declare `a` a shared mutable +borrow, while `b` is simply taken by value. This ensures that the loop body cannot +accidentally modify the wrong part of the structure. + +``` +// Bad +let mut values = vec![(2, 3), (3, 4)]; +for (a, b) in &mut values { + *a += *b; +} + +// Good +let mut values = vec![(2, 3), (3, 4)]; +for &mut (ref mut a, b) in &mut values { + *a += b; +} +``` \ No newline at end of file diff --git a/src/docs/positional_named_format_parameters.txt b/src/docs/positional_named_format_parameters.txt new file mode 100644 index 0000000000000..e391d2406677d --- /dev/null +++ b/src/docs/positional_named_format_parameters.txt @@ -0,0 +1,15 @@ +### What it does +This lint warns when a named parameter in a format string is used as a positional one. + +### Why is this bad? +It may be confused for an assignment and obfuscates which parameter is being used. + +### Example +``` +println!("{}", x = 10); +``` + +Use instead: +``` +println!("{x}", x = 10); +``` \ No newline at end of file diff --git a/src/docs/possible_missing_comma.txt b/src/docs/possible_missing_comma.txt new file mode 100644 index 0000000000000..5d92f4cae91e0 --- /dev/null +++ b/src/docs/possible_missing_comma.txt @@ -0,0 +1,14 @@ +### What it does +Checks for possible missing comma in an array. It lints if +an array element is a binary operator expression and it lies on two lines. + +### Why is this bad? +This could lead to unexpected results. + +### Example +``` +let a = &[ + -1, -2, -3 // <= no comma here + -4, -5, -6 +]; +``` \ No newline at end of file diff --git a/src/docs/precedence.txt b/src/docs/precedence.txt new file mode 100644 index 0000000000000..fda0b831f335f --- /dev/null +++ b/src/docs/precedence.txt @@ -0,0 +1,17 @@ +### What it does +Checks for operations where precedence may be unclear +and suggests to add parentheses. Currently it catches the following: +* mixed usage of arithmetic and bit shifting/combining operators without +parentheses +* a "negative" numeric literal (which is really a unary `-` followed by a +numeric literal) + followed by a method call + +### Why is this bad? +Not everyone knows the precedence of those operators by +heart, so expressions like these may trip others trying to reason about the +code. + +### Example +* `1 << 2 + 3` equals 32, while `(1 << 2) + 3` equals 7 +* `-1i32.abs()` equals -1, while `(-1i32).abs()` equals 1 \ No newline at end of file diff --git a/src/docs/print_in_format_impl.txt b/src/docs/print_in_format_impl.txt new file mode 100644 index 0000000000000..140d23d6faab4 --- /dev/null +++ b/src/docs/print_in_format_impl.txt @@ -0,0 +1,34 @@ +### What it does +Checks for use of `println`, `print`, `eprintln` or `eprint` in an +implementation of a formatting trait. + +### Why is this bad? +Using a print macro is likely unintentional since formatting traits +should write to the `Formatter`, not stdout/stderr. + +### Example +``` +use std::fmt::{Display, Error, Formatter}; + +struct S; +impl Display for S { + fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { + println!("S"); + + Ok(()) + } +} +``` +Use instead: +``` +use std::fmt::{Display, Error, Formatter}; + +struct S; +impl Display for S { + fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { + writeln!(f, "S"); + + Ok(()) + } +} +``` \ No newline at end of file diff --git a/src/docs/print_literal.txt b/src/docs/print_literal.txt new file mode 100644 index 0000000000000..160073414f9af --- /dev/null +++ b/src/docs/print_literal.txt @@ -0,0 +1,20 @@ +### What it does +This lint warns about the use of literals as `print!`/`println!` args. + +### Why is this bad? +Using literals as `println!` args is inefficient +(c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary +(i.e., just put the literal in the format string) + +### Known problems +Will also warn with macro calls as arguments that expand to literals +-- e.g., `println!("{}", env!("FOO"))`. + +### Example +``` +println!("{}", "foo"); +``` +use the literal without formatting: +``` +println!("foo"); +``` \ No newline at end of file diff --git a/src/docs/print_stderr.txt b/src/docs/print_stderr.txt new file mode 100644 index 0000000000000..fc14511cd6a65 --- /dev/null +++ b/src/docs/print_stderr.txt @@ -0,0 +1,21 @@ +### What it does +Checks for printing on *stderr*. The purpose of this lint +is to catch debugging remnants. + +### Why is this bad? +People often print on *stderr* while debugging an +application and might forget to remove those prints afterward. + +### Known problems +* Only catches `eprint!` and `eprintln!` calls. +* The lint level is unaffected by crate attributes. The level can still + be set for functions, modules and other items. To change the level for + the entire crate, please use command line flags. More information and a + configuration example can be found in [clippy#6610]. + +[clippy#6610]: https://github.com/rust-lang/rust-clippy/issues/6610#issuecomment-977120558 + +### Example +``` +eprintln!("Hello world!"); +``` \ No newline at end of file diff --git a/src/docs/print_stdout.txt b/src/docs/print_stdout.txt new file mode 100644 index 0000000000000..6c9a4b98e1e66 --- /dev/null +++ b/src/docs/print_stdout.txt @@ -0,0 +1,21 @@ +### What it does +Checks for printing on *stdout*. The purpose of this lint +is to catch debugging remnants. + +### Why is this bad? +People often print on *stdout* while debugging an +application and might forget to remove those prints afterward. + +### Known problems +* Only catches `print!` and `println!` calls. +* The lint level is unaffected by crate attributes. The level can still + be set for functions, modules and other items. To change the level for + the entire crate, please use command line flags. More information and a + configuration example can be found in [clippy#6610]. + +[clippy#6610]: https://github.com/rust-lang/rust-clippy/issues/6610#issuecomment-977120558 + +### Example +``` +println!("Hello world!"); +``` \ No newline at end of file diff --git a/src/docs/print_with_newline.txt b/src/docs/print_with_newline.txt new file mode 100644 index 0000000000000..640323e822dbf --- /dev/null +++ b/src/docs/print_with_newline.txt @@ -0,0 +1,16 @@ +### What it does +This lint warns when you use `print!()` with a format +string that ends in a newline. + +### Why is this bad? +You should use `println!()` instead, which appends the +newline. + +### Example +``` +print!("Hello {}!\n", name); +``` +use println!() instead +``` +println!("Hello {}!", name); +``` \ No newline at end of file diff --git a/src/docs/println_empty_string.txt b/src/docs/println_empty_string.txt new file mode 100644 index 0000000000000..b980413022cab --- /dev/null +++ b/src/docs/println_empty_string.txt @@ -0,0 +1,16 @@ +### What it does +This lint warns when you use `println!("")` to +print a newline. + +### Why is this bad? +You should use `println!()`, which is simpler. + +### Example +``` +println!(""); +``` + +Use instead: +``` +println!(); +``` \ No newline at end of file diff --git a/src/docs/ptr_arg.txt b/src/docs/ptr_arg.txt new file mode 100644 index 0000000000000..796b0a65b717f --- /dev/null +++ b/src/docs/ptr_arg.txt @@ -0,0 +1,29 @@ +### What it does +This lint checks for function arguments of type `&String`, `&Vec`, +`&PathBuf`, and `Cow<_>`. It will also suggest you replace `.clone()` calls +with the appropriate `.to_owned()`/`to_string()` calls. + +### Why is this bad? +Requiring the argument to be of the specific size +makes the function less useful for no benefit; slices in the form of `&[T]` +or `&str` usually suffice and can be obtained from other types, too. + +### Known problems +There may be `fn(&Vec)`-typed references pointing to your function. +If you have them, you will get a compiler error after applying this lint's +suggestions. You then have the choice to undo your changes or change the +type of the reference. + +Note that if the function is part of your public interface, there may be +other crates referencing it, of which you may not be aware. Carefully +deprecate the function before applying the lint suggestions in this case. + +### Example +``` +fn foo(&Vec) { .. } +``` + +Use instead: +``` +fn foo(&[u32]) { .. } +``` \ No newline at end of file diff --git a/src/docs/ptr_as_ptr.txt b/src/docs/ptr_as_ptr.txt new file mode 100644 index 0000000000000..8fb35c4aae8f1 --- /dev/null +++ b/src/docs/ptr_as_ptr.txt @@ -0,0 +1,22 @@ +### What it does +Checks for `as` casts between raw pointers without changing its mutability, +namely `*const T` to `*const U` and `*mut T` to `*mut U`. + +### Why is this bad? +Though `as` casts between raw pointers is not terrible, `pointer::cast` is safer because +it cannot accidentally change the pointer's mutability nor cast the pointer to other types like `usize`. + +### Example +``` +let ptr: *const u32 = &42_u32; +let mut_ptr: *mut u32 = &mut 42_u32; +let _ = ptr as *const i32; +let _ = mut_ptr as *mut i32; +``` +Use instead: +``` +let ptr: *const u32 = &42_u32; +let mut_ptr: *mut u32 = &mut 42_u32; +let _ = ptr.cast::(); +let _ = mut_ptr.cast::(); +``` \ No newline at end of file diff --git a/src/docs/ptr_eq.txt b/src/docs/ptr_eq.txt new file mode 100644 index 0000000000000..06b36ca55e691 --- /dev/null +++ b/src/docs/ptr_eq.txt @@ -0,0 +1,22 @@ +### What it does +Use `std::ptr::eq` when applicable + +### Why is this bad? +`ptr::eq` can be used to compare `&T` references +(which coerce to `*const T` implicitly) by their address rather than +comparing the values they point to. + +### Example +``` +let a = &[1, 2, 3]; +let b = &[1, 2, 3]; + +assert!(a as *const _ as usize == b as *const _ as usize); +``` +Use instead: +``` +let a = &[1, 2, 3]; +let b = &[1, 2, 3]; + +assert!(std::ptr::eq(a, b)); +``` \ No newline at end of file diff --git a/src/docs/ptr_offset_with_cast.txt b/src/docs/ptr_offset_with_cast.txt new file mode 100644 index 0000000000000..f204e769bf4b8 --- /dev/null +++ b/src/docs/ptr_offset_with_cast.txt @@ -0,0 +1,30 @@ +### What it does +Checks for usage of the `offset` pointer method with a `usize` casted to an +`isize`. + +### Why is this bad? +If we’re always increasing the pointer address, we can avoid the numeric +cast by using the `add` method instead. + +### Example +``` +let vec = vec![b'a', b'b', b'c']; +let ptr = vec.as_ptr(); +let offset = 1_usize; + +unsafe { + ptr.offset(offset as isize); +} +``` + +Could be written: + +``` +let vec = vec![b'a', b'b', b'c']; +let ptr = vec.as_ptr(); +let offset = 1_usize; + +unsafe { + ptr.add(offset); +} +``` \ No newline at end of file diff --git a/src/docs/pub_use.txt b/src/docs/pub_use.txt new file mode 100644 index 0000000000000..407cafa01903f --- /dev/null +++ b/src/docs/pub_use.txt @@ -0,0 +1,28 @@ +### What it does + +Restricts the usage of `pub use ...` + +### Why is this bad? + +`pub use` is usually fine, but a project may wish to limit `pub use` instances to prevent +unintentional exports or to encourage placing exported items directly in public modules + +### Example +``` +pub mod outer { + mod inner { + pub struct Test {} + } + pub use inner::Test; +} + +use outer::Test; +``` +Use instead: +``` +pub mod outer { + pub struct Test {} +} + +use outer::Test; +``` \ No newline at end of file diff --git a/src/docs/question_mark.txt b/src/docs/question_mark.txt new file mode 100644 index 0000000000000..4dc987be88132 --- /dev/null +++ b/src/docs/question_mark.txt @@ -0,0 +1,18 @@ +### What it does +Checks for expressions that could be replaced by the question mark operator. + +### Why is this bad? +Question mark usage is more idiomatic. + +### Example +``` +if option.is_none() { + return None; +} +``` + +Could be written: + +``` +option?; +``` \ No newline at end of file diff --git a/src/docs/range_minus_one.txt b/src/docs/range_minus_one.txt new file mode 100644 index 0000000000000..fcb96dcc34edf --- /dev/null +++ b/src/docs/range_minus_one.txt @@ -0,0 +1,27 @@ +### What it does +Checks for inclusive ranges where 1 is subtracted from +the upper bound, e.g., `x..=(y-1)`. + +### Why is this bad? +The code is more readable with an exclusive range +like `x..y`. + +### Known problems +This will cause a warning that cannot be fixed if +the consumer of the range only accepts a specific range type, instead of +the generic `RangeBounds` trait +([#3307](https://github.com/rust-lang/rust-clippy/issues/3307)). + +### Example +``` +for i in x..=(y-1) { + // .. +} +``` + +Use instead: +``` +for i in x..y { + // .. +} +``` \ No newline at end of file diff --git a/src/docs/range_plus_one.txt b/src/docs/range_plus_one.txt new file mode 100644 index 0000000000000..193c85f9cbc72 --- /dev/null +++ b/src/docs/range_plus_one.txt @@ -0,0 +1,36 @@ +### What it does +Checks for exclusive ranges where 1 is added to the +upper bound, e.g., `x..(y+1)`. + +### Why is this bad? +The code is more readable with an inclusive range +like `x..=y`. + +### Known problems +Will add unnecessary pair of parentheses when the +expression is not wrapped in a pair but starts with an opening parenthesis +and ends with a closing one. +I.e., `let _ = (f()+1)..(f()+1)` results in `let _ = ((f()+1)..=f())`. + +Also in many cases, inclusive ranges are still slower to run than +exclusive ranges, because they essentially add an extra branch that +LLVM may fail to hoist out of the loop. + +This will cause a warning that cannot be fixed if the consumer of the +range only accepts a specific range type, instead of the generic +`RangeBounds` trait +([#3307](https://github.com/rust-lang/rust-clippy/issues/3307)). + +### Example +``` +for i in x..(y+1) { + // .. +} +``` + +Use instead: +``` +for i in x..=y { + // .. +} +``` \ No newline at end of file diff --git a/src/docs/range_zip_with_len.txt b/src/docs/range_zip_with_len.txt new file mode 100644 index 0000000000000..24c1efec789a9 --- /dev/null +++ b/src/docs/range_zip_with_len.txt @@ -0,0 +1,16 @@ +### What it does +Checks for zipping a collection with the range of +`0.._.len()`. + +### Why is this bad? +The code is better expressed with `.enumerate()`. + +### Example +``` +let _ = x.iter().zip(0..x.len()); +``` + +Use instead: +``` +let _ = x.iter().enumerate(); +``` \ No newline at end of file diff --git a/src/docs/rc_buffer.txt b/src/docs/rc_buffer.txt new file mode 100644 index 0000000000000..82ac58eeb3081 --- /dev/null +++ b/src/docs/rc_buffer.txt @@ -0,0 +1,27 @@ +### What it does +Checks for `Rc` and `Arc` when `T` is a mutable buffer type such as `String` or `Vec`. + +### Why is this bad? +Expressions such as `Rc` usually have no advantage over `Rc`, since +it is larger and involves an extra level of indirection, and doesn't implement `Borrow`. + +While mutating a buffer type would still be possible with `Rc::get_mut()`, it only +works if there are no additional references yet, which usually defeats the purpose of +enclosing it in a shared ownership type. Instead, additionally wrapping the inner +type with an interior mutable container (such as `RefCell` or `Mutex`) would normally +be used. + +### Known problems +This pattern can be desirable to avoid the overhead of a `RefCell` or `Mutex` for +cases where mutation only happens before there are any additional references. + +### Example +``` +fn foo(interned: Rc) { ... } +``` + +Better: + +``` +fn foo(interned: Rc) { ... } +``` \ No newline at end of file diff --git a/src/docs/rc_clone_in_vec_init.txt b/src/docs/rc_clone_in_vec_init.txt new file mode 100644 index 0000000000000..6fc08aaf9ab57 --- /dev/null +++ b/src/docs/rc_clone_in_vec_init.txt @@ -0,0 +1,29 @@ +### What it does +Checks for reference-counted pointers (`Arc`, `Rc`, `rc::Weak`, and `sync::Weak`) +in `vec![elem; len]` + +### Why is this bad? +This will create `elem` once and clone it `len` times - doing so with `Arc`/`Rc`/`Weak` +is a bit misleading, as it will create references to the same pointer, rather +than different instances. + +### Example +``` +let v = vec![std::sync::Arc::new("some data".to_string()); 100]; +// or +let v = vec![std::rc::Rc::new("some data".to_string()); 100]; +``` +Use instead: +``` +// Initialize each value separately: +let mut data = Vec::with_capacity(100); +for _ in 0..100 { + data.push(std::rc::Rc::new("some data".to_string())); +} + +// Or if you want clones of the same reference, +// Create the reference beforehand to clarify that +// it should be cloned for each value +let data = std::rc::Rc::new("some data".to_string()); +let v = vec![data; 100]; +``` \ No newline at end of file diff --git a/src/docs/rc_mutex.txt b/src/docs/rc_mutex.txt new file mode 100644 index 0000000000000..ed7a1e344d086 --- /dev/null +++ b/src/docs/rc_mutex.txt @@ -0,0 +1,26 @@ +### What it does +Checks for `Rc>`. + +### Why is this bad? +`Rc` is used in single thread and `Mutex` is used in multi thread. +Consider using `Rc>` in single thread or `Arc>` in multi thread. + +### Known problems +Sometimes combining generic types can lead to the requirement that a +type use Rc in conjunction with Mutex. We must consider those cases false positives, but +alas they are quite hard to rule out. Luckily they are also rare. + +### Example +``` +use std::rc::Rc; +use std::sync::Mutex; +fn foo(interned: Rc>) { ... } +``` + +Better: + +``` +use std::rc::Rc; +use std::cell::RefCell +fn foo(interned: Rc>) { ... } +``` \ No newline at end of file diff --git a/src/docs/read_zero_byte_vec.txt b/src/docs/read_zero_byte_vec.txt new file mode 100644 index 0000000000000..cef5604e01c08 --- /dev/null +++ b/src/docs/read_zero_byte_vec.txt @@ -0,0 +1,30 @@ +### What it does +This lint catches reads into a zero-length `Vec`. +Especially in the case of a call to `with_capacity`, this lint warns that read +gets the number of bytes from the `Vec`'s length, not its capacity. + +### Why is this bad? +Reading zero bytes is almost certainly not the intended behavior. + +### Known problems +In theory, a very unusual read implementation could assign some semantic meaning +to zero-byte reads. But it seems exceptionally unlikely that code intending to do +a zero-byte read would allocate a `Vec` for it. + +### Example +``` +use std::io; +fn foo(mut f: F) { + let mut data = Vec::with_capacity(100); + f.read(&mut data).unwrap(); +} +``` +Use instead: +``` +use std::io; +fn foo(mut f: F) { + let mut data = Vec::with_capacity(100); + data.resize(100, 0); + f.read(&mut data).unwrap(); +} +``` \ No newline at end of file diff --git a/src/docs/recursive_format_impl.txt b/src/docs/recursive_format_impl.txt new file mode 100644 index 0000000000000..32fffd84cf432 --- /dev/null +++ b/src/docs/recursive_format_impl.txt @@ -0,0 +1,32 @@ +### What it does +Checks for format trait implementations (e.g. `Display`) with a recursive call to itself +which uses `self` as a parameter. +This is typically done indirectly with the `write!` macro or with `to_string()`. + +### Why is this bad? +This will lead to infinite recursion and a stack overflow. + +### Example + +``` +use std::fmt; + +struct Structure(i32); +impl fmt::Display for Structure { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.to_string()) + } +} + +``` +Use instead: +``` +use std::fmt; + +struct Structure(i32); +impl fmt::Display for Structure { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.0) + } +} +``` \ No newline at end of file diff --git a/src/docs/redundant_allocation.txt b/src/docs/redundant_allocation.txt new file mode 100644 index 0000000000000..86bf51e8dfec7 --- /dev/null +++ b/src/docs/redundant_allocation.txt @@ -0,0 +1,17 @@ +### What it does +Checks for use of redundant allocations anywhere in the code. + +### Why is this bad? +Expressions such as `Rc<&T>`, `Rc>`, `Rc>`, `Rc>`, `Arc<&T>`, `Arc>`, +`Arc>`, `Arc>`, `Box<&T>`, `Box>`, `Box>`, `Box>`, add an unnecessary level of indirection. + +### Example +``` +fn foo(bar: Rc<&usize>) {} +``` + +Better: + +``` +fn foo(bar: &usize) {} +``` \ No newline at end of file diff --git a/src/docs/redundant_clone.txt b/src/docs/redundant_clone.txt new file mode 100644 index 0000000000000..b29aed0b5e779 --- /dev/null +++ b/src/docs/redundant_clone.txt @@ -0,0 +1,23 @@ +### What it does +Checks for a redundant `clone()` (and its relatives) which clones an owned +value that is going to be dropped without further use. + +### Why is this bad? +It is not always possible for the compiler to eliminate useless +allocations and deallocations generated by redundant `clone()`s. + +### Known problems +False-negatives: analysis performed by this lint is conservative and limited. + +### Example +``` +{ + let x = Foo::new(); + call(x.clone()); + call(x.clone()); // this can just pass `x` +} + +["lorem", "ipsum"].join(" ").to_string(); + +Path::new("/a/b").join("c").to_path_buf(); +``` \ No newline at end of file diff --git a/src/docs/redundant_closure.txt b/src/docs/redundant_closure.txt new file mode 100644 index 0000000000000..0faa9513f97f2 --- /dev/null +++ b/src/docs/redundant_closure.txt @@ -0,0 +1,25 @@ +### What it does +Checks for closures which just call another function where +the function can be called directly. `unsafe` functions or calls where types +get adjusted are ignored. + +### Why is this bad? +Needlessly creating a closure adds code for no benefit +and gives the optimizer more work. + +### Known problems +If creating the closure inside the closure has a side- +effect then moving the closure creation out will change when that side- +effect runs. +See [#1439](https://github.com/rust-lang/rust-clippy/issues/1439) for more details. + +### Example +``` +xs.map(|x| foo(x)) +``` + +Use instead: +``` +// where `foo(_)` is a plain function that takes the exact argument type of `x`. +xs.map(foo) +``` \ No newline at end of file diff --git a/src/docs/redundant_closure_call.txt b/src/docs/redundant_closure_call.txt new file mode 100644 index 0000000000000..913d1a705e294 --- /dev/null +++ b/src/docs/redundant_closure_call.txt @@ -0,0 +1,17 @@ +### What it does +Detects closures called in the same expression where they +are defined. + +### Why is this bad? +It is unnecessarily adding to the expression's +complexity. + +### Example +``` +let a = (|| 42)(); +``` + +Use instead: +``` +let a = 42; +``` \ No newline at end of file diff --git a/src/docs/redundant_closure_for_method_calls.txt b/src/docs/redundant_closure_for_method_calls.txt new file mode 100644 index 0000000000000..865510e14755a --- /dev/null +++ b/src/docs/redundant_closure_for_method_calls.txt @@ -0,0 +1,15 @@ +### What it does +Checks for closures which only invoke a method on the closure +argument and can be replaced by referencing the method directly. + +### Why is this bad? +It's unnecessary to create the closure. + +### Example +``` +Some('a').map(|s| s.to_uppercase()); +``` +may be rewritten as +``` +Some('a').map(char::to_uppercase); +``` \ No newline at end of file diff --git a/src/docs/redundant_else.txt b/src/docs/redundant_else.txt new file mode 100644 index 0000000000000..3f4e86917603c --- /dev/null +++ b/src/docs/redundant_else.txt @@ -0,0 +1,30 @@ +### What it does +Checks for `else` blocks that can be removed without changing semantics. + +### Why is this bad? +The `else` block adds unnecessary indentation and verbosity. + +### Known problems +Some may prefer to keep the `else` block for clarity. + +### Example +``` +fn my_func(count: u32) { + if count == 0 { + print!("Nothing to do"); + return; + } else { + print!("Moving on..."); + } +} +``` +Use instead: +``` +fn my_func(count: u32) { + if count == 0 { + print!("Nothing to do"); + return; + } + print!("Moving on..."); +} +``` \ No newline at end of file diff --git a/src/docs/redundant_feature_names.txt b/src/docs/redundant_feature_names.txt new file mode 100644 index 0000000000000..5bd6925ed47d0 --- /dev/null +++ b/src/docs/redundant_feature_names.txt @@ -0,0 +1,23 @@ +### What it does +Checks for feature names with prefix `use-`, `with-` or suffix `-support` + +### Why is this bad? +These prefixes and suffixes have no significant meaning. + +### Example +``` +[features] +default = ["use-abc", "with-def", "ghi-support"] +use-abc = [] // redundant +with-def = [] // redundant +ghi-support = [] // redundant +``` + +Use instead: +``` +[features] +default = ["abc", "def", "ghi"] +abc = [] +def = [] +ghi = [] +``` diff --git a/src/docs/redundant_field_names.txt b/src/docs/redundant_field_names.txt new file mode 100644 index 0000000000000..35f20a466b378 --- /dev/null +++ b/src/docs/redundant_field_names.txt @@ -0,0 +1,22 @@ +### What it does +Checks for fields in struct literals where shorthands +could be used. + +### Why is this bad? +If the field and variable names are the same, +the field name is redundant. + +### Example +``` +let bar: u8 = 123; + +struct Foo { + bar: u8, +} + +let foo = Foo { bar: bar }; +``` +the last line can be simplified to +``` +let foo = Foo { bar }; +``` \ No newline at end of file diff --git a/src/docs/redundant_pattern.txt b/src/docs/redundant_pattern.txt new file mode 100644 index 0000000000000..45f6cfc86702c --- /dev/null +++ b/src/docs/redundant_pattern.txt @@ -0,0 +1,22 @@ +### What it does +Checks for patterns in the form `name @ _`. + +### Why is this bad? +It's almost always more readable to just use direct +bindings. + +### Example +``` +match v { + Some(x) => (), + y @ _ => (), +} +``` + +Use instead: +``` +match v { + Some(x) => (), + y => (), +} +``` \ No newline at end of file diff --git a/src/docs/redundant_pattern_matching.txt b/src/docs/redundant_pattern_matching.txt new file mode 100644 index 0000000000000..77b1021e0db3b --- /dev/null +++ b/src/docs/redundant_pattern_matching.txt @@ -0,0 +1,45 @@ +### What it does +Lint for redundant pattern matching over `Result`, `Option`, +`std::task::Poll` or `std::net::IpAddr` + +### Why is this bad? +It's more concise and clear to just use the proper +utility function + +### Known problems +This will change the drop order for the matched type. Both `if let` and +`while let` will drop the value at the end of the block, both `if` and `while` will drop the +value before entering the block. For most types this change will not matter, but for a few +types this will not be an acceptable change (e.g. locks). See the +[reference](https://doc.rust-lang.org/reference/destructors.html#drop-scopes) for more about +drop order. + +### Example +``` +if let Ok(_) = Ok::(42) {} +if let Err(_) = Err::(42) {} +if let None = None::<()> {} +if let Some(_) = Some(42) {} +if let Poll::Pending = Poll::Pending::<()> {} +if let Poll::Ready(_) = Poll::Ready(42) {} +if let IpAddr::V4(_) = IpAddr::V4(Ipv4Addr::LOCALHOST) {} +if let IpAddr::V6(_) = IpAddr::V6(Ipv6Addr::LOCALHOST) {} +match Ok::(42) { + Ok(_) => true, + Err(_) => false, +}; +``` + +The more idiomatic use would be: + +``` +if Ok::(42).is_ok() {} +if Err::(42).is_err() {} +if None::<()>.is_none() {} +if Some(42).is_some() {} +if Poll::Pending::<()>.is_pending() {} +if Poll::Ready(42).is_ready() {} +if IpAddr::V4(Ipv4Addr::LOCALHOST).is_ipv4() {} +if IpAddr::V6(Ipv6Addr::LOCALHOST).is_ipv6() {} +Ok::(42).is_ok(); +``` \ No newline at end of file diff --git a/src/docs/redundant_pub_crate.txt b/src/docs/redundant_pub_crate.txt new file mode 100644 index 0000000000000..a527bb5acda1e --- /dev/null +++ b/src/docs/redundant_pub_crate.txt @@ -0,0 +1,21 @@ +### What it does +Checks for items declared `pub(crate)` that are not crate visible because they +are inside a private module. + +### Why is this bad? +Writing `pub(crate)` is misleading when it's redundant due to the parent +module's visibility. + +### Example +``` +mod internal { + pub(crate) fn internal_fn() { } +} +``` +This function is not visible outside the module and it can be declared with `pub` or +private visibility +``` +mod internal { + pub fn internal_fn() { } +} +``` \ No newline at end of file diff --git a/src/docs/redundant_slicing.txt b/src/docs/redundant_slicing.txt new file mode 100644 index 0000000000000..6798911ed76c0 --- /dev/null +++ b/src/docs/redundant_slicing.txt @@ -0,0 +1,24 @@ +### What it does +Checks for redundant slicing expressions which use the full range, and +do not change the type. + +### Why is this bad? +It unnecessarily adds complexity to the expression. + +### Known problems +If the type being sliced has an implementation of `Index` +that actually changes anything then it can't be removed. However, this would be surprising +to people reading the code and should have a note with it. + +### Example +``` +fn get_slice(x: &[u32]) -> &[u32] { + &x[..] +} +``` +Use instead: +``` +fn get_slice(x: &[u32]) -> &[u32] { + x +} +``` \ No newline at end of file diff --git a/src/docs/redundant_static_lifetimes.txt b/src/docs/redundant_static_lifetimes.txt new file mode 100644 index 0000000000000..edb8e7b5c62bf --- /dev/null +++ b/src/docs/redundant_static_lifetimes.txt @@ -0,0 +1,19 @@ +### What it does +Checks for constants and statics with an explicit `'static` lifetime. + +### Why is this bad? +Adding `'static` to every reference can create very +complicated types. + +### Example +``` +const FOO: &'static [(&'static str, &'static str, fn(&Bar) -> bool)] = +&[...] +static FOO: &'static [(&'static str, &'static str, fn(&Bar) -> bool)] = +&[...] +``` +This code can be rewritten as +``` + const FOO: &[(&str, &str, fn(&Bar) -> bool)] = &[...] + static FOO: &[(&str, &str, fn(&Bar) -> bool)] = &[...] +``` \ No newline at end of file diff --git a/src/docs/ref_binding_to_reference.txt b/src/docs/ref_binding_to_reference.txt new file mode 100644 index 0000000000000..dc391cd988e58 --- /dev/null +++ b/src/docs/ref_binding_to_reference.txt @@ -0,0 +1,21 @@ +### What it does +Checks for `ref` bindings which create a reference to a reference. + +### Why is this bad? +The address-of operator at the use site is clearer about the need for a reference. + +### Example +``` +let x = Some(""); +if let Some(ref x) = x { + // use `x` here +} +``` + +Use instead: +``` +let x = Some(""); +if let Some(x) = x { + // use `&x` here +} +``` \ No newline at end of file diff --git a/src/docs/ref_option_ref.txt b/src/docs/ref_option_ref.txt new file mode 100644 index 0000000000000..951c7bd7f7ec6 --- /dev/null +++ b/src/docs/ref_option_ref.txt @@ -0,0 +1,19 @@ +### What it does +Checks for usage of `&Option<&T>`. + +### Why is this bad? +Since `&` is Copy, it's useless to have a +reference on `Option<&T>`. + +### Known problems +It may be irrelevant to use this lint on +public API code as it will make a breaking change to apply it. + +### Example +``` +let x: &Option<&u32> = &Some(&0u32); +``` +Use instead: +``` +let x: Option<&u32> = Some(&0u32); +``` \ No newline at end of file diff --git a/src/docs/repeat_once.txt b/src/docs/repeat_once.txt new file mode 100644 index 0000000000000..3ba189c1945d7 --- /dev/null +++ b/src/docs/repeat_once.txt @@ -0,0 +1,25 @@ +### What it does +Checks for usage of `.repeat(1)` and suggest the following method for each types. +- `.to_string()` for `str` +- `.clone()` for `String` +- `.to_vec()` for `slice` + +The lint will evaluate constant expressions and values as arguments of `.repeat(..)` and emit a message if +they are equivalent to `1`. (Related discussion in [rust-clippy#7306](https://github.com/rust-lang/rust-clippy/issues/7306)) + +### Why is this bad? +For example, `String.repeat(1)` is equivalent to `.clone()`. If cloning +the string is the intention behind this, `clone()` should be used. + +### Example +``` +fn main() { + let x = String::from("hello world").repeat(1); +} +``` +Use instead: +``` +fn main() { + let x = String::from("hello world").clone(); +} +``` \ No newline at end of file diff --git a/src/docs/rest_pat_in_fully_bound_structs.txt b/src/docs/rest_pat_in_fully_bound_structs.txt new file mode 100644 index 0000000000000..40ebbe754a372 --- /dev/null +++ b/src/docs/rest_pat_in_fully_bound_structs.txt @@ -0,0 +1,24 @@ +### What it does +Checks for unnecessary '..' pattern binding on struct when all fields are explicitly matched. + +### Why is this bad? +Correctness and readability. It's like having a wildcard pattern after +matching all enum variants explicitly. + +### Example +``` +let a = A { a: 5 }; + +match a { + A { a: 5, .. } => {}, + _ => {}, +} +``` + +Use instead: +``` +match a { + A { a: 5 } => {}, + _ => {}, +} +``` \ No newline at end of file diff --git a/src/docs/result_large_err.txt b/src/docs/result_large_err.txt new file mode 100644 index 0000000000000..e5fab3c5cfcfa --- /dev/null +++ b/src/docs/result_large_err.txt @@ -0,0 +1,36 @@ +### What it does +Checks for functions that return `Result` with an unusually large +`Err`-variant. + +### Why is this bad? +A `Result` is at least as large as the `Err`-variant. While we +expect that variant to be seldomly used, the compiler needs to reserve +and move that much memory every single time. + +### Known problems +The size determined by Clippy is platform-dependent. + +### Examples +``` +pub enum ParseError { + UnparsedBytes([u8; 512]), + UnexpectedEof, +} + +// The `Result` has at least 512 bytes, even in the `Ok`-case +pub fn parse() -> Result<(), ParseError> { + Ok(()) +} +``` +should be +``` +pub enum ParseError { + UnparsedBytes(Box<[u8; 512]>), + UnexpectedEof, +} + +// The `Result` is slightly larger than a pointer +pub fn parse() -> Result<(), ParseError> { + Ok(()) +} +``` \ No newline at end of file diff --git a/src/docs/result_map_or_into_option.txt b/src/docs/result_map_or_into_option.txt new file mode 100644 index 0000000000000..899d98c307c8f --- /dev/null +++ b/src/docs/result_map_or_into_option.txt @@ -0,0 +1,16 @@ +### What it does +Checks for usage of `_.map_or(None, Some)`. + +### Why is this bad? +Readability, this can be written more concisely as +`_.ok()`. + +### Example +``` +assert_eq!(Some(1), r.map_or(None, Some)); +``` + +Use instead: +``` +assert_eq!(Some(1), r.ok()); +``` \ No newline at end of file diff --git a/src/docs/result_map_unit_fn.txt b/src/docs/result_map_unit_fn.txt new file mode 100644 index 0000000000000..3455c5c1f9b8a --- /dev/null +++ b/src/docs/result_map_unit_fn.txt @@ -0,0 +1,26 @@ +### What it does +Checks for usage of `result.map(f)` where f is a function +or closure that returns the unit type `()`. + +### Why is this bad? +Readability, this can be written more clearly with +an if let statement + +### Example +``` +let x: Result = do_stuff(); +x.map(log_err_msg); +x.map(|msg| log_err_msg(format_msg(msg))); +``` + +The correct use would be: + +``` +let x: Result = do_stuff(); +if let Ok(msg) = x { + log_err_msg(msg); +}; +if let Ok(msg) = x { + log_err_msg(format_msg(msg)); +}; +``` \ No newline at end of file diff --git a/src/docs/result_unit_err.txt b/src/docs/result_unit_err.txt new file mode 100644 index 0000000000000..7c8ec2ffcf948 --- /dev/null +++ b/src/docs/result_unit_err.txt @@ -0,0 +1,40 @@ +### What it does +Checks for public functions that return a `Result` +with an `Err` type of `()`. It suggests using a custom type that +implements `std::error::Error`. + +### Why is this bad? +Unit does not implement `Error` and carries no +further information about what went wrong. + +### Known problems +Of course, this lint assumes that `Result` is used +for a fallible operation (which is after all the intended use). However +code may opt to (mis)use it as a basic two-variant-enum. In that case, +the suggestion is misguided, and the code should use a custom enum +instead. + +### Examples +``` +pub fn read_u8() -> Result { Err(()) } +``` +should become +``` +use std::fmt; + +#[derive(Debug)] +pub struct EndOfStream; + +impl fmt::Display for EndOfStream { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "End of Stream") + } +} + +impl std::error::Error for EndOfStream { } + +pub fn read_u8() -> Result { Err(EndOfStream) } +``` + +Note that there are crates that simplify creating the error type, e.g. +[`thiserror`](https://docs.rs/thiserror). \ No newline at end of file diff --git a/src/docs/return_self_not_must_use.txt b/src/docs/return_self_not_must_use.txt new file mode 100644 index 0000000000000..4a4fd2c6e517b --- /dev/null +++ b/src/docs/return_self_not_must_use.txt @@ -0,0 +1,46 @@ +### What it does +This lint warns when a method returning `Self` doesn't have the `#[must_use]` attribute. + +### Why is this bad? +Methods returning `Self` often create new values, having the `#[must_use]` attribute +prevents users from "forgetting" to use the newly created value. + +The `#[must_use]` attribute can be added to the type itself to ensure that instances +are never forgotten. Functions returning a type marked with `#[must_use]` will not be +linted, as the usage is already enforced by the type attribute. + +### Limitations +This lint is only applied on methods taking a `self` argument. It would be mostly noise +if it was added on constructors for example. + +### Example +``` +pub struct Bar; +impl Bar { + // Missing attribute + pub fn bar(&self) -> Self { + Self + } +} +``` + +Use instead: +``` +// It's better to have the `#[must_use]` attribute on the method like this: +pub struct Bar; +impl Bar { + #[must_use] + pub fn bar(&self) -> Self { + Self + } +} + +// Or on the type definition like this: +#[must_use] +pub struct Bar; +impl Bar { + pub fn bar(&self) -> Self { + Self + } +} +``` \ No newline at end of file diff --git a/src/docs/reversed_empty_ranges.txt b/src/docs/reversed_empty_ranges.txt new file mode 100644 index 0000000000000..39f4811938668 --- /dev/null +++ b/src/docs/reversed_empty_ranges.txt @@ -0,0 +1,26 @@ +### What it does +Checks for range expressions `x..y` where both `x` and `y` +are constant and `x` is greater or equal to `y`. + +### Why is this bad? +Empty ranges yield no values so iterating them is a no-op. +Moreover, trying to use a reversed range to index a slice will panic at run-time. + +### Example +``` +fn main() { + (10..=0).for_each(|x| println!("{}", x)); + + let arr = [1, 2, 3, 4, 5]; + let sub = &arr[3..1]; +} +``` +Use instead: +``` +fn main() { + (0..=10).rev().for_each(|x| println!("{}", x)); + + let arr = [1, 2, 3, 4, 5]; + let sub = &arr[1..3]; +} +``` \ No newline at end of file diff --git a/src/docs/same_functions_in_if_condition.txt b/src/docs/same_functions_in_if_condition.txt new file mode 100644 index 0000000000000..a0a90eec681e6 --- /dev/null +++ b/src/docs/same_functions_in_if_condition.txt @@ -0,0 +1,41 @@ +### What it does +Checks for consecutive `if`s with the same function call. + +### Why is this bad? +This is probably a copy & paste error. +Despite the fact that function can have side effects and `if` works as +intended, such an approach is implicit and can be considered a "code smell". + +### Example +``` +if foo() == bar { + … +} else if foo() == bar { + … +} +``` + +This probably should be: +``` +if foo() == bar { + … +} else if foo() == baz { + … +} +``` + +or if the original code was not a typo and called function mutates a state, +consider move the mutation out of the `if` condition to avoid similarity to +a copy & paste error: + +``` +let first = foo(); +if first == bar { + … +} else { + let second = foo(); + if second == bar { + … + } +} +``` \ No newline at end of file diff --git a/src/docs/same_item_push.txt b/src/docs/same_item_push.txt new file mode 100644 index 0000000000000..7e724073f8aa7 --- /dev/null +++ b/src/docs/same_item_push.txt @@ -0,0 +1,29 @@ +### What it does +Checks whether a for loop is being used to push a constant +value into a Vec. + +### Why is this bad? +This kind of operation can be expressed more succinctly with +`vec![item; SIZE]` or `vec.resize(NEW_SIZE, item)` and using these alternatives may also +have better performance. + +### Example +``` +let item1 = 2; +let item2 = 3; +let mut vec: Vec = Vec::new(); +for _ in 0..20 { + vec.push(item1); +} +for _ in 0..30 { + vec.push(item2); +} +``` + +Use instead: +``` +let item1 = 2; +let item2 = 3; +let mut vec: Vec = vec![item1; 20]; +vec.resize(20 + 30, item2); +``` \ No newline at end of file diff --git a/src/docs/same_name_method.txt b/src/docs/same_name_method.txt new file mode 100644 index 0000000000000..792dd717fc645 --- /dev/null +++ b/src/docs/same_name_method.txt @@ -0,0 +1,23 @@ +### What it does +It lints if a struct has two methods with the same name: +one from a trait, another not from trait. + +### Why is this bad? +Confusing. + +### Example +``` +trait T { + fn foo(&self) {} +} + +struct S; + +impl T for S { + fn foo(&self) {} +} + +impl S { + fn foo(&self) {} +} +``` \ No newline at end of file diff --git a/src/docs/search_is_some.txt b/src/docs/search_is_some.txt new file mode 100644 index 0000000000000..67292d54585f2 --- /dev/null +++ b/src/docs/search_is_some.txt @@ -0,0 +1,24 @@ +### What it does +Checks for an iterator or string search (such as `find()`, +`position()`, or `rposition()`) followed by a call to `is_some()` or `is_none()`. + +### Why is this bad? +Readability, this can be written more concisely as: +* `_.any(_)`, or `_.contains(_)` for `is_some()`, +* `!_.any(_)`, or `!_.contains(_)` for `is_none()`. + +### Example +``` +let vec = vec![1]; +vec.iter().find(|x| **x == 0).is_some(); + +"hello world".find("world").is_none(); +``` + +Use instead: +``` +let vec = vec![1]; +vec.iter().any(|x| *x == 0); + +!"hello world".contains("world"); +``` \ No newline at end of file diff --git a/src/docs/self_assignment.txt b/src/docs/self_assignment.txt new file mode 100644 index 0000000000000..ea60ea077ab5f --- /dev/null +++ b/src/docs/self_assignment.txt @@ -0,0 +1,32 @@ +### What it does +Checks for explicit self-assignments. + +### Why is this bad? +Self-assignments are redundant and unlikely to be +intentional. + +### Known problems +If expression contains any deref coercions or +indexing operations they are assumed not to have any side effects. + +### Example +``` +struct Event { + x: i32, +} + +fn copy_position(a: &mut Event, b: &Event) { + a.x = a.x; +} +``` + +Should be: +``` +struct Event { + x: i32, +} + +fn copy_position(a: &mut Event, b: &Event) { + a.x = b.x; +} +``` \ No newline at end of file diff --git a/src/docs/self_named_constructors.txt b/src/docs/self_named_constructors.txt new file mode 100644 index 0000000000000..a01669a84542d --- /dev/null +++ b/src/docs/self_named_constructors.txt @@ -0,0 +1,26 @@ +### What it does +Warns when constructors have the same name as their types. + +### Why is this bad? +Repeating the name of the type is redundant. + +### Example +``` +struct Foo {} + +impl Foo { + pub fn foo() -> Foo { + Foo {} + } +} +``` +Use instead: +``` +struct Foo {} + +impl Foo { + pub fn new() -> Foo { + Foo {} + } +} +``` \ No newline at end of file diff --git a/src/docs/self_named_module_files.txt b/src/docs/self_named_module_files.txt new file mode 100644 index 0000000000000..73e8051362883 --- /dev/null +++ b/src/docs/self_named_module_files.txt @@ -0,0 +1,22 @@ +### What it does +Checks that module layout uses only `mod.rs` files. + +### Why is this bad? +Having multiple module layout styles in a project can be confusing. + +### Example +``` +src/ + stuff/ + stuff_files.rs + stuff.rs + lib.rs +``` +Use instead: +``` +src/ + stuff/ + stuff_files.rs + mod.rs + lib.rs +``` \ No newline at end of file diff --git a/src/docs/semicolon_if_nothing_returned.txt b/src/docs/semicolon_if_nothing_returned.txt new file mode 100644 index 0000000000000..30c963ca211b3 --- /dev/null +++ b/src/docs/semicolon_if_nothing_returned.txt @@ -0,0 +1,20 @@ +### What it does +Looks for blocks of expressions and fires if the last expression returns +`()` but is not followed by a semicolon. + +### Why is this bad? +The semicolon might be optional but when extending the block with new +code, it doesn't require a change in previous last line. + +### Example +``` +fn main() { + println!("Hello world") +} +``` +Use instead: +``` +fn main() { + println!("Hello world"); +} +``` \ No newline at end of file diff --git a/src/docs/separated_literal_suffix.txt b/src/docs/separated_literal_suffix.txt new file mode 100644 index 0000000000000..226a6b8a98766 --- /dev/null +++ b/src/docs/separated_literal_suffix.txt @@ -0,0 +1,17 @@ +### What it does +Warns if literal suffixes are separated by an underscore. +To enforce separated literal suffix style, +see the `unseparated_literal_suffix` lint. + +### Why is this bad? +Suffix style should be consistent. + +### Example +``` +123832_i32 +``` + +Use instead: +``` +123832i32 +``` \ No newline at end of file diff --git a/src/docs/serde_api_misuse.txt b/src/docs/serde_api_misuse.txt new file mode 100644 index 0000000000000..8a3c89ac11adc --- /dev/null +++ b/src/docs/serde_api_misuse.txt @@ -0,0 +1,10 @@ +### What it does +Checks for mis-uses of the serde API. + +### Why is this bad? +Serde is very finnicky about how its API should be +used, but the type system can't be used to enforce it (yet?). + +### Example +Implementing `Visitor::visit_string` but not +`Visitor::visit_str`. \ No newline at end of file diff --git a/src/docs/shadow_reuse.txt b/src/docs/shadow_reuse.txt new file mode 100644 index 0000000000000..9eb8e7ad164bb --- /dev/null +++ b/src/docs/shadow_reuse.txt @@ -0,0 +1,20 @@ +### What it does +Checks for bindings that shadow other bindings already in +scope, while reusing the original value. + +### Why is this bad? +Not too much, in fact it's a common pattern in Rust +code. Still, some argue that name shadowing like this hurts readability, +because a value may be bound to different things depending on position in +the code. + +### Example +``` +let x = 2; +let x = x + 1; +``` +use different variable name: +``` +let x = 2; +let y = x + 1; +``` \ No newline at end of file diff --git a/src/docs/shadow_same.txt b/src/docs/shadow_same.txt new file mode 100644 index 0000000000000..3cd96f560a5e2 --- /dev/null +++ b/src/docs/shadow_same.txt @@ -0,0 +1,18 @@ +### What it does +Checks for bindings that shadow other bindings already in +scope, while just changing reference level or mutability. + +### Why is this bad? +Not much, in fact it's a very common pattern in Rust +code. Still, some may opt to avoid it in their code base, they can set this +lint to `Warn`. + +### Example +``` +let x = &x; +``` + +Use instead: +``` +let y = &x; // use different variable name +``` \ No newline at end of file diff --git a/src/docs/shadow_unrelated.txt b/src/docs/shadow_unrelated.txt new file mode 100644 index 0000000000000..436251c520a98 --- /dev/null +++ b/src/docs/shadow_unrelated.txt @@ -0,0 +1,22 @@ +### What it does +Checks for bindings that shadow other bindings already in +scope, either without an initialization or with one that does not even use +the original value. + +### Why is this bad? +Name shadowing can hurt readability, especially in +large code bases, because it is easy to lose track of the active binding at +any place in the code. This can be alleviated by either giving more specific +names to bindings or introducing more scopes to contain the bindings. + +### Example +``` +let x = y; +let x = z; // shadows the earlier binding +``` + +Use instead: +``` +let x = y; +let w = z; // use different variable name +``` \ No newline at end of file diff --git a/src/docs/short_circuit_statement.txt b/src/docs/short_circuit_statement.txt new file mode 100644 index 0000000000000..31492bed03d4b --- /dev/null +++ b/src/docs/short_circuit_statement.txt @@ -0,0 +1,14 @@ +### What it does +Checks for the use of short circuit boolean conditions as +a +statement. + +### Why is this bad? +Using a short circuit boolean condition as a statement +may hide the fact that the second part is executed or not depending on the +outcome of the first part. + +### Example +``` +f() && g(); // We should write `if f() { g(); }`. +``` \ No newline at end of file diff --git a/src/docs/should_implement_trait.txt b/src/docs/should_implement_trait.txt new file mode 100644 index 0000000000000..02e74751ae034 --- /dev/null +++ b/src/docs/should_implement_trait.txt @@ -0,0 +1,22 @@ +### What it does +Checks for methods that should live in a trait +implementation of a `std` trait (see [llogiq's blog +post](http://llogiq.github.io/2015/07/30/traits.html) for further +information) instead of an inherent implementation. + +### Why is this bad? +Implementing the traits improve ergonomics for users of +the code, often with very little cost. Also people seeing a `mul(...)` +method +may expect `*` to work equally, so you should have good reason to disappoint +them. + +### Example +``` +struct X; +impl X { + fn add(&self, other: &X) -> X { + // .. + } +} +``` \ No newline at end of file diff --git a/src/docs/significant_drop_in_scrutinee.txt b/src/docs/significant_drop_in_scrutinee.txt new file mode 100644 index 0000000000000..f869def0ddb7c --- /dev/null +++ b/src/docs/significant_drop_in_scrutinee.txt @@ -0,0 +1,43 @@ +### What it does +Check for temporaries returned from function calls in a match scrutinee that have the +`clippy::has_significant_drop` attribute. + +### Why is this bad? +The `clippy::has_significant_drop` attribute can be added to types whose Drop impls have +an important side-effect, such as unlocking a mutex, making it important for users to be +able to accurately understand their lifetimes. When a temporary is returned in a function +call in a match scrutinee, its lifetime lasts until the end of the match block, which may +be surprising. + +For `Mutex`es this can lead to a deadlock. This happens when the match scrutinee uses a +function call that returns a `MutexGuard` and then tries to lock again in one of the match +arms. In that case the `MutexGuard` in the scrutinee will not be dropped until the end of +the match block and thus will not unlock. + +### Example +``` +let mutex = Mutex::new(State {}); + +match mutex.lock().unwrap().foo() { + true => { + mutex.lock().unwrap().bar(); // Deadlock! + } + false => {} +}; + +println!("All done!"); +``` +Use instead: +``` +let mutex = Mutex::new(State {}); + +let is_foo = mutex.lock().unwrap().foo(); +match is_foo { + true => { + mutex.lock().unwrap().bar(); + } + false => {} +}; + +println!("All done!"); +``` \ No newline at end of file diff --git a/src/docs/similar_names.txt b/src/docs/similar_names.txt new file mode 100644 index 0000000000000..13aca9c0bb75b --- /dev/null +++ b/src/docs/similar_names.txt @@ -0,0 +1,12 @@ +### What it does +Checks for names that are very similar and thus confusing. + +### Why is this bad? +It's hard to distinguish between names that differ only +by a single character. + +### Example +``` +let checked_exp = something; +let checked_expr = something_else; +``` \ No newline at end of file diff --git a/src/docs/single_char_add_str.txt b/src/docs/single_char_add_str.txt new file mode 100644 index 0000000000000..cf23dc0c89bbb --- /dev/null +++ b/src/docs/single_char_add_str.txt @@ -0,0 +1,18 @@ +### What it does +Warns when using `push_str`/`insert_str` with a single-character string literal +where `push`/`insert` with a `char` would work fine. + +### Why is this bad? +It's less clear that we are pushing a single character. + +### Example +``` +string.insert_str(0, "R"); +string.push_str("R"); +``` + +Use instead: +``` +string.insert(0, 'R'); +string.push('R'); +``` \ No newline at end of file diff --git a/src/docs/single_char_lifetime_names.txt b/src/docs/single_char_lifetime_names.txt new file mode 100644 index 0000000000000..92dd24bf247ec --- /dev/null +++ b/src/docs/single_char_lifetime_names.txt @@ -0,0 +1,28 @@ +### What it does +Checks for lifetimes with names which are one character +long. + +### Why is this bad? +A single character is likely not enough to express the +purpose of a lifetime. Using a longer name can make code +easier to understand, especially for those who are new to +Rust. + +### Known problems +Rust programmers and learning resources tend to use single +character lifetimes, so this lint is at odds with the +ecosystem at large. In addition, the lifetime's purpose may +be obvious or, rarely, expressible in one character. + +### Example +``` +struct DiagnosticCtx<'a> { + source: &'a str, +} +``` +Use instead: +``` +struct DiagnosticCtx<'src> { + source: &'src str, +} +``` \ No newline at end of file diff --git a/src/docs/single_char_pattern.txt b/src/docs/single_char_pattern.txt new file mode 100644 index 0000000000000..9e5ad1e7d6395 --- /dev/null +++ b/src/docs/single_char_pattern.txt @@ -0,0 +1,20 @@ +### What it does +Checks for string methods that receive a single-character +`str` as an argument, e.g., `_.split("x")`. + +### Why is this bad? +Performing these methods using a `char` is faster than +using a `str`. + +### Known problems +Does not catch multi-byte unicode characters. + +### Example +``` +_.split("x"); +``` + +Use instead: +``` +_.split('x'); +``` \ No newline at end of file diff --git a/src/docs/single_component_path_imports.txt b/src/docs/single_component_path_imports.txt new file mode 100644 index 0000000000000..3a026388183e1 --- /dev/null +++ b/src/docs/single_component_path_imports.txt @@ -0,0 +1,21 @@ +### What it does +Checking for imports with single component use path. + +### Why is this bad? +Import with single component use path such as `use cratename;` +is not necessary, and thus should be removed. + +### Example +``` +use regex; + +fn main() { + regex::Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap(); +} +``` +Better as +``` +fn main() { + regex::Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap(); +} +``` \ No newline at end of file diff --git a/src/docs/single_element_loop.txt b/src/docs/single_element_loop.txt new file mode 100644 index 0000000000000..6f0c15a85f774 --- /dev/null +++ b/src/docs/single_element_loop.txt @@ -0,0 +1,21 @@ +### What it does +Checks whether a for loop has a single element. + +### Why is this bad? +There is no reason to have a loop of a +single element. + +### Example +``` +let item1 = 2; +for item in &[item1] { + println!("{}", item); +} +``` + +Use instead: +``` +let item1 = 2; +let item = &item1; +println!("{}", item); +``` \ No newline at end of file diff --git a/src/docs/single_match.txt b/src/docs/single_match.txt new file mode 100644 index 0000000000000..31dde4da8489c --- /dev/null +++ b/src/docs/single_match.txt @@ -0,0 +1,21 @@ +### What it does +Checks for matches with a single arm where an `if let` +will usually suffice. + +### Why is this bad? +Just readability – `if let` nests less than a `match`. + +### Example +``` +match x { + Some(ref foo) => bar(foo), + _ => (), +} +``` + +Use instead: +``` +if let Some(ref foo) = x { + bar(foo); +} +``` \ No newline at end of file diff --git a/src/docs/single_match_else.txt b/src/docs/single_match_else.txt new file mode 100644 index 0000000000000..29a447af09b86 --- /dev/null +++ b/src/docs/single_match_else.txt @@ -0,0 +1,29 @@ +### What it does +Checks for matches with two arms where an `if let else` will +usually suffice. + +### Why is this bad? +Just readability – `if let` nests less than a `match`. + +### Known problems +Personal style preferences may differ. + +### Example +Using `match`: + +``` +match x { + Some(ref foo) => bar(foo), + _ => bar(&other_ref), +} +``` + +Using `if let` with `else`: + +``` +if let Some(ref foo) = x { + bar(foo); +} else { + bar(&other_ref); +} +``` \ No newline at end of file diff --git a/src/docs/size_of_in_element_count.txt b/src/docs/size_of_in_element_count.txt new file mode 100644 index 0000000000000..d893ec6a2a014 --- /dev/null +++ b/src/docs/size_of_in_element_count.txt @@ -0,0 +1,16 @@ +### What it does +Detects expressions where +`size_of::` or `size_of_val::` is used as a +count of elements of type `T` + +### Why is this bad? +These functions expect a count +of `T` and not a number of bytes + +### Example +``` +const SIZE: usize = 128; +let x = [2u8; SIZE]; +let mut y = [2u8; SIZE]; +unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; +``` \ No newline at end of file diff --git a/src/docs/skip_while_next.txt b/src/docs/skip_while_next.txt new file mode 100644 index 0000000000000..1ec8a3a28d5b0 --- /dev/null +++ b/src/docs/skip_while_next.txt @@ -0,0 +1,16 @@ +### What it does +Checks for usage of `_.skip_while(condition).next()`. + +### Why is this bad? +Readability, this can be written more concisely as +`_.find(!condition)`. + +### Example +``` +vec.iter().skip_while(|x| **x == 0).next(); +``` + +Use instead: +``` +vec.iter().find(|x| **x != 0); +``` \ No newline at end of file diff --git a/src/docs/slow_vector_initialization.txt b/src/docs/slow_vector_initialization.txt new file mode 100644 index 0000000000000..53442e1796541 --- /dev/null +++ b/src/docs/slow_vector_initialization.txt @@ -0,0 +1,24 @@ +### What it does +Checks slow zero-filled vector initialization + +### Why is this bad? +These structures are non-idiomatic and less efficient than simply using +`vec![0; len]`. + +### Example +``` +let mut vec1 = Vec::with_capacity(len); +vec1.resize(len, 0); + +let mut vec1 = Vec::with_capacity(len); +vec1.resize(vec1.capacity(), 0); + +let mut vec2 = Vec::with_capacity(len); +vec2.extend(repeat(0).take(len)); +``` + +Use instead: +``` +let mut vec1 = vec![0; len]; +let mut vec2 = vec![0; len]; +``` \ No newline at end of file diff --git a/src/docs/stable_sort_primitive.txt b/src/docs/stable_sort_primitive.txt new file mode 100644 index 0000000000000..6465dbee46b10 --- /dev/null +++ b/src/docs/stable_sort_primitive.txt @@ -0,0 +1,31 @@ +### What it does +When sorting primitive values (integers, bools, chars, as well +as arrays, slices, and tuples of such items), it is typically better to +use an unstable sort than a stable sort. + +### Why is this bad? +Typically, using a stable sort consumes more memory and cpu cycles. +Because values which compare equal are identical, preserving their +relative order (the guarantee that a stable sort provides) means +nothing, while the extra costs still apply. + +### Known problems + +As pointed out in +[issue #8241](https://github.com/rust-lang/rust-clippy/issues/8241), +a stable sort can instead be significantly faster for certain scenarios +(eg. when a sorted vector is extended with new data and resorted). + +For more information and benchmarking results, please refer to the +issue linked above. + +### Example +``` +let mut vec = vec![2, 1, 3]; +vec.sort(); +``` +Use instead: +``` +let mut vec = vec![2, 1, 3]; +vec.sort_unstable(); +``` \ No newline at end of file diff --git a/src/docs/std_instead_of_alloc.txt b/src/docs/std_instead_of_alloc.txt new file mode 100644 index 0000000000000..c2d32704e5055 --- /dev/null +++ b/src/docs/std_instead_of_alloc.txt @@ -0,0 +1,18 @@ +### What it does + +Finds items imported through `std` when available through `alloc`. + +### Why is this bad? + +Crates which have `no_std` compatibility and require alloc may wish to ensure types are imported from +alloc to ensure disabling `std` does not cause the crate to fail to compile. This lint is also useful +for crates migrating to become `no_std` compatible. + +### Example +``` +use std::vec::Vec; +``` +Use instead: +``` +use alloc::vec::Vec; +``` \ No newline at end of file diff --git a/src/docs/std_instead_of_core.txt b/src/docs/std_instead_of_core.txt new file mode 100644 index 0000000000000..f1e1518c6a62a --- /dev/null +++ b/src/docs/std_instead_of_core.txt @@ -0,0 +1,18 @@ +### What it does + +Finds items imported through `std` when available through `core`. + +### Why is this bad? + +Crates which have `no_std` compatibility may wish to ensure types are imported from core to ensure +disabling `std` does not cause the crate to fail to compile. This lint is also useful for crates +migrating to become `no_std` compatible. + +### Example +``` +use std::hash::Hasher; +``` +Use instead: +``` +use core::hash::Hasher; +``` \ No newline at end of file diff --git a/src/docs/str_to_string.txt b/src/docs/str_to_string.txt new file mode 100644 index 0000000000000..a24755223747b --- /dev/null +++ b/src/docs/str_to_string.txt @@ -0,0 +1,18 @@ +### What it does +This lint checks for `.to_string()` method calls on values of type `&str`. + +### Why is this bad? +The `to_string` method is also used on other types to convert them to a string. +When called on a `&str` it turns the `&str` into the owned variant `String`, which can be better +expressed with `.to_owned()`. + +### Example +``` +// example code where clippy issues a warning +let _ = "str".to_string(); +``` +Use instead: +``` +// example code which does not raise clippy warning +let _ = "str".to_owned(); +``` \ No newline at end of file diff --git a/src/docs/string_add.txt b/src/docs/string_add.txt new file mode 100644 index 0000000000000..23dafd0d0333d --- /dev/null +++ b/src/docs/string_add.txt @@ -0,0 +1,27 @@ +### What it does +Checks for all instances of `x + _` where `x` is of type +`String`, but only if [`string_add_assign`](#string_add_assign) does *not* +match. + +### Why is this bad? +It's not bad in and of itself. However, this particular +`Add` implementation is asymmetric (the other operand need not be `String`, +but `x` does), while addition as mathematically defined is symmetric, also +the `String::push_str(_)` function is a perfectly good replacement. +Therefore, some dislike it and wish not to have it in their code. + +That said, other people think that string addition, having a long tradition +in other languages is actually fine, which is why we decided to make this +particular lint `allow` by default. + +### Example +``` +let x = "Hello".to_owned(); +x + ", World"; +``` + +Use instead: +``` +let mut x = "Hello".to_owned(); +x.push_str(", World"); +``` \ No newline at end of file diff --git a/src/docs/string_add_assign.txt b/src/docs/string_add_assign.txt new file mode 100644 index 0000000000000..7438be855db8c --- /dev/null +++ b/src/docs/string_add_assign.txt @@ -0,0 +1,17 @@ +### What it does +Checks for string appends of the form `x = x + y` (without +`let`!). + +### Why is this bad? +It's not really bad, but some people think that the +`.push_str(_)` method is more readable. + +### Example +``` +let mut x = "Hello".to_owned(); +x = x + ", World"; + +// More readable +x += ", World"; +x.push_str(", World"); +``` \ No newline at end of file diff --git a/src/docs/string_extend_chars.txt b/src/docs/string_extend_chars.txt new file mode 100644 index 0000000000000..619ea3e118673 --- /dev/null +++ b/src/docs/string_extend_chars.txt @@ -0,0 +1,23 @@ +### What it does +Checks for the use of `.extend(s.chars())` where s is a +`&str` or `String`. + +### Why is this bad? +`.push_str(s)` is clearer + +### Example +``` +let abc = "abc"; +let def = String::from("def"); +let mut s = String::new(); +s.extend(abc.chars()); +s.extend(def.chars()); +``` +The correct use would be: +``` +let abc = "abc"; +let def = String::from("def"); +let mut s = String::new(); +s.push_str(abc); +s.push_str(&def); +``` \ No newline at end of file diff --git a/src/docs/string_from_utf8_as_bytes.txt b/src/docs/string_from_utf8_as_bytes.txt new file mode 100644 index 0000000000000..9102d73471cb2 --- /dev/null +++ b/src/docs/string_from_utf8_as_bytes.txt @@ -0,0 +1,15 @@ +### What it does +Check if the string is transformed to byte array and casted back to string. + +### Why is this bad? +It's unnecessary, the string can be used directly. + +### Example +``` +std::str::from_utf8(&"Hello World!".as_bytes()[6..11]).unwrap(); +``` + +Use instead: +``` +&"Hello World!"[6..11]; +``` \ No newline at end of file diff --git a/src/docs/string_lit_as_bytes.txt b/src/docs/string_lit_as_bytes.txt new file mode 100644 index 0000000000000..a125b97ed6567 --- /dev/null +++ b/src/docs/string_lit_as_bytes.txt @@ -0,0 +1,39 @@ +### What it does +Checks for the `as_bytes` method called on string literals +that contain only ASCII characters. + +### Why is this bad? +Byte string literals (e.g., `b"foo"`) can be used +instead. They are shorter but less discoverable than `as_bytes()`. + +### Known problems +`"str".as_bytes()` and the suggested replacement of `b"str"` are not +equivalent because they have different types. The former is `&[u8]` +while the latter is `&[u8; 3]`. That means in general they will have a +different set of methods and different trait implementations. + +``` +fn f(v: Vec) {} + +f("...".as_bytes().to_owned()); // works +f(b"...".to_owned()); // does not work, because arg is [u8; 3] not Vec + +fn g(r: impl std::io::Read) {} + +g("...".as_bytes()); // works +g(b"..."); // does not work +``` + +The actual equivalent of `"str".as_bytes()` with the same type is not +`b"str"` but `&b"str"[..]`, which is a great deal of punctuation and not +more readable than a function call. + +### Example +``` +let bstr = "a byte string".as_bytes(); +``` + +Use instead: +``` +let bstr = b"a byte string"; +``` \ No newline at end of file diff --git a/src/docs/string_slice.txt b/src/docs/string_slice.txt new file mode 100644 index 0000000000000..3d9e49dd39eb7 --- /dev/null +++ b/src/docs/string_slice.txt @@ -0,0 +1,17 @@ +### What it does +Checks for slice operations on strings + +### Why is this bad? +UTF-8 characters span multiple bytes, and it is easy to inadvertently confuse character +counts and string indices. This may lead to panics, and should warrant some test cases +containing wide UTF-8 characters. This lint is most useful in code that should avoid +panics at all costs. + +### Known problems +Probably lots of false positives. If an index comes from a known valid position (e.g. +obtained via `char_indices` over the same string), it is totally OK. + +# Example +``` +&"Ölkanne"[1..]; +``` \ No newline at end of file diff --git a/src/docs/string_to_string.txt b/src/docs/string_to_string.txt new file mode 100644 index 0000000000000..deb7eebe7842c --- /dev/null +++ b/src/docs/string_to_string.txt @@ -0,0 +1,19 @@ +### What it does +This lint checks for `.to_string()` method calls on values of type `String`. + +### Why is this bad? +The `to_string` method is also used on other types to convert them to a string. +When called on a `String` it only clones the `String`, which can be better expressed with `.clone()`. + +### Example +``` +// example code where clippy issues a warning +let msg = String::from("Hello World"); +let _ = msg.to_string(); +``` +Use instead: +``` +// example code which does not raise clippy warning +let msg = String::from("Hello World"); +let _ = msg.clone(); +``` \ No newline at end of file diff --git a/src/docs/strlen_on_c_strings.txt b/src/docs/strlen_on_c_strings.txt new file mode 100644 index 0000000000000..0454abf55a204 --- /dev/null +++ b/src/docs/strlen_on_c_strings.txt @@ -0,0 +1,20 @@ +### What it does +Checks for usage of `libc::strlen` on a `CString` or `CStr` value, +and suggest calling `as_bytes().len()` or `to_bytes().len()` respectively instead. + +### Why is this bad? +This avoids calling an unsafe `libc` function. +Currently, it also avoids calculating the length. + +### Example +``` +use std::ffi::CString; +let cstring = CString::new("foo").expect("CString::new failed"); +let len = unsafe { libc::strlen(cstring.as_ptr()) }; +``` +Use instead: +``` +use std::ffi::CString; +let cstring = CString::new("foo").expect("CString::new failed"); +let len = cstring.as_bytes().len(); +``` \ No newline at end of file diff --git a/src/docs/struct_excessive_bools.txt b/src/docs/struct_excessive_bools.txt new file mode 100644 index 0000000000000..9e197c786201d --- /dev/null +++ b/src/docs/struct_excessive_bools.txt @@ -0,0 +1,29 @@ +### What it does +Checks for excessive +use of bools in structs. + +### Why is this bad? +Excessive bools in a struct +is often a sign that it's used as a state machine, +which is much better implemented as an enum. +If it's not the case, excessive bools usually benefit +from refactoring into two-variant enums for better +readability and API. + +### Example +``` +struct S { + is_pending: bool, + is_processing: bool, + is_finished: bool, +} +``` + +Use instead: +``` +enum S { + Pending, + Processing, + Finished, +} +``` \ No newline at end of file diff --git a/src/docs/suboptimal_flops.txt b/src/docs/suboptimal_flops.txt new file mode 100644 index 0000000000000..f1c9c665b085d --- /dev/null +++ b/src/docs/suboptimal_flops.txt @@ -0,0 +1,50 @@ +### What it does +Looks for floating-point expressions that +can be expressed using built-in methods to improve both +accuracy and performance. + +### Why is this bad? +Negatively impacts accuracy and performance. + +### Example +``` +use std::f32::consts::E; + +let a = 3f32; +let _ = (2f32).powf(a); +let _ = E.powf(a); +let _ = a.powf(1.0 / 2.0); +let _ = a.log(2.0); +let _ = a.log(10.0); +let _ = a.log(E); +let _ = a.powf(2.0); +let _ = a * 2.0 + 4.0; +let _ = if a < 0.0 { + -a +} else { + a +}; +let _ = if a < 0.0 { + a +} else { + -a +}; +``` + +is better expressed as + +``` +use std::f32::consts::E; + +let a = 3f32; +let _ = a.exp2(); +let _ = a.exp(); +let _ = a.sqrt(); +let _ = a.log2(); +let _ = a.log10(); +let _ = a.ln(); +let _ = a.powi(2); +let _ = a.mul_add(2.0, 4.0); +let _ = a.abs(); +let _ = -a.abs(); +``` \ No newline at end of file diff --git a/src/docs/suspicious_arithmetic_impl.txt b/src/docs/suspicious_arithmetic_impl.txt new file mode 100644 index 0000000000000..d67ff279346dc --- /dev/null +++ b/src/docs/suspicious_arithmetic_impl.txt @@ -0,0 +1,17 @@ +### What it does +Lints for suspicious operations in impls of arithmetic operators, e.g. +subtracting elements in an Add impl. + +### Why is this bad? +This is probably a typo or copy-and-paste error and not intended. + +### Example +``` +impl Add for Foo { + type Output = Foo; + + fn add(self, other: Foo) -> Foo { + Foo(self.0 - other.0) + } +} +``` \ No newline at end of file diff --git a/src/docs/suspicious_assignment_formatting.txt b/src/docs/suspicious_assignment_formatting.txt new file mode 100644 index 0000000000000..b889827cdf27f --- /dev/null +++ b/src/docs/suspicious_assignment_formatting.txt @@ -0,0 +1,12 @@ +### What it does +Checks for use of the non-existent `=*`, `=!` and `=-` +operators. + +### Why is this bad? +This is either a typo of `*=`, `!=` or `-=` or +confusing. + +### Example +``` +a =- 42; // confusing, should it be `a -= 42` or `a = -42`? +``` \ No newline at end of file diff --git a/src/docs/suspicious_else_formatting.txt b/src/docs/suspicious_else_formatting.txt new file mode 100644 index 0000000000000..3cf2f74868ebf --- /dev/null +++ b/src/docs/suspicious_else_formatting.txt @@ -0,0 +1,30 @@ +### What it does +Checks for formatting of `else`. It lints if the `else` +is followed immediately by a newline or the `else` seems to be missing. + +### Why is this bad? +This is probably some refactoring remnant, even if the +code is correct, it might look confusing. + +### Example +``` +if foo { +} { // looks like an `else` is missing here +} + +if foo { +} if bar { // looks like an `else` is missing here +} + +if foo { +} else + +{ // this is the `else` block of the previous `if`, but should it be? +} + +if foo { +} else + +if bar { // this is the `else` block of the previous `if`, but should it be? +} +``` \ No newline at end of file diff --git a/src/docs/suspicious_map.txt b/src/docs/suspicious_map.txt new file mode 100644 index 0000000000000..d8fa52c43fb0a --- /dev/null +++ b/src/docs/suspicious_map.txt @@ -0,0 +1,13 @@ +### What it does +Checks for calls to `map` followed by a `count`. + +### Why is this bad? +It looks suspicious. Maybe `map` was confused with `filter`. +If the `map` call is intentional, this should be rewritten +using `inspect`. Or, if you intend to drive the iterator to +completion, you can just use `for_each` instead. + +### Example +``` +let _ = (0..3).map(|x| x + 2).count(); +``` \ No newline at end of file diff --git a/src/docs/suspicious_op_assign_impl.txt b/src/docs/suspicious_op_assign_impl.txt new file mode 100644 index 0000000000000..81abfbecae073 --- /dev/null +++ b/src/docs/suspicious_op_assign_impl.txt @@ -0,0 +1,15 @@ +### What it does +Lints for suspicious operations in impls of OpAssign, e.g. +subtracting elements in an AddAssign impl. + +### Why is this bad? +This is probably a typo or copy-and-paste error and not intended. + +### Example +``` +impl AddAssign for Foo { + fn add_assign(&mut self, other: Foo) { + *self = *self - other; + } +} +``` \ No newline at end of file diff --git a/src/docs/suspicious_operation_groupings.txt b/src/docs/suspicious_operation_groupings.txt new file mode 100644 index 0000000000000..81ede5d3da575 --- /dev/null +++ b/src/docs/suspicious_operation_groupings.txt @@ -0,0 +1,41 @@ +### What it does +Checks for unlikely usages of binary operators that are almost +certainly typos and/or copy/paste errors, given the other usages +of binary operators nearby. + +### Why is this bad? +They are probably bugs and if they aren't then they look like bugs +and you should add a comment explaining why you are doing such an +odd set of operations. + +### Known problems +There may be some false positives if you are trying to do something +unusual that happens to look like a typo. + +### Example +``` +struct Vec3 { + x: f64, + y: f64, + z: f64, +} + +impl Eq for Vec3 {} + +impl PartialEq for Vec3 { + fn eq(&self, other: &Self) -> bool { + // This should trigger the lint because `self.x` is compared to `other.y` + self.x == other.y && self.y == other.y && self.z == other.z + } +} +``` +Use instead: +``` +// same as above except: +impl PartialEq for Vec3 { + fn eq(&self, other: &Self) -> bool { + // Note we now compare other.x to self.x + self.x == other.x && self.y == other.y && self.z == other.z + } +} +``` \ No newline at end of file diff --git a/src/docs/suspicious_splitn.txt b/src/docs/suspicious_splitn.txt new file mode 100644 index 0000000000000..79a3dbfa6f4a7 --- /dev/null +++ b/src/docs/suspicious_splitn.txt @@ -0,0 +1,22 @@ +### What it does +Checks for calls to [`splitn`] +(https://doc.rust-lang.org/std/primitive.str.html#method.splitn) and +related functions with either zero or one splits. + +### Why is this bad? +These calls don't actually split the value and are +likely to be intended as a different number. + +### Example +``` +for x in s.splitn(1, ":") { + // .. +} +``` + +Use instead: +``` +for x in s.splitn(2, ":") { + // .. +} +``` \ No newline at end of file diff --git a/src/docs/suspicious_to_owned.txt b/src/docs/suspicious_to_owned.txt new file mode 100644 index 0000000000000..8cbf61dc7175b --- /dev/null +++ b/src/docs/suspicious_to_owned.txt @@ -0,0 +1,39 @@ +### What it does +Checks for the usage of `_.to_owned()`, on a `Cow<'_, _>`. + +### Why is this bad? +Calling `to_owned()` on a `Cow` creates a clone of the `Cow` +itself, without taking ownership of the `Cow` contents (i.e. +it's equivalent to calling `Cow::clone`). +The similarly named `into_owned` method, on the other hand, +clones the `Cow` contents, effectively turning any `Cow::Borrowed` +into a `Cow::Owned`. + +Given the potential ambiguity, consider replacing `to_owned` +with `clone` for better readability or, if getting a `Cow::Owned` +was the original intent, using `into_owned` instead. + +### Example +``` +let s = "Hello world!"; +let cow = Cow::Borrowed(s); + +let data = cow.to_owned(); +assert!(matches!(data, Cow::Borrowed(_))) +``` +Use instead: +``` +let s = "Hello world!"; +let cow = Cow::Borrowed(s); + +let data = cow.clone(); +assert!(matches!(data, Cow::Borrowed(_))) +``` +or +``` +let s = "Hello world!"; +let cow = Cow::Borrowed(s); + +let data = cow.into_owned(); +assert!(matches!(data, String)) +``` \ No newline at end of file diff --git a/src/docs/suspicious_unary_op_formatting.txt b/src/docs/suspicious_unary_op_formatting.txt new file mode 100644 index 0000000000000..06fb09db76d0c --- /dev/null +++ b/src/docs/suspicious_unary_op_formatting.txt @@ -0,0 +1,18 @@ +### What it does +Checks the formatting of a unary operator on the right hand side +of a binary operator. It lints if there is no space between the binary and unary operators, +but there is a space between the unary and its operand. + +### Why is this bad? +This is either a typo in the binary operator or confusing. + +### Example +``` +// &&! looks like a different operator +if foo &&! bar {} +``` + +Use instead: +``` +if foo && !bar {} +``` \ No newline at end of file diff --git a/src/docs/swap_ptr_to_ref.txt b/src/docs/swap_ptr_to_ref.txt new file mode 100644 index 0000000000000..0215d1e8a4215 --- /dev/null +++ b/src/docs/swap_ptr_to_ref.txt @@ -0,0 +1,23 @@ +### What it does +Checks for calls to `core::mem::swap` where either parameter is derived from a pointer + +### Why is this bad? +When at least one parameter to `swap` is derived from a pointer it may overlap with the +other. This would then lead to undefined behavior. + +### Example +``` +unsafe fn swap(x: &[*mut u32], y: &[*mut u32]) { + for (&x, &y) in x.iter().zip(y) { + core::mem::swap(&mut *x, &mut *y); + } +} +``` +Use instead: +``` +unsafe fn swap(x: &[*mut u32], y: &[*mut u32]) { + for (&x, &y) in x.iter().zip(y) { + core::ptr::swap(x, y); + } +} +``` \ No newline at end of file diff --git a/src/docs/tabs_in_doc_comments.txt b/src/docs/tabs_in_doc_comments.txt new file mode 100644 index 0000000000000..f83dbe2b73cb7 --- /dev/null +++ b/src/docs/tabs_in_doc_comments.txt @@ -0,0 +1,44 @@ +### What it does +Checks doc comments for usage of tab characters. + +### Why is this bad? +The rust style-guide promotes spaces instead of tabs for indentation. +To keep a consistent view on the source, also doc comments should not have tabs. +Also, explaining ascii-diagrams containing tabs can get displayed incorrectly when the +display settings of the author and reader differ. + +### Example +``` +/// +/// Struct to hold two strings: +/// - first one +/// - second one +pub struct DoubleString { + /// + /// - First String: + /// - needs to be inside here + first_string: String, + /// + /// - Second String: + /// - needs to be inside here + second_string: String, +} +``` + +Will be converted to: +``` +/// +/// Struct to hold two strings: +/// - first one +/// - second one +pub struct DoubleString { + /// + /// - First String: + /// - needs to be inside here + first_string: String, + /// + /// - Second String: + /// - needs to be inside here + second_string: String, +} +``` \ No newline at end of file diff --git a/src/docs/temporary_assignment.txt b/src/docs/temporary_assignment.txt new file mode 100644 index 0000000000000..195b42cf0d492 --- /dev/null +++ b/src/docs/temporary_assignment.txt @@ -0,0 +1,12 @@ +### What it does +Checks for construction of a structure or tuple just to +assign a value in it. + +### Why is this bad? +Readability. If the structure is only created to be +updated, why not write the structure you want in the first place? + +### Example +``` +(0, 0).0 = 1 +``` \ No newline at end of file diff --git a/src/docs/to_digit_is_some.txt b/src/docs/to_digit_is_some.txt new file mode 100644 index 0000000000000..eee8375adf7ae --- /dev/null +++ b/src/docs/to_digit_is_some.txt @@ -0,0 +1,15 @@ +### What it does +Checks for `.to_digit(..).is_some()` on `char`s. + +### Why is this bad? +This is a convoluted way of checking if a `char` is a digit. It's +more straight forward to use the dedicated `is_digit` method. + +### Example +``` +let is_digit = c.to_digit(radix).is_some(); +``` +can be written as: +``` +let is_digit = c.is_digit(radix); +``` \ No newline at end of file diff --git a/src/docs/to_string_in_format_args.txt b/src/docs/to_string_in_format_args.txt new file mode 100644 index 0000000000000..34b20583585ad --- /dev/null +++ b/src/docs/to_string_in_format_args.txt @@ -0,0 +1,17 @@ +### What it does +Checks for [`ToString::to_string`](https://doc.rust-lang.org/std/string/trait.ToString.html#tymethod.to_string) +applied to a type that implements [`Display`](https://doc.rust-lang.org/std/fmt/trait.Display.html) +in a macro that does formatting. + +### Why is this bad? +Since the type implements `Display`, the use of `to_string` is +unnecessary. + +### Example +``` +println!("error: something failed at {}", Location::caller().to_string()); +``` +Use instead: +``` +println!("error: something failed at {}", Location::caller()); +``` \ No newline at end of file diff --git a/src/docs/todo.txt b/src/docs/todo.txt new file mode 100644 index 0000000000000..661eb1ac5cff4 --- /dev/null +++ b/src/docs/todo.txt @@ -0,0 +1,10 @@ +### What it does +Checks for usage of `todo!`. + +### Why is this bad? +This macro should not be present in production code + +### Example +``` +todo!(); +``` \ No newline at end of file diff --git a/src/docs/too_many_arguments.txt b/src/docs/too_many_arguments.txt new file mode 100644 index 0000000000000..4669f9f82e661 --- /dev/null +++ b/src/docs/too_many_arguments.txt @@ -0,0 +1,14 @@ +### What it does +Checks for functions with too many parameters. + +### Why is this bad? +Functions with lots of parameters are considered bad +style and reduce readability (“what does the 5th parameter mean?”). Consider +grouping some parameters into a new type. + +### Example +``` +fn foo(x: u32, y: u32, name: &str, c: Color, w: f32, h: f32, a: f32, b: f32) { + // .. +} +``` \ No newline at end of file diff --git a/src/docs/too_many_lines.txt b/src/docs/too_many_lines.txt new file mode 100644 index 0000000000000..425db348bbd75 --- /dev/null +++ b/src/docs/too_many_lines.txt @@ -0,0 +1,17 @@ +### What it does +Checks for functions with a large amount of lines. + +### Why is this bad? +Functions with a lot of lines are harder to understand +due to having to look at a larger amount of code to understand what the +function is doing. Consider splitting the body of the function into +multiple functions. + +### Example +``` +fn im_too_long() { + println!(""); + // ... 100 more LoC + println!(""); +} +``` \ No newline at end of file diff --git a/src/docs/toplevel_ref_arg.txt b/src/docs/toplevel_ref_arg.txt new file mode 100644 index 0000000000000..96a9e2db8b7e7 --- /dev/null +++ b/src/docs/toplevel_ref_arg.txt @@ -0,0 +1,28 @@ +### What it does +Checks for function arguments and let bindings denoted as +`ref`. + +### Why is this bad? +The `ref` declaration makes the function take an owned +value, but turns the argument into a reference (which means that the value +is destroyed when exiting the function). This adds not much value: either +take a reference type, or take an owned value and create references in the +body. + +For let bindings, `let x = &foo;` is preferred over `let ref x = foo`. The +type of `x` is more obvious with the former. + +### Known problems +If the argument is dereferenced within the function, +removing the `ref` will lead to errors. This can be fixed by removing the +dereferences, e.g., changing `*x` to `x` within the function. + +### Example +``` +fn foo(ref _x: u8) {} +``` + +Use instead: +``` +fn foo(_x: &u8) {} +``` \ No newline at end of file diff --git a/src/docs/trailing_empty_array.txt b/src/docs/trailing_empty_array.txt new file mode 100644 index 0000000000000..db1908cc96d03 --- /dev/null +++ b/src/docs/trailing_empty_array.txt @@ -0,0 +1,22 @@ +### What it does +Displays a warning when a struct with a trailing zero-sized array is declared without a `repr` attribute. + +### Why is this bad? +Zero-sized arrays aren't very useful in Rust itself, so such a struct is likely being created to pass to C code or in some other situation where control over memory layout matters (for example, in conjunction with manual allocation to make it easy to compute the offset of the array). Either way, `#[repr(C)]` (or another `repr` attribute) is needed. + +### Example +``` +struct RarelyUseful { + some_field: u32, + last: [u32; 0], +} +``` + +Use instead: +``` +#[repr(C)] +struct MoreOftenUseful { + some_field: usize, + last: [u32; 0], +} +``` \ No newline at end of file diff --git a/src/docs/trait_duplication_in_bounds.txt b/src/docs/trait_duplication_in_bounds.txt new file mode 100644 index 0000000000000..509736bb36444 --- /dev/null +++ b/src/docs/trait_duplication_in_bounds.txt @@ -0,0 +1,37 @@ +### What it does +Checks for cases where generics are being used and multiple +syntax specifications for trait bounds are used simultaneously. + +### Why is this bad? +Duplicate bounds makes the code +less readable than specifying them only once. + +### Example +``` +fn func(arg: T) where T: Clone + Default {} +``` + +Use instead: +``` +fn func(arg: T) {} + +// or + +fn func(arg: T) where T: Clone + Default {} +``` + +``` +fn foo(bar: T) {} +``` +Use instead: +``` +fn foo(bar: T) {} +``` + +``` +fn foo(bar: T) where T: Default + Default {} +``` +Use instead: +``` +fn foo(bar: T) where T: Default {} +``` \ No newline at end of file diff --git a/src/docs/transmute_bytes_to_str.txt b/src/docs/transmute_bytes_to_str.txt new file mode 100644 index 0000000000000..75889b9c73ae3 --- /dev/null +++ b/src/docs/transmute_bytes_to_str.txt @@ -0,0 +1,27 @@ +### What it does +Checks for transmutes from a `&[u8]` to a `&str`. + +### Why is this bad? +Not every byte slice is a valid UTF-8 string. + +### Known problems +- [`from_utf8`] which this lint suggests using is slower than `transmute` +as it needs to validate the input. +If you are certain that the input is always a valid UTF-8, +use [`from_utf8_unchecked`] which is as fast as `transmute` +but has a semantically meaningful name. +- You might want to handle errors returned from [`from_utf8`] instead of calling `unwrap`. + +[`from_utf8`]: https://doc.rust-lang.org/std/str/fn.from_utf8.html +[`from_utf8_unchecked`]: https://doc.rust-lang.org/std/str/fn.from_utf8_unchecked.html + +### Example +``` +let b: &[u8] = &[1_u8, 2_u8]; +unsafe { + let _: &str = std::mem::transmute(b); // where b: &[u8] +} + +// should be: +let _ = std::str::from_utf8(b).unwrap(); +``` \ No newline at end of file diff --git a/src/docs/transmute_float_to_int.txt b/src/docs/transmute_float_to_int.txt new file mode 100644 index 0000000000000..1877e5a465a4e --- /dev/null +++ b/src/docs/transmute_float_to_int.txt @@ -0,0 +1,16 @@ +### What it does +Checks for transmutes from a float to an integer. + +### Why is this bad? +Transmutes are dangerous and error-prone, whereas `to_bits` is intuitive +and safe. + +### Example +``` +unsafe { + let _: u32 = std::mem::transmute(1f32); +} + +// should be: +let _: u32 = 1f32.to_bits(); +``` \ No newline at end of file diff --git a/src/docs/transmute_int_to_bool.txt b/src/docs/transmute_int_to_bool.txt new file mode 100644 index 0000000000000..07c10f8d0bca7 --- /dev/null +++ b/src/docs/transmute_int_to_bool.txt @@ -0,0 +1,16 @@ +### What it does +Checks for transmutes from an integer to a `bool`. + +### Why is this bad? +This might result in an invalid in-memory representation of a `bool`. + +### Example +``` +let x = 1_u8; +unsafe { + let _: bool = std::mem::transmute(x); // where x: u8 +} + +// should be: +let _: bool = x != 0; +``` \ No newline at end of file diff --git a/src/docs/transmute_int_to_char.txt b/src/docs/transmute_int_to_char.txt new file mode 100644 index 0000000000000..836d22d3f99c0 --- /dev/null +++ b/src/docs/transmute_int_to_char.txt @@ -0,0 +1,27 @@ +### What it does +Checks for transmutes from an integer to a `char`. + +### Why is this bad? +Not every integer is a Unicode scalar value. + +### Known problems +- [`from_u32`] which this lint suggests using is slower than `transmute` +as it needs to validate the input. +If you are certain that the input is always a valid Unicode scalar value, +use [`from_u32_unchecked`] which is as fast as `transmute` +but has a semantically meaningful name. +- You might want to handle `None` returned from [`from_u32`] instead of calling `unwrap`. + +[`from_u32`]: https://doc.rust-lang.org/std/char/fn.from_u32.html +[`from_u32_unchecked`]: https://doc.rust-lang.org/std/char/fn.from_u32_unchecked.html + +### Example +``` +let x = 1_u32; +unsafe { + let _: char = std::mem::transmute(x); // where x: u32 +} + +// should be: +let _ = std::char::from_u32(x).unwrap(); +``` \ No newline at end of file diff --git a/src/docs/transmute_int_to_float.txt b/src/docs/transmute_int_to_float.txt new file mode 100644 index 0000000000000..75cdc62e97275 --- /dev/null +++ b/src/docs/transmute_int_to_float.txt @@ -0,0 +1,16 @@ +### What it does +Checks for transmutes from an integer to a float. + +### Why is this bad? +Transmutes are dangerous and error-prone, whereas `from_bits` is intuitive +and safe. + +### Example +``` +unsafe { + let _: f32 = std::mem::transmute(1_u32); // where x: u32 +} + +// should be: +let _: f32 = f32::from_bits(1_u32); +``` \ No newline at end of file diff --git a/src/docs/transmute_num_to_bytes.txt b/src/docs/transmute_num_to_bytes.txt new file mode 100644 index 0000000000000..a2c39a1b947e3 --- /dev/null +++ b/src/docs/transmute_num_to_bytes.txt @@ -0,0 +1,16 @@ +### What it does +Checks for transmutes from a number to an array of `u8` + +### Why this is bad? +Transmutes are dangerous and error-prone, whereas `to_ne_bytes` +is intuitive and safe. + +### Example +``` +unsafe { + let x: [u8; 8] = std::mem::transmute(1i64); +} + +// should be +let x: [u8; 8] = 0i64.to_ne_bytes(); +``` \ No newline at end of file diff --git a/src/docs/transmute_ptr_to_ptr.txt b/src/docs/transmute_ptr_to_ptr.txt new file mode 100644 index 0000000000000..65777db986186 --- /dev/null +++ b/src/docs/transmute_ptr_to_ptr.txt @@ -0,0 +1,21 @@ +### What it does +Checks for transmutes from a pointer to a pointer, or +from a reference to a reference. + +### Why is this bad? +Transmutes are dangerous, and these can instead be +written as casts. + +### Example +``` +let ptr = &1u32 as *const u32; +unsafe { + // pointer-to-pointer transmute + let _: *const f32 = std::mem::transmute(ptr); + // ref-ref transmute + let _: &f32 = std::mem::transmute(&1u32); +} +// These can be respectively written: +let _ = ptr as *const f32; +let _ = unsafe{ &*(&1u32 as *const u32 as *const f32) }; +``` \ No newline at end of file diff --git a/src/docs/transmute_ptr_to_ref.txt b/src/docs/transmute_ptr_to_ref.txt new file mode 100644 index 0000000000000..aca550f5036ec --- /dev/null +++ b/src/docs/transmute_ptr_to_ref.txt @@ -0,0 +1,21 @@ +### What it does +Checks for transmutes from a pointer to a reference. + +### Why is this bad? +This can always be rewritten with `&` and `*`. + +### Known problems +- `mem::transmute` in statics and constants is stable from Rust 1.46.0, +while dereferencing raw pointer is not stable yet. +If you need to do this in those places, +you would have to use `transmute` instead. + +### Example +``` +unsafe { + let _: &T = std::mem::transmute(p); // where p: *const T +} + +// can be written: +let _: &T = &*p; +``` \ No newline at end of file diff --git a/src/docs/transmute_undefined_repr.txt b/src/docs/transmute_undefined_repr.txt new file mode 100644 index 0000000000000..5ee6aaf4ca92c --- /dev/null +++ b/src/docs/transmute_undefined_repr.txt @@ -0,0 +1,22 @@ +### What it does +Checks for transmutes between types which do not have a representation defined relative to +each other. + +### Why is this bad? +The results of such a transmute are not defined. + +### Known problems +This lint has had multiple problems in the past and was moved to `nursery`. See issue +[#8496](https://github.com/rust-lang/rust-clippy/issues/8496) for more details. + +### Example +``` +struct Foo(u32, T); +let _ = unsafe { core::mem::transmute::, Foo>(Foo(0u32, 0u32)) }; +``` +Use instead: +``` +#[repr(C)] +struct Foo(u32, T); +let _ = unsafe { core::mem::transmute::, Foo>(Foo(0u32, 0u32)) }; +``` \ No newline at end of file diff --git a/src/docs/transmutes_expressible_as_ptr_casts.txt b/src/docs/transmutes_expressible_as_ptr_casts.txt new file mode 100644 index 0000000000000..b68a8cda9c74b --- /dev/null +++ b/src/docs/transmutes_expressible_as_ptr_casts.txt @@ -0,0 +1,16 @@ +### What it does +Checks for transmutes that could be a pointer cast. + +### Why is this bad? +Readability. The code tricks people into thinking that +something complex is going on. + +### Example + +``` +unsafe { std::mem::transmute::<*const [i32], *const [u16]>(p) }; +``` +Use instead: +``` +p as *const [u16]; +``` \ No newline at end of file diff --git a/src/docs/transmuting_null.txt b/src/docs/transmuting_null.txt new file mode 100644 index 0000000000000..f8bacfc0b90b4 --- /dev/null +++ b/src/docs/transmuting_null.txt @@ -0,0 +1,15 @@ +### What it does +Checks for transmute calls which would receive a null pointer. + +### Why is this bad? +Transmuting a null pointer is undefined behavior. + +### Known problems +Not all cases can be detected at the moment of this writing. +For example, variables which hold a null pointer and are then fed to a `transmute` +call, aren't detectable yet. + +### Example +``` +let null_ref: &u64 = unsafe { std::mem::transmute(0 as *const u64) }; +``` \ No newline at end of file diff --git a/src/docs/trim_split_whitespace.txt b/src/docs/trim_split_whitespace.txt new file mode 100644 index 0000000000000..f7e3e7858f949 --- /dev/null +++ b/src/docs/trim_split_whitespace.txt @@ -0,0 +1,14 @@ +### What it does +Warns about calling `str::trim` (or variants) before `str::split_whitespace`. + +### Why is this bad? +`split_whitespace` already ignores leading and trailing whitespace. + +### Example +``` +" A B C ".trim().split_whitespace(); +``` +Use instead: +``` +" A B C ".split_whitespace(); +``` \ No newline at end of file diff --git a/src/docs/trivial_regex.txt b/src/docs/trivial_regex.txt new file mode 100644 index 0000000000000..f71d667fd7711 --- /dev/null +++ b/src/docs/trivial_regex.txt @@ -0,0 +1,18 @@ +### What it does +Checks for trivial [regex](https://crates.io/crates/regex) +creation (with `Regex::new`, `RegexBuilder::new`, or `RegexSet::new`). + +### Why is this bad? +Matching the regex can likely be replaced by `==` or +`str::starts_with`, `str::ends_with` or `std::contains` or other `str` +methods. + +### Known problems +If the same regex is going to be applied to multiple +inputs, the precomputations done by `Regex` construction can give +significantly better performance than any of the `str`-based methods. + +### Example +``` +Regex::new("^foobar") +``` \ No newline at end of file diff --git a/src/docs/trivially_copy_pass_by_ref.txt b/src/docs/trivially_copy_pass_by_ref.txt new file mode 100644 index 0000000000000..f54cce5e2bd76 --- /dev/null +++ b/src/docs/trivially_copy_pass_by_ref.txt @@ -0,0 +1,43 @@ +### What it does +Checks for functions taking arguments by reference, where +the argument type is `Copy` and small enough to be more efficient to always +pass by value. + +### Why is this bad? +In many calling conventions instances of structs will +be passed through registers if they fit into two or less general purpose +registers. + +### Known problems +This lint is target register size dependent, it is +limited to 32-bit to try and reduce portability problems between 32 and +64-bit, but if you are compiling for 8 or 16-bit targets then the limit +will be different. + +The configuration option `trivial_copy_size_limit` can be set to override +this limit for a project. + +This lint attempts to allow passing arguments by reference if a reference +to that argument is returned. This is implemented by comparing the lifetime +of the argument and return value for equality. However, this can cause +false positives in cases involving multiple lifetimes that are bounded by +each other. + +Also, it does not take account of other similar cases where getting memory addresses +matters; namely, returning the pointer to the argument in question, +and passing the argument, as both references and pointers, +to a function that needs the memory address. For further details, refer to +[this issue](https://github.com/rust-lang/rust-clippy/issues/5953) +that explains a real case in which this false positive +led to an **undefined behavior** introduced with unsafe code. + +### Example + +``` +fn foo(v: &u32) {} +``` + +Use instead: +``` +fn foo(v: u32) {} +``` \ No newline at end of file diff --git a/src/docs/try_err.txt b/src/docs/try_err.txt new file mode 100644 index 0000000000000..e3d4ef3a09df1 --- /dev/null +++ b/src/docs/try_err.txt @@ -0,0 +1,28 @@ +### What it does +Checks for usages of `Err(x)?`. + +### Why is this bad? +The `?` operator is designed to allow calls that +can fail to be easily chained. For example, `foo()?.bar()` or +`foo(bar()?)`. Because `Err(x)?` can't be used that way (it will +always return), it is more clear to write `return Err(x)`. + +### Example +``` +fn foo(fail: bool) -> Result { + if fail { + Err("failed")?; + } + Ok(0) +} +``` +Could be written: + +``` +fn foo(fail: bool) -> Result { + if fail { + return Err("failed".into()); + } + Ok(0) +} +``` \ No newline at end of file diff --git a/src/docs/type_complexity.txt b/src/docs/type_complexity.txt new file mode 100644 index 0000000000000..69cd875005043 --- /dev/null +++ b/src/docs/type_complexity.txt @@ -0,0 +1,14 @@ +### What it does +Checks for types used in structs, parameters and `let` +declarations above a certain complexity threshold. + +### Why is this bad? +Too complex types make the code less readable. Consider +using a `type` definition to simplify them. + +### Example +``` +struct Foo { + inner: Rc>>>, +} +``` \ No newline at end of file diff --git a/src/docs/type_repetition_in_bounds.txt b/src/docs/type_repetition_in_bounds.txt new file mode 100644 index 0000000000000..18ed372fd13e3 --- /dev/null +++ b/src/docs/type_repetition_in_bounds.txt @@ -0,0 +1,16 @@ +### What it does +This lint warns about unnecessary type repetitions in trait bounds + +### Why is this bad? +Repeating the type for every bound makes the code +less readable than combining the bounds + +### Example +``` +pub fn foo(t: T) where T: Copy, T: Clone {} +``` + +Use instead: +``` +pub fn foo(t: T) where T: Copy + Clone {} +``` \ No newline at end of file diff --git a/src/docs/undocumented_unsafe_blocks.txt b/src/docs/undocumented_unsafe_blocks.txt new file mode 100644 index 0000000000000..f3af4753c5f75 --- /dev/null +++ b/src/docs/undocumented_unsafe_blocks.txt @@ -0,0 +1,43 @@ +### What it does +Checks for `unsafe` blocks and impls without a `// SAFETY: ` comment +explaining why the unsafe operations performed inside +the block are safe. + +Note the comment must appear on the line(s) preceding the unsafe block +with nothing appearing in between. The following is ok: +``` +foo( + // SAFETY: + // This is a valid safety comment + unsafe { *x } +) +``` +But neither of these are: +``` +// SAFETY: +// This is not a valid safety comment +foo( + /* SAFETY: Neither is this */ unsafe { *x }, +); +``` + +### Why is this bad? +Undocumented unsafe blocks and impls can make it difficult to +read and maintain code, as well as uncover unsoundness +and bugs. + +### Example +``` +use std::ptr::NonNull; +let a = &mut 42; + +let ptr = unsafe { NonNull::new_unchecked(a) }; +``` +Use instead: +``` +use std::ptr::NonNull; +let a = &mut 42; + +// SAFETY: references are guaranteed to be non-null. +let ptr = unsafe { NonNull::new_unchecked(a) }; +``` \ No newline at end of file diff --git a/src/docs/undropped_manually_drops.txt b/src/docs/undropped_manually_drops.txt new file mode 100644 index 0000000000000..85e3ec56653c9 --- /dev/null +++ b/src/docs/undropped_manually_drops.txt @@ -0,0 +1,22 @@ +### What it does +Prevents the safe `std::mem::drop` function from being called on `std::mem::ManuallyDrop`. + +### Why is this bad? +The safe `drop` function does not drop the inner value of a `ManuallyDrop`. + +### Known problems +Does not catch cases if the user binds `std::mem::drop` +to a different name and calls it that way. + +### Example +``` +struct S; +drop(std::mem::ManuallyDrop::new(S)); +``` +Use instead: +``` +struct S; +unsafe { + std::mem::ManuallyDrop::drop(&mut std::mem::ManuallyDrop::new(S)); +} +``` \ No newline at end of file diff --git a/src/docs/unicode_not_nfc.txt b/src/docs/unicode_not_nfc.txt new file mode 100644 index 0000000000000..c660c51dadb26 --- /dev/null +++ b/src/docs/unicode_not_nfc.txt @@ -0,0 +1,12 @@ +### What it does +Checks for string literals that contain Unicode in a form +that is not equal to its +[NFC-recomposition](http://www.unicode.org/reports/tr15/#Norm_Forms). + +### Why is this bad? +If such a string is compared to another, the results +may be surprising. + +### Example +You may not see it, but "à"" and "à"" aren't the same string. The +former when escaped is actually `"a\u{300}"` while the latter is `"\u{e0}"`. \ No newline at end of file diff --git a/src/docs/unimplemented.txt b/src/docs/unimplemented.txt new file mode 100644 index 0000000000000..7095594fb2e73 --- /dev/null +++ b/src/docs/unimplemented.txt @@ -0,0 +1,10 @@ +### What it does +Checks for usage of `unimplemented!`. + +### Why is this bad? +This macro should not be present in production code + +### Example +``` +unimplemented!(); +``` \ No newline at end of file diff --git a/src/docs/uninit_assumed_init.txt b/src/docs/uninit_assumed_init.txt new file mode 100644 index 0000000000000..cca24093d40df --- /dev/null +++ b/src/docs/uninit_assumed_init.txt @@ -0,0 +1,28 @@ +### What it does +Checks for `MaybeUninit::uninit().assume_init()`. + +### Why is this bad? +For most types, this is undefined behavior. + +### Known problems +For now, we accept empty tuples and tuples / arrays +of `MaybeUninit`. There may be other types that allow uninitialized +data, but those are not yet rigorously defined. + +### Example +``` +// Beware the UB +use std::mem::MaybeUninit; + +let _: usize = unsafe { MaybeUninit::uninit().assume_init() }; +``` + +Note that the following is OK: + +``` +use std::mem::MaybeUninit; + +let _: [MaybeUninit; 5] = unsafe { + MaybeUninit::uninit().assume_init() +}; +``` \ No newline at end of file diff --git a/src/docs/uninit_vec.txt b/src/docs/uninit_vec.txt new file mode 100644 index 0000000000000..cd50afe78f6f2 --- /dev/null +++ b/src/docs/uninit_vec.txt @@ -0,0 +1,41 @@ +### What it does +Checks for `set_len()` call that creates `Vec` with uninitialized elements. +This is commonly caused by calling `set_len()` right after allocating or +reserving a buffer with `new()`, `default()`, `with_capacity()`, or `reserve()`. + +### Why is this bad? +It creates a `Vec` with uninitialized data, which leads to +undefined behavior with most safe operations. Notably, uninitialized +`Vec` must not be used with generic `Read`. + +Moreover, calling `set_len()` on a `Vec` created with `new()` or `default()` +creates out-of-bound values that lead to heap memory corruption when used. + +### Known Problems +This lint only checks directly adjacent statements. + +### Example +``` +let mut vec: Vec = Vec::with_capacity(1000); +unsafe { vec.set_len(1000); } +reader.read(&mut vec); // undefined behavior! +``` + +### How to fix? +1. Use an initialized buffer: + ```rust,ignore + let mut vec: Vec = vec![0; 1000]; + reader.read(&mut vec); + ``` +2. Wrap the content in `MaybeUninit`: + ```rust,ignore + let mut vec: Vec> = Vec::with_capacity(1000); + vec.set_len(1000); // `MaybeUninit` can be uninitialized + ``` +3. If you are on 1.60.0 or later, `Vec::spare_capacity_mut()` is available: + ```rust,ignore + let mut vec: Vec = Vec::with_capacity(1000); + let remaining = vec.spare_capacity_mut(); // `&mut [MaybeUninit]` + // perform initialization with `remaining` + vec.set_len(...); // Safe to call `set_len()` on initialized part + ``` \ No newline at end of file diff --git a/src/docs/unit_arg.txt b/src/docs/unit_arg.txt new file mode 100644 index 0000000000000..eb83403bb275c --- /dev/null +++ b/src/docs/unit_arg.txt @@ -0,0 +1,14 @@ +### What it does +Checks for passing a unit value as an argument to a function without using a +unit literal (`()`). + +### Why is this bad? +This is likely the result of an accidental semicolon. + +### Example +``` +foo({ + let a = bar(); + baz(a); +}) +``` \ No newline at end of file diff --git a/src/docs/unit_cmp.txt b/src/docs/unit_cmp.txt new file mode 100644 index 0000000000000..6f3d62010dc51 --- /dev/null +++ b/src/docs/unit_cmp.txt @@ -0,0 +1,33 @@ +### What it does +Checks for comparisons to unit. This includes all binary +comparisons (like `==` and `<`) and asserts. + +### Why is this bad? +Unit is always equal to itself, and thus is just a +clumsily written constant. Mostly this happens when someone accidentally +adds semicolons at the end of the operands. + +### Example +``` +if { + foo(); +} == { + bar(); +} { + baz(); +} +``` +is equal to +``` +{ + foo(); + bar(); + baz(); +} +``` + +For asserts: +``` +assert_eq!({ foo(); }, { bar(); }); +``` +will always succeed \ No newline at end of file diff --git a/src/docs/unit_hash.txt b/src/docs/unit_hash.txt new file mode 100644 index 0000000000000..a22d2994602ac --- /dev/null +++ b/src/docs/unit_hash.txt @@ -0,0 +1,20 @@ +### What it does +Detects `().hash(_)`. + +### Why is this bad? +Hashing a unit value doesn't do anything as the implementation of `Hash` for `()` is a no-op. + +### Example +``` +match my_enum { + Empty => ().hash(&mut state), + WithValue(x) => x.hash(&mut state), +} +``` +Use instead: +``` +match my_enum { + Empty => 0_u8.hash(&mut state), + WithValue(x) => x.hash(&mut state), +} +``` \ No newline at end of file diff --git a/src/docs/unit_return_expecting_ord.txt b/src/docs/unit_return_expecting_ord.txt new file mode 100644 index 0000000000000..781feac5afcfc --- /dev/null +++ b/src/docs/unit_return_expecting_ord.txt @@ -0,0 +1,20 @@ +### What it does +Checks for functions that expect closures of type +Fn(...) -> Ord where the implemented closure returns the unit type. +The lint also suggests to remove the semi-colon at the end of the statement if present. + +### Why is this bad? +Likely, returning the unit type is unintentional, and +could simply be caused by an extra semi-colon. Since () implements Ord +it doesn't cause a compilation error. +This is the same reasoning behind the unit_cmp lint. + +### Known problems +If returning unit is intentional, then there is no +way of specifying this without triggering needless_return lint + +### Example +``` +let mut twins = vec!((1, 1), (2, 2)); +twins.sort_by_key(|x| { x.1; }); +``` \ No newline at end of file diff --git a/src/docs/unnecessary_cast.txt b/src/docs/unnecessary_cast.txt new file mode 100644 index 0000000000000..603f2606099c8 --- /dev/null +++ b/src/docs/unnecessary_cast.txt @@ -0,0 +1,19 @@ +### What it does +Checks for casts to the same type, casts of int literals to integer types +and casts of float literals to float types. + +### Why is this bad? +It's just unnecessary. + +### Example +``` +let _ = 2i32 as i32; +let _ = 0.5 as f32; +``` + +Better: + +``` +let _ = 2_i32; +let _ = 0.5_f32; +``` \ No newline at end of file diff --git a/src/docs/unnecessary_filter_map.txt b/src/docs/unnecessary_filter_map.txt new file mode 100644 index 0000000000000..b19341ecf660e --- /dev/null +++ b/src/docs/unnecessary_filter_map.txt @@ -0,0 +1,23 @@ +### What it does +Checks for `filter_map` calls that could be replaced by `filter` or `map`. +More specifically it checks if the closure provided is only performing one of the +filter or map operations and suggests the appropriate option. + +### Why is this bad? +Complexity. The intent is also clearer if only a single +operation is being performed. + +### Example +``` +let _ = (0..3).filter_map(|x| if x > 2 { Some(x) } else { None }); + +// As there is no transformation of the argument this could be written as: +let _ = (0..3).filter(|&x| x > 2); +``` + +``` +let _ = (0..4).filter_map(|x| Some(x + 1)); + +// As there is no conditional check on the argument this could be written as: +let _ = (0..4).map(|x| x + 1); +``` \ No newline at end of file diff --git a/src/docs/unnecessary_find_map.txt b/src/docs/unnecessary_find_map.txt new file mode 100644 index 0000000000000..f9444dc48ad6a --- /dev/null +++ b/src/docs/unnecessary_find_map.txt @@ -0,0 +1,23 @@ +### What it does +Checks for `find_map` calls that could be replaced by `find` or `map`. More +specifically it checks if the closure provided is only performing one of the +find or map operations and suggests the appropriate option. + +### Why is this bad? +Complexity. The intent is also clearer if only a single +operation is being performed. + +### Example +``` +let _ = (0..3).find_map(|x| if x > 2 { Some(x) } else { None }); + +// As there is no transformation of the argument this could be written as: +let _ = (0..3).find(|&x| x > 2); +``` + +``` +let _ = (0..4).find_map(|x| Some(x + 1)); + +// As there is no conditional check on the argument this could be written as: +let _ = (0..4).map(|x| x + 1).next(); +``` \ No newline at end of file diff --git a/src/docs/unnecessary_fold.txt b/src/docs/unnecessary_fold.txt new file mode 100644 index 0000000000000..e1b0e65f51971 --- /dev/null +++ b/src/docs/unnecessary_fold.txt @@ -0,0 +1,17 @@ +### What it does +Checks for using `fold` when a more succinct alternative exists. +Specifically, this checks for `fold`s which could be replaced by `any`, `all`, +`sum` or `product`. + +### Why is this bad? +Readability. + +### Example +``` +(0..3).fold(false, |acc, x| acc || x > 2); +``` + +Use instead: +``` +(0..3).any(|x| x > 2); +``` \ No newline at end of file diff --git a/src/docs/unnecessary_join.txt b/src/docs/unnecessary_join.txt new file mode 100644 index 0000000000000..ee4e78601f847 --- /dev/null +++ b/src/docs/unnecessary_join.txt @@ -0,0 +1,25 @@ +### What it does +Checks for use of `.collect::>().join("")` on iterators. + +### Why is this bad? +`.collect::()` is more concise and might be more performant + +### Example +``` +let vector = vec!["hello", "world"]; +let output = vector.iter().map(|item| item.to_uppercase()).collect::>().join(""); +println!("{}", output); +``` +The correct use would be: +``` +let vector = vec!["hello", "world"]; +let output = vector.iter().map(|item| item.to_uppercase()).collect::(); +println!("{}", output); +``` +### Known problems +While `.collect::()` is sometimes more performant, there are cases where +using `.collect::()` over `.collect::>().join("")` +will prevent loop unrolling and will result in a negative performance impact. + +Additionally, differences have been observed between aarch64 and x86_64 assembly output, +with aarch64 tending to producing faster assembly in more cases when using `.collect::()` \ No newline at end of file diff --git a/src/docs/unnecessary_lazy_evaluations.txt b/src/docs/unnecessary_lazy_evaluations.txt new file mode 100644 index 0000000000000..208188ce971a5 --- /dev/null +++ b/src/docs/unnecessary_lazy_evaluations.txt @@ -0,0 +1,32 @@ +### What it does +As the counterpart to `or_fun_call`, this lint looks for unnecessary +lazily evaluated closures on `Option` and `Result`. + +This lint suggests changing the following functions, when eager evaluation results in +simpler code: + - `unwrap_or_else` to `unwrap_or` + - `and_then` to `and` + - `or_else` to `or` + - `get_or_insert_with` to `get_or_insert` + - `ok_or_else` to `ok_or` + +### Why is this bad? +Using eager evaluation is shorter and simpler in some cases. + +### Known problems +It is possible, but not recommended for `Deref` and `Index` to have +side effects. Eagerly evaluating them can change the semantics of the program. + +### Example +``` +// example code where clippy issues a warning +let opt: Option = None; + +opt.unwrap_or_else(|| 42); +``` +Use instead: +``` +let opt: Option = None; + +opt.unwrap_or(42); +``` \ No newline at end of file diff --git a/src/docs/unnecessary_mut_passed.txt b/src/docs/unnecessary_mut_passed.txt new file mode 100644 index 0000000000000..2f8bdd113dfdb --- /dev/null +++ b/src/docs/unnecessary_mut_passed.txt @@ -0,0 +1,17 @@ +### What it does +Detects passing a mutable reference to a function that only +requires an immutable reference. + +### Why is this bad? +The mutable reference rules out all other references to +the value. Also the code misleads about the intent of the call site. + +### Example +``` +vec.push(&mut value); +``` + +Use instead: +``` +vec.push(&value); +``` \ No newline at end of file diff --git a/src/docs/unnecessary_operation.txt b/src/docs/unnecessary_operation.txt new file mode 100644 index 0000000000000..7f455e264cb30 --- /dev/null +++ b/src/docs/unnecessary_operation.txt @@ -0,0 +1,12 @@ +### What it does +Checks for expression statements that can be reduced to a +sub-expression. + +### Why is this bad? +Expressions by themselves often have no side-effects. +Having such expressions reduces readability. + +### Example +``` +compute_array()[0]; +``` \ No newline at end of file diff --git a/src/docs/unnecessary_owned_empty_strings.txt b/src/docs/unnecessary_owned_empty_strings.txt new file mode 100644 index 0000000000000..8cd9fba603e06 --- /dev/null +++ b/src/docs/unnecessary_owned_empty_strings.txt @@ -0,0 +1,16 @@ +### What it does + +Detects cases of owned empty strings being passed as an argument to a function expecting `&str` + +### Why is this bad? + +This results in longer and less readable code + +### Example +``` +vec!["1", "2", "3"].join(&String::new()); +``` +Use instead: +``` +vec!["1", "2", "3"].join(""); +``` \ No newline at end of file diff --git a/src/docs/unnecessary_self_imports.txt b/src/docs/unnecessary_self_imports.txt new file mode 100644 index 0000000000000..b909cd5a76dae --- /dev/null +++ b/src/docs/unnecessary_self_imports.txt @@ -0,0 +1,19 @@ +### What it does +Checks for imports ending in `::{self}`. + +### Why is this bad? +In most cases, this can be written much more cleanly by omitting `::{self}`. + +### Known problems +Removing `::{self}` will cause any non-module items at the same path to also be imported. +This might cause a naming conflict (https://github.com/rust-lang/rustfmt/issues/3568). This lint makes no attempt +to detect this scenario and that is why it is a restriction lint. + +### Example +``` +use std::io::{self}; +``` +Use instead: +``` +use std::io; +``` \ No newline at end of file diff --git a/src/docs/unnecessary_sort_by.txt b/src/docs/unnecessary_sort_by.txt new file mode 100644 index 0000000000000..6913b62c48eb4 --- /dev/null +++ b/src/docs/unnecessary_sort_by.txt @@ -0,0 +1,21 @@ +### What it does +Detects uses of `Vec::sort_by` passing in a closure +which compares the two arguments, either directly or indirectly. + +### Why is this bad? +It is more clear to use `Vec::sort_by_key` (or `Vec::sort` if +possible) than to use `Vec::sort_by` and a more complicated +closure. + +### Known problems +If the suggested `Vec::sort_by_key` uses Reverse and it isn't already +imported by a use statement, then it will need to be added manually. + +### Example +``` +vec.sort_by(|a, b| a.foo().cmp(&b.foo())); +``` +Use instead: +``` +vec.sort_by_key(|a| a.foo()); +``` \ No newline at end of file diff --git a/src/docs/unnecessary_to_owned.txt b/src/docs/unnecessary_to_owned.txt new file mode 100644 index 0000000000000..5d4213bdaf899 --- /dev/null +++ b/src/docs/unnecessary_to_owned.txt @@ -0,0 +1,24 @@ +### What it does +Checks for unnecessary calls to [`ToOwned::to_owned`](https://doc.rust-lang.org/std/borrow/trait.ToOwned.html#tymethod.to_owned) +and other `to_owned`-like functions. + +### Why is this bad? +The unnecessary calls result in useless allocations. + +### Known problems +`unnecessary_to_owned` can falsely trigger if `IntoIterator::into_iter` is applied to an +owned copy of a resource and the resource is later used mutably. See +[#8148](https://github.com/rust-lang/rust-clippy/issues/8148). + +### Example +``` +let path = std::path::Path::new("x"); +foo(&path.to_string_lossy().to_string()); +fn foo(s: &str) {} +``` +Use instead: +``` +let path = std::path::Path::new("x"); +foo(&path.to_string_lossy()); +fn foo(s: &str) {} +``` \ No newline at end of file diff --git a/src/docs/unnecessary_unwrap.txt b/src/docs/unnecessary_unwrap.txt new file mode 100644 index 0000000000000..50ae845bb44f7 --- /dev/null +++ b/src/docs/unnecessary_unwrap.txt @@ -0,0 +1,20 @@ +### What it does +Checks for calls of `unwrap[_err]()` that cannot fail. + +### Why is this bad? +Using `if let` or `match` is more idiomatic. + +### Example +``` +if option.is_some() { + do_something_with(option.unwrap()) +} +``` + +Could be written: + +``` +if let Some(value) = option { + do_something_with(value) +} +``` \ No newline at end of file diff --git a/src/docs/unnecessary_wraps.txt b/src/docs/unnecessary_wraps.txt new file mode 100644 index 0000000000000..c0a23d492889a --- /dev/null +++ b/src/docs/unnecessary_wraps.txt @@ -0,0 +1,36 @@ +### What it does +Checks for private functions that only return `Ok` or `Some`. + +### Why is this bad? +It is not meaningful to wrap values when no `None` or `Err` is returned. + +### Known problems +There can be false positives if the function signature is designed to +fit some external requirement. + +### Example +``` +fn get_cool_number(a: bool, b: bool) -> Option { + if a && b { + return Some(50); + } + if a { + Some(0) + } else { + Some(10) + } +} +``` +Use instead: +``` +fn get_cool_number(a: bool, b: bool) -> i32 { + if a && b { + return 50; + } + if a { + 0 + } else { + 10 + } +} +``` \ No newline at end of file diff --git a/src/docs/unneeded_field_pattern.txt b/src/docs/unneeded_field_pattern.txt new file mode 100644 index 0000000000000..3cd00a0f3e384 --- /dev/null +++ b/src/docs/unneeded_field_pattern.txt @@ -0,0 +1,26 @@ +### What it does +Checks for structure field patterns bound to wildcards. + +### Why is this bad? +Using `..` instead is shorter and leaves the focus on +the fields that are actually bound. + +### Example +``` +let f = Foo { a: 0, b: 0, c: 0 }; + +match f { + Foo { a: _, b: 0, .. } => {}, + Foo { a: _, b: _, c: _ } => {}, +} +``` + +Use instead: +``` +let f = Foo { a: 0, b: 0, c: 0 }; + +match f { + Foo { b: 0, .. } => {}, + Foo { .. } => {}, +} +``` \ No newline at end of file diff --git a/src/docs/unneeded_wildcard_pattern.txt b/src/docs/unneeded_wildcard_pattern.txt new file mode 100644 index 0000000000000..817061efd1622 --- /dev/null +++ b/src/docs/unneeded_wildcard_pattern.txt @@ -0,0 +1,28 @@ +### What it does +Checks for tuple patterns with a wildcard +pattern (`_`) is next to a rest pattern (`..`). + +_NOTE_: While `_, ..` means there is at least one element left, `..` +means there are 0 or more elements left. This can make a difference +when refactoring, but shouldn't result in errors in the refactored code, +since the wildcard pattern isn't used anyway. + +### Why is this bad? +The wildcard pattern is unneeded as the rest pattern +can match that element as well. + +### Example +``` +match t { + TupleStruct(0, .., _) => (), + _ => (), +} +``` + +Use instead: +``` +match t { + TupleStruct(0, ..) => (), + _ => (), +} +``` \ No newline at end of file diff --git a/src/docs/unnested_or_patterns.txt b/src/docs/unnested_or_patterns.txt new file mode 100644 index 0000000000000..49c45d4ee5e9c --- /dev/null +++ b/src/docs/unnested_or_patterns.txt @@ -0,0 +1,22 @@ +### What it does +Checks for unnested or-patterns, e.g., `Some(0) | Some(2)` and +suggests replacing the pattern with a nested one, `Some(0 | 2)`. + +Another way to think of this is that it rewrites patterns in +*disjunctive normal form (DNF)* into *conjunctive normal form (CNF)*. + +### Why is this bad? +In the example above, `Some` is repeated, which unnecessarily complicates the pattern. + +### Example +``` +fn main() { + if let Some(0) | Some(2) = Some(0) {} +} +``` +Use instead: +``` +fn main() { + if let Some(0 | 2) = Some(0) {} +} +``` \ No newline at end of file diff --git a/src/docs/unreachable.txt b/src/docs/unreachable.txt new file mode 100644 index 0000000000000..10469ca77454f --- /dev/null +++ b/src/docs/unreachable.txt @@ -0,0 +1,10 @@ +### What it does +Checks for usage of `unreachable!`. + +### Why is this bad? +This macro can cause code to panic + +### Example +``` +unreachable!(); +``` \ No newline at end of file diff --git a/src/docs/unreadable_literal.txt b/src/docs/unreadable_literal.txt new file mode 100644 index 0000000000000..e168f90a84c19 --- /dev/null +++ b/src/docs/unreadable_literal.txt @@ -0,0 +1,16 @@ +### What it does +Warns if a long integral or floating-point constant does +not contain underscores. + +### Why is this bad? +Reading long numbers is difficult without separators. + +### Example +``` +61864918973511 +``` + +Use instead: +``` +61_864_918_973_511 +``` \ No newline at end of file diff --git a/src/docs/unsafe_derive_deserialize.txt b/src/docs/unsafe_derive_deserialize.txt new file mode 100644 index 0000000000000..f56c48044f4fa --- /dev/null +++ b/src/docs/unsafe_derive_deserialize.txt @@ -0,0 +1,27 @@ +### What it does +Checks for deriving `serde::Deserialize` on a type that +has methods using `unsafe`. + +### Why is this bad? +Deriving `serde::Deserialize` will create a constructor +that may violate invariants hold by another constructor. + +### Example +``` +use serde::Deserialize; + +#[derive(Deserialize)] +pub struct Foo { + // .. +} + +impl Foo { + pub fn new() -> Self { + // setup here .. + } + + pub unsafe fn parts() -> (&str, &str) { + // assumes invariants hold + } +} +``` \ No newline at end of file diff --git a/src/docs/unsafe_removed_from_name.txt b/src/docs/unsafe_removed_from_name.txt new file mode 100644 index 0000000000000..6f55c1815dd65 --- /dev/null +++ b/src/docs/unsafe_removed_from_name.txt @@ -0,0 +1,15 @@ +### What it does +Checks for imports that remove "unsafe" from an item's +name. + +### Why is this bad? +Renaming makes it less clear which traits and +structures are unsafe. + +### Example +``` +use std::cell::{UnsafeCell as TotallySafeCell}; + +extern crate crossbeam; +use crossbeam::{spawn_unsafe as spawn}; +``` \ No newline at end of file diff --git a/src/docs/unseparated_literal_suffix.txt b/src/docs/unseparated_literal_suffix.txt new file mode 100644 index 0000000000000..d80248e34d0c7 --- /dev/null +++ b/src/docs/unseparated_literal_suffix.txt @@ -0,0 +1,18 @@ +### What it does +Warns if literal suffixes are not separated by an +underscore. +To enforce unseparated literal suffix style, +see the `separated_literal_suffix` lint. + +### Why is this bad? +Suffix style should be consistent. + +### Example +``` +123832i32 +``` + +Use instead: +``` +123832_i32 +``` \ No newline at end of file diff --git a/src/docs/unsound_collection_transmute.txt b/src/docs/unsound_collection_transmute.txt new file mode 100644 index 0000000000000..29db9258e83fb --- /dev/null +++ b/src/docs/unsound_collection_transmute.txt @@ -0,0 +1,25 @@ +### What it does +Checks for transmutes between collections whose +types have different ABI, size or alignment. + +### Why is this bad? +This is undefined behavior. + +### Known problems +Currently, we cannot know whether a type is a +collection, so we just lint the ones that come with `std`. + +### Example +``` +// different size, therefore likely out-of-bounds memory access +// You absolutely do not want this in your code! +unsafe { + std::mem::transmute::<_, Vec>(vec![2_u16]) +}; +``` + +You must always iterate, map and collect the values: + +``` +vec![2_u16].into_iter().map(u32::from).collect::>(); +``` \ No newline at end of file diff --git a/src/docs/unused_async.txt b/src/docs/unused_async.txt new file mode 100644 index 0000000000000..26def11aa17a5 --- /dev/null +++ b/src/docs/unused_async.txt @@ -0,0 +1,23 @@ +### What it does +Checks for functions that are declared `async` but have no `.await`s inside of them. + +### Why is this bad? +Async functions with no async code create overhead, both mentally and computationally. +Callers of async methods either need to be calling from an async function themselves or run it on an executor, both of which +causes runtime overhead and hassle for the caller. + +### Example +``` +async fn get_random_number() -> i64 { + 4 // Chosen by fair dice roll. Guaranteed to be random. +} +let number_future = get_random_number(); +``` + +Use instead: +``` +fn get_random_number_improved() -> i64 { + 4 // Chosen by fair dice roll. Guaranteed to be random. +} +let number_future = async { get_random_number_improved() }; +``` \ No newline at end of file diff --git a/src/docs/unused_io_amount.txt b/src/docs/unused_io_amount.txt new file mode 100644 index 0000000000000..fbc4c299c7bb7 --- /dev/null +++ b/src/docs/unused_io_amount.txt @@ -0,0 +1,31 @@ +### What it does +Checks for unused written/read amount. + +### Why is this bad? +`io::Write::write(_vectored)` and +`io::Read::read(_vectored)` are not guaranteed to +process the entire buffer. They return how many bytes were processed, which +might be smaller +than a given buffer's length. If you don't need to deal with +partial-write/read, use +`write_all`/`read_exact` instead. + +When working with asynchronous code (either with the `futures` +crate or with `tokio`), a similar issue exists for +`AsyncWriteExt::write()` and `AsyncReadExt::read()` : these +functions are also not guaranteed to process the entire +buffer. Your code should either handle partial-writes/reads, or +call the `write_all`/`read_exact` methods on those traits instead. + +### Known problems +Detects only common patterns. + +### Examples +``` +use std::io; +fn foo(w: &mut W) -> io::Result<()> { + // must be `w.write_all(b"foo")?;` + w.write(b"foo")?; + Ok(()) +} +``` \ No newline at end of file diff --git a/src/docs/unused_peekable.txt b/src/docs/unused_peekable.txt new file mode 100644 index 0000000000000..268de1ce3bec3 --- /dev/null +++ b/src/docs/unused_peekable.txt @@ -0,0 +1,26 @@ +### What it does +Checks for the creation of a `peekable` iterator that is never `.peek()`ed + +### Why is this bad? +Creating a peekable iterator without using any of its methods is likely a mistake, +or just a leftover after a refactor. + +### Example +``` +let collection = vec![1, 2, 3]; +let iter = collection.iter().peekable(); + +for item in iter { + // ... +} +``` + +Use instead: +``` +let collection = vec![1, 2, 3]; +let iter = collection.iter(); + +for item in iter { + // ... +} +``` \ No newline at end of file diff --git a/src/docs/unused_rounding.txt b/src/docs/unused_rounding.txt new file mode 100644 index 0000000000000..70947aceee77b --- /dev/null +++ b/src/docs/unused_rounding.txt @@ -0,0 +1,17 @@ +### What it does + +Detects cases where a whole-number literal float is being rounded, using +the `floor`, `ceil`, or `round` methods. + +### Why is this bad? + +This is unnecessary and confusing to the reader. Doing this is probably a mistake. + +### Example +``` +let x = 1f32.ceil(); +``` +Use instead: +``` +let x = 1f32; +``` \ No newline at end of file diff --git a/src/docs/unused_self.txt b/src/docs/unused_self.txt new file mode 100644 index 0000000000000..a8d0fc7598954 --- /dev/null +++ b/src/docs/unused_self.txt @@ -0,0 +1,23 @@ +### What it does +Checks methods that contain a `self` argument but don't use it + +### Why is this bad? +It may be clearer to define the method as an associated function instead +of an instance method if it doesn't require `self`. + +### Example +``` +struct A; +impl A { + fn method(&self) {} +} +``` + +Could be written: + +``` +struct A; +impl A { + fn method() {} +} +``` \ No newline at end of file diff --git a/src/docs/unused_unit.txt b/src/docs/unused_unit.txt new file mode 100644 index 0000000000000..48d16ca655232 --- /dev/null +++ b/src/docs/unused_unit.txt @@ -0,0 +1,18 @@ +### What it does +Checks for unit (`()`) expressions that can be removed. + +### Why is this bad? +Such expressions add no value, but can make the code +less readable. Depending on formatting they can make a `break` or `return` +statement look like a function call. + +### Example +``` +fn return_unit() -> () { + () +} +``` +is equivalent to +``` +fn return_unit() {} +``` \ No newline at end of file diff --git a/src/docs/unusual_byte_groupings.txt b/src/docs/unusual_byte_groupings.txt new file mode 100644 index 0000000000000..9a1f132a6112f --- /dev/null +++ b/src/docs/unusual_byte_groupings.txt @@ -0,0 +1,12 @@ +### What it does +Warns if hexadecimal or binary literals are not grouped +by nibble or byte. + +### Why is this bad? +Negatively impacts readability. + +### Example +``` +let x: u32 = 0xFFF_FFF; +let y: u8 = 0b01_011_101; +``` \ No newline at end of file diff --git a/src/docs/unwrap_in_result.txt b/src/docs/unwrap_in_result.txt new file mode 100644 index 0000000000000..7497dd863d354 --- /dev/null +++ b/src/docs/unwrap_in_result.txt @@ -0,0 +1,39 @@ +### What it does +Checks for functions of type `Result` that contain `expect()` or `unwrap()` + +### Why is this bad? +These functions promote recoverable errors to non-recoverable errors which may be undesirable in code bases which wish to avoid panics. + +### Known problems +This can cause false positives in functions that handle both recoverable and non recoverable errors. + +### Example +Before: +``` +fn divisible_by_3(i_str: String) -> Result<(), String> { + let i = i_str + .parse::() + .expect("cannot divide the input by three"); + + if i % 3 != 0 { + Err("Number is not divisible by 3")? + } + + Ok(()) +} +``` + +After: +``` +fn divisible_by_3(i_str: String) -> Result<(), String> { + let i = i_str + .parse::() + .map_err(|e| format!("cannot divide the input by three: {}", e))?; + + if i % 3 != 0 { + Err("Number is not divisible by 3")? + } + + Ok(()) +} +``` \ No newline at end of file diff --git a/src/docs/unwrap_or_else_default.txt b/src/docs/unwrap_or_else_default.txt new file mode 100644 index 0000000000000..34b4cf088581f --- /dev/null +++ b/src/docs/unwrap_or_else_default.txt @@ -0,0 +1,18 @@ +### What it does +Checks for usages of `_.unwrap_or_else(Default::default)` on `Option` and +`Result` values. + +### Why is this bad? +Readability, these can be written as `_.unwrap_or_default`, which is +simpler and more concise. + +### Examples +``` +x.unwrap_or_else(Default::default); +x.unwrap_or_else(u32::default); +``` + +Use instead: +``` +x.unwrap_or_default(); +``` \ No newline at end of file diff --git a/src/docs/unwrap_used.txt b/src/docs/unwrap_used.txt new file mode 100644 index 0000000000000..9b4713df515d6 --- /dev/null +++ b/src/docs/unwrap_used.txt @@ -0,0 +1,37 @@ +### What it does +Checks for `.unwrap()` or `.unwrap_err()` calls on `Result`s and `.unwrap()` call on `Option`s. + +### Why is this bad? +It is better to handle the `None` or `Err` case, +or at least call `.expect(_)` with a more helpful message. Still, for a lot of +quick-and-dirty code, `unwrap` is a good choice, which is why this lint is +`Allow` by default. + +`result.unwrap()` will let the thread panic on `Err` values. +Normally, you want to implement more sophisticated error handling, +and propagate errors upwards with `?` operator. + +Even if you want to panic on errors, not all `Error`s implement good +messages on display. Therefore, it may be beneficial to look at the places +where they may get displayed. Activate this lint to do just that. + +### Examples +``` +option.unwrap(); +result.unwrap(); +``` + +Use instead: +``` +option.expect("more helpful message"); +result.expect("more helpful message"); +``` + +If [expect_used](#expect_used) is enabled, instead: +``` +option?; + +// or + +result?; +``` \ No newline at end of file diff --git a/src/docs/upper_case_acronyms.txt b/src/docs/upper_case_acronyms.txt new file mode 100644 index 0000000000000..a1e39c7e10c6e --- /dev/null +++ b/src/docs/upper_case_acronyms.txt @@ -0,0 +1,25 @@ +### What it does +Checks for fully capitalized names and optionally names containing a capitalized acronym. + +### Why is this bad? +In CamelCase, acronyms count as one word. +See [naming conventions](https://rust-lang.github.io/api-guidelines/naming.html#casing-conforms-to-rfc-430-c-case) +for more. + +By default, the lint only triggers on fully-capitalized names. +You can use the `upper-case-acronyms-aggressive: true` config option to enable linting +on all camel case names + +### Known problems +When two acronyms are contiguous, the lint can't tell where +the first acronym ends and the second starts, so it suggests to lowercase all of +the letters in the second acronym. + +### Example +``` +struct HTTPResponse; +``` +Use instead: +``` +struct HttpResponse; +``` \ No newline at end of file diff --git a/src/docs/use_debug.txt b/src/docs/use_debug.txt new file mode 100644 index 0000000000000..94d4a6fd29ae5 --- /dev/null +++ b/src/docs/use_debug.txt @@ -0,0 +1,12 @@ +### What it does +Checks for use of `Debug` formatting. The purpose of this +lint is to catch debugging remnants. + +### Why is this bad? +The purpose of the `Debug` trait is to facilitate +debugging Rust code. It should not be used in user-facing output. + +### Example +``` +println!("{:?}", foo); +``` \ No newline at end of file diff --git a/src/docs/use_self.txt b/src/docs/use_self.txt new file mode 100644 index 0000000000000..bd37ed1e00256 --- /dev/null +++ b/src/docs/use_self.txt @@ -0,0 +1,31 @@ +### What it does +Checks for unnecessary repetition of structure name when a +replacement with `Self` is applicable. + +### Why is this bad? +Unnecessary repetition. Mixed use of `Self` and struct +name +feels inconsistent. + +### Known problems +- Unaddressed false negative in fn bodies of trait implementations +- False positive with associated types in traits (#4140) + +### Example +``` +struct Foo; +impl Foo { + fn new() -> Foo { + Foo {} + } +} +``` +could be +``` +struct Foo; +impl Foo { + fn new() -> Self { + Self {} + } +} +``` \ No newline at end of file diff --git a/src/docs/used_underscore_binding.txt b/src/docs/used_underscore_binding.txt new file mode 100644 index 0000000000000..ed67c41eb0dbf --- /dev/null +++ b/src/docs/used_underscore_binding.txt @@ -0,0 +1,19 @@ +### What it does +Checks for the use of bindings with a single leading +underscore. + +### Why is this bad? +A single leading underscore is usually used to indicate +that a binding will not be used. Using such a binding breaks this +expectation. + +### Known problems +The lint does not work properly with desugaring and +macro, it has been allowed in the mean time. + +### Example +``` +let _x = 0; +let y = _x + 1; // Here we are using `_x`, even though it has a leading + // underscore. We should rename `_x` to `x` +``` \ No newline at end of file diff --git a/src/docs/useless_asref.txt b/src/docs/useless_asref.txt new file mode 100644 index 0000000000000..f777cd3775edf --- /dev/null +++ b/src/docs/useless_asref.txt @@ -0,0 +1,17 @@ +### What it does +Checks for usage of `.as_ref()` or `.as_mut()` where the +types before and after the call are the same. + +### Why is this bad? +The call is unnecessary. + +### Example +``` +let x: &[i32] = &[1, 2, 3, 4, 5]; +do_stuff(x.as_ref()); +``` +The correct use would be: +``` +let x: &[i32] = &[1, 2, 3, 4, 5]; +do_stuff(x); +``` \ No newline at end of file diff --git a/src/docs/useless_attribute.txt b/src/docs/useless_attribute.txt new file mode 100644 index 0000000000000..e02d4c9078984 --- /dev/null +++ b/src/docs/useless_attribute.txt @@ -0,0 +1,36 @@ +### What it does +Checks for `extern crate` and `use` items annotated with +lint attributes. + +This lint permits lint attributes for lints emitted on the items themself. +For `use` items these lints are: +* deprecated +* unreachable_pub +* unused_imports +* clippy::enum_glob_use +* clippy::macro_use_imports +* clippy::wildcard_imports + +For `extern crate` items these lints are: +* `unused_imports` on items with `#[macro_use]` + +### Why is this bad? +Lint attributes have no effect on crate imports. Most +likely a `!` was forgotten. + +### Example +``` +#[deny(dead_code)] +extern crate foo; +#[forbid(dead_code)] +use foo::bar; +``` + +Use instead: +``` +#[allow(unused_imports)] +use foo::baz; +#[allow(unused_imports)] +#[macro_use] +extern crate baz; +``` \ No newline at end of file diff --git a/src/docs/useless_conversion.txt b/src/docs/useless_conversion.txt new file mode 100644 index 0000000000000..06000a7ad98d5 --- /dev/null +++ b/src/docs/useless_conversion.txt @@ -0,0 +1,17 @@ +### What it does +Checks for `Into`, `TryInto`, `From`, `TryFrom`, or `IntoIter` calls +which uselessly convert to the same type. + +### Why is this bad? +Redundant code. + +### Example +``` +// format!() returns a `String` +let s: String = format!("hello").into(); +``` + +Use instead: +``` +let s: String = format!("hello"); +``` \ No newline at end of file diff --git a/src/docs/useless_format.txt b/src/docs/useless_format.txt new file mode 100644 index 0000000000000..eb4819da1e95a --- /dev/null +++ b/src/docs/useless_format.txt @@ -0,0 +1,22 @@ +### What it does +Checks for the use of `format!("string literal with no +argument")` and `format!("{}", foo)` where `foo` is a string. + +### Why is this bad? +There is no point of doing that. `format!("foo")` can +be replaced by `"foo".to_owned()` if you really need a `String`. The even +worse `&format!("foo")` is often encountered in the wild. `format!("{}", +foo)` can be replaced by `foo.clone()` if `foo: String` or `foo.to_owned()` +if `foo: &str`. + +### Examples +``` +let foo = "foo"; +format!("{}", foo); +``` + +Use instead: +``` +let foo = "foo"; +foo.to_owned(); +``` \ No newline at end of file diff --git a/src/docs/useless_let_if_seq.txt b/src/docs/useless_let_if_seq.txt new file mode 100644 index 0000000000000..c6dcd57eb2e2d --- /dev/null +++ b/src/docs/useless_let_if_seq.txt @@ -0,0 +1,39 @@ +### What it does +Checks for variable declarations immediately followed by a +conditional affectation. + +### Why is this bad? +This is not idiomatic Rust. + +### Example +``` +let foo; + +if bar() { + foo = 42; +} else { + foo = 0; +} + +let mut baz = None; + +if bar() { + baz = Some(42); +} +``` + +should be written + +``` +let foo = if bar() { + 42 +} else { + 0 +}; + +let baz = if bar() { + Some(42) +} else { + None +}; +``` \ No newline at end of file diff --git a/src/docs/useless_transmute.txt b/src/docs/useless_transmute.txt new file mode 100644 index 0000000000000..1d3a175881455 --- /dev/null +++ b/src/docs/useless_transmute.txt @@ -0,0 +1,12 @@ +### What it does +Checks for transmutes to the original type of the object +and transmutes that could be a cast. + +### Why is this bad? +Readability. The code tricks people into thinking that +something complex is going on. + +### Example +``` +core::intrinsics::transmute(t); // where the result type is the same as `t`'s +``` \ No newline at end of file diff --git a/src/docs/useless_vec.txt b/src/docs/useless_vec.txt new file mode 100644 index 0000000000000..ee5afc99e4bf2 --- /dev/null +++ b/src/docs/useless_vec.txt @@ -0,0 +1,18 @@ +### What it does +Checks for usage of `&vec![..]` when using `&[..]` would +be possible. + +### Why is this bad? +This is less efficient. + +### Example +``` +fn foo(_x: &[u8]) {} + +foo(&vec![1, 2]); +``` + +Use instead: +``` +foo(&[1, 2]); +``` \ No newline at end of file diff --git a/src/docs/vec_box.txt b/src/docs/vec_box.txt new file mode 100644 index 0000000000000..701b1c9ce9b94 --- /dev/null +++ b/src/docs/vec_box.txt @@ -0,0 +1,26 @@ +### What it does +Checks for use of `Vec>` where T: Sized anywhere in the code. +Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information. + +### Why is this bad? +`Vec` already keeps its contents in a separate area on +the heap. So if you `Box` its contents, you just add another level of indirection. + +### Known problems +Vec> makes sense if T is a large type (see [#3530](https://github.com/rust-lang/rust-clippy/issues/3530), +1st comment). + +### Example +``` +struct X { + values: Vec>, +} +``` + +Better: + +``` +struct X { + values: Vec, +} +``` \ No newline at end of file diff --git a/src/docs/vec_init_then_push.txt b/src/docs/vec_init_then_push.txt new file mode 100644 index 0000000000000..445f2874796bb --- /dev/null +++ b/src/docs/vec_init_then_push.txt @@ -0,0 +1,23 @@ +### What it does +Checks for calls to `push` immediately after creating a new `Vec`. + +If the `Vec` is created using `with_capacity` this will only lint if the capacity is a +constant and the number of pushes is greater than or equal to the initial capacity. + +If the `Vec` is extended after the initial sequence of pushes and it was default initialized +then this will only lint after there were at least four pushes. This number may change in +the future. + +### Why is this bad? +The `vec![]` macro is both more performant and easier to read than +multiple `push` calls. + +### Example +``` +let mut v = Vec::new(); +v.push(0); +``` +Use instead: +``` +let v = vec![0]; +``` \ No newline at end of file diff --git a/src/docs/vec_resize_to_zero.txt b/src/docs/vec_resize_to_zero.txt new file mode 100644 index 0000000000000..0b92686772bb0 --- /dev/null +++ b/src/docs/vec_resize_to_zero.txt @@ -0,0 +1,15 @@ +### What it does +Finds occurrences of `Vec::resize(0, an_int)` + +### Why is this bad? +This is probably an argument inversion mistake. + +### Example +``` +vec!(1, 2, 3, 4, 5).resize(0, 5) +``` + +Use instead: +``` +vec!(1, 2, 3, 4, 5).clear() +``` \ No newline at end of file diff --git a/src/docs/verbose_bit_mask.txt b/src/docs/verbose_bit_mask.txt new file mode 100644 index 0000000000000..87a84702925ed --- /dev/null +++ b/src/docs/verbose_bit_mask.txt @@ -0,0 +1,15 @@ +### What it does +Checks for bit masks that can be replaced by a call +to `trailing_zeros` + +### Why is this bad? +`x.trailing_zeros() > 4` is much clearer than `x & 15 +== 0` + +### Known problems +llvm generates better code for `x & 15 == 0` on x86 + +### Example +``` +if x & 0b1111 == 0 { } +``` \ No newline at end of file diff --git a/src/docs/verbose_file_reads.txt b/src/docs/verbose_file_reads.txt new file mode 100644 index 0000000000000..9703df423a575 --- /dev/null +++ b/src/docs/verbose_file_reads.txt @@ -0,0 +1,17 @@ +### What it does +Checks for use of File::read_to_end and File::read_to_string. + +### Why is this bad? +`fs::{read, read_to_string}` provide the same functionality when `buf` is empty with fewer imports and no intermediate values. +See also: [fs::read docs](https://doc.rust-lang.org/std/fs/fn.read.html), [fs::read_to_string docs](https://doc.rust-lang.org/std/fs/fn.read_to_string.html) + +### Example +``` +let mut f = File::open("foo.txt").unwrap(); +let mut bytes = Vec::new(); +f.read_to_end(&mut bytes).unwrap(); +``` +Can be written more concisely as +``` +let mut bytes = fs::read("foo.txt").unwrap(); +``` \ No newline at end of file diff --git a/src/docs/vtable_address_comparisons.txt b/src/docs/vtable_address_comparisons.txt new file mode 100644 index 0000000000000..4a34e4ba78ef4 --- /dev/null +++ b/src/docs/vtable_address_comparisons.txt @@ -0,0 +1,17 @@ +### What it does +Checks for comparisons with an address of a trait vtable. + +### Why is this bad? +Comparing trait objects pointers compares an vtable addresses which +are not guaranteed to be unique and could vary between different code generation units. +Furthermore vtables for different types could have the same address after being merged +together. + +### Example +``` +let a: Rc = ... +let b: Rc = ... +if Rc::ptr_eq(&a, &b) { + ... +} +``` \ No newline at end of file diff --git a/src/docs/while_immutable_condition.txt b/src/docs/while_immutable_condition.txt new file mode 100644 index 0000000000000..71800701f4897 --- /dev/null +++ b/src/docs/while_immutable_condition.txt @@ -0,0 +1,20 @@ +### What it does +Checks whether variables used within while loop condition +can be (and are) mutated in the body. + +### Why is this bad? +If the condition is unchanged, entering the body of the loop +will lead to an infinite loop. + +### Known problems +If the `while`-loop is in a closure, the check for mutation of the +condition variables in the body can cause false negatives. For example when only `Upvar` `a` is +in the condition and only `Upvar` `b` gets mutated in the body, the lint will not trigger. + +### Example +``` +let i = 0; +while i > 10 { + println!("let me loop forever!"); +} +``` \ No newline at end of file diff --git a/src/docs/while_let_loop.txt b/src/docs/while_let_loop.txt new file mode 100644 index 0000000000000..ab7bf60975ec5 --- /dev/null +++ b/src/docs/while_let_loop.txt @@ -0,0 +1,25 @@ +### What it does +Detects `loop + match` combinations that are easier +written as a `while let` loop. + +### Why is this bad? +The `while let` loop is usually shorter and more +readable. + +### Known problems +Sometimes the wrong binding is displayed ([#383](https://github.com/rust-lang/rust-clippy/issues/383)). + +### Example +``` +loop { + let x = match y { + Some(x) => x, + None => break, + }; + // .. do something with x +} +// is easier written as +while let Some(x) = y { + // .. do something with x +}; +``` \ No newline at end of file diff --git a/src/docs/while_let_on_iterator.txt b/src/docs/while_let_on_iterator.txt new file mode 100644 index 0000000000000..af053c541199d --- /dev/null +++ b/src/docs/while_let_on_iterator.txt @@ -0,0 +1,20 @@ +### What it does +Checks for `while let` expressions on iterators. + +### Why is this bad? +Readability. A simple `for` loop is shorter and conveys +the intent better. + +### Example +``` +while let Some(val) = iter.next() { + .. +} +``` + +Use instead: +``` +for val in &mut iter { + .. +} +``` \ No newline at end of file diff --git a/src/docs/wildcard_dependencies.txt b/src/docs/wildcard_dependencies.txt new file mode 100644 index 0000000000000..2affaf9740d9f --- /dev/null +++ b/src/docs/wildcard_dependencies.txt @@ -0,0 +1,13 @@ +### What it does +Checks for wildcard dependencies in the `Cargo.toml`. + +### Why is this bad? +[As the edition guide says](https://rust-lang-nursery.github.io/edition-guide/rust-2018/cargo-and-crates-io/crates-io-disallows-wildcard-dependencies.html), +it is highly unlikely that you work with any possible version of your dependency, +and wildcard dependencies would cause unnecessary breakage in the ecosystem. + +### Example +``` +[dependencies] +regex = "*" +``` \ No newline at end of file diff --git a/src/docs/wildcard_enum_match_arm.txt b/src/docs/wildcard_enum_match_arm.txt new file mode 100644 index 0000000000000..09807c01c652b --- /dev/null +++ b/src/docs/wildcard_enum_match_arm.txt @@ -0,0 +1,25 @@ +### What it does +Checks for wildcard enum matches using `_`. + +### Why is this bad? +New enum variants added by library updates can be missed. + +### Known problems +Suggested replacements may be incorrect if guards exhaustively cover some +variants, and also may not use correct path to enum if it's not present in the current scope. + +### Example +``` +match x { + Foo::A(_) => {}, + _ => {}, +} +``` + +Use instead: +``` +match x { + Foo::A(_) => {}, + Foo::B(_) => {}, +} +``` \ No newline at end of file diff --git a/src/docs/wildcard_imports.txt b/src/docs/wildcard_imports.txt new file mode 100644 index 0000000000000..bd56aa5b08282 --- /dev/null +++ b/src/docs/wildcard_imports.txt @@ -0,0 +1,45 @@ +### What it does +Checks for wildcard imports `use _::*`. + +### Why is this bad? +wildcard imports can pollute the namespace. This is especially bad if +you try to import something through a wildcard, that already has been imported by name from +a different source: + +``` +use crate1::foo; // Imports a function named foo +use crate2::*; // Has a function named foo + +foo(); // Calls crate1::foo +``` + +This can lead to confusing error messages at best and to unexpected behavior at worst. + +### Exceptions +Wildcard imports are allowed from modules named `prelude`. Many crates (including the standard library) +provide modules named "prelude" specifically designed for wildcard import. + +`use super::*` is allowed in test modules. This is defined as any module with "test" in the name. + +These exceptions can be disabled using the `warn-on-all-wildcard-imports` configuration flag. + +### Known problems +If macros are imported through the wildcard, this macro is not included +by the suggestion and has to be added by hand. + +Applying the suggestion when explicit imports of the things imported with a glob import +exist, may result in `unused_imports` warnings. + +### Example +``` +use crate1::*; + +foo(); +``` + +Use instead: +``` +use crate1::foo; + +foo(); +``` \ No newline at end of file diff --git a/src/docs/wildcard_in_or_patterns.txt b/src/docs/wildcard_in_or_patterns.txt new file mode 100644 index 0000000000000..70468ca41e0b8 --- /dev/null +++ b/src/docs/wildcard_in_or_patterns.txt @@ -0,0 +1,22 @@ +### What it does +Checks for wildcard pattern used with others patterns in same match arm. + +### Why is this bad? +Wildcard pattern already covers any other pattern as it will match anyway. +It makes the code less readable, especially to spot wildcard pattern use in match arm. + +### Example +``` +match s { + "a" => {}, + "bar" | _ => {}, +} +``` + +Use instead: +``` +match s { + "a" => {}, + _ => {}, +} +``` \ No newline at end of file diff --git a/src/docs/write_literal.txt b/src/docs/write_literal.txt new file mode 100644 index 0000000000000..9c41a48f9f731 --- /dev/null +++ b/src/docs/write_literal.txt @@ -0,0 +1,21 @@ +### What it does +This lint warns about the use of literals as `write!`/`writeln!` args. + +### Why is this bad? +Using literals as `writeln!` args is inefficient +(c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary +(i.e., just put the literal in the format string) + +### Known problems +Will also warn with macro calls as arguments that expand to literals +-- e.g., `writeln!(buf, "{}", env!("FOO"))`. + +### Example +``` +writeln!(buf, "{}", "foo"); +``` + +Use instead: +``` +writeln!(buf, "foo"); +``` \ No newline at end of file diff --git a/src/docs/write_with_newline.txt b/src/docs/write_with_newline.txt new file mode 100644 index 0000000000000..22845fd6515bd --- /dev/null +++ b/src/docs/write_with_newline.txt @@ -0,0 +1,18 @@ +### What it does +This lint warns when you use `write!()` with a format +string that +ends in a newline. + +### Why is this bad? +You should use `writeln!()` instead, which appends the +newline. + +### Example +``` +write!(buf, "Hello {}!\n", name); +``` + +Use instead: +``` +writeln!(buf, "Hello {}!", name); +``` \ No newline at end of file diff --git a/src/docs/writeln_empty_string.txt b/src/docs/writeln_empty_string.txt new file mode 100644 index 0000000000000..3b3aeb79a48bc --- /dev/null +++ b/src/docs/writeln_empty_string.txt @@ -0,0 +1,16 @@ +### What it does +This lint warns when you use `writeln!(buf, "")` to +print a newline. + +### Why is this bad? +You should use `writeln!(buf)`, which is simpler. + +### Example +``` +writeln!(buf, ""); +``` + +Use instead: +``` +writeln!(buf); +``` \ No newline at end of file diff --git a/src/docs/wrong_self_convention.txt b/src/docs/wrong_self_convention.txt new file mode 100644 index 0000000000000..d6b69ab87f862 --- /dev/null +++ b/src/docs/wrong_self_convention.txt @@ -0,0 +1,39 @@ +### What it does +Checks for methods with certain name prefixes and which +doesn't match how self is taken. The actual rules are: + +|Prefix |Postfix |`self` taken | `self` type | +|-------|------------|-------------------------------|--------------| +|`as_` | none |`&self` or `&mut self` | any | +|`from_`| none | none | any | +|`into_`| none |`self` | any | +|`is_` | none |`&mut self` or `&self` or none | any | +|`to_` | `_mut` |`&mut self` | any | +|`to_` | not `_mut` |`self` | `Copy` | +|`to_` | not `_mut` |`&self` | not `Copy` | + +Note: Clippy doesn't trigger methods with `to_` prefix in: +- Traits definition. +Clippy can not tell if a type that implements a trait is `Copy` or not. +- Traits implementation, when `&self` is taken. +The method signature is controlled by the trait and often `&self` is required for all types that implement the trait +(see e.g. the `std::string::ToString` trait). + +Clippy allows `Pin<&Self>` and `Pin<&mut Self>` if `&self` and `&mut self` is required. + +Please find more info here: +https://rust-lang.github.io/api-guidelines/naming.html#ad-hoc-conversions-follow-as_-to_-into_-conventions-c-conv + +### Why is this bad? +Consistency breeds readability. If you follow the +conventions, your users won't be surprised that they, e.g., need to supply a +mutable reference to a `as_..` function. + +### Example +``` +impl X { + fn as_str(self) -> &'static str { + // .. + } +} +``` \ No newline at end of file diff --git a/src/docs/wrong_transmute.txt b/src/docs/wrong_transmute.txt new file mode 100644 index 0000000000000..9fc71e0e382e3 --- /dev/null +++ b/src/docs/wrong_transmute.txt @@ -0,0 +1,15 @@ +### What it does +Checks for transmutes that can't ever be correct on any +architecture. + +### Why is this bad? +It's basically guaranteed to be undefined behavior. + +### Known problems +When accessing C, users might want to store pointer +sized objects in `extradata` arguments to save an allocation. + +### Example +``` +let ptr: *const T = core::intrinsics::transmute('x') +``` \ No newline at end of file diff --git a/src/docs/zero_divided_by_zero.txt b/src/docs/zero_divided_by_zero.txt new file mode 100644 index 0000000000000..394de20c0c0c6 --- /dev/null +++ b/src/docs/zero_divided_by_zero.txt @@ -0,0 +1,15 @@ +### What it does +Checks for `0.0 / 0.0`. + +### Why is this bad? +It's less readable than `f32::NAN` or `f64::NAN`. + +### Example +``` +let nan = 0.0f32 / 0.0; +``` + +Use instead: +``` +let nan = f32::NAN; +``` \ No newline at end of file diff --git a/src/docs/zero_prefixed_literal.txt b/src/docs/zero_prefixed_literal.txt new file mode 100644 index 0000000000000..5c5588725363e --- /dev/null +++ b/src/docs/zero_prefixed_literal.txt @@ -0,0 +1,32 @@ +### What it does +Warns if an integral constant literal starts with `0`. + +### Why is this bad? +In some languages (including the infamous C language +and most of its +family), this marks an octal constant. In Rust however, this is a decimal +constant. This could +be confusing for both the writer and a reader of the constant. + +### Example + +In Rust: +``` +fn main() { + let a = 0123; + println!("{}", a); +} +``` + +prints `123`, while in C: + +``` +#include + +int main() { + int a = 0123; + printf("%d\n", a); +} +``` + +prints `83` (as `83 == 0o123` while `123 == 0o173`). \ No newline at end of file diff --git a/src/docs/zero_ptr.txt b/src/docs/zero_ptr.txt new file mode 100644 index 0000000000000..e768a02366009 --- /dev/null +++ b/src/docs/zero_ptr.txt @@ -0,0 +1,16 @@ +### What it does +Catch casts from `0` to some pointer type + +### Why is this bad? +This generally means `null` and is better expressed as +{`std`, `core`}`::ptr::`{`null`, `null_mut`}. + +### Example +``` +let a = 0 as *const u32; +``` + +Use instead: +``` +let a = std::ptr::null::(); +``` \ No newline at end of file diff --git a/src/docs/zero_sized_map_values.txt b/src/docs/zero_sized_map_values.txt new file mode 100644 index 0000000000000..0502bdbf3950e --- /dev/null +++ b/src/docs/zero_sized_map_values.txt @@ -0,0 +1,24 @@ +### What it does +Checks for maps with zero-sized value types anywhere in the code. + +### Why is this bad? +Since there is only a single value for a zero-sized type, a map +containing zero sized values is effectively a set. Using a set in that case improves +readability and communicates intent more clearly. + +### Known problems +* A zero-sized type cannot be recovered later if it contains private fields. +* This lints the signature of public items + +### Example +``` +fn unique_words(text: &str) -> HashMap<&str, ()> { + todo!(); +} +``` +Use instead: +``` +fn unique_words(text: &str) -> HashSet<&str> { + todo!(); +} +``` \ No newline at end of file diff --git a/src/docs/zst_offset.txt b/src/docs/zst_offset.txt new file mode 100644 index 0000000000000..5810455ee9550 --- /dev/null +++ b/src/docs/zst_offset.txt @@ -0,0 +1,11 @@ +### What it does +Checks for `offset(_)`, `wrapping_`{`add`, `sub`}, etc. on raw pointers to +zero-sized types + +### Why is this bad? +This is a no-op, and likely unintended + +### Example +``` +unsafe { (&() as *const ()).offset(1) }; +``` \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 9ee4a40cbf242..4a32e0e54a81b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,6 +7,8 @@ use std::env; use std::path::PathBuf; use std::process::{self, Command}; +mod docs; + const CARGO_CLIPPY_HELP: &str = r#"Checks a package to catch common mistakes and improve your Rust code. Usage: @@ -17,6 +19,7 @@ Common options: --fix Automatically apply lint suggestions. This flag implies `--no-deps` -h, --help Print this message -V, --version Print version info and exit + --explain LINT Print the documentation for a given lint Other options are the same as `cargo check`. @@ -54,6 +57,16 @@ pub fn main() { return; } + if let Some(pos) = env::args().position(|a| a == "--explain") { + if let Some(mut lint) = env::args().nth(pos + 1) { + lint.make_ascii_lowercase(); + docs::explain(&lint.strip_prefix("clippy::").unwrap_or(&lint).replace('-', "_")); + } else { + show_help(); + } + return; + } + if let Err(code) = process(env::args().skip(2)) { process::exit(code); } diff --git a/tests/ui-toml/arithmetic_allowed/clippy.toml b/tests/ui-toml/arithmetic_allowed/clippy.toml deleted file mode 100644 index cc40570b12a08..0000000000000 --- a/tests/ui-toml/arithmetic_allowed/clippy.toml +++ /dev/null @@ -1 +0,0 @@ -arithmetic-allowed = ["Point"] diff --git a/tests/ui-toml/arithmetic_allowed/arithmetic_allowed.rs b/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs similarity index 89% rename from tests/ui-toml/arithmetic_allowed/arithmetic_allowed.rs rename to tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs index 195fabdbf710b..1aed09b7c7bd4 100644 --- a/tests/ui-toml/arithmetic_allowed/arithmetic_allowed.rs +++ b/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs @@ -1,4 +1,4 @@ -#![warn(clippy::arithmetic)] +#![warn(clippy::arithmetic_side_effects)] use core::ops::Add; diff --git a/tests/ui-toml/arithmetic_side_effects_allowed/clippy.toml b/tests/ui-toml/arithmetic_side_effects_allowed/clippy.toml new file mode 100644 index 0000000000000..e736256f29a47 --- /dev/null +++ b/tests/ui-toml/arithmetic_side_effects_allowed/clippy.toml @@ -0,0 +1 @@ +arithmetic-side-effects-allowed = ["Point"] diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index a52a0b5289fe4..f27f78d15d3a0 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -3,7 +3,7 @@ error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown fie allow-expect-in-tests allow-unwrap-in-tests allowed-scripts - arithmetic-allowed + arithmetic-side-effects-allowed array-size-threshold avoid-breaking-exported-api await-holding-invalid-types diff --git a/tests/ui/arithmetic.fixed b/tests/ui/arithmetic.fixed deleted file mode 100644 index a2a1c4394c21f..0000000000000 --- a/tests/ui/arithmetic.fixed +++ /dev/null @@ -1,27 +0,0 @@ -// run-rustfix - -#![allow(clippy::unnecessary_owned_empty_strings)] -#![feature(saturating_int_impl)] -#![warn(clippy::arithmetic)] - -use core::num::{Saturating, Wrapping}; - -pub fn hard_coded_allowed() { - let _ = Saturating(0u32) + Saturating(0u32); - let _ = String::new() + ""; - let _ = Wrapping(0u32) + Wrapping(0u32); - - let saturating: Saturating = Saturating(0u32); - let string: String = String::new(); - let wrapping: Wrapping = Wrapping(0u32); - - let inferred_saturating = saturating + saturating; - let inferred_string = string + ""; - let inferred_wrapping = wrapping + wrapping; - - let _ = inferred_saturating + inferred_saturating; - let _ = inferred_string + ""; - let _ = inferred_wrapping + inferred_wrapping; -} - -fn main() {} diff --git a/tests/ui/arithmetic.rs b/tests/ui/arithmetic.rs deleted file mode 100644 index a2a1c4394c21f..0000000000000 --- a/tests/ui/arithmetic.rs +++ /dev/null @@ -1,27 +0,0 @@ -// run-rustfix - -#![allow(clippy::unnecessary_owned_empty_strings)] -#![feature(saturating_int_impl)] -#![warn(clippy::arithmetic)] - -use core::num::{Saturating, Wrapping}; - -pub fn hard_coded_allowed() { - let _ = Saturating(0u32) + Saturating(0u32); - let _ = String::new() + ""; - let _ = Wrapping(0u32) + Wrapping(0u32); - - let saturating: Saturating = Saturating(0u32); - let string: String = String::new(); - let wrapping: Wrapping = Wrapping(0u32); - - let inferred_saturating = saturating + saturating; - let inferred_string = string + ""; - let inferred_wrapping = wrapping + wrapping; - - let _ = inferred_saturating + inferred_saturating; - let _ = inferred_string + ""; - let _ = inferred_wrapping + inferred_wrapping; -} - -fn main() {} diff --git a/tests/ui/arithmetic_side_effects.rs b/tests/ui/arithmetic_side_effects.rs new file mode 100644 index 0000000000000..f5390c7464250 --- /dev/null +++ b/tests/ui/arithmetic_side_effects.rs @@ -0,0 +1,57 @@ +#![allow(clippy::assign_op_pattern, clippy::unnecessary_owned_empty_strings)] +#![feature(inline_const, saturating_int_impl)] +#![warn(clippy::arithmetic_side_effects)] + +use core::num::{Saturating, Wrapping}; + +pub fn hard_coded_allowed() { + let _ = 1f32 + 1f32; + let _ = 1f64 + 1f64; + + let _ = Saturating(0u32) + Saturating(0u32); + let _ = String::new() + ""; + let _ = Wrapping(0u32) + Wrapping(0u32); + + let saturating: Saturating = Saturating(0u32); + let string: String = String::new(); + let wrapping: Wrapping = Wrapping(0u32); + + let inferred_saturating = saturating + saturating; + let inferred_string = string + ""; + let inferred_wrapping = wrapping + wrapping; + + let _ = inferred_saturating + inferred_saturating; + let _ = inferred_string + ""; + let _ = inferred_wrapping + inferred_wrapping; +} + +#[rustfmt::skip] +pub fn non_overflowing_ops() { + const _: i32 = { let mut n = 1; n += 1; n }; + let _ = const { let mut n = 1; n += 1; n }; + + const _: i32 = { let mut n = 1; n = n + 1; n }; + let _ = const { let mut n = 1; n = n + 1; n }; + + const _: i32 = { let mut n = 1; n = 1 + n; n }; + let _ = const { let mut n = 1; n = 1 + n; n }; + + const _: i32 = 1 + 1; + let _ = 1 + 1; + let _ = const { 1 + 1 }; + + let mut _a = 1; + _a *= 1; + _a /= 1; +} + +#[rustfmt::skip] +pub fn overflowing_ops() { + let mut _a = 1; _a += 1; + + let mut _b = 1; _b = _b + 1; + + let mut _c = 1; _c = 1 + _c; +} + +fn main() {} diff --git a/tests/ui/arithmetic_side_effects.stderr b/tests/ui/arithmetic_side_effects.stderr new file mode 100644 index 0000000000000..6c4c8bdec0f05 --- /dev/null +++ b/tests/ui/arithmetic_side_effects.stderr @@ -0,0 +1,22 @@ +error: arithmetic detected + --> $DIR/arithmetic_side_effects.rs:50:21 + | +LL | let mut _a = 1; _a += 1; + | ^^^^^^^ + | + = note: `-D clippy::arithmetic-side-effects` implied by `-D warnings` + +error: arithmetic detected + --> $DIR/arithmetic_side_effects.rs:52:26 + | +LL | let mut _b = 1; _b = _b + 1; + | ^^^^^^ + +error: arithmetic detected + --> $DIR/arithmetic_side_effects.rs:54:26 + | +LL | let mut _c = 1; _c = 1 + _c; + | ^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/author/struct.rs b/tests/ui/author/struct.rs index 5fdf3433a3702..a99bdfc131379 100644 --- a/tests/ui/author/struct.rs +++ b/tests/ui/author/struct.rs @@ -1,4 +1,9 @@ -#[allow(clippy::unnecessary_operation, clippy::single_match)] +#![allow( + clippy::unnecessary_operation, + clippy::single_match, + clippy::no_effect, + clippy::bool_to_int_with_if +)] fn main() { struct Test { field: u32, diff --git a/tests/ui/bool_to_int_with_if.fixed b/tests/ui/bool_to_int_with_if.fixed new file mode 100644 index 0000000000000..9c1098dc4c17a --- /dev/null +++ b/tests/ui/bool_to_int_with_if.fixed @@ -0,0 +1,85 @@ +// run-rustfix + +#![warn(clippy::bool_to_int_with_if)] +#![allow(unused, dead_code, clippy::unnecessary_operation, clippy::no_effect)] + +fn main() { + let a = true; + let b = false; + + let x = 1; + let y = 2; + + // Should lint + // precedence + i32::from(a); + i32::from(!a); + i32::from(a || b); + i32::from(cond(a, b)); + i32::from(x + y < 4); + + // if else if + if a { + 123 + } else {i32::from(b)}; + + // Shouldn't lint + + if a { + 1 + } else if b { + 0 + } else { + 3 + }; + + if a { + 3 + } else if b { + 1 + } else { + -2 + }; + + if a { + 3 + } else { + 0 + }; + if a { + side_effect(); + 1 + } else { + 0 + }; + if a { + 1 + } else { + side_effect(); + 0 + }; + + // multiple else ifs + if a { + 123 + } else if b { + 1 + } else if a | b { + 0 + } else { + 123 + }; + + some_fn(a); +} + +// Lint returns and type inference +fn some_fn(a: bool) -> u8 { + u8::from(a) +} + +fn side_effect() {} + +fn cond(a: bool, b: bool) -> bool { + a || b +} diff --git a/tests/ui/bool_to_int_with_if.rs b/tests/ui/bool_to_int_with_if.rs new file mode 100644 index 0000000000000..0c967dac6e2dd --- /dev/null +++ b/tests/ui/bool_to_int_with_if.rs @@ -0,0 +1,109 @@ +// run-rustfix + +#![warn(clippy::bool_to_int_with_if)] +#![allow(unused, dead_code, clippy::unnecessary_operation, clippy::no_effect)] + +fn main() { + let a = true; + let b = false; + + let x = 1; + let y = 2; + + // Should lint + // precedence + if a { + 1 + } else { + 0 + }; + if !a { + 1 + } else { + 0 + }; + if a || b { + 1 + } else { + 0 + }; + if cond(a, b) { + 1 + } else { + 0 + }; + if x + y < 4 { + 1 + } else { + 0 + }; + + // if else if + if a { + 123 + } else if b { + 1 + } else { + 0 + }; + + // Shouldn't lint + + if a { + 1 + } else if b { + 0 + } else { + 3 + }; + + if a { + 3 + } else if b { + 1 + } else { + -2 + }; + + if a { + 3 + } else { + 0 + }; + if a { + side_effect(); + 1 + } else { + 0 + }; + if a { + 1 + } else { + side_effect(); + 0 + }; + + // multiple else ifs + if a { + 123 + } else if b { + 1 + } else if a | b { + 0 + } else { + 123 + }; + + some_fn(a); +} + +// Lint returns and type inference +fn some_fn(a: bool) -> u8 { + if a { 1 } else { 0 } +} + +fn side_effect() {} + +fn cond(a: bool, b: bool) -> bool { + a || b +} diff --git a/tests/ui/bool_to_int_with_if.stderr b/tests/ui/bool_to_int_with_if.stderr new file mode 100644 index 0000000000000..8647a9cffbede --- /dev/null +++ b/tests/ui/bool_to_int_with_if.stderr @@ -0,0 +1,84 @@ +error: boolean to int conversion using if + --> $DIR/bool_to_int_with_if.rs:15:5 + | +LL | / if a { +LL | | 1 +LL | | } else { +LL | | 0 +LL | | }; + | |_____^ help: replace with from: `i32::from(a)` + | + = note: `-D clippy::bool-to-int-with-if` implied by `-D warnings` + = note: `a as i32` or `a.into()` can also be valid options + +error: boolean to int conversion using if + --> $DIR/bool_to_int_with_if.rs:20:5 + | +LL | / if !a { +LL | | 1 +LL | | } else { +LL | | 0 +LL | | }; + | |_____^ help: replace with from: `i32::from(!a)` + | + = note: `!a as i32` or `!a.into()` can also be valid options + +error: boolean to int conversion using if + --> $DIR/bool_to_int_with_if.rs:25:5 + | +LL | / if a || b { +LL | | 1 +LL | | } else { +LL | | 0 +LL | | }; + | |_____^ help: replace with from: `i32::from(a || b)` + | + = note: `(a || b) as i32` or `(a || b).into()` can also be valid options + +error: boolean to int conversion using if + --> $DIR/bool_to_int_with_if.rs:30:5 + | +LL | / if cond(a, b) { +LL | | 1 +LL | | } else { +LL | | 0 +LL | | }; + | |_____^ help: replace with from: `i32::from(cond(a, b))` + | + = note: `cond(a, b) as i32` or `cond(a, b).into()` can also be valid options + +error: boolean to int conversion using if + --> $DIR/bool_to_int_with_if.rs:35:5 + | +LL | / if x + y < 4 { +LL | | 1 +LL | | } else { +LL | | 0 +LL | | }; + | |_____^ help: replace with from: `i32::from(x + y < 4)` + | + = note: `(x + y < 4) as i32` or `(x + y < 4).into()` can also be valid options + +error: boolean to int conversion using if + --> $DIR/bool_to_int_with_if.rs:44:12 + | +LL | } else if b { + | ____________^ +LL | | 1 +LL | | } else { +LL | | 0 +LL | | }; + | |_____^ help: replace with from: `{i32::from(b)}` + | + = note: `b as i32` or `b.into()` can also be valid options + +error: boolean to int conversion using if + --> $DIR/bool_to_int_with_if.rs:102:5 + | +LL | if a { 1 } else { 0 } + | ^^^^^^^^^^^^^^^^^^^^^ help: replace with from: `u8::from(a)` + | + = note: `a as u8` or `a.into()` can also be valid options + +error: aborting due to 7 previous errors + diff --git a/tests/ui/crashes/ice-9405.rs b/tests/ui/crashes/ice-9405.rs new file mode 100644 index 0000000000000..e2d274aeb0442 --- /dev/null +++ b/tests/ui/crashes/ice-9405.rs @@ -0,0 +1,11 @@ +#![warn(clippy::useless_format)] +#![allow(clippy::print_literal)] + +fn main() { + println!( + "\ + + {}", + "multiple skipped lines" + ); +} diff --git a/tests/ui/crashes/ice-9405.stderr b/tests/ui/crashes/ice-9405.stderr new file mode 100644 index 0000000000000..9a6e410f21ea8 --- /dev/null +++ b/tests/ui/crashes/ice-9405.stderr @@ -0,0 +1,11 @@ +warning: multiple lines skipped by escaped newline + --> $DIR/ice-9405.rs:6:10 + | +LL | "/ + | __________^ +LL | | +LL | | {}", + | |____________^ skipping everything up to and including this point + +warning: 1 warning emitted + diff --git a/tests/ui/crashes/ice-9414.rs b/tests/ui/crashes/ice-9414.rs new file mode 100644 index 0000000000000..02cf5d5c240fa --- /dev/null +++ b/tests/ui/crashes/ice-9414.rs @@ -0,0 +1,8 @@ +#![warn(clippy::result_large_err)] + +trait T {} +fn f(_: &u32) -> Result<(), *const (dyn '_ + T)> { + Ok(()) +} + +fn main() {} diff --git a/tests/ui/floating_point_powf.fixed b/tests/ui/floating_point_powf.fixed index 7efe10a10f9e9..e7ef45634dff4 100644 --- a/tests/ui/floating_point_powf.fixed +++ b/tests/ui/floating_point_powf.fixed @@ -18,6 +18,11 @@ fn main() { let _ = x.powi(-16_777_215); let _ = (x as f32).powi(-16_777_215); let _ = (x as f32).powi(3); + let _ = (1.5_f32 + 1.0).cbrt(); + let _ = 1.5_f64.cbrt(); + let _ = 1.5_f64.sqrt(); + let _ = 1.5_f64.powi(3); + // Cases where the lint shouldn't be applied let _ = x.powf(2.1); let _ = x.powf(-2.1); diff --git a/tests/ui/floating_point_powf.rs b/tests/ui/floating_point_powf.rs index 445080417f2ed..d749aa2d48a41 100644 --- a/tests/ui/floating_point_powf.rs +++ b/tests/ui/floating_point_powf.rs @@ -18,6 +18,11 @@ fn main() { let _ = x.powf(-16_777_215.0); let _ = (x as f32).powf(-16_777_215.0); let _ = (x as f32).powf(3.0); + let _ = (1.5_f32 + 1.0).powf(1.0 / 3.0); + let _ = 1.5_f64.powf(1.0 / 3.0); + let _ = 1.5_f64.powf(1.0 / 2.0); + let _ = 1.5_f64.powf(3.0); + // Cases where the lint shouldn't be applied let _ = x.powf(2.1); let _ = x.powf(-2.1); diff --git a/tests/ui/floating_point_powf.stderr b/tests/ui/floating_point_powf.stderr index 6ee696e6ada5f..e9693de8fc909 100644 --- a/tests/ui/floating_point_powf.stderr +++ b/tests/ui/floating_point_powf.stderr @@ -92,77 +92,101 @@ error: exponentiation with integer powers can be computed more efficiently LL | let _ = (x as f32).powf(3.0); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).powi(3)` +error: cube-root of a number can be computed more accurately + --> $DIR/floating_point_powf.rs:21:13 + | +LL | let _ = (1.5_f32 + 1.0).powf(1.0 / 3.0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(1.5_f32 + 1.0).cbrt()` + +error: cube-root of a number can be computed more accurately + --> $DIR/floating_point_powf.rs:22:13 + | +LL | let _ = 1.5_f64.powf(1.0 / 3.0); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1.5_f64.cbrt()` + +error: square-root of a number can be computed more efficiently and accurately + --> $DIR/floating_point_powf.rs:23:13 + | +LL | let _ = 1.5_f64.powf(1.0 / 2.0); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1.5_f64.sqrt()` + +error: exponentiation with integer powers can be computed more efficiently + --> $DIR/floating_point_powf.rs:24:13 + | +LL | let _ = 1.5_f64.powf(3.0); + | ^^^^^^^^^^^^^^^^^ help: consider using: `1.5_f64.powi(3)` + error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:28:13 + --> $DIR/floating_point_powf.rs:33:13 | LL | let _ = 2f64.powf(x); | ^^^^^^^^^^^^ help: consider using: `x.exp2()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:29:13 + --> $DIR/floating_point_powf.rs:34:13 | LL | let _ = 2f64.powf(3.1); | ^^^^^^^^^^^^^^ help: consider using: `3.1f64.exp2()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:30:13 + --> $DIR/floating_point_powf.rs:35:13 | LL | let _ = 2f64.powf(-3.1); | ^^^^^^^^^^^^^^^ help: consider using: `(-3.1f64).exp2()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:31:13 + --> $DIR/floating_point_powf.rs:36:13 | LL | let _ = std::f64::consts::E.powf(x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.exp()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:32:13 + --> $DIR/floating_point_powf.rs:37:13 | LL | let _ = std::f64::consts::E.powf(3.1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `3.1f64.exp()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:33:13 + --> $DIR/floating_point_powf.rs:38:13 | LL | let _ = std::f64::consts::E.powf(-3.1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(-3.1f64).exp()` error: square-root of a number can be computed more efficiently and accurately - --> $DIR/floating_point_powf.rs:34:13 + --> $DIR/floating_point_powf.rs:39:13 | LL | let _ = x.powf(1.0 / 2.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `x.sqrt()` error: cube-root of a number can be computed more accurately - --> $DIR/floating_point_powf.rs:35:13 + --> $DIR/floating_point_powf.rs:40:13 | LL | let _ = x.powf(1.0 / 3.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `x.cbrt()` error: exponentiation with integer powers can be computed more efficiently - --> $DIR/floating_point_powf.rs:36:13 + --> $DIR/floating_point_powf.rs:41:13 | LL | let _ = x.powf(3.0); | ^^^^^^^^^^^ help: consider using: `x.powi(3)` error: exponentiation with integer powers can be computed more efficiently - --> $DIR/floating_point_powf.rs:37:13 + --> $DIR/floating_point_powf.rs:42:13 | LL | let _ = x.powf(-2.0); | ^^^^^^^^^^^^ help: consider using: `x.powi(-2)` error: exponentiation with integer powers can be computed more efficiently - --> $DIR/floating_point_powf.rs:38:13 + --> $DIR/floating_point_powf.rs:43:13 | LL | let _ = x.powf(-2_147_483_648.0); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(-2_147_483_648)` error: exponentiation with integer powers can be computed more efficiently - --> $DIR/floating_point_powf.rs:39:13 + --> $DIR/floating_point_powf.rs:44:13 | LL | let _ = x.powf(2_147_483_647.0); | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2_147_483_647)` -error: aborting due to 27 previous errors +error: aborting due to 31 previous errors diff --git a/tests/ui/large_enum_variant.rs b/tests/ui/large_enum_variant.rs index 23152a13322e8..717009e4c4cca 100644 --- a/tests/ui/large_enum_variant.rs +++ b/tests/ui/large_enum_variant.rs @@ -130,6 +130,30 @@ impl Clone for SomeGenericPossiblyCopyEnum { impl Copy for SomeGenericPossiblyCopyEnum {} +enum LargeEnumWithGenerics { + Small, + Large((T, [u8; 512])), +} + +struct Foo { + foo: T, +} + +enum WithGenerics { + Large([Foo; 64]), + Small(u8), +} + +enum PossiblyLargeEnumWithConst { + SmallBuffer([u8; 4]), + MightyBuffer([u16; U]), +} + +enum LargeEnumOfConst { + Ok, + Error(PossiblyLargeEnumWithConst<256>), +} + fn main() { large_enum_variant!(); } diff --git a/tests/ui/large_enum_variant.stderr b/tests/ui/large_enum_variant.stderr index 0248327262da0..c6ed97487c0e3 100644 --- a/tests/ui/large_enum_variant.stderr +++ b/tests/ui/large_enum_variant.stderr @@ -1,143 +1,177 @@ error: large size difference between variants - --> $DIR/large_enum_variant.rs:12:5 + --> $DIR/large_enum_variant.rs:10:1 | -LL | B([i32; 8000]), - | ^^^^^^^^^^^^^^ this variant is 32000 bytes +LL | / enum LargeEnum { +LL | | A(i32), + | | ------ the second-largest variant contains at least 4 bytes +LL | | B([i32; 8000]), + | | -------------- the largest variant contains at least 32000 bytes +LL | | } + | |_^ the entire enum is at least 32004 bytes | = note: `-D clippy::large-enum-variant` implied by `-D warnings` -note: and the second-largest variant is 4 bytes: - --> $DIR/large_enum_variant.rs:11:5 - | -LL | A(i32), - | ^^^^^^ help: consider boxing the large fields to reduce the total size of the enum | LL | B(Box<[i32; 8000]>), | ~~~~~~~~~~~~~~~~ error: large size difference between variants - --> $DIR/large_enum_variant.rs:36:5 - | -LL | ContainingLargeEnum(LargeEnum), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 32004 bytes + --> $DIR/large_enum_variant.rs:34:1 | -note: and the second-largest variant is 8 bytes: - --> $DIR/large_enum_variant.rs:35:5 +LL | / enum LargeEnum2 { +LL | | VariantOk(i32, u32), + | | ------------------- the second-largest variant contains at least 8 bytes +LL | | ContainingLargeEnum(LargeEnum), + | | ------------------------------ the largest variant contains at least 32004 bytes +LL | | } + | |_^ the entire enum is at least 32004 bytes | -LL | VariantOk(i32, u32), - | ^^^^^^^^^^^^^^^^^^^ help: consider boxing the large fields to reduce the total size of the enum | LL | ContainingLargeEnum(Box), | ~~~~~~~~~~~~~~ error: large size difference between variants - --> $DIR/large_enum_variant.rs:40:5 - | -LL | ContainingMoreThanOneField(i32, [i32; 8000], [i32; 9500]), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 70004 bytes + --> $DIR/large_enum_variant.rs:39:1 | -note: and the second-largest variant is 8 bytes: - --> $DIR/large_enum_variant.rs:42:5 +LL | / enum LargeEnum3 { +LL | | ContainingMoreThanOneField(i32, [i32; 8000], [i32; 9500]), + | | --------------------------------------------------------- the largest variant contains at least 70004 bytes +LL | | VoidVariant, +LL | | StructLikeLittle { x: i32, y: i32 }, + | | ----------------------------------- the second-largest variant contains at least 8 bytes +LL | | } + | |_^ the entire enum is at least 70008 bytes | -LL | StructLikeLittle { x: i32, y: i32 }, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider boxing the large fields to reduce the total size of the enum | LL | ContainingMoreThanOneField(i32, Box<[i32; 8000]>, Box<[i32; 9500]>), | ~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~ error: large size difference between variants - --> $DIR/large_enum_variant.rs:47:5 + --> $DIR/large_enum_variant.rs:45:1 | -LL | StructLikeLarge { x: [i32; 8000], y: i32 }, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 32004 bytes +LL | / enum LargeEnum4 { +LL | | VariantOk(i32, u32), + | | ------------------- the second-largest variant contains at least 8 bytes +LL | | StructLikeLarge { x: [i32; 8000], y: i32 }, + | | ------------------------------------------ the largest variant contains at least 32004 bytes +LL | | } + | |_^ the entire enum is at least 32008 bytes | -note: and the second-largest variant is 8 bytes: - --> $DIR/large_enum_variant.rs:46:5 - | -LL | VariantOk(i32, u32), - | ^^^^^^^^^^^^^^^^^^^ help: consider boxing the large fields to reduce the total size of the enum | LL | StructLikeLarge { x: Box<[i32; 8000]>, y: i32 }, | ~~~~~~~~~~~~~~~~ error: large size difference between variants - --> $DIR/large_enum_variant.rs:52:5 - | -LL | StructLikeLarge2 { x: [i32; 8000] }, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 32000 bytes + --> $DIR/large_enum_variant.rs:50:1 | -note: and the second-largest variant is 8 bytes: - --> $DIR/large_enum_variant.rs:51:5 +LL | / enum LargeEnum5 { +LL | | VariantOk(i32, u32), + | | ------------------- the second-largest variant contains at least 8 bytes +LL | | StructLikeLarge2 { x: [i32; 8000] }, + | | ----------------------------------- the largest variant contains at least 32000 bytes +LL | | } + | |_^ the entire enum is at least 32004 bytes | -LL | VariantOk(i32, u32), - | ^^^^^^^^^^^^^^^^^^^ help: consider boxing the large fields to reduce the total size of the enum | LL | StructLikeLarge2 { x: Box<[i32; 8000]> }, | ~~~~~~~~~~~~~~~~ error: large size difference between variants - --> $DIR/large_enum_variant.rs:68:5 - | -LL | B([u8; 1255]), - | ^^^^^^^^^^^^^ this variant is 1255 bytes + --> $DIR/large_enum_variant.rs:66:1 | -note: and the second-largest variant is 200 bytes: - --> $DIR/large_enum_variant.rs:69:5 +LL | / enum LargeEnum7 { +LL | | A, +LL | | B([u8; 1255]), + | | ------------- the largest variant contains at least 1255 bytes +LL | | C([u8; 200]), + | | ------------ the second-largest variant contains at least 200 bytes +LL | | } + | |_^ the entire enum is at least 1256 bytes | -LL | C([u8; 200]), - | ^^^^^^^^^^^^ help: consider boxing the large fields to reduce the total size of the enum | LL | B(Box<[u8; 1255]>), | ~~~~~~~~~~~~~~~ error: large size difference between variants - --> $DIR/large_enum_variant.rs:74:5 + --> $DIR/large_enum_variant.rs:72:1 | -LL | ContainingMoreThanOneField([i32; 8000], [i32; 2], [i32; 9500], [i32; 30]), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 70128 bytes +LL | / enum LargeEnum8 { +LL | | VariantOk(i32, u32), + | | ------------------- the second-largest variant contains at least 8 bytes +LL | | ContainingMoreThanOneField([i32; 8000], [i32; 2], [i32; 9500], [i32; 30]), + | | ------------------------------------------------------------------------- the largest variant contains at least 70128 bytes +LL | | } + | |_^ the entire enum is at least 70132 bytes | -note: and the second-largest variant is 8 bytes: - --> $DIR/large_enum_variant.rs:73:5 - | -LL | VariantOk(i32, u32), - | ^^^^^^^^^^^^^^^^^^^ help: consider boxing the large fields to reduce the total size of the enum | LL | ContainingMoreThanOneField(Box<[i32; 8000]>, [i32; 2], Box<[i32; 9500]>, [i32; 30]), | ~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~ error: large size difference between variants - --> $DIR/large_enum_variant.rs:79:5 + --> $DIR/large_enum_variant.rs:77:1 + | +LL | / enum LargeEnum9 { +LL | | A(Struct<()>), + | | ------------- the second-largest variant contains at least 4 bytes +LL | | B(Struct2), + | | ---------- the largest variant contains at least 32000 bytes +LL | | } + | |_^ the entire enum is at least 32004 bytes + | +help: consider boxing the large fields to reduce the total size of the enum | -LL | B(Struct2), - | ^^^^^^^^^^ this variant is 32000 bytes +LL | B(Box), + | ~~~~~~~~~~~~ + +error: large size difference between variants + --> $DIR/large_enum_variant.rs:82:1 | -note: and the second-largest variant is 4 bytes: - --> $DIR/large_enum_variant.rs:78:5 +LL | / enum LargeEnumOk2 { +LL | | A(T), + | | ---- the second-largest variant contains at least 0 bytes +LL | | B(Struct2), + | | ---------- the largest variant contains at least 32000 bytes +LL | | } + | |_^ the entire enum is at least 32000 bytes | -LL | A(Struct<()>), - | ^^^^^^^^^^^^^ help: consider boxing the large fields to reduce the total size of the enum | LL | B(Box), | ~~~~~~~~~~~~ error: large size difference between variants - --> $DIR/large_enum_variant.rs:104:5 + --> $DIR/large_enum_variant.rs:87:1 | -LL | B([u128; 4000]), - | ^^^^^^^^^^^^^^^ this variant is 64000 bytes +LL | / enum LargeEnumOk3 { +LL | | A(Struct), + | | ------------ the second-largest variant contains at least 4 bytes +LL | | B(Struct2), + | | ---------- the largest variant contains at least 32000 bytes +LL | | } + | |_^ the entire enum is at least 32000 bytes + | +help: consider boxing the large fields to reduce the total size of the enum | -note: and the second-largest variant is 1 bytes: - --> $DIR/large_enum_variant.rs:103:5 +LL | B(Box), + | ~~~~~~~~~~~~ + +error: large size difference between variants + --> $DIR/large_enum_variant.rs:102:1 + | +LL | / enum CopyableLargeEnum { +LL | | A(bool), + | | ------- the second-largest variant contains at least 1 bytes +LL | | B([u128; 4000]), + | | --------------- the largest variant contains at least 64000 bytes +LL | | } + | |_^ the entire enum is at least 64008 bytes | -LL | A(bool), - | ^^^^^^^ note: boxing a variant would require the type no longer be `Copy` --> $DIR/large_enum_variant.rs:102:6 | @@ -150,16 +184,16 @@ LL | B([u128; 4000]), | ^^^^^^^^^^^^^^^ error: large size difference between variants - --> $DIR/large_enum_variant.rs:109:5 + --> $DIR/large_enum_variant.rs:107:1 | -LL | B([u128; 4000]), - | ^^^^^^^^^^^^^^^ this variant is 64000 bytes - | -note: and the second-largest variant is 1 bytes: - --> $DIR/large_enum_variant.rs:108:5 +LL | / enum ManuallyCopyLargeEnum { +LL | | A(bool), + | | ------- the second-largest variant contains at least 1 bytes +LL | | B([u128; 4000]), + | | --------------- the largest variant contains at least 64000 bytes +LL | | } + | |_^ the entire enum is at least 64008 bytes | -LL | A(bool), - | ^^^^^^^ note: boxing a variant would require the type no longer be `Copy` --> $DIR/large_enum_variant.rs:107:6 | @@ -172,16 +206,16 @@ LL | B([u128; 4000]), | ^^^^^^^^^^^^^^^ error: large size difference between variants - --> $DIR/large_enum_variant.rs:122:5 + --> $DIR/large_enum_variant.rs:120:1 | -LL | B([u64; 4000]), - | ^^^^^^^^^^^^^^ this variant is 32000 bytes - | -note: and the second-largest variant is 1 bytes: - --> $DIR/large_enum_variant.rs:121:5 +LL | / enum SomeGenericPossiblyCopyEnum { +LL | | A(bool, std::marker::PhantomData), + | | ------------------------------------ the second-largest variant contains at least 1 bytes +LL | | B([u64; 4000]), + | | -------------- the largest variant contains at least 32000 bytes +LL | | } + | |_^ the entire enum is at least 32008 bytes | -LL | A(bool, std::marker::PhantomData), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: boxing a variant would require the type no longer be `Copy` --> $DIR/large_enum_variant.rs:120:6 | @@ -193,5 +227,53 @@ help: consider boxing the large fields to reduce the total size of the enum LL | B([u64; 4000]), | ^^^^^^^^^^^^^^ -error: aborting due to 11 previous errors +error: large size difference between variants + --> $DIR/large_enum_variant.rs:133:1 + | +LL | / enum LargeEnumWithGenerics { +LL | | Small, + | | ----- the second-largest variant carries no data at all +LL | | Large((T, [u8; 512])), + | | --------------------- the largest variant contains at least 512 bytes +LL | | } + | |_^ the entire enum is at least 512 bytes + | +help: consider boxing the large fields to reduce the total size of the enum + | +LL | Large(Box<(T, [u8; 512])>), + | ~~~~~~~~~~~~~~~~~~~ + +error: large size difference between variants + --> $DIR/large_enum_variant.rs:142:1 + | +LL | / enum WithGenerics { +LL | | Large([Foo; 64]), + | | --------------------- the largest variant contains at least 512 bytes +LL | | Small(u8), + | | --------- the second-largest variant contains at least 1 bytes +LL | | } + | |_^ the entire enum is at least 520 bytes + | +help: consider boxing the large fields to reduce the total size of the enum + | +LL | Large(Box<[Foo; 64]>), + | ~~~~~~~~~~~~~~~~~~~ + +error: large size difference between variants + --> $DIR/large_enum_variant.rs:152:1 + | +LL | / enum LargeEnumOfConst { +LL | | Ok, + | | -- the second-largest variant carries no data at all +LL | | Error(PossiblyLargeEnumWithConst<256>), + | | -------------------------------------- the largest variant contains at least 514 bytes +LL | | } + | |_^ the entire enum is at least 514 bytes + | +help: consider boxing the large fields to reduce the total size of the enum + | +LL | Error(Box>), + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to 16 previous errors diff --git a/tests/ui/match_wild_err_arm.edition2018.stderr b/tests/ui/match_wild_err_arm.edition2018.stderr index 2a4012039ba97..2d66daea8046e 100644 --- a/tests/ui/match_wild_err_arm.edition2018.stderr +++ b/tests/ui/match_wild_err_arm.edition2018.stderr @@ -5,7 +5,7 @@ LL | Err(_) => panic!("err"), | ^^^^^^ | = note: `-D clippy::match-wild-err-arm` implied by `-D warnings` - = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable + = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable error: `Err(_)` matches all errors --> $DIR/match_wild_err_arm.rs:20:9 @@ -13,7 +13,7 @@ error: `Err(_)` matches all errors LL | Err(_) => panic!(), | ^^^^^^ | - = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable + = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable error: `Err(_)` matches all errors --> $DIR/match_wild_err_arm.rs:26:9 @@ -21,7 +21,7 @@ error: `Err(_)` matches all errors LL | Err(_) => { | ^^^^^^ | - = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable + = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable error: `Err(_e)` matches all errors --> $DIR/match_wild_err_arm.rs:34:9 @@ -29,7 +29,7 @@ error: `Err(_e)` matches all errors LL | Err(_e) => panic!(), | ^^^^^^^ | - = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable + = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable error: aborting due to 4 previous errors diff --git a/tests/ui/match_wild_err_arm.edition2021.stderr b/tests/ui/match_wild_err_arm.edition2021.stderr index 2a4012039ba97..2d66daea8046e 100644 --- a/tests/ui/match_wild_err_arm.edition2021.stderr +++ b/tests/ui/match_wild_err_arm.edition2021.stderr @@ -5,7 +5,7 @@ LL | Err(_) => panic!("err"), | ^^^^^^ | = note: `-D clippy::match-wild-err-arm` implied by `-D warnings` - = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable + = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable error: `Err(_)` matches all errors --> $DIR/match_wild_err_arm.rs:20:9 @@ -13,7 +13,7 @@ error: `Err(_)` matches all errors LL | Err(_) => panic!(), | ^^^^^^ | - = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable + = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable error: `Err(_)` matches all errors --> $DIR/match_wild_err_arm.rs:26:9 @@ -21,7 +21,7 @@ error: `Err(_)` matches all errors LL | Err(_) => { | ^^^^^^ | - = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable + = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable error: `Err(_e)` matches all errors --> $DIR/match_wild_err_arm.rs:34:9 @@ -29,7 +29,7 @@ error: `Err(_e)` matches all errors LL | Err(_e) => panic!(), | ^^^^^^^ | - = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable + = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable error: aborting due to 4 previous errors diff --git a/tests/ui/mut_mutex_lock.fixed b/tests/ui/mut_mutex_lock.fixed index 36bc52e3374e1..ecad10a829038 100644 --- a/tests/ui/mut_mutex_lock.fixed +++ b/tests/ui/mut_mutex_lock.fixed @@ -18,4 +18,11 @@ fn no_owned_mutex_lock() { *value += 1; } +fn issue9415() { + let mut arc_mutex = Arc::new(Mutex::new(42_u8)); + let arc_mutex: &mut Arc> = &mut arc_mutex; + let mut guard = arc_mutex.lock().unwrap(); + *guard += 1; +} + fn main() {} diff --git a/tests/ui/mut_mutex_lock.rs b/tests/ui/mut_mutex_lock.rs index ea60df5ae1bbc..f2b1d6fbfbc3e 100644 --- a/tests/ui/mut_mutex_lock.rs +++ b/tests/ui/mut_mutex_lock.rs @@ -18,4 +18,11 @@ fn no_owned_mutex_lock() { *value += 1; } +fn issue9415() { + let mut arc_mutex = Arc::new(Mutex::new(42_u8)); + let arc_mutex: &mut Arc> = &mut arc_mutex; + let mut guard = arc_mutex.lock().unwrap(); + *guard += 1; +} + fn main() {} diff --git a/tests/ui/or_fun_call.fixed b/tests/ui/or_fun_call.fixed index 18ea4e550292a..5991188ab6372 100644 --- a/tests/ui/or_fun_call.fixed +++ b/tests/ui/or_fun_call.fixed @@ -79,16 +79,16 @@ fn or_fun_call() { without_default.unwrap_or_else(Foo::new); let mut map = HashMap::::new(); - map.entry(42).or_insert(String::new()); + map.entry(42).or_default(); let mut map_vec = HashMap::>::new(); - map_vec.entry(42).or_insert(vec![]); + map_vec.entry(42).or_default(); let mut btree = BTreeMap::::new(); - btree.entry(42).or_insert(String::new()); + btree.entry(42).or_default(); let mut btree_vec = BTreeMap::>::new(); - btree_vec.entry(42).or_insert(vec![]); + btree_vec.entry(42).or_default(); let stringy = Some(String::new()); let _ = stringy.unwrap_or_default(); diff --git a/tests/ui/or_fun_call.stderr b/tests/ui/or_fun_call.stderr index 887f23ac9761d..e3dab4cb14778 100644 --- a/tests/ui/or_fun_call.stderr +++ b/tests/ui/or_fun_call.stderr @@ -66,6 +66,30 @@ error: use of `unwrap_or` followed by a function call LL | without_default.unwrap_or(Foo::new()); | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(Foo::new)` +error: use of `or_insert` followed by a call to `new` + --> $DIR/or_fun_call.rs:82:19 + | +LL | map.entry(42).or_insert(String::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_default()` + +error: use of `or_insert` followed by a call to `new` + --> $DIR/or_fun_call.rs:85:23 + | +LL | map_vec.entry(42).or_insert(vec![]); + | ^^^^^^^^^^^^^^^^^ help: try this: `or_default()` + +error: use of `or_insert` followed by a call to `new` + --> $DIR/or_fun_call.rs:88:21 + | +LL | btree.entry(42).or_insert(String::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_default()` + +error: use of `or_insert` followed by a call to `new` + --> $DIR/or_fun_call.rs:91:25 + | +LL | btree_vec.entry(42).or_insert(vec![]); + | ^^^^^^^^^^^^^^^^^ help: try this: `or_default()` + error: use of `unwrap_or` followed by a call to `new` --> $DIR/or_fun_call.rs:94:21 | @@ -132,5 +156,5 @@ error: use of `unwrap_or` followed by a call to `new` LL | .unwrap_or(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` -error: aborting due to 22 previous errors +error: aborting due to 26 previous errors diff --git a/tests/ui/range_plus_minus_one.fixed b/tests/ui/range_plus_minus_one.fixed index 40d7791df281a..a16a3e54d45ea 100644 --- a/tests/ui/range_plus_minus_one.fixed +++ b/tests/ui/range_plus_minus_one.fixed @@ -6,6 +6,22 @@ fn f() -> usize { 42 } +macro_rules! macro_plus_one { + ($m: literal) => { + for i in 0..$m + 1 { + println!("{}", i); + } + }; +} + +macro_rules! macro_minus_one { + ($m: literal) => { + for i in 0..=$m - 1 { + println!("{}", i); + } + }; +} + #[warn(clippy::range_plus_one)] #[warn(clippy::range_minus_one)] fn main() { @@ -39,4 +55,7 @@ fn main() { let mut vec: Vec<()> = std::vec::Vec::new(); vec.drain(..); + + macro_plus_one!(5); + macro_minus_one!(5); } diff --git a/tests/ui/range_plus_minus_one.rs b/tests/ui/range_plus_minus_one.rs index a8ddd9b5f751b..bd6cb4d21be51 100644 --- a/tests/ui/range_plus_minus_one.rs +++ b/tests/ui/range_plus_minus_one.rs @@ -6,6 +6,22 @@ fn f() -> usize { 42 } +macro_rules! macro_plus_one { + ($m: literal) => { + for i in 0..$m + 1 { + println!("{}", i); + } + }; +} + +macro_rules! macro_minus_one { + ($m: literal) => { + for i in 0..=$m - 1 { + println!("{}", i); + } + }; +} + #[warn(clippy::range_plus_one)] #[warn(clippy::range_minus_one)] fn main() { @@ -39,4 +55,7 @@ fn main() { let mut vec: Vec<()> = std::vec::Vec::new(); vec.drain(..); + + macro_plus_one!(5); + macro_minus_one!(5); } diff --git a/tests/ui/range_plus_minus_one.stderr b/tests/ui/range_plus_minus_one.stderr index fb4f1658597a5..0223696243b20 100644 --- a/tests/ui/range_plus_minus_one.stderr +++ b/tests/ui/range_plus_minus_one.stderr @@ -1,5 +1,5 @@ error: an inclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:15:14 + --> $DIR/range_plus_minus_one.rs:31:14 | LL | for _ in 0..3 + 1 {} | ^^^^^^^^ help: use: `0..=3` @@ -7,25 +7,25 @@ LL | for _ in 0..3 + 1 {} = note: `-D clippy::range-plus-one` implied by `-D warnings` error: an inclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:18:14 + --> $DIR/range_plus_minus_one.rs:34:14 | LL | for _ in 0..1 + 5 {} | ^^^^^^^^ help: use: `0..=5` error: an inclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:21:14 + --> $DIR/range_plus_minus_one.rs:37:14 | LL | for _ in 1..1 + 1 {} | ^^^^^^^^ help: use: `1..=1` error: an inclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:27:14 + --> $DIR/range_plus_minus_one.rs:43:14 | LL | for _ in 0..(1 + f()) {} | ^^^^^^^^^^^^ help: use: `0..=f()` error: an exclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:31:13 + --> $DIR/range_plus_minus_one.rs:47:13 | LL | let _ = ..=11 - 1; | ^^^^^^^^^ help: use: `..11` @@ -33,25 +33,25 @@ LL | let _ = ..=11 - 1; = note: `-D clippy::range-minus-one` implied by `-D warnings` error: an exclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:32:13 + --> $DIR/range_plus_minus_one.rs:48:13 | LL | let _ = ..=(11 - 1); | ^^^^^^^^^^^ help: use: `..11` error: an inclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:33:13 + --> $DIR/range_plus_minus_one.rs:49:13 | LL | let _ = (1..11 + 1); | ^^^^^^^^^^^ help: use: `(1..=11)` error: an inclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:34:13 + --> $DIR/range_plus_minus_one.rs:50:13 | LL | let _ = (f() + 1)..(f() + 1); | ^^^^^^^^^^^^^^^^^^^^ help: use: `((f() + 1)..=f())` error: an inclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:38:14 + --> $DIR/range_plus_minus_one.rs:54:14 | LL | for _ in 1..ONE + ONE {} | ^^^^^^^^^^^^ help: use: `1..=ONE` diff --git a/tests/ui/result_large_err.rs b/tests/ui/result_large_err.rs index 78d8f76fe669f..f7df3b8565501 100644 --- a/tests/ui/result_large_err.rs +++ b/tests/ui/result_large_err.rs @@ -1,4 +1,5 @@ #![warn(clippy::result_large_err)] +#![allow(clippy::large_enum_variant)] pub fn small_err() -> Result<(), u128> { Ok(()) diff --git a/tests/ui/result_large_err.stderr b/tests/ui/result_large_err.stderr index 0f1f39d72cba1..ef19f2854ab12 100644 --- a/tests/ui/result_large_err.stderr +++ b/tests/ui/result_large_err.stderr @@ -1,5 +1,5 @@ error: the `Err`-variant returned from this function is very large - --> $DIR/result_large_err.rs:7:23 + --> $DIR/result_large_err.rs:8:23 | LL | pub fn large_err() -> Result<(), [u8; 512]> { | ^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 512 bytes @@ -8,7 +8,7 @@ LL | pub fn large_err() -> Result<(), [u8; 512]> { = help: try reducing the size of `[u8; 512]`, for example by boxing large elements or replacing it with `Box<[u8; 512]>` error: the `Err`-variant returned from this function is very large - --> $DIR/result_large_err.rs:18:21 + --> $DIR/result_large_err.rs:19:21 | LL | pub fn ret() -> Result<(), Self> { | ^^^^^^^^^^^^^^^^ the `Err`-variant is at least 240 bytes @@ -16,7 +16,7 @@ LL | pub fn ret() -> Result<(), Self> { = help: try reducing the size of `FullyDefinedLargeError`, for example by boxing large elements or replacing it with `Box` error: the `Err`-variant returned from this function is very large - --> $DIR/result_large_err.rs:23:26 + --> $DIR/result_large_err.rs:24:26 | LL | pub fn struct_error() -> Result<(), FullyDefinedLargeError> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 240 bytes @@ -24,7 +24,7 @@ LL | pub fn struct_error() -> Result<(), FullyDefinedLargeError> { = help: try reducing the size of `FullyDefinedLargeError`, for example by boxing large elements or replacing it with `Box` error: the `Err`-variant returned from this function is very large - --> $DIR/result_large_err.rs:28:45 + --> $DIR/result_large_err.rs:29:45 | LL | pub fn large_err_via_type_alias(x: T) -> Fdlr { | ^^^^^^^ the `Err`-variant is at least 240 bytes @@ -32,7 +32,7 @@ LL | pub fn large_err_via_type_alias(x: T) -> Fdlr { = help: try reducing the size of `FullyDefinedLargeError`, for example by boxing large elements or replacing it with `Box` error: the `Err`-variant returned from this function is very large - --> $DIR/result_large_err.rs:36:34 + --> $DIR/result_large_err.rs:37:34 | LL | pub fn param_large_error() -> Result<(), (u128, R, FullyDefinedLargeError)> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 256 bytes @@ -40,7 +40,7 @@ LL | pub fn param_large_error() -> Result<(), (u128, R, FullyDefinedLargeErro = help: try reducing the size of `(u128, R, FullyDefinedLargeError)`, for example by boxing large elements or replacing it with `Box<(u128, R, FullyDefinedLargeError)>` error: the `Err`-variant returned from this function is very large - --> $DIR/result_large_err.rs:47:34 + --> $DIR/result_large_err.rs:48:34 | LL | pub fn large_enum_error() -> Result<(), Self> { | ^^^^^^^^^^^^^^^^ the `Err`-variant is at least 513 bytes @@ -48,7 +48,7 @@ LL | pub fn large_enum_error() -> Result<(), Self> { = help: try reducing the size of `LargeErrorVariants<()>`, for example by boxing large elements or replacing it with `Box>` error: the `Err`-variant returned from this function is very large - --> $DIR/result_large_err.rs:53:25 + --> $DIR/result_large_err.rs:54:25 | LL | fn large_error() -> Result<(), [u8; 512]> { | ^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 512 bytes @@ -56,7 +56,7 @@ LL | fn large_error() -> Result<(), [u8; 512]> { = help: try reducing the size of `[u8; 512]`, for example by boxing large elements or replacing it with `Box<[u8; 512]>` error: the `Err`-variant returned from this function is very large - --> $DIR/result_large_err.rs:72:29 + --> $DIR/result_large_err.rs:73:29 | LL | pub fn large_union_err() -> Result<(), FullyDefinedUnionError> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 512 bytes @@ -64,7 +64,7 @@ LL | pub fn large_union_err() -> Result<(), FullyDefinedUnionError> { = help: try reducing the size of `FullyDefinedUnionError`, for example by boxing large elements or replacing it with `Box` error: the `Err`-variant returned from this function is very large - --> $DIR/result_large_err.rs:81:40 + --> $DIR/result_large_err.rs:82:40 | LL | pub fn param_large_union() -> Result<(), UnionError> { | ^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 512 bytes @@ -72,7 +72,7 @@ LL | pub fn param_large_union() -> Result<(), UnionError> { = help: try reducing the size of `UnionError`, for example by boxing large elements or replacing it with `Box>` error: the `Err`-variant returned from this function is very large - --> $DIR/result_large_err.rs:90:34 + --> $DIR/result_large_err.rs:91:34 | LL | pub fn array_error_subst() -> Result<(), ArrayError> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 128 bytes @@ -80,7 +80,7 @@ LL | pub fn array_error_subst() -> Result<(), ArrayError> { = help: try reducing the size of `ArrayError`, for example by boxing large elements or replacing it with `Box>` error: the `Err`-variant returned from this function is very large - --> $DIR/result_large_err.rs:94:31 + --> $DIR/result_large_err.rs:95:31 | LL | pub fn array_error() -> Result<(), ArrayError<(i32, T), U>> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 128 bytes diff --git a/tests/ui/unnecessary_to_owned.fixed b/tests/ui/unnecessary_to_owned.fixed index 9cd5bc73b1ec5..a920c63b199c1 100644 --- a/tests/ui/unnecessary_to_owned.fixed +++ b/tests/ui/unnecessary_to_owned.fixed @@ -357,3 +357,63 @@ mod issue_9317 { consume(b.to_string()); } } + +mod issue_9351 { + #![allow(dead_code)] + + use std::ops::Deref; + use std::path::{Path, PathBuf}; + + fn require_deref_path>(x: T) -> T { + x + } + + fn generic_arg_used_elsewhere>(_x: T, _y: T) {} + + fn id>(x: T) -> T { + x + } + + fn predicates_are_satisfied(_x: impl std::fmt::Write) {} + + // Should lint + fn single_return() -> impl AsRef { + id("abc") + } + + // Should not lint + fn multiple_returns(b: bool) -> impl AsRef { + if b { + return String::new(); + } + + id("abc".to_string()) + } + + struct S1(String); + + // Should not lint + fn fields1() -> S1 { + S1(id("abc".to_string())) + } + + struct S2 { + s: String, + } + + // Should not lint + fn fields2() { + let mut s = S2 { s: "abc".into() }; + s.s = id("abc".to_string()); + } + + pub fn main() { + let path = std::path::Path::new("x"); + let path_buf = path.to_owned(); + + // Should not lint. + let _x: PathBuf = require_deref_path(path.to_owned()); + generic_arg_used_elsewhere(path.to_owned(), path_buf); + predicates_are_satisfied(id("abc".to_string())); + } +} diff --git a/tests/ui/unnecessary_to_owned.rs b/tests/ui/unnecessary_to_owned.rs index 7f62ba3ab5d55..2128bdacddadf 100644 --- a/tests/ui/unnecessary_to_owned.rs +++ b/tests/ui/unnecessary_to_owned.rs @@ -357,3 +357,63 @@ mod issue_9317 { consume(b.to_string()); } } + +mod issue_9351 { + #![allow(dead_code)] + + use std::ops::Deref; + use std::path::{Path, PathBuf}; + + fn require_deref_path>(x: T) -> T { + x + } + + fn generic_arg_used_elsewhere>(_x: T, _y: T) {} + + fn id>(x: T) -> T { + x + } + + fn predicates_are_satisfied(_x: impl std::fmt::Write) {} + + // Should lint + fn single_return() -> impl AsRef { + id("abc".to_string()) + } + + // Should not lint + fn multiple_returns(b: bool) -> impl AsRef { + if b { + return String::new(); + } + + id("abc".to_string()) + } + + struct S1(String); + + // Should not lint + fn fields1() -> S1 { + S1(id("abc".to_string())) + } + + struct S2 { + s: String, + } + + // Should not lint + fn fields2() { + let mut s = S2 { s: "abc".into() }; + s.s = id("abc".to_string()); + } + + pub fn main() { + let path = std::path::Path::new("x"); + let path_buf = path.to_owned(); + + // Should not lint. + let _x: PathBuf = require_deref_path(path.to_owned()); + generic_arg_used_elsewhere(path.to_owned(), path_buf); + predicates_are_satisfied(id("abc".to_string())); + } +} diff --git a/tests/ui/unnecessary_to_owned.stderr b/tests/ui/unnecessary_to_owned.stderr index 243b4599dba42..7deb90b06f3b7 100644 --- a/tests/ui/unnecessary_to_owned.stderr +++ b/tests/ui/unnecessary_to_owned.stderr @@ -509,5 +509,11 @@ error: unnecessary use of `to_string` LL | Box::new(build(y.to_string())) | ^^^^^^^^^^^^^ help: use: `y` -error: aborting due to 78 previous errors +error: unnecessary use of `to_string` + --> $DIR/unnecessary_to_owned.rs:381:12 + | +LL | id("abc".to_string()) + | ^^^^^^^^^^^^^^^^^ help: use: `"abc"` + +error: aborting due to 79 previous errors diff --git a/tests/ui/unwrap_or_else_default.fixed b/tests/ui/unwrap_or_else_default.fixed index c2b9bd2c881fe..84f779569ff9d 100644 --- a/tests/ui/unwrap_or_else_default.fixed +++ b/tests/ui/unwrap_or_else_default.fixed @@ -69,6 +69,9 @@ fn unwrap_or_else_default() { let with_default_type: Option> = None; with_default_type.unwrap_or_default(); + + let empty_string = None::; + empty_string.unwrap_or_default(); } fn main() {} diff --git a/tests/ui/unwrap_or_else_default.rs b/tests/ui/unwrap_or_else_default.rs index d55664990aeb9..1735bd5808e5a 100644 --- a/tests/ui/unwrap_or_else_default.rs +++ b/tests/ui/unwrap_or_else_default.rs @@ -69,6 +69,9 @@ fn unwrap_or_else_default() { let with_default_type: Option> = None; with_default_type.unwrap_or_else(Vec::new); + + let empty_string = None::; + empty_string.unwrap_or_else(|| "".to_string()); } fn main() {} diff --git a/tests/ui/unwrap_or_else_default.stderr b/tests/ui/unwrap_or_else_default.stderr index 53e31d85edfca..d2b9212223f77 100644 --- a/tests/ui/unwrap_or_else_default.stderr +++ b/tests/ui/unwrap_or_else_default.stderr @@ -30,5 +30,11 @@ error: use of `.unwrap_or_else(..)` to construct default value LL | with_default_type.unwrap_or_else(Vec::new); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_default_type.unwrap_or_default()` -error: aborting due to 5 previous errors +error: use of `.unwrap_or_else(..)` to construct default value + --> $DIR/unwrap_or_else_default.rs:74:5 + | +LL | empty_string.unwrap_or_else(|| "".to_string()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `empty_string.unwrap_or_default()` + +error: aborting due to 6 previous errors diff --git a/tests/ui/vec_init_then_push.rs b/tests/ui/vec_init_then_push.rs index 531745424a7d0..8dd098a5b5405 100644 --- a/tests/ui/vec_init_then_push.rs +++ b/tests/ui/vec_init_then_push.rs @@ -104,3 +104,9 @@ fn _cond_push_with_large_start(x: bool) -> Vec { v2 } + +fn f() { + let mut v = Vec::new(); + v.push((0i32, 0i32)); + let y = v[0].0.abs(); +} diff --git a/tests/ui/vec_init_then_push.stderr b/tests/ui/vec_init_then_push.stderr index 50b029fc33727..a9da1c520197d 100644 --- a/tests/ui/vec_init_then_push.stderr +++ b/tests/ui/vec_init_then_push.stderr @@ -62,5 +62,12 @@ LL | | v2.push(1); LL | | v2.push(0); | |_______________^ help: consider using the `vec![]` macro: `let mut v2 = vec![..];` -error: aborting due to 7 previous errors +error: calls to `push` immediately after creation + --> $DIR/vec_init_then_push.rs:109:5 + | +LL | / let mut v = Vec::new(); +LL | | v.push((0i32, 0i32)); + | |_________________________^ help: consider using the `vec![]` macro: `let v = vec![..];` + +error: aborting due to 8 previous errors From 41b30843910b160c0daa69d737cac46ed2c13f09 Mon Sep 17 00:00:00 2001 From: Niklas Jonsson Date: Sat, 16 Jul 2022 15:16:57 +0200 Subject: [PATCH 009/114] rustc_error, rustc_private, rustc_ast: Switch to stable hash containers --- clippy_lints/src/matches/match_same_arms.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/matches/match_same_arms.rs b/clippy_lints/src/matches/match_same_arms.rs index 93874b103b461..d37f44d4a17e4 100644 --- a/clippy_lints/src/matches/match_same_arms.rs +++ b/clippy_lints/src/matches/match_same_arms.rs @@ -8,11 +8,10 @@ use rustc_arena::DroplessArena; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; -use rustc_hir::{Arm, Expr, ExprKind, HirId, HirIdMap, HirIdSet, Pat, PatKind, RangeEnd}; +use rustc_hir::{Arm, Expr, ExprKind, HirId, HirIdMap, HirIdMapEntry, HirIdSet, Pat, PatKind, RangeEnd}; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_span::Symbol; -use std::collections::hash_map::Entry; use super::MATCH_SAME_ARMS; @@ -71,9 +70,9 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) { if let Some(a_id) = path_to_local(a); if let Some(b_id) = path_to_local(b); let entry = match local_map.entry(a_id) { - Entry::Vacant(entry) => entry, + HirIdMapEntry::Vacant(entry) => entry, // check if using the same bindings as before - Entry::Occupied(entry) => return *entry.get() == b_id, + HirIdMapEntry::Occupied(entry) => return *entry.get() == b_id, }; // the names technically don't have to match; this makes the lint more conservative if cx.tcx.hir().name(a_id) == cx.tcx.hir().name(b_id); From f6005c6b89e1d4752add58a49a3e84884a513022 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 12 Sep 2022 13:13:22 +1000 Subject: [PATCH 010/114] Remove unused span argument from `walk_fn`. --- clippy_lints/src/derive.rs | 4 ++-- clippy_lints/src/unused_async.rs | 2 +- clippy_lints/src/unwrap.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index 23c86482b46cb..751ca24d5f598 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -425,7 +425,7 @@ struct UnsafeVisitor<'a, 'tcx> { impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> { type NestedFilter = nested_filter::All; - fn visit_fn(&mut self, kind: FnKind<'tcx>, decl: &'tcx FnDecl<'_>, body_id: BodyId, span: Span, id: HirId) { + fn visit_fn(&mut self, kind: FnKind<'tcx>, decl: &'tcx FnDecl<'_>, body_id: BodyId, _: Span, id: HirId) { if self.has_unsafe { return; } @@ -438,7 +438,7 @@ impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> { } } - walk_fn(self, kind, decl, body_id, span, id); + walk_fn(self, kind, decl, body_id, id); } fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { diff --git a/clippy_lints/src/unused_async.rs b/clippy_lints/src/unused_async.rs index a832dfcccaf36..bf487c7ca20c8 100644 --- a/clippy_lints/src/unused_async.rs +++ b/clippy_lints/src/unused_async.rs @@ -70,7 +70,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAsync { ) { if !span.from_expansion() && fn_kind.asyncness() == IsAsync::Async { let mut visitor = AsyncFnVisitor { cx, found_await: false }; - walk_fn(&mut visitor, fn_kind, fn_decl, body.id(), span, hir_id); + walk_fn(&mut visitor, fn_kind, fn_decl, body.id(), hir_id); if !visitor.found_await { span_lint_and_help( cx, diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index 7e451b7b7a419..3ef2655807974 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -326,6 +326,6 @@ impl<'tcx> LateLintPass<'tcx> for Unwrap { unwrappables: Vec::new(), }; - walk_fn(&mut v, kind, decl, body.id(), span, fn_id); + walk_fn(&mut v, kind, decl, body.id(), fn_id); } } From 308153563bf008ab3cadec9148c4930521189844 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 12 Sep 2022 13:30:15 +1000 Subject: [PATCH 011/114] Remove unused span argument from `visit_name`. --- clippy_utils/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index bdb858e1f9384..23b51ec2d0849 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1121,7 +1121,7 @@ pub struct ContainsName { } impl<'tcx> Visitor<'tcx> for ContainsName { - fn visit_name(&mut self, _: Span, name: Symbol) { + fn visit_name(&mut self, name: Symbol) { if self.name == name { self.result = true; } From 0d1469ad348f5ac1b6ed6d6847e8b613b49e00fa Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 12 Sep 2022 13:37:18 +1000 Subject: [PATCH 012/114] Remove unused argument from `visit_poly_trait_ref`. --- clippy_lints/src/disallowed_types.rs | 4 ++-- clippy_lints/src/lifetimes.rs | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/clippy_lints/src/disallowed_types.rs b/clippy_lints/src/disallowed_types.rs index 14f89edce615d..28dbfbab2e19b 100644 --- a/clippy_lints/src/disallowed_types.rs +++ b/clippy_lints/src/disallowed_types.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use rustc_data_structures::fx::FxHashMap; use rustc_hir::{ - def::Res, def_id::DefId, Item, ItemKind, PolyTraitRef, PrimTy, TraitBoundModifier, Ty, TyKind, UseKind, + def::Res, def_id::DefId, Item, ItemKind, PolyTraitRef, PrimTy, Ty, TyKind, UseKind, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; @@ -120,7 +120,7 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedTypes { } } - fn check_poly_trait_ref(&mut self, cx: &LateContext<'tcx>, poly: &'tcx PolyTraitRef<'tcx>, _: TraitBoundModifier) { + fn check_poly_trait_ref(&mut self, cx: &LateContext<'tcx>, poly: &'tcx PolyTraitRef<'tcx>) { self.check_res_emit(cx, &poly.trait_ref.path.res, poly.trait_ref.path.span); } } diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index f2b6e0b7ef9ba..643a7cfd577b7 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -10,7 +10,7 @@ use rustc_hir::FnRetTy::Return; use rustc_hir::{ BareFnTy, BodyId, FnDecl, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, Impl, ImplItem, ImplItemKind, Item, ItemKind, LangItem, Lifetime, LifetimeName, ParamName, PolyTraitRef, PredicateOrigin, - TraitBoundModifier, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate, + TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter as middle_nested_filter; @@ -422,7 +422,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> { self.record(&Some(*lifetime)); } - fn visit_poly_trait_ref(&mut self, poly_tref: &'tcx PolyTraitRef<'tcx>, tbm: TraitBoundModifier) { + fn visit_poly_trait_ref(&mut self, poly_tref: &'tcx PolyTraitRef<'tcx>) { let trait_ref = &poly_tref.trait_ref; if CLOSURE_TRAIT_BOUNDS.iter().any(|&item| { self.cx @@ -435,7 +435,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> { sub_visitor.visit_trait_ref(trait_ref); self.nested_elision_site_lts.append(&mut sub_visitor.all_lts()); } else { - walk_poly_trait_ref(self, poly_tref, tbm); + walk_poly_trait_ref(self, poly_tref); } } @@ -466,7 +466,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> { self.unelided_trait_object_lifetime = true; } for bound in bounds { - self.visit_poly_trait_ref(bound, TraitBoundModifier::None); + self.visit_poly_trait_ref(bound); } }, _ => walk_ty(self, ty), From c0e249ce675924f760e94b0426fbb450f1d1c2cb Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Fri, 2 Sep 2022 01:11:20 +0200 Subject: [PATCH 013/114] Fix clippy. --- .../src/matches/redundant_pattern_match.rs | 81 +++++++++++++++---- 1 file changed, 65 insertions(+), 16 deletions(-) diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs index f7443471e31dd..39c8e9a93f06d 100644 --- a/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/clippy_lints/src/matches/redundant_pattern_match.rs @@ -2,7 +2,7 @@ use super::REDUNDANT_PATTERN_MATCHING; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; use clippy_utils::sugg::Sugg; -use clippy_utils::ty::needs_ordered_drop; +use clippy_utils::ty::{is_type_diagnostic_item, needs_ordered_drop}; use clippy_utils::visitors::any_temporaries_need_ordered_drop; use clippy_utils::{higher, is_lang_ctor, is_trait_method, match_def_path, paths}; use if_chain::if_chain; @@ -12,7 +12,7 @@ use rustc_hir::LangItem::{OptionNone, PollPending}; use rustc_hir::{Arm, Expr, ExprKind, Node, Pat, PatKind, QPath, UnOp}; use rustc_lint::LateContext; use rustc_middle::ty::{self, subst::GenericArgKind, DefIdTree, Ty}; -use rustc_span::sym; +use rustc_span::{sym, Symbol, def_id::DefId}; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if let Some(higher::WhileLet { let_pat, let_expr, .. }) = higher::WhileLet::hir(expr) { @@ -75,9 +75,9 @@ fn find_sugg_for_if_let<'tcx>( ("is_some()", op_ty) } else if Some(id) == lang_items.poll_ready_variant() { ("is_ready()", op_ty) - } else if match_def_path(cx, id, &paths::IPADDR_V4) { + } else if is_pat_variant(cx, check_pat, qpath, &paths::IPADDR_V4, Item::Diag(sym!(IpAddr), sym!(V4))) { ("is_ipv4()", op_ty) - } else if match_def_path(cx, id, &paths::IPADDR_V6) { + } else if is_pat_variant(cx, check_pat, qpath, &paths::IPADDR_V6, Item::Diag(sym!(IpAddr), sym!(V6))) { ("is_ipv6()", op_ty) } else { return; @@ -174,6 +174,7 @@ fn find_sugg_for_if_let<'tcx>( pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op: &Expr<'_>, arms: &[Arm<'_>]) { if arms.len() == 2 { + let lang_items = cx.tcx.lang_items(); let node_pair = (&arms[0].pat.kind, &arms[1].pat.kind); let found_good_method = match node_pair { @@ -188,7 +189,9 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op path_left, path_right, &paths::RESULT_OK, + Item::Lang(lang_items.result_ok_variant()), &paths::RESULT_ERR, + Item::Lang(lang_items.result_err_variant()), "is_ok()", "is_err()", ) @@ -199,7 +202,9 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op path_left, path_right, &paths::IPADDR_V4, + Item::Diag(sym!(IpAddr), sym!(V4)), &paths::IPADDR_V6, + Item::Diag(sym!(IpAddr), sym!(V6)), "is_ipv4()", "is_ipv6()", ) @@ -213,13 +218,16 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op if patterns.len() == 1 => { if let PatKind::Wild = patterns[0].kind { + find_good_method_for_match( cx, arms, path_left, path_right, &paths::OPTION_SOME, + Item::Lang(lang_items.option_some_variant()), &paths::OPTION_NONE, + Item::Lang(lang_items.option_none_variant()), "is_some()", "is_none()", ) @@ -230,7 +238,9 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op path_left, path_right, &paths::POLL_READY, + Item::Lang(lang_items.poll_ready_variant()), &paths::POLL_PENDING, + Item::Lang(lang_items.poll_pending_variant()), "is_ready()", "is_pending()", ) @@ -266,28 +276,67 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op } } +#[derive(Clone, Copy)] +enum Item { + Lang(Option), + Diag(Symbol, Symbol), +} + +fn is_pat_variant(cx: &LateContext<'_>, pat: &Pat<'_>, path: &QPath<'_>, expected_path: &[&str], expected_item: Item) -> bool { + let Some(id) = cx.typeck_results().qpath_res(path, pat.hir_id).opt_def_id() else { return false }; + + // TODO: Path matching can be removed when `IpAddr` is a diagnostic item. + if match_def_path(cx, id, expected_path) { + return true + } + + match expected_item { + Item::Lang(expected_id) => { + Some(cx.tcx.parent(id)) == expected_id + }, + Item::Diag(expected_ty, expected_variant) => { + let ty = cx.typeck_results().pat_ty(pat); + + if is_type_diagnostic_item(cx, ty, expected_ty) { + let variant = ty.ty_adt_def() + .expect("struct pattern type is not an ADT") + .variant_of_res(cx.qpath_res(path, pat.hir_id)); + + return variant.name == expected_variant + } + + false + } + } +} + #[expect(clippy::too_many_arguments)] fn find_good_method_for_match<'a>( cx: &LateContext<'_>, arms: &[Arm<'_>], path_left: &QPath<'_>, path_right: &QPath<'_>, - expected_left: &[&str], - expected_right: &[&str], + expected_path_left: &[&str], + expected_item_left: Item, + expected_path_right: &[&str], + expected_item_right: Item, should_be_left: &'a str, should_be_right: &'a str, ) -> Option<&'a str> { - let left_id = cx - .typeck_results() - .qpath_res(path_left, arms[0].pat.hir_id) - .opt_def_id()?; - let right_id = cx - .typeck_results() - .qpath_res(path_right, arms[1].pat.hir_id) - .opt_def_id()?; - let body_node_pair = if match_def_path(cx, left_id, expected_left) && match_def_path(cx, right_id, expected_right) { + let pat_left = arms[0].pat; + let pat_right = arms[1].pat; + + let body_node_pair = if ( + is_pat_variant(cx, pat_left, path_left, expected_path_left, expected_item_left) + ) && ( + is_pat_variant(cx, pat_right, path_right, expected_path_right, expected_item_right) + ) { (&arms[0].body.kind, &arms[1].body.kind) - } else if match_def_path(cx, right_id, expected_left) && match_def_path(cx, right_id, expected_right) { + } else if ( + is_pat_variant(cx, pat_left, path_left, expected_path_right, expected_item_right) + ) && ( + is_pat_variant(cx, pat_right, path_right, expected_path_left, expected_item_left) + ) { (&arms[1].body.kind, &arms[0].body.kind) } else { return None; From 64a42db51a8d866031fe69cd68a9ca108a8435fa Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Mon, 12 Sep 2022 19:03:24 +0200 Subject: [PATCH 014/114] Simplify `clippy` fix. --- .../src/matches/redundant_pattern_match.rs | 59 +++++++------------ clippy_utils/src/paths.rs | 2 - 2 files changed, 22 insertions(+), 39 deletions(-) diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs index 39c8e9a93f06d..c89784065b8be 100644 --- a/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/clippy_lints/src/matches/redundant_pattern_match.rs @@ -4,15 +4,15 @@ use clippy_utils::source::snippet; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{is_type_diagnostic_item, needs_ordered_drop}; use clippy_utils::visitors::any_temporaries_need_ordered_drop; -use clippy_utils::{higher, is_lang_ctor, is_trait_method, match_def_path, paths}; +use clippy_utils::{higher, is_lang_ctor, is_trait_method}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; -use rustc_hir::LangItem::{OptionNone, PollPending}; +use rustc_hir::LangItem::{self, OptionSome, OptionNone, PollPending, PollReady, ResultOk, ResultErr}; use rustc_hir::{Arm, Expr, ExprKind, Node, Pat, PatKind, QPath, UnOp}; use rustc_lint::LateContext; use rustc_middle::ty::{self, subst::GenericArgKind, DefIdTree, Ty}; -use rustc_span::{sym, Symbol, def_id::DefId}; +use rustc_span::{sym, Symbol}; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if let Some(higher::WhileLet { let_pat, let_expr, .. }) = higher::WhileLet::hir(expr) { @@ -75,9 +75,9 @@ fn find_sugg_for_if_let<'tcx>( ("is_some()", op_ty) } else if Some(id) == lang_items.poll_ready_variant() { ("is_ready()", op_ty) - } else if is_pat_variant(cx, check_pat, qpath, &paths::IPADDR_V4, Item::Diag(sym!(IpAddr), sym!(V4))) { + } else if is_pat_variant(cx, check_pat, qpath, Item::Diag(sym::IpAddr, sym!(V4))) { ("is_ipv4()", op_ty) - } else if is_pat_variant(cx, check_pat, qpath, &paths::IPADDR_V6, Item::Diag(sym!(IpAddr), sym!(V6))) { + } else if is_pat_variant(cx, check_pat, qpath, Item::Diag(sym::IpAddr, sym!(V6))) { ("is_ipv6()", op_ty) } else { return; @@ -174,7 +174,6 @@ fn find_sugg_for_if_let<'tcx>( pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op: &Expr<'_>, arms: &[Arm<'_>]) { if arms.len() == 2 { - let lang_items = cx.tcx.lang_items(); let node_pair = (&arms[0].pat.kind, &arms[1].pat.kind); let found_good_method = match node_pair { @@ -188,10 +187,8 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op arms, path_left, path_right, - &paths::RESULT_OK, - Item::Lang(lang_items.result_ok_variant()), - &paths::RESULT_ERR, - Item::Lang(lang_items.result_err_variant()), + Item::Lang(ResultOk), + Item::Lang(ResultErr), "is_ok()", "is_err()", ) @@ -201,10 +198,8 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op arms, path_left, path_right, - &paths::IPADDR_V4, - Item::Diag(sym!(IpAddr), sym!(V4)), - &paths::IPADDR_V6, - Item::Diag(sym!(IpAddr), sym!(V6)), + Item::Diag(sym::IpAddr, sym!(V4)), + Item::Diag(sym::IpAddr, sym!(V6)), "is_ipv4()", "is_ipv6()", ) @@ -224,10 +219,8 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op arms, path_left, path_right, - &paths::OPTION_SOME, - Item::Lang(lang_items.option_some_variant()), - &paths::OPTION_NONE, - Item::Lang(lang_items.option_none_variant()), + Item::Lang(OptionSome), + Item::Lang(OptionNone), "is_some()", "is_none()", ) @@ -237,10 +230,8 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op arms, path_left, path_right, - &paths::POLL_READY, - Item::Lang(lang_items.poll_ready_variant()), - &paths::POLL_PENDING, - Item::Lang(lang_items.poll_pending_variant()), + Item::Lang(PollReady), + Item::Lang(PollPending), "is_ready()", "is_pending()", ) @@ -278,21 +269,17 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op #[derive(Clone, Copy)] enum Item { - Lang(Option), + Lang(LangItem), Diag(Symbol, Symbol), } -fn is_pat_variant(cx: &LateContext<'_>, pat: &Pat<'_>, path: &QPath<'_>, expected_path: &[&str], expected_item: Item) -> bool { +fn is_pat_variant(cx: &LateContext<'_>, pat: &Pat<'_>, path: &QPath<'_>, expected_item: Item) -> bool { let Some(id) = cx.typeck_results().qpath_res(path, pat.hir_id).opt_def_id() else { return false }; - // TODO: Path matching can be removed when `IpAddr` is a diagnostic item. - if match_def_path(cx, id, expected_path) { - return true - } - match expected_item { - Item::Lang(expected_id) => { - Some(cx.tcx.parent(id)) == expected_id + Item::Lang(expected_lang_item) => { + let expected_id = cx.tcx.lang_items().require(expected_lang_item).unwrap(); + cx.tcx.parent(id) == expected_id }, Item::Diag(expected_ty, expected_variant) => { let ty = cx.typeck_results().pat_ty(pat); @@ -316,9 +303,7 @@ fn find_good_method_for_match<'a>( arms: &[Arm<'_>], path_left: &QPath<'_>, path_right: &QPath<'_>, - expected_path_left: &[&str], expected_item_left: Item, - expected_path_right: &[&str], expected_item_right: Item, should_be_left: &'a str, should_be_right: &'a str, @@ -327,15 +312,15 @@ fn find_good_method_for_match<'a>( let pat_right = arms[1].pat; let body_node_pair = if ( - is_pat_variant(cx, pat_left, path_left, expected_path_left, expected_item_left) + is_pat_variant(cx, pat_left, path_left, expected_item_left) ) && ( - is_pat_variant(cx, pat_right, path_right, expected_path_right, expected_item_right) + is_pat_variant(cx, pat_right, path_right, expected_item_right) ) { (&arms[0].body.kind, &arms[1].body.kind) } else if ( - is_pat_variant(cx, pat_left, path_left, expected_path_right, expected_item_right) + is_pat_variant(cx, pat_left, path_left, expected_item_right) ) && ( - is_pat_variant(cx, pat_right, path_right, expected_path_left, expected_item_left) + is_pat_variant(cx, pat_right, path_right, expected_item_left) ) { (&arms[1].body.kind, &arms[0].body.kind) } else { diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index fb0d34e02eece..07170e2df12ab 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -66,8 +66,6 @@ pub const INDEX_MUT: [&str; 3] = ["core", "ops", "IndexMut"]; pub const INSERT_STR: [&str; 4] = ["alloc", "string", "String", "insert_str"]; pub const IO_READ: [&str; 3] = ["std", "io", "Read"]; pub const IO_WRITE: [&str; 3] = ["std", "io", "Write"]; -pub const IPADDR_V4: [&str; 5] = ["std", "net", "ip", "IpAddr", "V4"]; -pub const IPADDR_V6: [&str; 5] = ["std", "net", "ip", "IpAddr", "V6"]; pub const ITER_COUNT: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "count"]; pub const ITER_EMPTY: [&str; 5] = ["core", "iter", "sources", "empty", "Empty"]; pub const ITER_REPEAT: [&str; 5] = ["core", "iter", "sources", "repeat", "repeat"]; From b95b285ef4831ea1342e4aead7aa245156b24cb7 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Tue, 30 Aug 2022 12:39:28 -0700 Subject: [PATCH 015/114] Make x.py check work --- clippy_lints/src/transmute/utils.rs | 29 ++-- clippy_utils/src/qualify_min_const_fn.rs | 141 +++++++++++-------- clippy_utils/src/ty.rs | 165 ++++++++++++++--------- 3 files changed, 204 insertions(+), 131 deletions(-) diff --git a/clippy_lints/src/transmute/utils.rs b/clippy_lints/src/transmute/utils.rs index 74927570b40eb..78cc589cc291b 100644 --- a/clippy_lints/src/transmute/utils.rs +++ b/clippy_lints/src/transmute/utils.rs @@ -2,11 +2,18 @@ use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::{cast::CastKind, Ty}; use rustc_span::DUMMY_SP; -use rustc_typeck::check::{cast::CastCheck, FnCtxt, Inherited}; +use rustc_typeck::check::{ + cast::{self, CastCheckResult}, + FnCtxt, Inherited, +}; // check if the component types of the transmuted collection and the result have different ABI, // size or alignment -pub(super) fn is_layout_incompatible<'tcx>(cx: &LateContext<'tcx>, from: Ty<'tcx>, to: Ty<'tcx>) -> bool { +pub(super) fn is_layout_incompatible<'tcx>( + cx: &LateContext<'tcx>, + from: Ty<'tcx>, + to: Ty<'tcx>, +) -> bool { if let Ok(from) = cx.tcx.try_normalize_erasing_regions(cx.param_env, from) && let Ok(to) = cx.tcx.try_normalize_erasing_regions(cx.param_env, to) && let Ok(from_layout) = cx.tcx.layout_of(cx.param_env.and(from)) @@ -29,7 +36,9 @@ pub(super) fn can_be_expressed_as_pointer_cast<'tcx>( from_ty: Ty<'tcx>, to_ty: Ty<'tcx>, ) -> bool { - use CastKind::{AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast}; + use CastKind::{ + AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast, + }; matches!( check_cast(cx, e, from_ty, to_ty), Some(PtrPtrCast | PtrAddrCast | AddrPtrCast | ArrayPtrCast | FnPtrPtrCast | FnPtrAddrCast) @@ -40,7 +49,12 @@ pub(super) fn can_be_expressed_as_pointer_cast<'tcx>( /// the cast. In certain cases, including some invalid casts from array references /// to pointers, this may cause additional errors to be emitted and/or ICE error /// messages. This function will panic if that occurs. -fn check_cast<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx>, to_ty: Ty<'tcx>) -> Option { +fn check_cast<'tcx>( + cx: &LateContext<'tcx>, + e: &'tcx Expr<'_>, + from_ty: Ty<'tcx>, + to_ty: Ty<'tcx>, +) -> Option { let hir_id = e.hir_id; let local_def_id = hir_id.owner; @@ -48,12 +62,9 @@ fn check_cast<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx> let fn_ctxt = FnCtxt::new(&inherited, cx.param_env, hir_id); // If we already have errors, we can't be sure we can pointer cast. - assert!( - !fn_ctxt.errors_reported_since_creation(), - "Newly created FnCtxt contained errors" - ); + assert!(!fn_ctxt.errors_reported_since_creation(), "Newly created FnCtxt contained errors"); - if let Ok(check) = CastCheck::new( + if let CastCheckResult::Deferred(check) = cast::check_cast( &fn_ctxt, e, from_ty, to_ty, // We won't show any error to the user, so we don't care what the span is here. DUMMY_SP, DUMMY_SP, diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index d5f64e5118f56..781744870cb91 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -18,7 +18,11 @@ use std::borrow::Cow; type McfResult = Result<(), (Span, Cow<'static, str>)>; -pub fn is_min_const_fn<'a, 'tcx>(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, msrv: Option) -> McfResult { +pub fn is_min_const_fn<'a, 'tcx>( + tcx: TyCtxt<'tcx>, + body: &'a Body<'tcx>, + msrv: Option, +) -> McfResult { let def_id = body.source.def_id(); let mut current = def_id; loop { @@ -33,10 +37,18 @@ pub fn is_min_const_fn<'a, 'tcx>(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, msrv: | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Trait(..) | ty::PredicateKind::TypeWellFormedFromEnv(..) => continue, - ty::PredicateKind::ObjectSafe(_) => panic!("object safe predicate on function: {:#?}", predicate), - ty::PredicateKind::ClosureKind(..) => panic!("closure kind predicate on function: {:#?}", predicate), - ty::PredicateKind::Subtype(_) => panic!("subtype predicate on function: {:#?}", predicate), - ty::PredicateKind::Coerce(_) => panic!("coerce predicate on function: {:#?}", predicate), + ty::PredicateKind::ObjectSafe(_) => { + panic!("object safe predicate on function: {:#?}", predicate) + } + ty::PredicateKind::ClosureKind(..) => { + panic!("closure kind predicate on function: {:#?}", predicate) + } + ty::PredicateKind::Subtype(_) => { + panic!("subtype predicate on function: {:#?}", predicate) + } + ty::PredicateKind::Coerce(_) => { + panic!("coerce predicate on function: {:#?}", predicate) + } } } match predicates.parent { @@ -77,22 +89,23 @@ fn check_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) -> McfResult { match ty.kind() { ty::Ref(_, _, hir::Mutability::Mut) => { return Err((span, "mutable references in const fn are unstable".into())); - }, + } ty::Opaque(..) => return Err((span, "`impl Trait` in const fn is unstable".into())), ty::FnPtr(..) => { return Err((span, "function pointers in const fn are unstable".into())); - }, - ty::Dynamic(preds, _) => { + } + ty::Dynamic(preds, _, _) => { for pred in preds.iter() { match pred.skip_binder() { - ty::ExistentialPredicate::AutoTrait(_) | ty::ExistentialPredicate::Projection(_) => { + ty::ExistentialPredicate::AutoTrait(_) + | ty::ExistentialPredicate::Projection(_) => { return Err(( span, "trait bounds other than `Sized` \ on const fn parameters are unstable" .into(), )); - }, + } ty::ExistentialPredicate::Trait(trait_ref) => { if Some(trait_ref.def_id) != tcx.lang_items().sized_trait() { return Err(( @@ -102,11 +115,11 @@ fn check_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) -> McfResult { .into(), )); } - }, + } } } - }, - _ => {}, + } + _ => {} } } Ok(()) @@ -120,10 +133,13 @@ fn check_rvalue<'tcx>( span: Span, ) -> McfResult { match rvalue { - Rvalue::ThreadLocalRef(_) => Err((span, "cannot access thread local storage in const fn".into())), - Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => { - check_place(tcx, *place, span, body) - }, + Rvalue::ThreadLocalRef(_) => { + Err((span, "cannot access thread local storage in const fn".into())) + } + Rvalue::Len(place) + | Rvalue::Discriminant(place) + | Rvalue::Ref(_, _, place) + | Rvalue::AddressOf(_, place) => check_place(tcx, *place, span, body), Rvalue::CopyForDeref(place) => check_place(tcx, *place, span, body), Rvalue::Repeat(operand, _) | Rvalue::Use(operand) @@ -136,7 +152,9 @@ fn check_rvalue<'tcx>( ) => check_operand(tcx, operand, span, body), Rvalue::Cast( CastKind::Pointer( - PointerCast::UnsafeFnPointer | PointerCast::ClosureFnPointer(_) | PointerCast::ReifyFnPointer, + PointerCast::UnsafeFnPointer + | PointerCast::ClosureFnPointer(_) + | PointerCast::ReifyFnPointer, ), _, _, @@ -146,7 +164,10 @@ fn check_rvalue<'tcx>( deref_ty.ty } else { // We cannot allow this for now. - return Err((span, "unsizing casts are only allowed for references right now".into())); + return Err(( + span, + "unsizing casts are only allowed for references right now".into(), + )); }; let unsized_ty = tcx.struct_tail_erasing_lifetimes(pointee_ty, tcx.param_env(def_id)); if let ty::Slice(_) | ty::Str = unsized_ty.kind() { @@ -157,10 +178,14 @@ fn check_rvalue<'tcx>( // We just can't allow trait objects until we have figured out trait method calls. Err((span, "unsizing casts are not allowed in const fn".into())) } - }, + } Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => { Err((span, "casting pointers to ints is unstable in const fn".into())) - }, + } + Rvalue::Cast(CastKind::DynStar, _, _) => { + // FIXME(dyn-star) + unimplemented!() + } // binops are fine on integers Rvalue::BinaryOp(_, box (lhs, rhs)) | Rvalue::CheckedBinaryOp(_, box (lhs, rhs)) => { check_operand(tcx, lhs, span, body)?; @@ -169,13 +194,12 @@ fn check_rvalue<'tcx>( if ty.is_integral() || ty.is_bool() || ty.is_char() { Ok(()) } else { - Err(( - span, - "only int, `bool` and `char` operations are stable in const fn".into(), - )) + Err((span, "only int, `bool` and `char` operations are stable in const fn".into())) } - }, - Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) | Rvalue::ShallowInitBox(_, _) => Ok(()), + } + Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) | Rvalue::ShallowInitBox(_, _) => { + Ok(()) + } Rvalue::UnaryOp(_, operand) => { let ty = operand.ty(body, tcx); if ty.is_integral() || ty.is_bool() { @@ -183,13 +207,13 @@ fn check_rvalue<'tcx>( } else { Err((span, "only int and `bool` operations are stable in const fn".into())) } - }, + } Rvalue::Aggregate(_, operands) => { for operand in operands { check_operand(tcx, operand, span, body)?; } Ok(()) - }, + } } } @@ -204,7 +228,7 @@ fn check_statement<'tcx>( StatementKind::Assign(box (place, rval)) => { check_place(tcx, *place, span, body)?; check_rvalue(tcx, body, def_id, rval, span) - }, + } StatementKind::FakeRead(box (_, place)) => check_place(tcx, *place, span, body), // just an assignment @@ -214,14 +238,15 @@ fn check_statement<'tcx>( StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => check_operand(tcx, op, span, body), - StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping( - rustc_middle::mir::CopyNonOverlapping { dst, src, count }, - )) => { + StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { + dst, + src, + count, + }) => { check_operand(tcx, dst, span, body)?; check_operand(tcx, src, span, body)?; check_operand(tcx, count, span, body) - }, - + } // These are all NOPs StatementKind::StorageLive(_) | StatementKind::StorageDead(_) @@ -232,7 +257,12 @@ fn check_statement<'tcx>( } } -fn check_operand<'tcx>(tcx: TyCtxt<'tcx>, operand: &Operand<'tcx>, span: Span, body: &Body<'tcx>) -> McfResult { +fn check_operand<'tcx>( + tcx: TyCtxt<'tcx>, + operand: &Operand<'tcx>, + span: Span, + body: &Body<'tcx>, +) -> McfResult { match operand { Operand::Move(place) | Operand::Copy(place) => check_place(tcx, *place, span, body), Operand::Constant(c) => match c.check_static_ptr(tcx) { @@ -242,7 +272,12 @@ fn check_operand<'tcx>(tcx: TyCtxt<'tcx>, operand: &Operand<'tcx>, span: Span, b } } -fn check_place<'tcx>(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &Body<'tcx>) -> McfResult { +fn check_place<'tcx>( + tcx: TyCtxt<'tcx>, + place: Place<'tcx>, + span: Span, + body: &Body<'tcx>, +) -> McfResult { let mut cursor = place.projection.as_ref(); while let [ref proj_base @ .., elem] = *cursor { cursor = proj_base; @@ -255,12 +290,12 @@ fn check_place<'tcx>(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &B return Err((span, "accessing union fields is unstable".into())); } } - }, + } ProjectionElem::ConstantIndex { .. } | ProjectionElem::Downcast(..) | ProjectionElem::Subslice { .. } | ProjectionElem::Deref - | ProjectionElem::Index(_) => {}, + | ProjectionElem::Index(_) => {} } } @@ -286,18 +321,16 @@ fn check_terminator<'a, 'tcx>( TerminatorKind::DropAndReplace { place, value, .. } => { check_place(tcx, *place, span, body)?; check_operand(tcx, value, span, body) - }, + } - TerminatorKind::SwitchInt { - discr, - switch_ty: _, - targets: _, - } => check_operand(tcx, discr, span, body), + TerminatorKind::SwitchInt { discr, switch_ty: _, targets: _ } => { + check_operand(tcx, discr, span, body) + } TerminatorKind::Abort => Err((span, "abort is not stable in const fn".into())), TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => { Err((span, "const fn generators are unstable".into())) - }, + } TerminatorKind::Call { func, @@ -342,17 +375,15 @@ fn check_terminator<'a, 'tcx>( } else { Err((span, "can only call other const fns within const fn".into())) } - }, + } - TerminatorKind::Assert { - cond, - expected: _, - msg: _, - target: _, - cleanup: _, - } => check_operand(tcx, cond, span, body), + TerminatorKind::Assert { cond, expected: _, msg: _, target: _, cleanup: _ } => { + check_operand(tcx, cond, span, body) + } - TerminatorKind::InlineAsm { .. } => Err((span, "cannot use inline assembly in const fn".into())), + TerminatorKind::InlineAsm { .. } => { + Err((span, "cannot use inline assembly in const fn".into())) + } } } diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 5a7f9568441c9..99803ae93a712 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -14,8 +14,9 @@ use rustc_lint::LateContext; use rustc_middle::mir::interpret::{ConstValue, Scalar}; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst}; use rustc_middle::ty::{ - self, AdtDef, Binder, BoundRegion, DefIdTree, FnSig, IntTy, ParamEnv, Predicate, PredicateKind, ProjectionTy, - Region, RegionKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, UintTy, VariantDef, VariantDiscr, + self, AdtDef, Binder, BoundRegion, DefIdTree, FnSig, IntTy, ParamEnv, Predicate, PredicateKind, + ProjectionTy, Region, RegionKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, + UintTy, VariantDef, VariantDiscr, }; use rustc_span::symbol::Ident; use rustc_span::{sym, Span, Symbol, DUMMY_SP}; @@ -166,9 +167,7 @@ pub fn implements_trait_with_env<'tcx>( } let ty_params = tcx.mk_substs(ty_params.iter()); tcx.infer_ctxt().enter(|infcx| { - infcx - .type_implements_trait(trait_id, ty, ty_params, param_env) - .must_apply_modulo_regions() + infcx.type_implements_trait(trait_id, ty, ty_params, param_env).must_apply_modulo_regions() }) } @@ -185,11 +184,14 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { match ty.kind() { ty::Adt(adt, _) => cx.tcx.has_attr(adt.did(), sym::must_use), ty::Foreign(did) => cx.tcx.has_attr(*did, sym::must_use), - ty::Slice(ty) | ty::Array(ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) => { + ty::Slice(ty) + | ty::Array(ty, _) + | ty::RawPtr(ty::TypeAndMut { ty, .. }) + | ty::Ref(_, ty, _) => { // for the Array case we don't need to care for the len == 0 case // because we don't want to lint functions returning empty arrays is_must_use_ty(cx, *ty) - }, + } ty::Tuple(substs) => substs.iter().any(|ty| is_must_use_ty(cx, ty)), ty::Opaque(def_id, _) => { for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) { @@ -200,8 +202,8 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { } } false - }, - ty::Dynamic(binder, _) => { + } + ty::Dynamic(binder, _, _) => { for predicate in binder.iter() { if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() { if cx.tcx.has_attr(trait_ref.def_id, sym::must_use) { @@ -210,7 +212,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { } } false - }, + } _ => false, } } @@ -220,7 +222,11 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { // not succeed /// Checks if `Ty` is normalizable. This function is useful /// to avoid crashes on `layout_of`. -pub fn is_normalizable<'tcx>(cx: &LateContext<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { +pub fn is_normalizable<'tcx>( + cx: &LateContext<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, +) -> bool { is_normalizable_helper(cx, param_env, ty, &mut FxHashMap::default()) } @@ -240,15 +246,14 @@ fn is_normalizable_helper<'tcx>( if infcx.at(&cause, param_env).normalize(ty).is_ok() { match ty.kind() { ty::Adt(def, substs) => def.variants().iter().all(|variant| { - variant - .fields - .iter() - .all(|field| is_normalizable_helper(cx, param_env, field.ty(cx.tcx, substs), cache)) + variant.fields.iter().all(|field| { + is_normalizable_helper(cx, param_env, field.ty(cx.tcx, substs), cache) + }) }), _ => ty.walk().all(|generic_arg| match generic_arg.unpack() { GenericArgKind::Type(inner_ty) if inner_ty != ty => { is_normalizable_helper(cx, param_env, inner_ty, cache) - }, + } _ => true, // if inner_ty == ty, we've already checked it }), } @@ -273,7 +278,9 @@ pub fn is_recursively_primitive_type(ty: Ty<'_>) -> bool { match *ty.kind() { ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => true, ty::Ref(_, inner, _) if *inner.kind() == ty::Str => true, - ty::Array(inner_type, _) | ty::Slice(inner_type) => is_recursively_primitive_type(inner_type), + ty::Array(inner_type, _) | ty::Slice(inner_type) => { + is_recursively_primitive_type(inner_type) + } ty::Tuple(inner_types) => inner_types.iter().all(is_recursively_primitive_type), _ => false, } @@ -313,11 +320,9 @@ pub fn is_type_diagnostic_item(cx: &LateContext<'_>, ty: Ty<'_>, diag_item: Symb /// Returns `false` if the `LangItem` is not defined. pub fn is_type_lang_item(cx: &LateContext<'_>, ty: Ty<'_>, lang_item: hir::LangItem) -> bool { match ty.kind() { - ty::Adt(adt, _) => cx - .tcx - .lang_items() - .require(lang_item) - .map_or(false, |li| li == adt.did()), + ty::Adt(adt, _) => { + cx.tcx.lang_items().require(lang_item).map_or(false, |li| li == adt.did()) + } _ => false, } } @@ -342,7 +347,11 @@ pub fn match_type(cx: &LateContext<'_>, ty: Ty<'_>, path: &[&str]) -> bool { /// deallocate memory. For these types, and composites containing them, changing the drop order /// won't result in any observable side effects. pub fn needs_ordered_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { - fn needs_ordered_drop_inner<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, seen: &mut FxHashSet>) -> bool { + fn needs_ordered_drop_inner<'tcx>( + cx: &LateContext<'tcx>, + ty: Ty<'tcx>, + seen: &mut FxHashSet>, + ) -> bool { if !seen.insert(ty) { return false; } @@ -393,11 +402,7 @@ pub fn needs_ordered_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { /// removed. pub fn peel_mid_ty_refs(ty: Ty<'_>) -> (Ty<'_>, usize) { fn peel(ty: Ty<'_>, count: usize) -> (Ty<'_>, usize) { - if let ty::Ref(_, ty, _) = ty.kind() { - peel(*ty, count + 1) - } else { - (ty, count) - } + if let ty::Ref(_, ty, _) = ty.kind() { peel(*ty, count + 1) } else { (ty, count) } } peel(ty, 0) } @@ -452,17 +457,18 @@ pub fn same_type_and_consts<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { return false; } - substs_a - .iter() - .zip(substs_b.iter()) - .all(|(arg_a, arg_b)| match (arg_a.unpack(), arg_b.unpack()) { - (GenericArgKind::Const(inner_a), GenericArgKind::Const(inner_b)) => inner_a == inner_b, + substs_a.iter().zip(substs_b.iter()).all(|(arg_a, arg_b)| { + match (arg_a.unpack(), arg_b.unpack()) { + (GenericArgKind::Const(inner_a), GenericArgKind::Const(inner_b)) => { + inner_a == inner_b + } (GenericArgKind::Type(type_a), GenericArgKind::Type(type_b)) => { same_type_and_consts(type_a, type_b) - }, + } _ => true, - }) - }, + } + }) + } _ => a == b, } } @@ -478,7 +484,10 @@ pub fn is_uninit_value_valid_for_ty(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { } /// Gets an iterator over all predicates which apply to the given item. -pub fn all_predicates_of(tcx: TyCtxt<'_>, id: DefId) -> impl Iterator, Span)> { +pub fn all_predicates_of( + tcx: TyCtxt<'_>, + id: DefId, +) -> impl Iterator, Span)> { let mut next_id = Some(id); iter::from_fn(move || { next_id.take().map(|id| { @@ -508,7 +517,7 @@ impl<'tcx> ExprFnSig<'tcx> { } else { Some(sig.input(i)) } - }, + } Self::Closure(_, sig) => Some(sig.input(0).map_bound(|ty| ty.tuple_fields()[i])), Self::Trait(inputs, _, _) => Some(inputs.map_bound(|ty| ty.tuple_fields()[i])), } @@ -517,7 +526,10 @@ impl<'tcx> ExprFnSig<'tcx> { /// Gets the argument type at the given offset. For closures this will also get the type as /// written. This will return `None` when the index is out of bounds only for variadic /// functions, otherwise this will panic. - pub fn input_with_hir(self, i: usize) -> Option<(Option<&'tcx hir::Ty<'tcx>>, Binder<'tcx, Ty<'tcx>>)> { + pub fn input_with_hir( + self, + i: usize, + ) -> Option<(Option<&'tcx hir::Ty<'tcx>>, Binder<'tcx, Ty<'tcx>>)> { match self { Self::Sig(sig, _) => { if sig.c_variadic() { @@ -528,7 +540,7 @@ impl<'tcx> ExprFnSig<'tcx> { } else { Some((None, sig.input(i))) } - }, + } Self::Closure(decl, sig) => Some(( decl.and_then(|decl| decl.inputs.get(i)), sig.input(0).map_bound(|ty| ty.tuple_fields()[i]), @@ -547,17 +559,15 @@ impl<'tcx> ExprFnSig<'tcx> { } pub fn predicates_id(&self) -> Option { - if let ExprFnSig::Sig(_, id) | ExprFnSig::Trait(_, _, id) = *self { - id - } else { - None - } + if let ExprFnSig::Sig(_, id) | ExprFnSig::Trait(_, _, id) = *self { id } else { None } } } /// If the expression is function like, get the signature for it. pub fn expr_sig<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option> { - if let Res::Def(DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::AssocFn, id) = path_res(cx, expr) { + if let Res::Def(DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::AssocFn, id) = + path_res(cx, expr) + { Some(ExprFnSig::Sig(cx.tcx.fn_sig(id), Some(id))) } else { ty_sig(cx, cx.typeck_results().expr_ty_adjusted(expr).peel_refs()) @@ -571,15 +581,17 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option { - let decl = id - .as_local() - .and_then(|id| cx.tcx.hir().fn_decl_by_hir_id(cx.tcx.hir().local_def_id_to_hir_id(id))); + let decl = id.as_local().and_then(|id| { + cx.tcx.hir().fn_decl_by_hir_id(cx.tcx.hir().local_def_id_to_hir_id(id)) + }); Some(ExprFnSig::Closure(decl, subs.as_closure().sig())) - }, - ty::FnDef(id, subs) => Some(ExprFnSig::Sig(cx.tcx.bound_fn_sig(id).subst(cx.tcx, subs), Some(id))), + } + ty::FnDef(id, subs) => { + Some(ExprFnSig::Sig(cx.tcx.bound_fn_sig(id).subst(cx.tcx, subs), Some(id))) + } ty::Opaque(id, _) => sig_from_bounds(cx, ty, cx.tcx.item_bounds(id), cx.tcx.opt_parent(id)), ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig, None)), - ty::Dynamic(bounds, _) => { + ty::Dynamic(bounds, _, _) => { let lang_items = cx.tcx.lang_items(); match bounds.principal() { Some(bound) @@ -589,16 +601,19 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option None, } - }, + } ty::Projection(proj) => match cx.tcx.try_normalize_erasing_regions(cx.param_env, ty) { Ok(normalized_ty) if normalized_ty != ty => ty_sig(cx, normalized_ty), - _ => sig_for_projection(cx, proj).or_else(|| sig_from_bounds(cx, ty, cx.param_env.caller_bounds(), None)), + _ => sig_for_projection(cx, proj) + .or_else(|| sig_from_bounds(cx, ty, cx.param_env.caller_bounds(), None)), }, ty::Param(_) => sig_from_bounds(cx, ty, cx.param_env.caller_bounds(), None), _ => None, @@ -629,7 +644,7 @@ fn sig_from_bounds<'tcx>( return None; } inputs = Some(i); - }, + } PredicateKind::Projection(p) if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output() && p.projection_ty.self_ty() == ty => @@ -639,7 +654,7 @@ fn sig_from_bounds<'tcx>( return None; } output = Some(pred.kind().rebind(p.term.ty().unwrap())); - }, + } _ => (), } } @@ -647,7 +662,10 @@ fn sig_from_bounds<'tcx>( inputs.map(|ty| ExprFnSig::Trait(ty, output, predicates_id)) } -fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: ProjectionTy<'tcx>) -> Option> { +fn sig_for_projection<'tcx>( + cx: &LateContext<'tcx>, + ty: ProjectionTy<'tcx>, +) -> Option> { let mut inputs = None; let mut output = None; let lang_items = cx.tcx.lang_items(); @@ -673,8 +691,10 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: ProjectionTy<'tcx>) -> O return None; } inputs = Some(i); - }, - PredicateKind::Projection(p) if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output() => { + } + PredicateKind::Projection(p) + if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output() => + { if output.is_some() { // Multiple different fn trait impls. Is this even allowed? return None; @@ -683,7 +703,7 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: ProjectionTy<'tcx>) -> O pred.map_bound(|pred| pred.kind().rebind(p.term.ty().unwrap())) .subst(cx.tcx, ty.substs), ); - }, + } _ => (), } } @@ -777,7 +797,10 @@ pub fn for_each_top_level_late_bound_region( ControlFlow::Continue(()) } } - fn visit_binder>(&mut self, t: &Binder<'tcx, T>) -> ControlFlow { + fn visit_binder>( + &mut self, + t: &Binder<'tcx, T>, + ) -> ControlFlow { self.index += 1; let res = t.super_visit_with(self); self.index -= 1; @@ -791,19 +814,27 @@ pub fn for_each_top_level_late_bound_region( pub fn variant_of_res<'tcx>(cx: &LateContext<'tcx>, res: Res) -> Option<&'tcx VariantDef> { match res { Res::Def(DefKind::Struct, id) => Some(cx.tcx.adt_def(id).non_enum_variant()), - Res::Def(DefKind::Variant, id) => Some(cx.tcx.adt_def(cx.tcx.parent(id)).variant_with_id(id)), - Res::Def(DefKind::Ctor(CtorOf::Struct, _), id) => Some(cx.tcx.adt_def(cx.tcx.parent(id)).non_enum_variant()), + Res::Def(DefKind::Variant, id) => { + Some(cx.tcx.adt_def(cx.tcx.parent(id)).variant_with_id(id)) + } + Res::Def(DefKind::Ctor(CtorOf::Struct, _), id) => { + Some(cx.tcx.adt_def(cx.tcx.parent(id)).non_enum_variant()) + } Res::Def(DefKind::Ctor(CtorOf::Variant, _), id) => { let var_id = cx.tcx.parent(id); Some(cx.tcx.adt_def(cx.tcx.parent(var_id)).variant_with_id(var_id)) - }, + } Res::SelfCtor(id) => Some(cx.tcx.type_of(id).ty_adt_def().unwrap().non_enum_variant()), _ => None, } } /// Checks if the type is a type parameter implementing `FnOnce`, but not `FnMut`. -pub fn ty_is_fn_once_param<'tcx>(tcx: TyCtxt<'_>, ty: Ty<'tcx>, predicates: &'tcx [Predicate<'_>]) -> bool { +pub fn ty_is_fn_once_param<'tcx>( + tcx: TyCtxt<'_>, + ty: Ty<'tcx>, + predicates: &'tcx [Predicate<'_>], +) -> bool { let ty::Param(ty) = *ty.kind() else { return false; }; From 27e91b65d565a21b11a0f31fdd2c61a582ea966e Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Tue, 30 Aug 2022 12:44:00 -0700 Subject: [PATCH 016/114] Address code review comments --- clippy_lints/src/transmute/utils.rs | 27 ++-- clippy_utils/src/qualify_min_const_fn.rs | 136 ++++++++----------- clippy_utils/src/ty.rs | 161 +++++++++-------------- 3 files changed, 127 insertions(+), 197 deletions(-) diff --git a/clippy_lints/src/transmute/utils.rs b/clippy_lints/src/transmute/utils.rs index 78cc589cc291b..8bdadf2440231 100644 --- a/clippy_lints/src/transmute/utils.rs +++ b/clippy_lints/src/transmute/utils.rs @@ -2,18 +2,11 @@ use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::{cast::CastKind, Ty}; use rustc_span::DUMMY_SP; -use rustc_typeck::check::{ - cast::{self, CastCheckResult}, - FnCtxt, Inherited, -}; +use rustc_typeck::check::{cast::{self, CastCheckResult}, FnCtxt, Inherited}; // check if the component types of the transmuted collection and the result have different ABI, // size or alignment -pub(super) fn is_layout_incompatible<'tcx>( - cx: &LateContext<'tcx>, - from: Ty<'tcx>, - to: Ty<'tcx>, -) -> bool { +pub(super) fn is_layout_incompatible<'tcx>(cx: &LateContext<'tcx>, from: Ty<'tcx>, to: Ty<'tcx>) -> bool { if let Ok(from) = cx.tcx.try_normalize_erasing_regions(cx.param_env, from) && let Ok(to) = cx.tcx.try_normalize_erasing_regions(cx.param_env, to) && let Ok(from_layout) = cx.tcx.layout_of(cx.param_env.and(from)) @@ -36,9 +29,7 @@ pub(super) fn can_be_expressed_as_pointer_cast<'tcx>( from_ty: Ty<'tcx>, to_ty: Ty<'tcx>, ) -> bool { - use CastKind::{ - AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast, - }; + use CastKind::{AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast}; matches!( check_cast(cx, e, from_ty, to_ty), Some(PtrPtrCast | PtrAddrCast | AddrPtrCast | ArrayPtrCast | FnPtrPtrCast | FnPtrAddrCast) @@ -49,12 +40,7 @@ pub(super) fn can_be_expressed_as_pointer_cast<'tcx>( /// the cast. In certain cases, including some invalid casts from array references /// to pointers, this may cause additional errors to be emitted and/or ICE error /// messages. This function will panic if that occurs. -fn check_cast<'tcx>( - cx: &LateContext<'tcx>, - e: &'tcx Expr<'_>, - from_ty: Ty<'tcx>, - to_ty: Ty<'tcx>, -) -> Option { +fn check_cast<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx>, to_ty: Ty<'tcx>) -> Option { let hir_id = e.hir_id; let local_def_id = hir_id.owner; @@ -62,7 +48,10 @@ fn check_cast<'tcx>( let fn_ctxt = FnCtxt::new(&inherited, cx.param_env, hir_id); // If we already have errors, we can't be sure we can pointer cast. - assert!(!fn_ctxt.errors_reported_since_creation(), "Newly created FnCtxt contained errors"); + assert!( + !fn_ctxt.errors_reported_since_creation(), + "Newly created FnCtxt contained errors" + ); if let CastCheckResult::Deferred(check) = cast::check_cast( &fn_ctxt, e, from_ty, to_ty, diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index 781744870cb91..8835b93290958 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -18,11 +18,7 @@ use std::borrow::Cow; type McfResult = Result<(), (Span, Cow<'static, str>)>; -pub fn is_min_const_fn<'a, 'tcx>( - tcx: TyCtxt<'tcx>, - body: &'a Body<'tcx>, - msrv: Option, -) -> McfResult { +pub fn is_min_const_fn<'a, 'tcx>(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, msrv: Option) -> McfResult { let def_id = body.source.def_id(); let mut current = def_id; loop { @@ -37,18 +33,10 @@ pub fn is_min_const_fn<'a, 'tcx>( | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Trait(..) | ty::PredicateKind::TypeWellFormedFromEnv(..) => continue, - ty::PredicateKind::ObjectSafe(_) => { - panic!("object safe predicate on function: {:#?}", predicate) - } - ty::PredicateKind::ClosureKind(..) => { - panic!("closure kind predicate on function: {:#?}", predicate) - } - ty::PredicateKind::Subtype(_) => { - panic!("subtype predicate on function: {:#?}", predicate) - } - ty::PredicateKind::Coerce(_) => { - panic!("coerce predicate on function: {:#?}", predicate) - } + ty::PredicateKind::ObjectSafe(_) => panic!("object safe predicate on function: {:#?}", predicate), + ty::PredicateKind::ClosureKind(..) => panic!("closure kind predicate on function: {:#?}", predicate), + ty::PredicateKind::Subtype(_) => panic!("subtype predicate on function: {:#?}", predicate), + ty::PredicateKind::Coerce(_) => panic!("coerce predicate on function: {:#?}", predicate), } } match predicates.parent { @@ -89,23 +77,22 @@ fn check_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) -> McfResult { match ty.kind() { ty::Ref(_, _, hir::Mutability::Mut) => { return Err((span, "mutable references in const fn are unstable".into())); - } + }, ty::Opaque(..) => return Err((span, "`impl Trait` in const fn is unstable".into())), ty::FnPtr(..) => { return Err((span, "function pointers in const fn are unstable".into())); - } + }, ty::Dynamic(preds, _, _) => { for pred in preds.iter() { match pred.skip_binder() { - ty::ExistentialPredicate::AutoTrait(_) - | ty::ExistentialPredicate::Projection(_) => { + ty::ExistentialPredicate::AutoTrait(_) | ty::ExistentialPredicate::Projection(_) => { return Err(( span, "trait bounds other than `Sized` \ on const fn parameters are unstable" .into(), )); - } + }, ty::ExistentialPredicate::Trait(trait_ref) => { if Some(trait_ref.def_id) != tcx.lang_items().sized_trait() { return Err(( @@ -115,11 +102,11 @@ fn check_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) -> McfResult { .into(), )); } - } + }, } } - } - _ => {} + }, + _ => {}, } } Ok(()) @@ -133,13 +120,10 @@ fn check_rvalue<'tcx>( span: Span, ) -> McfResult { match rvalue { - Rvalue::ThreadLocalRef(_) => { - Err((span, "cannot access thread local storage in const fn".into())) - } - Rvalue::Len(place) - | Rvalue::Discriminant(place) - | Rvalue::Ref(_, _, place) - | Rvalue::AddressOf(_, place) => check_place(tcx, *place, span, body), + Rvalue::ThreadLocalRef(_) => Err((span, "cannot access thread local storage in const fn".into())), + Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => { + check_place(tcx, *place, span, body) + }, Rvalue::CopyForDeref(place) => check_place(tcx, *place, span, body), Rvalue::Repeat(operand, _) | Rvalue::Use(operand) @@ -152,9 +136,7 @@ fn check_rvalue<'tcx>( ) => check_operand(tcx, operand, span, body), Rvalue::Cast( CastKind::Pointer( - PointerCast::UnsafeFnPointer - | PointerCast::ClosureFnPointer(_) - | PointerCast::ReifyFnPointer, + PointerCast::UnsafeFnPointer | PointerCast::ClosureFnPointer(_) | PointerCast::ReifyFnPointer, ), _, _, @@ -164,10 +146,7 @@ fn check_rvalue<'tcx>( deref_ty.ty } else { // We cannot allow this for now. - return Err(( - span, - "unsizing casts are only allowed for references right now".into(), - )); + return Err((span, "unsizing casts are only allowed for references right now".into())); }; let unsized_ty = tcx.struct_tail_erasing_lifetimes(pointee_ty, tcx.param_env(def_id)); if let ty::Slice(_) | ty::Str = unsized_ty.kind() { @@ -178,14 +157,14 @@ fn check_rvalue<'tcx>( // We just can't allow trait objects until we have figured out trait method calls. Err((span, "unsizing casts are not allowed in const fn".into())) } - } + }, Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => { Err((span, "casting pointers to ints is unstable in const fn".into())) - } + }, Rvalue::Cast(CastKind::DynStar, _, _) => { // FIXME(dyn-star) unimplemented!() - } + }, // binops are fine on integers Rvalue::BinaryOp(_, box (lhs, rhs)) | Rvalue::CheckedBinaryOp(_, box (lhs, rhs)) => { check_operand(tcx, lhs, span, body)?; @@ -194,12 +173,13 @@ fn check_rvalue<'tcx>( if ty.is_integral() || ty.is_bool() || ty.is_char() { Ok(()) } else { - Err((span, "only int, `bool` and `char` operations are stable in const fn".into())) + Err(( + span, + "only int, `bool` and `char` operations are stable in const fn".into(), + )) } - } - Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) | Rvalue::ShallowInitBox(_, _) => { - Ok(()) - } + }, + Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) | Rvalue::ShallowInitBox(_, _) => Ok(()), Rvalue::UnaryOp(_, operand) => { let ty = operand.ty(body, tcx); if ty.is_integral() || ty.is_bool() { @@ -207,13 +187,13 @@ fn check_rvalue<'tcx>( } else { Err((span, "only int and `bool` operations are stable in const fn".into())) } - } + }, Rvalue::Aggregate(_, operands) => { for operand in operands { check_operand(tcx, operand, span, body)?; } Ok(()) - } + }, } } @@ -228,7 +208,7 @@ fn check_statement<'tcx>( StatementKind::Assign(box (place, rval)) => { check_place(tcx, *place, span, body)?; check_rvalue(tcx, body, def_id, rval, span) - } + }, StatementKind::FakeRead(box (_, place)) => check_place(tcx, *place, span, body), // just an assignment @@ -238,15 +218,13 @@ fn check_statement<'tcx>( StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => check_operand(tcx, op, span, body), - StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { - dst, - src, - count, - }) => { + StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping( + rustc_middle::mir::CopyNonOverlapping { dst, src, count }, + )) => { check_operand(tcx, dst, span, body)?; check_operand(tcx, src, span, body)?; check_operand(tcx, count, span, body) - } + }, // These are all NOPs StatementKind::StorageLive(_) | StatementKind::StorageDead(_) @@ -257,12 +235,7 @@ fn check_statement<'tcx>( } } -fn check_operand<'tcx>( - tcx: TyCtxt<'tcx>, - operand: &Operand<'tcx>, - span: Span, - body: &Body<'tcx>, -) -> McfResult { +fn check_operand<'tcx>(tcx: TyCtxt<'tcx>, operand: &Operand<'tcx>, span: Span, body: &Body<'tcx>) -> McfResult { match operand { Operand::Move(place) | Operand::Copy(place) => check_place(tcx, *place, span, body), Operand::Constant(c) => match c.check_static_ptr(tcx) { @@ -272,12 +245,7 @@ fn check_operand<'tcx>( } } -fn check_place<'tcx>( - tcx: TyCtxt<'tcx>, - place: Place<'tcx>, - span: Span, - body: &Body<'tcx>, -) -> McfResult { +fn check_place<'tcx>(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &Body<'tcx>) -> McfResult { let mut cursor = place.projection.as_ref(); while let [ref proj_base @ .., elem] = *cursor { cursor = proj_base; @@ -290,12 +258,12 @@ fn check_place<'tcx>( return Err((span, "accessing union fields is unstable".into())); } } - } + }, ProjectionElem::ConstantIndex { .. } | ProjectionElem::Downcast(..) | ProjectionElem::Subslice { .. } | ProjectionElem::Deref - | ProjectionElem::Index(_) => {} + | ProjectionElem::Index(_) => {}, } } @@ -321,16 +289,18 @@ fn check_terminator<'a, 'tcx>( TerminatorKind::DropAndReplace { place, value, .. } => { check_place(tcx, *place, span, body)?; check_operand(tcx, value, span, body) - } + }, - TerminatorKind::SwitchInt { discr, switch_ty: _, targets: _ } => { - check_operand(tcx, discr, span, body) - } + TerminatorKind::SwitchInt { + discr, + switch_ty: _, + targets: _, + } => check_operand(tcx, discr, span, body), TerminatorKind::Abort => Err((span, "abort is not stable in const fn".into())), TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => { Err((span, "const fn generators are unstable".into())) - } + }, TerminatorKind::Call { func, @@ -375,15 +345,17 @@ fn check_terminator<'a, 'tcx>( } else { Err((span, "can only call other const fns within const fn".into())) } - } + }, - TerminatorKind::Assert { cond, expected: _, msg: _, target: _, cleanup: _ } => { - check_operand(tcx, cond, span, body) - } + TerminatorKind::Assert { + cond, + expected: _, + msg: _, + target: _, + cleanup: _, + } => check_operand(tcx, cond, span, body), - TerminatorKind::InlineAsm { .. } => { - Err((span, "cannot use inline assembly in const fn".into())) - } + TerminatorKind::InlineAsm { .. } => Err((span, "cannot use inline assembly in const fn".into())), } } diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 99803ae93a712..a8ad6cf4f6a3c 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -14,9 +14,8 @@ use rustc_lint::LateContext; use rustc_middle::mir::interpret::{ConstValue, Scalar}; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst}; use rustc_middle::ty::{ - self, AdtDef, Binder, BoundRegion, DefIdTree, FnSig, IntTy, ParamEnv, Predicate, PredicateKind, - ProjectionTy, Region, RegionKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, - UintTy, VariantDef, VariantDiscr, + self, AdtDef, Binder, BoundRegion, DefIdTree, FnSig, IntTy, ParamEnv, Predicate, PredicateKind, ProjectionTy, + Region, RegionKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, UintTy, VariantDef, VariantDiscr, }; use rustc_span::symbol::Ident; use rustc_span::{sym, Span, Symbol, DUMMY_SP}; @@ -167,7 +166,9 @@ pub fn implements_trait_with_env<'tcx>( } let ty_params = tcx.mk_substs(ty_params.iter()); tcx.infer_ctxt().enter(|infcx| { - infcx.type_implements_trait(trait_id, ty, ty_params, param_env).must_apply_modulo_regions() + infcx + .type_implements_trait(trait_id, ty, ty_params, param_env) + .must_apply_modulo_regions() }) } @@ -184,14 +185,11 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { match ty.kind() { ty::Adt(adt, _) => cx.tcx.has_attr(adt.did(), sym::must_use), ty::Foreign(did) => cx.tcx.has_attr(*did, sym::must_use), - ty::Slice(ty) - | ty::Array(ty, _) - | ty::RawPtr(ty::TypeAndMut { ty, .. }) - | ty::Ref(_, ty, _) => { + ty::Slice(ty) | ty::Array(ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) => { // for the Array case we don't need to care for the len == 0 case // because we don't want to lint functions returning empty arrays is_must_use_ty(cx, *ty) - } + }, ty::Tuple(substs) => substs.iter().any(|ty| is_must_use_ty(cx, ty)), ty::Opaque(def_id, _) => { for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) { @@ -202,7 +200,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { } } false - } + }, ty::Dynamic(binder, _, _) => { for predicate in binder.iter() { if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() { @@ -212,7 +210,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { } } false - } + }, _ => false, } } @@ -222,11 +220,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { // not succeed /// Checks if `Ty` is normalizable. This function is useful /// to avoid crashes on `layout_of`. -pub fn is_normalizable<'tcx>( - cx: &LateContext<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx>, -) -> bool { +pub fn is_normalizable<'tcx>(cx: &LateContext<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { is_normalizable_helper(cx, param_env, ty, &mut FxHashMap::default()) } @@ -246,14 +240,15 @@ fn is_normalizable_helper<'tcx>( if infcx.at(&cause, param_env).normalize(ty).is_ok() { match ty.kind() { ty::Adt(def, substs) => def.variants().iter().all(|variant| { - variant.fields.iter().all(|field| { - is_normalizable_helper(cx, param_env, field.ty(cx.tcx, substs), cache) - }) + variant + .fields + .iter() + .all(|field| is_normalizable_helper(cx, param_env, field.ty(cx.tcx, substs), cache)) }), _ => ty.walk().all(|generic_arg| match generic_arg.unpack() { GenericArgKind::Type(inner_ty) if inner_ty != ty => { is_normalizable_helper(cx, param_env, inner_ty, cache) - } + }, _ => true, // if inner_ty == ty, we've already checked it }), } @@ -278,9 +273,7 @@ pub fn is_recursively_primitive_type(ty: Ty<'_>) -> bool { match *ty.kind() { ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => true, ty::Ref(_, inner, _) if *inner.kind() == ty::Str => true, - ty::Array(inner_type, _) | ty::Slice(inner_type) => { - is_recursively_primitive_type(inner_type) - } + ty::Array(inner_type, _) | ty::Slice(inner_type) => is_recursively_primitive_type(inner_type), ty::Tuple(inner_types) => inner_types.iter().all(is_recursively_primitive_type), _ => false, } @@ -320,9 +313,11 @@ pub fn is_type_diagnostic_item(cx: &LateContext<'_>, ty: Ty<'_>, diag_item: Symb /// Returns `false` if the `LangItem` is not defined. pub fn is_type_lang_item(cx: &LateContext<'_>, ty: Ty<'_>, lang_item: hir::LangItem) -> bool { match ty.kind() { - ty::Adt(adt, _) => { - cx.tcx.lang_items().require(lang_item).map_or(false, |li| li == adt.did()) - } + ty::Adt(adt, _) => cx + .tcx + .lang_items() + .require(lang_item) + .map_or(false, |li| li == adt.did()), _ => false, } } @@ -347,11 +342,7 @@ pub fn match_type(cx: &LateContext<'_>, ty: Ty<'_>, path: &[&str]) -> bool { /// deallocate memory. For these types, and composites containing them, changing the drop order /// won't result in any observable side effects. pub fn needs_ordered_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { - fn needs_ordered_drop_inner<'tcx>( - cx: &LateContext<'tcx>, - ty: Ty<'tcx>, - seen: &mut FxHashSet>, - ) -> bool { + fn needs_ordered_drop_inner<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, seen: &mut FxHashSet>) -> bool { if !seen.insert(ty) { return false; } @@ -402,7 +393,11 @@ pub fn needs_ordered_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { /// removed. pub fn peel_mid_ty_refs(ty: Ty<'_>) -> (Ty<'_>, usize) { fn peel(ty: Ty<'_>, count: usize) -> (Ty<'_>, usize) { - if let ty::Ref(_, ty, _) = ty.kind() { peel(*ty, count + 1) } else { (ty, count) } + if let ty::Ref(_, ty, _) = ty.kind() { + peel(*ty, count + 1) + } else { + (ty, count) + } } peel(ty, 0) } @@ -457,18 +452,17 @@ pub fn same_type_and_consts<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { return false; } - substs_a.iter().zip(substs_b.iter()).all(|(arg_a, arg_b)| { - match (arg_a.unpack(), arg_b.unpack()) { - (GenericArgKind::Const(inner_a), GenericArgKind::Const(inner_b)) => { - inner_a == inner_b - } + substs_a + .iter() + .zip(substs_b.iter()) + .all(|(arg_a, arg_b)| match (arg_a.unpack(), arg_b.unpack()) { + (GenericArgKind::Const(inner_a), GenericArgKind::Const(inner_b)) => inner_a == inner_b, (GenericArgKind::Type(type_a), GenericArgKind::Type(type_b)) => { same_type_and_consts(type_a, type_b) - } + }, _ => true, - } - }) - } + }) + }, _ => a == b, } } @@ -484,10 +478,7 @@ pub fn is_uninit_value_valid_for_ty(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { } /// Gets an iterator over all predicates which apply to the given item. -pub fn all_predicates_of( - tcx: TyCtxt<'_>, - id: DefId, -) -> impl Iterator, Span)> { +pub fn all_predicates_of(tcx: TyCtxt<'_>, id: DefId) -> impl Iterator, Span)> { let mut next_id = Some(id); iter::from_fn(move || { next_id.take().map(|id| { @@ -517,7 +508,7 @@ impl<'tcx> ExprFnSig<'tcx> { } else { Some(sig.input(i)) } - } + }, Self::Closure(_, sig) => Some(sig.input(0).map_bound(|ty| ty.tuple_fields()[i])), Self::Trait(inputs, _, _) => Some(inputs.map_bound(|ty| ty.tuple_fields()[i])), } @@ -526,10 +517,7 @@ impl<'tcx> ExprFnSig<'tcx> { /// Gets the argument type at the given offset. For closures this will also get the type as /// written. This will return `None` when the index is out of bounds only for variadic /// functions, otherwise this will panic. - pub fn input_with_hir( - self, - i: usize, - ) -> Option<(Option<&'tcx hir::Ty<'tcx>>, Binder<'tcx, Ty<'tcx>>)> { + pub fn input_with_hir(self, i: usize) -> Option<(Option<&'tcx hir::Ty<'tcx>>, Binder<'tcx, Ty<'tcx>>)> { match self { Self::Sig(sig, _) => { if sig.c_variadic() { @@ -540,7 +528,7 @@ impl<'tcx> ExprFnSig<'tcx> { } else { Some((None, sig.input(i))) } - } + }, Self::Closure(decl, sig) => Some(( decl.and_then(|decl| decl.inputs.get(i)), sig.input(0).map_bound(|ty| ty.tuple_fields()[i]), @@ -559,15 +547,17 @@ impl<'tcx> ExprFnSig<'tcx> { } pub fn predicates_id(&self) -> Option { - if let ExprFnSig::Sig(_, id) | ExprFnSig::Trait(_, _, id) = *self { id } else { None } + if let ExprFnSig::Sig(_, id) | ExprFnSig::Trait(_, _, id) = *self { + id + } else { + None + } } } /// If the expression is function like, get the signature for it. pub fn expr_sig<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option> { - if let Res::Def(DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::AssocFn, id) = - path_res(cx, expr) - { + if let Res::Def(DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::AssocFn, id) = path_res(cx, expr) { Some(ExprFnSig::Sig(cx.tcx.fn_sig(id), Some(id))) } else { ty_sig(cx, cx.typeck_results().expr_ty_adjusted(expr).peel_refs()) @@ -581,14 +571,12 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option { - let decl = id.as_local().and_then(|id| { - cx.tcx.hir().fn_decl_by_hir_id(cx.tcx.hir().local_def_id_to_hir_id(id)) - }); + let decl = id + .as_local() + .and_then(|id| cx.tcx.hir().fn_decl_by_hir_id(cx.tcx.hir().local_def_id_to_hir_id(id))); Some(ExprFnSig::Closure(decl, subs.as_closure().sig())) - } - ty::FnDef(id, subs) => { - Some(ExprFnSig::Sig(cx.tcx.bound_fn_sig(id).subst(cx.tcx, subs), Some(id))) - } + }, + ty::FnDef(id, subs) => Some(ExprFnSig::Sig(cx.tcx.bound_fn_sig(id).subst(cx.tcx, subs), Some(id))), ty::Opaque(id, _) => sig_from_bounds(cx, ty, cx.tcx.item_bounds(id), cx.tcx.opt_parent(id)), ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig, None)), ty::Dynamic(bounds, _, _) => { @@ -601,19 +589,16 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option None, } - } + }, ty::Projection(proj) => match cx.tcx.try_normalize_erasing_regions(cx.param_env, ty) { Ok(normalized_ty) if normalized_ty != ty => ty_sig(cx, normalized_ty), - _ => sig_for_projection(cx, proj) - .or_else(|| sig_from_bounds(cx, ty, cx.param_env.caller_bounds(), None)), + _ => sig_for_projection(cx, proj).or_else(|| sig_from_bounds(cx, ty, cx.param_env.caller_bounds(), None)), }, ty::Param(_) => sig_from_bounds(cx, ty, cx.param_env.caller_bounds(), None), _ => None, @@ -644,7 +629,7 @@ fn sig_from_bounds<'tcx>( return None; } inputs = Some(i); - } + }, PredicateKind::Projection(p) if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output() && p.projection_ty.self_ty() == ty => @@ -654,7 +639,7 @@ fn sig_from_bounds<'tcx>( return None; } output = Some(pred.kind().rebind(p.term.ty().unwrap())); - } + }, _ => (), } } @@ -662,10 +647,7 @@ fn sig_from_bounds<'tcx>( inputs.map(|ty| ExprFnSig::Trait(ty, output, predicates_id)) } -fn sig_for_projection<'tcx>( - cx: &LateContext<'tcx>, - ty: ProjectionTy<'tcx>, -) -> Option> { +fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: ProjectionTy<'tcx>) -> Option> { let mut inputs = None; let mut output = None; let lang_items = cx.tcx.lang_items(); @@ -691,10 +673,8 @@ fn sig_for_projection<'tcx>( return None; } inputs = Some(i); - } - PredicateKind::Projection(p) - if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output() => - { + }, + PredicateKind::Projection(p) if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output() => { if output.is_some() { // Multiple different fn trait impls. Is this even allowed? return None; @@ -703,7 +683,7 @@ fn sig_for_projection<'tcx>( pred.map_bound(|pred| pred.kind().rebind(p.term.ty().unwrap())) .subst(cx.tcx, ty.substs), ); - } + }, _ => (), } } @@ -797,10 +777,7 @@ pub fn for_each_top_level_late_bound_region( ControlFlow::Continue(()) } } - fn visit_binder>( - &mut self, - t: &Binder<'tcx, T>, - ) -> ControlFlow { + fn visit_binder>(&mut self, t: &Binder<'tcx, T>) -> ControlFlow { self.index += 1; let res = t.super_visit_with(self); self.index -= 1; @@ -814,27 +791,19 @@ pub fn for_each_top_level_late_bound_region( pub fn variant_of_res<'tcx>(cx: &LateContext<'tcx>, res: Res) -> Option<&'tcx VariantDef> { match res { Res::Def(DefKind::Struct, id) => Some(cx.tcx.adt_def(id).non_enum_variant()), - Res::Def(DefKind::Variant, id) => { - Some(cx.tcx.adt_def(cx.tcx.parent(id)).variant_with_id(id)) - } - Res::Def(DefKind::Ctor(CtorOf::Struct, _), id) => { - Some(cx.tcx.adt_def(cx.tcx.parent(id)).non_enum_variant()) - } + Res::Def(DefKind::Variant, id) => Some(cx.tcx.adt_def(cx.tcx.parent(id)).variant_with_id(id)), + Res::Def(DefKind::Ctor(CtorOf::Struct, _), id) => Some(cx.tcx.adt_def(cx.tcx.parent(id)).non_enum_variant()), Res::Def(DefKind::Ctor(CtorOf::Variant, _), id) => { let var_id = cx.tcx.parent(id); Some(cx.tcx.adt_def(cx.tcx.parent(var_id)).variant_with_id(var_id)) - } + }, Res::SelfCtor(id) => Some(cx.tcx.type_of(id).ty_adt_def().unwrap().non_enum_variant()), _ => None, } } /// Checks if the type is a type parameter implementing `FnOnce`, but not `FnMut`. -pub fn ty_is_fn_once_param<'tcx>( - tcx: TyCtxt<'_>, - ty: Ty<'tcx>, - predicates: &'tcx [Predicate<'_>], -) -> bool { +pub fn ty_is_fn_once_param<'tcx>(tcx: TyCtxt<'_>, ty: Ty<'tcx>, predicates: &'tcx [Predicate<'_>]) -> bool { let ty::Param(ty) = *ty.kind() else { return false; }; From 525e0c86bc8e11f9b8585f987a973302bb86ff33 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Wed, 14 Sep 2022 20:13:30 +0200 Subject: [PATCH 017/114] Temporarily move clippy::unused_peekable to nursery --- clippy_lints/src/lib.register_all.rs | 1 - clippy_lints/src/lib.register_nursery.rs | 1 + clippy_lints/src/lib.register_suspicious.rs | 1 - clippy_lints/src/unused_peekable.rs | 2 +- 4 files changed, 2 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index 1f85382347aa1..59d1760fe6064 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -344,7 +344,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ 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_peekable::UNUSED_PEEKABLE), LintId::of(unused_unit::UNUSED_UNIT), LintId::of(unwrap::PANICKING_UNWRAP), LintId::of(unwrap::UNNECESSARY_UNWRAP), diff --git a/clippy_lints/src/lib.register_nursery.rs b/clippy_lints/src/lib.register_nursery.rs index e319e7ee72c57..f1783dd9ddef2 100644 --- a/clippy_lints/src/lib.register_nursery.rs +++ b/clippy_lints/src/lib.register_nursery.rs @@ -31,6 +31,7 @@ store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![ 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), ]) diff --git a/clippy_lints/src/lib.register_suspicious.rs b/clippy_lints/src/lib.register_suspicious.rs index 8f131bbf98be3..bede91f183e79 100644 --- a/clippy_lints/src/lib.register_suspicious.rs +++ b/clippy_lints/src/lib.register_suspicious.rs @@ -35,6 +35,5 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec! 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), - LintId::of(unused_peekable::UNUSED_PEEKABLE), LintId::of(write::POSITIONAL_NAMED_FORMAT_PARAMETERS), ]) diff --git a/clippy_lints/src/unused_peekable.rs b/clippy_lints/src/unused_peekable.rs index cfc181e435b9c..cc86564359459 100644 --- a/clippy_lints/src/unused_peekable.rs +++ b/clippy_lints/src/unused_peekable.rs @@ -38,7 +38,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.64.0"] pub UNUSED_PEEKABLE, - suspicious, + nursery, "creating a peekable iterator without using any of its methods" } From 2be8b7332819d9819502f54e45a2c70f1f9903cf Mon Sep 17 00:00:00 2001 From: est31 Date: Fri, 4 Feb 2022 10:13:48 +0100 Subject: [PATCH 018/114] Fix clippy --- clippy_dev/src/lib.rs | 2 +- clippy_lints/src/lib.rs | 2 +- clippy_utils/src/lib.rs | 2 +- tests/ui/needless_return.fixed | 1 - tests/ui/needless_return.rs | 1 - tests/ui/needless_return.stderr | 74 +++++++++---------- tests/ui/semicolon_if_nothing_returned.rs | 1 - tests/ui/semicolon_if_nothing_returned.stderr | 10 +-- 8 files changed, 45 insertions(+), 48 deletions(-) diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs index 82574a8e64b0a..54c7456a2a3b0 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -1,5 +1,5 @@ #![feature(let_chains)] -#![feature(let_else)] +#![cfg_attr(bootstrap, feature(let_else))] #![feature(once_cell)] #![feature(rustc_private)] #![cfg_attr(feature = "deny-warnings", deny(warnings))] diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index e984254bf2919..ceaaf5c6d6ed6 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -5,7 +5,7 @@ #![feature(drain_filter)] #![feature(iter_intersperse)] #![feature(let_chains)] -#![feature(let_else)] +#![cfg_attr(bootstrap, feature(let_else))] #![feature(lint_reasons)] #![feature(never_type)] #![feature(once_cell)] diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 23b51ec2d0849..62da850a15e70 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1,9 +1,9 @@ #![feature(array_chunks)] #![feature(box_patterns)] #![feature(control_flow_enum)] -#![feature(let_else)] #![feature(let_chains)] #![feature(lint_reasons)] +#![cfg_attr(bootstrap, feature(let_else))] #![feature(once_cell)] #![feature(rustc_private)] #![recursion_limit = "512"] diff --git a/tests/ui/needless_return.fixed b/tests/ui/needless_return.fixed index 87c8fc03b3c36..695883e8dff77 100644 --- a/tests/ui/needless_return.fixed +++ b/tests/ui/needless_return.fixed @@ -1,7 +1,6 @@ // run-rustfix #![feature(lint_reasons)] -#![feature(let_else)] #![allow(unused)] #![allow( clippy::if_same_then_else, diff --git a/tests/ui/needless_return.rs b/tests/ui/needless_return.rs index 5a86e656255dd..63d9fe9ecdf8e 100644 --- a/tests/ui/needless_return.rs +++ b/tests/ui/needless_return.rs @@ -1,7 +1,6 @@ // run-rustfix #![feature(lint_reasons)] -#![feature(let_else)] #![allow(unused)] #![allow( clippy::if_same_then_else, diff --git a/tests/ui/needless_return.stderr b/tests/ui/needless_return.stderr index 83ff07638693c..cadee6e00dff2 100644 --- a/tests/ui/needless_return.stderr +++ b/tests/ui/needless_return.stderr @@ -1,5 +1,5 @@ error: unneeded `return` statement - --> $DIR/needless_return.rs:27:5 + --> $DIR/needless_return.rs:26:5 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` @@ -7,217 +7,217 @@ LL | return true; = note: `-D clippy::needless-return` implied by `-D warnings` error: unneeded `return` statement - --> $DIR/needless_return.rs:31:5 + --> $DIR/needless_return.rs:30:5 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:36:9 + --> $DIR/needless_return.rs:35:9 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:38:9 + --> $DIR/needless_return.rs:37:9 | LL | return false; | ^^^^^^^^^^^^^ help: remove `return`: `false` error: unneeded `return` statement - --> $DIR/needless_return.rs:44:17 + --> $DIR/needless_return.rs:43:17 | LL | true => return false, | ^^^^^^^^^^^^ help: remove `return`: `false` error: unneeded `return` statement - --> $DIR/needless_return.rs:46:13 + --> $DIR/needless_return.rs:45:13 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:53:9 + --> $DIR/needless_return.rs:52:9 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:55:16 + --> $DIR/needless_return.rs:54:16 | LL | let _ = || return true; | ^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:59:5 + --> $DIR/needless_return.rs:58:5 | LL | return the_answer!(); | ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `the_answer!()` error: unneeded `return` statement - --> $DIR/needless_return.rs:63:5 + --> $DIR/needless_return.rs:62:5 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:68:9 + --> $DIR/needless_return.rs:67:9 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:70:9 + --> $DIR/needless_return.rs:69:9 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:77:14 + --> $DIR/needless_return.rs:76:14 | LL | _ => return, | ^^^^^^ help: replace `return` with a unit value: `()` error: unneeded `return` statement - --> $DIR/needless_return.rs:86:13 + --> $DIR/needless_return.rs:85:13 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:88:14 + --> $DIR/needless_return.rs:87:14 | LL | _ => return, | ^^^^^^ help: replace `return` with a unit value: `()` error: unneeded `return` statement - --> $DIR/needless_return.rs:101:9 + --> $DIR/needless_return.rs:100:9 | LL | return String::from("test"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::from("test")` error: unneeded `return` statement - --> $DIR/needless_return.rs:103:9 + --> $DIR/needless_return.rs:102:9 | LL | return String::new(); | ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::new()` error: unneeded `return` statement - --> $DIR/needless_return.rs:125:32 + --> $DIR/needless_return.rs:124:32 | LL | bar.unwrap_or_else(|_| return) | ^^^^^^ help: replace `return` with an empty block: `{}` error: unneeded `return` statement - --> $DIR/needless_return.rs:130:13 + --> $DIR/needless_return.rs:129:13 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:132:20 + --> $DIR/needless_return.rs:131:20 | LL | let _ = || return; | ^^^^^^ help: replace `return` with an empty block: `{}` error: unneeded `return` statement - --> $DIR/needless_return.rs:138:32 + --> $DIR/needless_return.rs:137:32 | LL | res.unwrap_or_else(|_| return Foo) | ^^^^^^^^^^ help: remove `return`: `Foo` error: unneeded `return` statement - --> $DIR/needless_return.rs:147:5 + --> $DIR/needless_return.rs:146:5 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:151:5 + --> $DIR/needless_return.rs:150:5 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:156:9 + --> $DIR/needless_return.rs:155:9 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:158:9 + --> $DIR/needless_return.rs:157:9 | LL | return false; | ^^^^^^^^^^^^^ help: remove `return`: `false` error: unneeded `return` statement - --> $DIR/needless_return.rs:164:17 + --> $DIR/needless_return.rs:163:17 | LL | true => return false, | ^^^^^^^^^^^^ help: remove `return`: `false` error: unneeded `return` statement - --> $DIR/needless_return.rs:166:13 + --> $DIR/needless_return.rs:165:13 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:173:9 + --> $DIR/needless_return.rs:172:9 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:175:16 + --> $DIR/needless_return.rs:174:16 | LL | let _ = || return true; | ^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:179:5 + --> $DIR/needless_return.rs:178:5 | LL | return the_answer!(); | ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `the_answer!()` error: unneeded `return` statement - --> $DIR/needless_return.rs:183:5 + --> $DIR/needless_return.rs:182:5 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:188:9 + --> $DIR/needless_return.rs:187:9 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:190:9 + --> $DIR/needless_return.rs:189:9 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:197:14 + --> $DIR/needless_return.rs:196:14 | LL | _ => return, | ^^^^^^ help: replace `return` with a unit value: `()` error: unneeded `return` statement - --> $DIR/needless_return.rs:210:9 + --> $DIR/needless_return.rs:209:9 | LL | return String::from("test"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::from("test")` error: unneeded `return` statement - --> $DIR/needless_return.rs:212:9 + --> $DIR/needless_return.rs:211:9 | LL | return String::new(); | ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::new()` error: unneeded `return` statement - --> $DIR/needless_return.rs:228:5 + --> $DIR/needless_return.rs:227:5 | LL | return format!("Hello {}", "world!"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `format!("Hello {}", "world!")` diff --git a/tests/ui/semicolon_if_nothing_returned.rs b/tests/ui/semicolon_if_nothing_returned.rs index c3235f06779b3..c4dfbd9210e0d 100644 --- a/tests/ui/semicolon_if_nothing_returned.rs +++ b/tests/ui/semicolon_if_nothing_returned.rs @@ -1,6 +1,5 @@ #![warn(clippy::semicolon_if_nothing_returned)] #![allow(clippy::redundant_closure)] -#![feature(let_else)] fn get_unit() {} diff --git a/tests/ui/semicolon_if_nothing_returned.stderr b/tests/ui/semicolon_if_nothing_returned.stderr index 78813e7cc1c39..8d9a67585cf12 100644 --- a/tests/ui/semicolon_if_nothing_returned.stderr +++ b/tests/ui/semicolon_if_nothing_returned.stderr @@ -1,5 +1,5 @@ error: consider adding a `;` to the last statement for consistent formatting - --> $DIR/semicolon_if_nothing_returned.rs:9:5 + --> $DIR/semicolon_if_nothing_returned.rs:8:5 | LL | println!("Hello") | ^^^^^^^^^^^^^^^^^ help: add a `;` here: `println!("Hello");` @@ -7,25 +7,25 @@ LL | println!("Hello") = note: `-D clippy::semicolon-if-nothing-returned` implied by `-D warnings` error: consider adding a `;` to the last statement for consistent formatting - --> $DIR/semicolon_if_nothing_returned.rs:13:5 + --> $DIR/semicolon_if_nothing_returned.rs:12:5 | LL | get_unit() | ^^^^^^^^^^ help: add a `;` here: `get_unit();` error: consider adding a `;` to the last statement for consistent formatting - --> $DIR/semicolon_if_nothing_returned.rs:18:5 + --> $DIR/semicolon_if_nothing_returned.rs:17:5 | LL | y = x + 1 | ^^^^^^^^^ help: add a `;` here: `y = x + 1;` error: consider adding a `;` to the last statement for consistent formatting - --> $DIR/semicolon_if_nothing_returned.rs:24:9 + --> $DIR/semicolon_if_nothing_returned.rs:23:9 | LL | hello() | ^^^^^^^ help: add a `;` here: `hello();` error: consider adding a `;` to the last statement for consistent formatting - --> $DIR/semicolon_if_nothing_returned.rs:35:9 + --> $DIR/semicolon_if_nothing_returned.rs:34:9 | LL | ptr::drop_in_place(s.as_mut_ptr()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add a `;` here: `ptr::drop_in_place(s.as_mut_ptr());` From c2e9c991d59d3aae0809165dbd9237515ae57ce3 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 27 Jul 2022 11:58:34 +0000 Subject: [PATCH 019/114] Revert "Revert "Rollup merge of #98582 - oli-obk:unconstrained_opaque_type, r=estebank"" This reverts commit 4a742a691e7dd2522bad68b86fe2fd5a199d5561. --- clippy_utils/src/qualify_min_const_fn.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index 8835b93290958..405f022868395 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -260,6 +260,7 @@ fn check_place<'tcx>(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &B } }, ProjectionElem::ConstantIndex { .. } + | ProjectionElem::OpaqueCast(..) | ProjectionElem::Downcast(..) | ProjectionElem::Subslice { .. } | ProjectionElem::Deref From 3ca6b9d03193128e00d48101306d6d3cefc2f241 Mon Sep 17 00:00:00 2001 From: kraktus Date: Fri, 16 Sep 2022 22:02:09 +0200 Subject: [PATCH 020/114] Silence [`question_mark`] in const context --- clippy_lints/src/question_mark.rs | 10 ++++++---- tests/ui/question_mark.fixed | 9 +++++++++ tests/ui/question_mark.rs | 9 +++++++++ 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index f4f1fd336df7c..565c48f72847f 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -3,8 +3,8 @@ use clippy_utils::higher; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{ - eq_expr_value, get_parent_node, is_else_clause, is_lang_ctor, path_to_local, path_to_local_id, peel_blocks, - peel_blocks_with_stmt, + eq_expr_value, get_parent_node, in_constant, is_else_clause, is_lang_ctor, path_to_local, path_to_local_id, + peel_blocks, peel_blocks_with_stmt, }; use if_chain::if_chain; use rustc_errors::Applicability; @@ -223,7 +223,9 @@ fn expr_return_none_or_err( impl<'tcx> LateLintPass<'tcx> for QuestionMark { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - check_is_none_or_err_and_early_return(cx, expr); - check_if_let_some_or_err_and_early_return(cx, expr); + if !in_constant(cx, expr.hir_id) { + check_is_none_or_err_and_early_return(cx, expr); + check_if_let_some_or_err_and_early_return(cx, expr); + } } } diff --git a/tests/ui/question_mark.fixed b/tests/ui/question_mark.fixed index 57f23bd1916ff..993389232cc29 100644 --- a/tests/ui/question_mark.fixed +++ b/tests/ui/question_mark.fixed @@ -223,3 +223,12 @@ fn pattern() -> Result<(), PatternedError> { } fn main() {} + +// should not lint, `?` operator not available in const context +const fn issue9175(option: Option<()>) -> Option<()> { + if option.is_none() { + return None; + } + //stuff + Some(()) +} diff --git a/tests/ui/question_mark.rs b/tests/ui/question_mark.rs index 436f027c215d5..9ae0d88829af5 100644 --- a/tests/ui/question_mark.rs +++ b/tests/ui/question_mark.rs @@ -259,3 +259,12 @@ fn pattern() -> Result<(), PatternedError> { } fn main() {} + +// should not lint, `?` operator not available in const context +const fn issue9175(option: Option<()>) -> Option<()> { + if option.is_none() { + return None; + } + //stuff + Some(()) +} From 88a57963da0d55f5a27c7b3dfe899d972136659c Mon Sep 17 00:00:00 2001 From: kraktus Date: Sat, 17 Sep 2022 15:33:38 +0200 Subject: [PATCH 021/114] [`drop_copy`]: Do not lint idiomatic in match arm --- clippy_lints/src/drop_forget_ref.rs | 28 ++++++++++++++++++--- tests/ui/drop_forget_copy.rs | 20 +++++++++++++++ tests/ui/drop_forget_copy.stderr | 38 ++++++++++++++++++++++++++++- 3 files changed, 81 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/drop_forget_ref.rs b/clippy_lints/src/drop_forget_ref.rs index b35f0b8ca52da..de94b87cc409f 100644 --- a/clippy_lints/src/drop_forget_ref.rs +++ b/clippy_lints/src/drop_forget_ref.rs @@ -1,7 +1,8 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note}; +use clippy_utils::get_parent_node; use clippy_utils::is_must_use_func_call; use clippy_utils::ty::{is_copy, is_must_use_ty, is_type_lang_item}; -use rustc_hir::{Expr, ExprKind, LangItem}; +use rustc_hir::{Arm, Expr, ExprKind, LangItem, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; @@ -202,11 +203,13 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef { && let Some(fn_name) = cx.tcx.get_diagnostic_name(def_id) { let arg_ty = cx.typeck_results().expr_ty(arg); + let is_copy = is_copy(cx, arg_ty); + let drop_is_only_expr_in_arm = and_only_expr_in_arm(cx, arg, expr); let (lint, msg) = match fn_name { sym::mem_drop if arg_ty.is_ref() => (DROP_REF, DROP_REF_SUMMARY), sym::mem_forget if arg_ty.is_ref() => (FORGET_REF, FORGET_REF_SUMMARY), - sym::mem_drop if is_copy(cx, arg_ty) => (DROP_COPY, DROP_COPY_SUMMARY), - sym::mem_forget if is_copy(cx, arg_ty) => (FORGET_COPY, FORGET_COPY_SUMMARY), + sym::mem_drop if is_copy && !drop_is_only_expr_in_arm => (DROP_COPY, DROP_COPY_SUMMARY), + sym::mem_forget if is_copy => (FORGET_COPY, FORGET_COPY_SUMMARY), sym::mem_drop if is_type_lang_item(cx, arg_ty, LangItem::ManuallyDrop) => { span_lint_and_help( cx, @@ -221,7 +224,9 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef { sym::mem_drop if !(arg_ty.needs_drop(cx.tcx, cx.param_env) || is_must_use_func_call(cx, arg) - || is_must_use_ty(cx, arg_ty)) => + || is_must_use_ty(cx, arg_ty) + || drop_is_only_expr_in_arm + ) => { (DROP_NON_DROP, DROP_NON_DROP_SUMMARY) }, @@ -241,3 +246,18 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef { } } } + +// dropping returned value of a function like in the following snippet is considered idiomatic, see +// #9482 for examples match { +// => drop(fn_with_side_effect_and_returning_some_value()), +// .. +// } +fn and_only_expr_in_arm<'tcx>(cx: &LateContext<'tcx>, arg: &'tcx Expr<'_>, drop_expr: &'tcx Expr<'_>) -> bool { + if matches!(arg.kind, ExprKind::Call(..) | ExprKind::MethodCall(..)) { + let parent_node = get_parent_node(cx.tcx, drop_expr.hir_id); + if let Some(Node::Arm(Arm { body, .. })) = &parent_node { + return body.hir_id == drop_expr.hir_id; + } + } + false +} diff --git a/tests/ui/drop_forget_copy.rs b/tests/ui/drop_forget_copy.rs index 7c7a9ecff67f5..a7276dd59f434 100644 --- a/tests/ui/drop_forget_copy.rs +++ b/tests/ui/drop_forget_copy.rs @@ -64,3 +64,23 @@ fn main() { let a5 = a1.clone(); forget(a5); } + +#[allow(unused)] +#[allow(clippy::unit_cmp)] +fn issue9482(x: u8) { + fn println_and(t: T) -> T { + println!("foo"); + t + } + + match x { + 0 => drop(println_and(12)), // Don't lint (copy type), we only care about side-effects + 1 => drop(println_and(String::new())), // Don't lint (no copy type), we only care about side-effects + 2 => { + drop(println_and(13)); // Lint, even if we only care about the side-effect, it's already in a block + }, + 3 if drop(println_and(14)) == () => (), // Lint, idiomatic use is only in body of `Arm` + 4 => drop(2), // Lint, not a fn/method call + _ => (), + } +} diff --git a/tests/ui/drop_forget_copy.stderr b/tests/ui/drop_forget_copy.stderr index 88228afae89c0..ec7dd2f08f1d5 100644 --- a/tests/ui/drop_forget_copy.stderr +++ b/tests/ui/drop_forget_copy.stderr @@ -72,5 +72,41 @@ note: argument has type `SomeStruct` LL | forget(s4); | ^^ -error: aborting due to 6 previous errors +error: calls to `std::mem::drop` with a value that implements `Copy`. Dropping a copy leaves the original intact + --> $DIR/drop_forget_copy.rs:80:13 + | +LL | drop(println_and(13)); // Lint, even if we only care about the side-effect, it's already in a block + | ^^^^^^^^^^^^^^^^^^^^^ + | +note: argument has type `i32` + --> $DIR/drop_forget_copy.rs:80:18 + | +LL | drop(println_and(13)); // Lint, even if we only care about the side-effect, it's already in a block + | ^^^^^^^^^^^^^^^ + +error: calls to `std::mem::drop` with a value that implements `Copy`. Dropping a copy leaves the original intact + --> $DIR/drop_forget_copy.rs:82:14 + | +LL | 3 if drop(println_and(14)) == () => (), // Lint, idiomatic use is only in body of `Arm` + | ^^^^^^^^^^^^^^^^^^^^^ + | +note: argument has type `i32` + --> $DIR/drop_forget_copy.rs:82:19 + | +LL | 3 if drop(println_and(14)) == () => (), // Lint, idiomatic use is only in body of `Arm` + | ^^^^^^^^^^^^^^^ + +error: calls to `std::mem::drop` with a value that implements `Copy`. Dropping a copy leaves the original intact + --> $DIR/drop_forget_copy.rs:83:14 + | +LL | 4 => drop(2), // Lint, not a fn/method call + | ^^^^^^^ + | +note: argument has type `i32` + --> $DIR/drop_forget_copy.rs:83:19 + | +LL | 4 => drop(2), // Lint, not a fn/method call + | ^ + +error: aborting due to 9 previous errors From d1dbdcf332e1a91666999d25ee6a0900512dda82 Mon Sep 17 00:00:00 2001 From: kraktus Date: Sun, 18 Sep 2022 20:41:41 +0200 Subject: [PATCH 022/114] refactor `needless_return` --- clippy_lints/src/returns.rs | 111 +++++++++++++++--------------------- 1 file changed, 47 insertions(+), 64 deletions(-) diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index 91553240e3c91..63c8811f62d9a 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -72,6 +72,28 @@ enum RetReplacement { Unit, } +impl RetReplacement { + fn sugg_help(&self) -> &'static str { + match *self { + Self::Empty => "remove `return`", + Self::Block => "replace `return` with an empty block", + Self::Unit => "replace `return` with a unit value", + + } + } +} + +impl ToString for RetReplacement { + fn to_string(&self) -> String { + match *self { + Self::Empty => "", + Self::Block => "{}", + Self::Unit => "()", + } + .to_string() + } +} + declare_lint_pass!(Return => [LET_AND_RETURN, NEEDLESS_RETURN]); impl<'tcx> LateLintPass<'tcx> for Return { @@ -221,74 +243,35 @@ fn emit_return_lint( if ret_span.from_expansion() { return; } - match inner_span { - Some(inner_span) => { - let mut applicability = Applicability::MachineApplicable; - span_lint_hir_and_then( - cx, - NEEDLESS_RETURN, - emission_place, - ret_span, - "unneeded `return` statement", - |diag| { - let (snippet, _) = snippet_with_context(cx, inner_span, ret_span.ctxt(), "..", &mut applicability); - diag.span_suggestion(ret_span, "remove `return`", snippet, applicability); - }, - ); - }, - None => match replacement { - RetReplacement::Empty => { - span_lint_hir_and_then( - cx, - NEEDLESS_RETURN, - emission_place, - ret_span, - "unneeded `return` statement", - |diag| { - diag.span_suggestion( - ret_span, - "remove `return`", - String::new(), - Applicability::MachineApplicable, - ); - }, - ); - }, - RetReplacement::Block => { - span_lint_hir_and_then( - cx, - NEEDLESS_RETURN, - emission_place, - ret_span, - "unneeded `return` statement", - |diag| { - diag.span_suggestion( - ret_span, - "replace `return` with an empty block", - "{}".to_string(), - Applicability::MachineApplicable, - ); - }, - ); + if let Some(inner_span) = inner_span { + let mut applicability = Applicability::MachineApplicable; + span_lint_hir_and_then( + cx, + NEEDLESS_RETURN, + emission_place, + ret_span, + "unneeded `return` statement", + |diag| { + let (snippet, _) = snippet_with_context(cx, inner_span, ret_span.ctxt(), "..", &mut applicability); + diag.span_suggestion(ret_span, "remove `return`", snippet, applicability); }, - RetReplacement::Unit => { - span_lint_hir_and_then( - cx, - NEEDLESS_RETURN, - emission_place, + ); + } else { + span_lint_hir_and_then( + cx, + NEEDLESS_RETURN, + emission_place, + ret_span, + "unneeded `return` statement", + |diag| { + diag.span_suggestion( ret_span, - "unneeded `return` statement", - |diag| { - diag.span_suggestion( - ret_span, - "replace `return` with a unit value", - "()".to_string(), - Applicability::MachineApplicable, - ); - }, + replacement.sugg_help(), + replacement.to_string(), + Applicability::MachineApplicable, ); }, - }, + ) } } From bf8870eeadf4ce73c5e7dfed071fbc41231aa324 Mon Sep 17 00:00:00 2001 From: kraktus Date: Sun, 18 Sep 2022 21:06:06 +0200 Subject: [PATCH 023/114] further refactor of `needless_return` --- clippy_lints/src/returns.rs | 55 +++++++++++++++---------------------- 1 file changed, 22 insertions(+), 33 deletions(-) diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index 63c8811f62d9a..e4692a8d84beb 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -78,7 +78,6 @@ impl RetReplacement { Self::Empty => "remove `return`", Self::Block => "replace `return` with an empty block", Self::Unit => "replace `return` with a unit value", - } } } @@ -161,37 +160,33 @@ impl<'tcx> LateLintPass<'tcx> for Return { } else { RetReplacement::Empty }; - check_final_expr(cx, body.value, Some(body.value.span), replacement); + check_final_expr(cx, body.value, body.value.span, replacement); }, FnKind::ItemFn(..) | FnKind::Method(..) => { - if let ExprKind::Block(block, _) = body.value.kind { - check_block_return(cx, block); - } + check_block_return(cx, &body.value.kind); }, } } } -fn check_block_return<'tcx>(cx: &LateContext<'tcx>, block: &Block<'tcx>) { - if let Some(expr) = block.expr { - check_final_expr(cx, expr, Some(expr.span), RetReplacement::Empty); - } else if let Some(stmt) = block.stmts.iter().last() { - match stmt.kind { - StmtKind::Expr(expr) | StmtKind::Semi(expr) => { - check_final_expr(cx, expr, Some(stmt.span), RetReplacement::Empty); - }, - _ => (), +// if `expr` is a block, check if there are needless returns in it +fn check_block_return<'tcx>(cx: &LateContext<'tcx>, expr_kind: &ExprKind<'tcx>) { + if let ExprKind::Block(block, _) = expr_kind { + if let Some(block_expr) = block.expr { + check_final_expr(cx, block_expr, block_expr.span, RetReplacement::Empty); + } else if let Some(stmt) = block.stmts.iter().last() { + match stmt.kind { + StmtKind::Expr(expr) | StmtKind::Semi(expr) => { + check_final_expr(cx, expr, stmt.span, RetReplacement::Empty); + }, + _ => (), + } } } } -fn check_final_expr<'tcx>( - cx: &LateContext<'tcx>, - expr: &'tcx Expr<'tcx>, - span: Option, - replacement: RetReplacement, -) { - match expr.kind { +fn check_final_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, span: Span, replacement: RetReplacement) { + match &expr.peel_drop_temps().kind { // simple return is always "bad" ExprKind::Ret(ref inner) => { if cx.tcx.hir().attrs(expr.hir_id).is_empty() { @@ -200,23 +195,17 @@ fn check_final_expr<'tcx>( emit_return_lint( cx, inner.map_or(expr.hir_id, |inner| inner.hir_id), - span.expect("`else return` is not possible"), + span, inner.as_ref().map(|i| i.span), replacement, ); } } }, - // a whole block? check it! - ExprKind::Block(block, _) => { - check_block_return(cx, block); - }, ExprKind::If(_, then, else_clause_opt) => { - if let ExprKind::Block(ifblock, _) = then.kind { - check_block_return(cx, ifblock); - } + check_block_return(cx, &then.kind); if let Some(else_clause) = else_clause_opt { - check_final_expr(cx, else_clause, None, RetReplacement::Empty); + check_block_return(cx, &else_clause.kind) } }, // a match expr, check all arms @@ -225,11 +214,11 @@ fn check_final_expr<'tcx>( // (except for unit type functions) so we don't match it ExprKind::Match(_, arms, MatchSource::Normal) => { for arm in arms.iter() { - check_final_expr(cx, arm.body, Some(arm.body.span), RetReplacement::Unit); + check_final_expr(cx, arm.body, arm.body.span, RetReplacement::Unit); } }, - ExprKind::DropTemps(expr) => check_final_expr(cx, expr, None, RetReplacement::Empty), - _ => (), + // if it's a whole block, check it + other_expr_kind => check_block_return(cx, &other_expr_kind), } } From 15ec5d26084fe13c984b4e6c2933e048e070680c Mon Sep 17 00:00:00 2001 From: kraktus Date: Sun, 18 Sep 2022 21:26:23 +0200 Subject: [PATCH 024/114] further refactor --- clippy_lints/src/returns.rs | 51 ++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 29 deletions(-) diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index e4692a8d84beb..26b6898e58802 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -232,36 +232,29 @@ fn emit_return_lint( if ret_span.from_expansion() { return; } - if let Some(inner_span) = inner_span { - let mut applicability = Applicability::MachineApplicable; - span_lint_hir_and_then( - cx, - NEEDLESS_RETURN, - emission_place, - ret_span, - "unneeded `return` statement", - |diag| { - let (snippet, _) = snippet_with_context(cx, inner_span, ret_span.ctxt(), "..", &mut applicability); - diag.span_suggestion(ret_span, "remove `return`", snippet, applicability); - }, - ); + let mut applicability = Applicability::MachineApplicable; + let return_replacement = inner_span.map_or_else( + || replacement.to_string(), + |inner_span| { + let (snippet, _) = snippet_with_context(cx, inner_span, ret_span.ctxt(), "..", &mut applicability); + snippet.to_string() + }, + ); + let sugg_help = if inner_span.is_some() { + "remove `return`" } else { - span_lint_hir_and_then( - cx, - NEEDLESS_RETURN, - emission_place, - ret_span, - "unneeded `return` statement", - |diag| { - diag.span_suggestion( - ret_span, - replacement.sugg_help(), - replacement.to_string(), - Applicability::MachineApplicable, - ); - }, - ) - } + replacement.sugg_help() + }; + span_lint_hir_and_then( + cx, + NEEDLESS_RETURN, + emission_place, + ret_span, + "unneeded `return` statement", + |diag| { + diag.span_suggestion(ret_span, sugg_help, return_replacement, applicability); + }, + ); } fn last_statement_borrows<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { From 23d1d07861457a42a401ea512b11614952339497 Mon Sep 17 00:00:00 2001 From: kraktus Date: Mon, 19 Sep 2022 07:43:16 +0200 Subject: [PATCH 025/114] small refactor --- clippy_lints/src/returns.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index 26b6898e58802..721c5f64a9050 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::span_lint_hir_and_then; +use clippy_utils::diagnostics::{span_lint_hir_and_then, span_lint_and_then}; use clippy_utils::source::{snippet_opt, snippet_with_context}; use clippy_utils::{fn_def_id, path_to_local_id}; use if_chain::if_chain; @@ -194,7 +194,6 @@ fn check_final_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, span: if !borrows { emit_return_lint( cx, - inner.map_or(expr.hir_id, |inner| inner.hir_id), span, inner.as_ref().map(|i| i.span), replacement, @@ -224,7 +223,6 @@ fn check_final_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, span: fn emit_return_lint( cx: &LateContext<'_>, - emission_place: HirId, ret_span: Span, inner_span: Option, replacement: RetReplacement, @@ -245,10 +243,9 @@ fn emit_return_lint( } else { replacement.sugg_help() }; - span_lint_hir_and_then( + span_lint_and_then( cx, NEEDLESS_RETURN, - emission_place, ret_span, "unneeded `return` statement", |diag| { From 70f4c712c55929a2584b0a45bbca8ebf03079b9c Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 16 Sep 2022 15:31:10 +0200 Subject: [PATCH 026/114] remove the `Subst` trait, always use `EarlyBinder` --- clippy_lints/src/dereference.rs | 2 +- clippy_lints/src/eta_reduction.rs | 1 - clippy_lints/src/future_not_send.rs | 1 - clippy_lints/src/methods/unnecessary_to_owned.rs | 1 - clippy_lints/src/mut_reference.rs | 1 - clippy_lints/src/transmute/transmute_undefined_repr.rs | 2 +- clippy_utils/src/consts.rs | 2 +- clippy_utils/src/ty.rs | 2 +- 8 files changed, 4 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 88e28018e5d00..45b5d79d44522 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -20,7 +20,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::{ - self, subst::Subst, Binder, BoundVariableKind, EarlyBinder, FnSig, GenericArgKind, List, ParamTy, PredicateKind, + self, Binder, BoundVariableKind, EarlyBinder, FnSig, GenericArgKind, List, ParamTy, PredicateKind, ProjectionPredicate, Ty, TyCtxt, TypeVisitable, TypeckResults, }; use rustc_semver::RustcVersion; diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index 53bc617a4f5b7..598f8c31859ed 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -11,7 +11,6 @@ use rustc_hir::{Closure, Expr, ExprKind, Param, PatKind, Unsafety}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; use rustc_middle::ty::binding::BindingMode; -use rustc_middle::ty::subst::Subst; use rustc_middle::ty::{self, ClosureKind, Ty, TypeVisitable}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::sym; diff --git a/clippy_lints/src/future_not_send.rs b/clippy_lints/src/future_not_send.rs index ef7d75aa8ed9b..eb2eefe0d5a16 100644 --- a/clippy_lints/src/future_not_send.rs +++ b/clippy_lints/src/future_not_send.rs @@ -4,7 +4,6 @@ use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl, HirId}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::subst::Subst; use rustc_middle::ty::{EarlyBinder, Opaque, PredicateKind::Trait}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{sym, Span}; diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index 763bfafecef14..8d3cede70f70d 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -1,6 +1,5 @@ use super::implicit_clone::is_clone_like; use super::unnecessary_iter_cloned::{self, is_into_iter}; -use crate::rustc_middle::ty::Subst; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; use clippy_utils::ty::{get_associated_type, get_iterator_item_ty, implements_trait, is_copy, peel_mid_ty_refs}; diff --git a/clippy_lints/src/mut_reference.rs b/clippy_lints/src/mut_reference.rs index 82dc03ef5c5bc..084c0d471dded 100644 --- a/clippy_lints/src/mut_reference.rs +++ b/clippy_lints/src/mut_reference.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::subst::Subst; use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use std::iter; diff --git a/clippy_lints/src/transmute/transmute_undefined_repr.rs b/clippy_lints/src/transmute/transmute_undefined_repr.rs index b6d7d9f5b42ec..ae55a6bf5586e 100644 --- a/clippy_lints/src/transmute/transmute_undefined_repr.rs +++ b/clippy_lints/src/transmute/transmute_undefined_repr.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::is_c_void; use rustc_hir::Expr; use rustc_lint::LateContext; -use rustc_middle::ty::subst::{Subst, SubstsRef}; +use rustc_middle::ty::SubstsRef; use rustc_middle::ty::{self, IntTy, Ty, TypeAndMut, UintTy}; use rustc_span::DUMMY_SP; diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index e053708edd507..96c55111fbaff 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -9,7 +9,7 @@ use rustc_hir::{BinOp, BinOpKind, Block, Expr, ExprKind, HirId, Item, ItemKind, use rustc_lint::LateContext; use rustc_middle::mir; use rustc_middle::mir::interpret::Scalar; -use rustc_middle::ty::subst::{Subst, SubstsRef}; +use rustc_middle::ty::SubstsRef; use rustc_middle::ty::{self, EarlyBinder, FloatTy, ScalarInt, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_span::symbol::Symbol; diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index a8ad6cf4f6a3c..926ecf9659321 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -12,7 +12,7 @@ use rustc_hir::{Expr, FnDecl, LangItem, TyKind, Unsafety}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; use rustc_middle::mir::interpret::{ConstValue, Scalar}; -use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst}; +use rustc_middle::ty::{GenericArg, GenericArgKind}; use rustc_middle::ty::{ self, AdtDef, Binder, BoundRegion, DefIdTree, FnSig, IntTy, ParamEnv, Predicate, PredicateKind, ProjectionTy, Region, RegionKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, UintTy, VariantDef, VariantDiscr, From 5c0cb0deaa116755bfb3f1fd05314c96f64959c9 Mon Sep 17 00:00:00 2001 From: kraktus Date: Mon, 19 Sep 2022 12:07:53 +0200 Subject: [PATCH 027/114] [`needless_return`] Recursively remove unneeded semicolons --- clippy_lints/src/returns.rs | 65 ++++++----- tests/ui/needless_return.fixed | 27 +++++ tests/ui/needless_return.rs | 27 +++++ tests/ui/needless_return.stderr | 189 +++++++++++++++++++++++++------- 4 files changed, 244 insertions(+), 64 deletions(-) diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index 721c5f64a9050..f7ceb415a798c 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::{span_lint_hir_and_then, span_lint_and_then}; +use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::source::{snippet_opt, snippet_with_context}; use clippy_utils::{fn_def_id, path_to_local_id}; use if_chain::if_chain; @@ -9,7 +9,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; 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::source_map::Span; +use rustc_span::source_map::{Span, DUMMY_SP}; declare_clippy_lint! { /// ### What it does @@ -73,8 +73,8 @@ enum RetReplacement { } impl RetReplacement { - fn sugg_help(&self) -> &'static str { - match *self { + fn sugg_help(self) -> &'static str { + match self { Self::Empty => "remove `return`", Self::Block => "replace `return` with an empty block", Self::Unit => "replace `return` with a unit value", @@ -160,24 +160,30 @@ impl<'tcx> LateLintPass<'tcx> for Return { } else { RetReplacement::Empty }; - check_final_expr(cx, body.value, body.value.span, replacement); + check_final_expr(cx, body.value, vec![], replacement); }, FnKind::ItemFn(..) | FnKind::Method(..) => { - check_block_return(cx, &body.value.kind); + check_block_return(cx, &body.value.kind, vec![]); }, } } } // if `expr` is a block, check if there are needless returns in it -fn check_block_return<'tcx>(cx: &LateContext<'tcx>, expr_kind: &ExprKind<'tcx>) { +fn check_block_return<'tcx>(cx: &LateContext<'tcx>, expr_kind: &ExprKind<'tcx>, semi_spans: Vec) { if let ExprKind::Block(block, _) = expr_kind { if let Some(block_expr) = block.expr { - check_final_expr(cx, block_expr, block_expr.span, RetReplacement::Empty); + check_final_expr(cx, block_expr, semi_spans, RetReplacement::Empty); } else if let Some(stmt) = block.stmts.iter().last() { match stmt.kind { - StmtKind::Expr(expr) | StmtKind::Semi(expr) => { - check_final_expr(cx, expr, stmt.span, RetReplacement::Empty); + StmtKind::Expr(expr) => { + check_final_expr(cx, expr, semi_spans, RetReplacement::Empty); + }, + StmtKind::Semi(semi_expr) => { + let mut semi_spans_and_this_one = semi_spans; + // we only want the span containing the semicolon so we can remove it later. From `entry.rs:382` + semi_spans_and_this_one.push(stmt.span.trim_start(semi_expr.span).unwrap_or(DUMMY_SP)); + check_final_expr(cx, semi_expr, semi_spans_and_this_one, RetReplacement::Empty); }, _ => (), } @@ -185,8 +191,15 @@ fn check_block_return<'tcx>(cx: &LateContext<'tcx>, expr_kind: &ExprKind<'tcx>) } } -fn check_final_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, span: Span, replacement: RetReplacement) { - match &expr.peel_drop_temps().kind { +fn check_final_expr<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'tcx>, + semi_spans: Vec, /* containing all the places where we would need to remove semicolons if finding an + * needless return */ + replacement: RetReplacement, +) { + let peeled_drop_expr = expr.peel_drop_temps(); + match &peeled_drop_expr.kind { // simple return is always "bad" ExprKind::Ret(ref inner) => { if cx.tcx.hir().attrs(expr.hir_id).is_empty() { @@ -194,7 +207,8 @@ fn check_final_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, span: if !borrows { emit_return_lint( cx, - span, + peeled_drop_expr.span, + semi_spans, inner.as_ref().map(|i| i.span), replacement, ); @@ -202,9 +216,9 @@ fn check_final_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, span: } }, ExprKind::If(_, then, else_clause_opt) => { - check_block_return(cx, &then.kind); + check_block_return(cx, &then.kind, semi_spans.clone()); if let Some(else_clause) = else_clause_opt { - check_block_return(cx, &else_clause.kind) + check_block_return(cx, &else_clause.kind, semi_spans); } }, // a match expr, check all arms @@ -213,17 +227,18 @@ fn check_final_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, span: // (except for unit type functions) so we don't match it ExprKind::Match(_, arms, MatchSource::Normal) => { for arm in arms.iter() { - check_final_expr(cx, arm.body, arm.body.span, RetReplacement::Unit); + check_final_expr(cx, arm.body, semi_spans.clone(), RetReplacement::Unit); } }, // if it's a whole block, check it - other_expr_kind => check_block_return(cx, &other_expr_kind), + other_expr_kind => check_block_return(cx, other_expr_kind, semi_spans), } } fn emit_return_lint( cx: &LateContext<'_>, ret_span: Span, + semi_spans: Vec, inner_span: Option, replacement: RetReplacement, ) { @@ -243,15 +258,13 @@ fn emit_return_lint( } else { replacement.sugg_help() }; - span_lint_and_then( - cx, - NEEDLESS_RETURN, - ret_span, - "unneeded `return` statement", - |diag| { - diag.span_suggestion(ret_span, sugg_help, return_replacement, applicability); - }, - ); + span_lint_and_then(cx, NEEDLESS_RETURN, ret_span, "unneeded `return` statement", |diag| { + diag.span_suggestion_hidden(ret_span, sugg_help, return_replacement, applicability); + // for each parent statement, we need to remove the semicolon + for semi_stmt_span in semi_spans { + diag.tool_only_span_suggestion(semi_stmt_span, "remove this semicolon", "", applicability); + } + }); } fn last_statement_borrows<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { diff --git a/tests/ui/needless_return.fixed b/tests/ui/needless_return.fixed index 87c8fc03b3c36..a5e28b9b1a447 100644 --- a/tests/ui/needless_return.fixed +++ b/tests/ui/needless_return.fixed @@ -233,4 +233,31 @@ fn issue_9361() -> i32 { return 1 + 2; } +fn issue8336(x: i32) -> bool { + if x > 0 { + println!("something"); + true + } else { + false + } +} + +fn issue8156(x: u8) -> u64 { + match x { + 80 => { + 10 + }, + _ => { + 100 + }, + } +} + +// Ideally the compiler should throw `unused_braces` in this case +fn issue9192() -> i32 { + { + 0 + } +} + fn main() {} diff --git a/tests/ui/needless_return.rs b/tests/ui/needless_return.rs index 5a86e656255dd..49fd49c72936e 100644 --- a/tests/ui/needless_return.rs +++ b/tests/ui/needless_return.rs @@ -233,4 +233,31 @@ fn issue_9361() -> i32 { return 1 + 2; } +fn issue8336(x: i32) -> bool { + if x > 0 { + println!("something"); + return true; + } else { + return false; + }; +} + +fn issue8156(x: u8) -> u64 { + match x { + 80 => { + return 10; + }, + _ => { + return 100; + }, + }; +} + +// Ideally the compiler should throw `unused_braces` in this case +fn issue9192() -> i32 { + { + return 0; + }; +} + fn main() {} diff --git a/tests/ui/needless_return.stderr b/tests/ui/needless_return.stderr index 83ff07638693c..d8dba766bf4ae 100644 --- a/tests/ui/needless_return.stderr +++ b/tests/ui/needless_return.stderr @@ -2,225 +2,338 @@ error: unneeded `return` statement --> $DIR/needless_return.rs:27:5 | LL | return true; - | ^^^^^^^^^^^^ help: remove `return`: `true` + | ^^^^^^^^^^^ | = note: `-D clippy::needless-return` implied by `-D warnings` + = help: remove `return` error: unneeded `return` statement --> $DIR/needless_return.rs:31:5 | LL | return true; - | ^^^^^^^^^^^^ help: remove `return`: `true` + | ^^^^^^^^^^^ + | + = help: remove `return` error: unneeded `return` statement --> $DIR/needless_return.rs:36:9 | LL | return true; - | ^^^^^^^^^^^^ help: remove `return`: `true` + | ^^^^^^^^^^^ + | + = help: remove `return` error: unneeded `return` statement --> $DIR/needless_return.rs:38:9 | LL | return false; - | ^^^^^^^^^^^^^ help: remove `return`: `false` + | ^^^^^^^^^^^^ + | + = help: remove `return` error: unneeded `return` statement --> $DIR/needless_return.rs:44:17 | LL | true => return false, - | ^^^^^^^^^^^^ help: remove `return`: `false` + | ^^^^^^^^^^^^ + | + = help: remove `return` error: unneeded `return` statement --> $DIR/needless_return.rs:46:13 | LL | return true; - | ^^^^^^^^^^^^ help: remove `return`: `true` + | ^^^^^^^^^^^ + | + = help: remove `return` error: unneeded `return` statement --> $DIR/needless_return.rs:53:9 | LL | return true; - | ^^^^^^^^^^^^ help: remove `return`: `true` + | ^^^^^^^^^^^ + | + = help: remove `return` error: unneeded `return` statement --> $DIR/needless_return.rs:55:16 | LL | let _ = || return true; - | ^^^^^^^^^^^ help: remove `return`: `true` + | ^^^^^^^^^^^ + | + = help: remove `return` error: unneeded `return` statement --> $DIR/needless_return.rs:59:5 | LL | return the_answer!(); - | ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `the_answer!()` + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: remove `return` error: unneeded `return` statement --> $DIR/needless_return.rs:63:5 | LL | return; - | ^^^^^^^ help: remove `return` + | ^^^^^^ + | + = help: remove `return` error: unneeded `return` statement --> $DIR/needless_return.rs:68:9 | LL | return; - | ^^^^^^^ help: remove `return` + | ^^^^^^ + | + = help: remove `return` error: unneeded `return` statement --> $DIR/needless_return.rs:70:9 | LL | return; - | ^^^^^^^ help: remove `return` + | ^^^^^^ + | + = help: remove `return` error: unneeded `return` statement --> $DIR/needless_return.rs:77:14 | LL | _ => return, - | ^^^^^^ help: replace `return` with a unit value: `()` + | ^^^^^^ + | + = help: replace `return` with a unit value error: unneeded `return` statement --> $DIR/needless_return.rs:86:13 | LL | return; - | ^^^^^^^ help: remove `return` + | ^^^^^^ + | + = help: remove `return` error: unneeded `return` statement --> $DIR/needless_return.rs:88:14 | LL | _ => return, - | ^^^^^^ help: replace `return` with a unit value: `()` + | ^^^^^^ + | + = help: replace `return` with a unit value error: unneeded `return` statement --> $DIR/needless_return.rs:101:9 | LL | return String::from("test"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::from("test")` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: remove `return` error: unneeded `return` statement --> $DIR/needless_return.rs:103:9 | LL | return String::new(); - | ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::new()` + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: remove `return` error: unneeded `return` statement --> $DIR/needless_return.rs:125:32 | LL | bar.unwrap_or_else(|_| return) - | ^^^^^^ help: replace `return` with an empty block: `{}` + | ^^^^^^ + | + = help: replace `return` with an empty block error: unneeded `return` statement --> $DIR/needless_return.rs:130:13 | LL | return; - | ^^^^^^^ help: remove `return` + | ^^^^^^ + | + = help: remove `return` error: unneeded `return` statement --> $DIR/needless_return.rs:132:20 | LL | let _ = || return; - | ^^^^^^ help: replace `return` with an empty block: `{}` + | ^^^^^^ + | + = help: replace `return` with an empty block error: unneeded `return` statement --> $DIR/needless_return.rs:138:32 | LL | res.unwrap_or_else(|_| return Foo) - | ^^^^^^^^^^ help: remove `return`: `Foo` + | ^^^^^^^^^^ + | + = help: remove `return` error: unneeded `return` statement --> $DIR/needless_return.rs:147:5 | LL | return true; - | ^^^^^^^^^^^^ help: remove `return`: `true` + | ^^^^^^^^^^^ + | + = help: remove `return` error: unneeded `return` statement --> $DIR/needless_return.rs:151:5 | LL | return true; - | ^^^^^^^^^^^^ help: remove `return`: `true` + | ^^^^^^^^^^^ + | + = help: remove `return` error: unneeded `return` statement --> $DIR/needless_return.rs:156:9 | LL | return true; - | ^^^^^^^^^^^^ help: remove `return`: `true` + | ^^^^^^^^^^^ + | + = help: remove `return` error: unneeded `return` statement --> $DIR/needless_return.rs:158:9 | LL | return false; - | ^^^^^^^^^^^^^ help: remove `return`: `false` + | ^^^^^^^^^^^^ + | + = help: remove `return` error: unneeded `return` statement --> $DIR/needless_return.rs:164:17 | LL | true => return false, - | ^^^^^^^^^^^^ help: remove `return`: `false` + | ^^^^^^^^^^^^ + | + = help: remove `return` error: unneeded `return` statement --> $DIR/needless_return.rs:166:13 | LL | return true; - | ^^^^^^^^^^^^ help: remove `return`: `true` + | ^^^^^^^^^^^ + | + = help: remove `return` error: unneeded `return` statement --> $DIR/needless_return.rs:173:9 | LL | return true; - | ^^^^^^^^^^^^ help: remove `return`: `true` + | ^^^^^^^^^^^ + | + = help: remove `return` error: unneeded `return` statement --> $DIR/needless_return.rs:175:16 | LL | let _ = || return true; - | ^^^^^^^^^^^ help: remove `return`: `true` + | ^^^^^^^^^^^ + | + = help: remove `return` error: unneeded `return` statement --> $DIR/needless_return.rs:179:5 | LL | return the_answer!(); - | ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `the_answer!()` + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: remove `return` error: unneeded `return` statement --> $DIR/needless_return.rs:183:5 | LL | return; - | ^^^^^^^ help: remove `return` + | ^^^^^^ + | + = help: remove `return` error: unneeded `return` statement --> $DIR/needless_return.rs:188:9 | LL | return; - | ^^^^^^^ help: remove `return` + | ^^^^^^ + | + = help: remove `return` error: unneeded `return` statement --> $DIR/needless_return.rs:190:9 | LL | return; - | ^^^^^^^ help: remove `return` + | ^^^^^^ + | + = help: remove `return` error: unneeded `return` statement --> $DIR/needless_return.rs:197:14 | LL | _ => return, - | ^^^^^^ help: replace `return` with a unit value: `()` + | ^^^^^^ + | + = help: replace `return` with a unit value error: unneeded `return` statement --> $DIR/needless_return.rs:210:9 | LL | return String::from("test"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::from("test")` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: remove `return` error: unneeded `return` statement --> $DIR/needless_return.rs:212:9 | LL | return String::new(); - | ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::new()` + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: remove `return` error: unneeded `return` statement --> $DIR/needless_return.rs:228:5 | LL | return format!("Hello {}", "world!"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `format!("Hello {}", "world!")` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: remove `return` + +error: unneeded `return` statement + --> $DIR/needless_return.rs:239:9 + | +LL | return true; + | ^^^^^^^^^^^ + | + = help: remove `return` + +error: unneeded `return` statement + --> $DIR/needless_return.rs:241:9 + | +LL | return false; + | ^^^^^^^^^^^^ + | + = help: remove `return` + +error: unneeded `return` statement + --> $DIR/needless_return.rs:248:13 + | +LL | return 10; + | ^^^^^^^^^ + | + = help: remove `return` + +error: unneeded `return` statement + --> $DIR/needless_return.rs:251:13 + | +LL | return 100; + | ^^^^^^^^^^ + | + = help: remove `return` + +error: unneeded `return` statement + --> $DIR/needless_return.rs:259:9 + | +LL | return 0; + | ^^^^^^^^ + | + = help: remove `return` -error: aborting due to 37 previous errors +error: aborting due to 42 previous errors From d63aeceaa1f4f175ad63456e691395912460ef41 Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Mon, 19 Sep 2022 10:02:17 +0000 Subject: [PATCH 028/114] [`never_loop`]: Fix FP with let..else statements. --- clippy_lints/src/loops/never_loop.rs | 31 +++++++++++++++++--------- tests/ui/never_loop.rs | 27 +++++++++++++++++++++++ tests/ui/never_loop.stderr | 33 +++++++++++++++++++--------- 3 files changed, 71 insertions(+), 20 deletions(-) diff --git a/clippy_lints/src/loops/never_loop.rs b/clippy_lints/src/loops/never_loop.rs index 116e589cad6f3..2386f4f4f4ee5 100644 --- a/clippy_lints/src/loops/never_loop.rs +++ b/clippy_lints/src/loops/never_loop.rs @@ -42,6 +42,7 @@ pub(super) fn check( } } +#[derive(Copy, Clone)] enum NeverLoopResult { // A break/return always get triggered but not necessarily for the main loop. AlwaysBreak, @@ -51,8 +52,8 @@ enum NeverLoopResult { } #[must_use] -fn absorb_break(arg: &NeverLoopResult) -> NeverLoopResult { - match *arg { +fn absorb_break(arg: NeverLoopResult) -> NeverLoopResult { + match arg { NeverLoopResult::AlwaysBreak | NeverLoopResult::Otherwise => NeverLoopResult::Otherwise, NeverLoopResult::MayContinueMainLoop => NeverLoopResult::MayContinueMainLoop, } @@ -92,19 +93,29 @@ fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult) -> NeverLoopResult } fn never_loop_block(block: &Block<'_>, main_loop_id: HirId) -> NeverLoopResult { - let mut iter = block.stmts.iter().filter_map(stmt_to_expr).chain(block.expr); + let mut 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>>(es: &mut T, main_loop_id: HirId) -> NeverLoopResult { - es.map(|e| never_loop_expr(e, main_loop_id)) - .fold(NeverLoopResult::Otherwise, combine_seq) +fn never_loop_expr_seq<'a, T: Iterator, 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))) + }) + .fold(NeverLoopResult::Otherwise, combine_seq) } -fn stmt_to_expr<'tcx>(stmt: &Stmt<'tcx>) -> Option<&'tcx Expr<'tcx>> { +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), - StmtKind::Local(local) => local.init, + StmtKind::Semi(e, ..) | StmtKind::Expr(e, ..) => Some((e, None)), + StmtKind::Local(local) => local.init.map(|init| (init, local.els)), StmtKind::Item(..) => None, } } @@ -139,7 +150,7 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult { | ExprKind::Index(e1, e2) => never_loop_expr_all(&mut [e1, e2].iter().copied(), 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, main_loop_id)) }, ExprKind::If(e, e2, e3) => { let e1 = never_loop_expr(e, main_loop_id); diff --git a/tests/ui/never_loop.rs b/tests/ui/never_loop.rs index 0a21589dd0d40..fc60b4407668a 100644 --- a/tests/ui/never_loop.rs +++ b/tests/ui/never_loop.rs @@ -1,3 +1,4 @@ +#![feature(let_else)] #![allow( clippy::single_match, unused_assignments, @@ -203,6 +204,32 @@ pub fn test17() { }; } +// Issue #9356: `continue` in else branch of let..else +pub fn test18() { + let x = Some(0); + let y = 0; + // might loop + let _ = loop { + let Some(x) = x else { + if y > 0 { + continue; + } else { + return; + } + }; + + break x; + }; + // never loops + let _ = loop { + let Some(x) = x else { + return; + }; + + break x; + }; +} + fn main() { test1(); test2(); diff --git a/tests/ui/never_loop.stderr b/tests/ui/never_loop.stderr index f49b23924efe8..1709e7512eb65 100644 --- a/tests/ui/never_loop.stderr +++ b/tests/ui/never_loop.stderr @@ -1,5 +1,5 @@ error: this loop never actually loops - --> $DIR/never_loop.rs:10:5 + --> $DIR/never_loop.rs:11:5 | LL | / loop { LL | | // clippy::never_loop @@ -13,7 +13,7 @@ LL | | } = note: `#[deny(clippy::never_loop)]` on by default error: this loop never actually loops - --> $DIR/never_loop.rs:32:5 + --> $DIR/never_loop.rs:33:5 | LL | / loop { LL | | // never loops @@ -23,7 +23,7 @@ LL | | } | |_____^ error: this loop never actually loops - --> $DIR/never_loop.rs:52:5 + --> $DIR/never_loop.rs:53:5 | LL | / loop { LL | | // never loops @@ -35,7 +35,7 @@ LL | | } | |_____^ error: this loop never actually loops - --> $DIR/never_loop.rs:54:9 + --> $DIR/never_loop.rs:55:9 | LL | / while i == 0 { LL | | // never loops @@ -44,7 +44,7 @@ LL | | } | |_________^ error: this loop never actually loops - --> $DIR/never_loop.rs:66:9 + --> $DIR/never_loop.rs:67:9 | LL | / loop { LL | | // never loops @@ -56,7 +56,7 @@ LL | | } | |_________^ error: this loop never actually loops - --> $DIR/never_loop.rs:102:5 + --> $DIR/never_loop.rs:103:5 | LL | / while let Some(y) = x { LL | | // never loops @@ -65,7 +65,7 @@ LL | | } | |_____^ error: this loop never actually loops - --> $DIR/never_loop.rs:109:5 + --> $DIR/never_loop.rs:110:5 | LL | / for x in 0..10 { LL | | // never loops @@ -82,7 +82,7 @@ LL | if let Some(x) = (0..10).next() { | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: this loop never actually loops - --> $DIR/never_loop.rs:157:5 + --> $DIR/never_loop.rs:158:5 | LL | / 'outer: while a { LL | | // never loops @@ -94,12 +94,25 @@ LL | | } | |_____^ error: this loop never actually loops - --> $DIR/never_loop.rs:172:9 + --> $DIR/never_loop.rs:173:9 | LL | / while false { LL | | break 'label; LL | | } | |_________^ -error: aborting due to 9 previous errors +error: this loop never actually loops + --> $DIR/never_loop.rs:224:13 + | +LL | let _ = loop { + | _____________^ +LL | | let Some(x) = x else { +LL | | return; +LL | | }; +LL | | +LL | | break x; +LL | | }; + | |_____^ + +error: aborting due to 10 previous errors From e279f22a91ea633d88da154631a494eb09812829 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Tue, 20 Sep 2022 12:14:18 +0200 Subject: [PATCH 029/114] Changelog for Rust 1.64 :apple: --- CHANGELOG.md | 154 +++++++++++++++++- .../src/default_instead_of_iter_empty.rs | 2 +- clippy_lints/src/dereference.rs | 2 +- clippy_lints/src/loops/mod.rs | 2 +- clippy_lints/src/manual_rem_euclid.rs | 2 +- clippy_lints/src/manual_retain.rs | 2 +- 6 files changed, 157 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 044cbff4b78e5..a56be486217e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,11 +6,161 @@ document. ## Unreleased / In Rust Nightly -[d7b5cbf0...master](https://github.com/rust-lang/rust-clippy/compare/d7b5cbf0...master) +[3c7e7dbc...master](https://github.com/rust-lang/rust-clippy/compare/3c7e7dbc...master) + +## Rust 1.64 + +Current stable, released 2022-09-22 + +[d7b5cbf0...3c7e7dbc](https://github.com/rust-lang/rust-clippy/compare/d7b5cbf0...3c7e7dbc) + +### New Lints + +* [`arithmetic_side_effects`] + [#9130](https://github.com/rust-lang/rust-clippy/pull/9130) +* [`invalid_utf8_in_unchecked`] + [#9105](https://github.com/rust-lang/rust-clippy/pull/9105) +* [`assertions_on_result_states`] + [#9225](https://github.com/rust-lang/rust-clippy/pull/9225) +* [`manual_find`] + [#8649](https://github.com/rust-lang/rust-clippy/pull/8649) +* [`manual_retain`] + [#8972](https://github.com/rust-lang/rust-clippy/pull/8972) +* [`default_instead_of_iter_empty`] + [#8989](https://github.com/rust-lang/rust-clippy/pull/8989) +* [`manual_rem_euclid`] + [#9031](https://github.com/rust-lang/rust-clippy/pull/9031) +* [`obfuscated_if_else`] + [#9148](https://github.com/rust-lang/rust-clippy/pull/9148) +* [`std_instead_of_core`] + [#9103](https://github.com/rust-lang/rust-clippy/pull/9103) +* [`std_instead_of_alloc`] + [#9103](https://github.com/rust-lang/rust-clippy/pull/9103) +* [`alloc_instead_of_core`] + [#9103](https://github.com/rust-lang/rust-clippy/pull/9103) +* [`explicit_auto_deref`] + [#8355](https://github.com/rust-lang/rust-clippy/pull/8355) + + +### Moves and Deprecations + +* Moved [`format_push_string`] to `restriction` (now allow-by-default) + [#9161](https://github.com/rust-lang/rust-clippy/pull/9161) + +### Enhancements + +* [`significant_drop_in_scrutinee`]: Now gives more context in the lint message + [#8981](https://github.com/rust-lang/rust-clippy/pull/8981) +* [`single_match`], [`single_match_else`]: Now catches more `Option` cases + [#8985](https://github.com/rust-lang/rust-clippy/pull/8985) +* [`unused_async`]: Now works for async methods + [#9025](https://github.com/rust-lang/rust-clippy/pull/9025) +* [`manual_filter_map`], [`manual_find_map`]: Now lint more expressions + [#8958](https://github.com/rust-lang/rust-clippy/pull/8958) +* [`question_mark`]: Now works for simple `if let` expressions + [#8356](https://github.com/rust-lang/rust-clippy/pull/8356) +* [`undocumented_unsafe_blocks`]: Now finds comments before the start of closures + [#9117](https://github.com/rust-lang/rust-clippy/pull/9117) +* [`trait_duplication_in_bounds`]: Now catches duplicate bounds in where clauses + [#8703](https://github.com/rust-lang/rust-clippy/pull/8703) +* [`shadow_reuse`], [`shadow_same`], [`shadow_unrelated`]: Now lint in const blocks + [#9124](https://github.com/rust-lang/rust-clippy/pull/9124) +* [`slow_vector_initialization`]: Now detects cases with `vec.capacity()` + [#8953](https://github.com/rust-lang/rust-clippy/pull/8953) +* [`unused_self`]: Now respects the `avoid-breaking-exported-api` config option + [#9199](https://github.com/rust-lang/rust-clippy/pull/9199) +* [`box_collection`]: Now supports all std collections + [#9170](https://github.com/rust-lang/rust-clippy/pull/9170) + +### False Positive Fixes + +* [`significant_drop_in_scrutinee`]: Now ignores calls to `IntoIterator::into_iter` + [#9140](https://github.com/rust-lang/rust-clippy/pull/9140) +* [`while_let_loop`]: Now ignores cases when the significant drop order would change + [#8981](https://github.com/rust-lang/rust-clippy/pull/8981) +* [`branches_sharing_code`]: Now ignores cases where moved variables have a significant + drop or variable modifications can affect the conditions + [#9138](https://github.com/rust-lang/rust-clippy/pull/9138) +* [`let_underscore_lock`]: Now ignores bindings that aren't locked + [#8990](https://github.com/rust-lang/rust-clippy/pull/8990) +* [`trivially_copy_pass_by_ref`]: Now tracks lifetimes and ignores cases where unsafe + pointers are used + [#8639](https://github.com/rust-lang/rust-clippy/pull/8639) +* [`let_unit_value`]: No longer ignores `#[allow]` attributes on the value + [#9082](https://github.com/rust-lang/rust-clippy/pull/9082) +* [`declare_interior_mutable_const`]: Now ignores the `thread_local!` macro + [#9015](https://github.com/rust-lang/rust-clippy/pull/9015) +* [`if_same_then_else`]: Now ignores branches with `todo!` and `unimplemented!` + [#9006](https://github.com/rust-lang/rust-clippy/pull/9006) +* [`enum_variant_names`]: Now ignores names with `_` prefixes + [#9032](https://github.com/rust-lang/rust-clippy/pull/9032) +* [`let_unit_value`]: Now ignores cases, where the unit type is manually specified + [#9056](https://github.com/rust-lang/rust-clippy/pull/9056) +* [`match_same_arms`]: Now ignores branches with `todo!` + [#9207](https://github.com/rust-lang/rust-clippy/pull/9207) +* [`assign_op_pattern`]: Ignores cases that break borrowing rules + [#9214](https://github.com/rust-lang/rust-clippy/pull/9214) +* [`extra_unused_lifetimes`]: No longer triggers in derive macros + [#9037](https://github.com/rust-lang/rust-clippy/pull/9037) +* [`mismatching_type_param_order`]: Now ignores complicated generic parameters + [#9146](https://github.com/rust-lang/rust-clippy/pull/9146) +* [`equatable_if_let`]: No longer lints in macros + [#9074](https://github.com/rust-lang/rust-clippy/pull/9074) +* [`new_without_default`]: Now ignores generics and lifetime parameters on `fn new` + [#9115](https://github.com/rust-lang/rust-clippy/pull/9115) +* [`needless_borrow`]: Now ignores cases that result in the execution of different traits + [#9096](https://github.com/rust-lang/rust-clippy/pull/9096) +* [`declare_interior_mutable_const`]: No longer triggers in thread-local initializers + [#9246](https://github.com/rust-lang/rust-clippy/pull/9246) + +### Suggestion Fixes/Improvements + +* [`type_repetition_in_bounds`]: The suggestion now works with maybe bounds + [#9132](https://github.com/rust-lang/rust-clippy/pull/9132) +* [`transmute_ptr_to_ref`]: Now suggests `pointer::cast` when possible + [#8939](https://github.com/rust-lang/rust-clippy/pull/8939) +* [`useless_format`]: Now suggests the correct variable name + [#9237](https://github.com/rust-lang/rust-clippy/pull/9237) +* [`or_fun_call`]: The lint emission will now only span over the `unwrap_or` call + [#9144](https://github.com/rust-lang/rust-clippy/pull/9144) +* [`neg_multiply`]: Now suggests adding parentheses around suggestion if needed + [#9026](https://github.com/rust-lang/rust-clippy/pull/9026) +* [`unnecessary_lazy_evaluations`]: Now suggest for `bool::then_some` for lazy evaluation + [#9099](https://github.com/rust-lang/rust-clippy/pull/9099) +* [`manual_flatten`]: Improved message for long code snippets + [#9156](https://github.com/rust-lang/rust-clippy/pull/9156) +* [`explicit_counter_loop`]: The suggestion is now machine applicable + [#9149](https://github.com/rust-lang/rust-clippy/pull/9149) +* [`needless_borrow`]: Now keeps parentheses around fields, when needed + [#9210](https://github.com/rust-lang/rust-clippy/pull/9210) +* [`while_let_on_iterator`]: The suggestion now works in `FnOnce` closures + [#9134](https://github.com/rust-lang/rust-clippy/pull/9134) + +### ICE Fixes + +* Fix ICEs related to `#![feature(generic_const_exprs)]` usage + [#9241](https://github.com/rust-lang/rust-clippy/pull/9241) +* Fix ICEs related to reference lints + [#9093](https://github.com/rust-lang/rust-clippy/pull/9093) +* [`question_mark`]: Fix ICE on zero field tuple structs + [#9244](https://github.com/rust-lang/rust-clippy/pull/9244) + +### Documentation Improvements + +* [`needless_option_take`]: Now includes a "What it does" and "Why is this bad?" section. + [#9022](https://github.com/rust-lang/rust-clippy/pull/9022) + +### Others + +* Using `--cap-lints=allow` and only `--force-warn`ing some will now work with Clippy's driver + [#9036](https://github.com/rust-lang/rust-clippy/pull/9036) +* Clippy now tries to read the `rust-version` from `Cargo.toml` to identify the + minimum supported rust version + [#8774](https://github.com/rust-lang/rust-clippy/pull/8774) ## Rust 1.63 -Current stable, released 2022-08-11 +Released 2022-08-11 [7c21f91b...d7b5cbf0](https://github.com/rust-lang/rust-clippy/compare/7c21f91b...d7b5cbf0) diff --git a/clippy_lints/src/default_instead_of_iter_empty.rs b/clippy_lints/src/default_instead_of_iter_empty.rs index 3c996d3d2aeee..1ad929864b2a0 100644 --- a/clippy_lints/src/default_instead_of_iter_empty.rs +++ b/clippy_lints/src/default_instead_of_iter_empty.rs @@ -23,7 +23,7 @@ declare_clippy_lint! { /// let _ = std::iter::empty::(); /// let iter: std::iter::Empty = std::iter::empty(); /// ``` - #[clippy::version = "1.63.0"] + #[clippy::version = "1.64.0"] pub DEFAULT_INSTEAD_OF_ITER_EMPTY, style, "check `std::iter::Empty::default()` and replace with `std::iter::empty()`" diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index d1b25a0f1b535..b965d27afce35 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -135,7 +135,7 @@ declare_clippy_lint! { /// let x = String::new(); /// let y: &str = &x; /// ``` - #[clippy::version = "1.60.0"] + #[clippy::version = "1.64.0"] pub EXPLICIT_AUTO_DEREF, complexity, "dereferencing when the compiler would automatically dereference" diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs index 74f3bda9f43ef..c0a0444485e3b 100644 --- a/clippy_lints/src/loops/mod.rs +++ b/clippy_lints/src/loops/mod.rs @@ -635,7 +635,7 @@ declare_clippy_lint! { /// arr.into_iter().find(|&el| el == 1) /// } /// ``` - #[clippy::version = "1.61.0"] + #[clippy::version = "1.64.0"] pub MANUAL_FIND, complexity, "manual implementation of `Iterator::find`" diff --git a/clippy_lints/src/manual_rem_euclid.rs b/clippy_lints/src/manual_rem_euclid.rs index 95cc6bdbd8ba7..6f25a2ed8e434 100644 --- a/clippy_lints/src/manual_rem_euclid.rs +++ b/clippy_lints/src/manual_rem_euclid.rs @@ -27,7 +27,7 @@ declare_clippy_lint! { /// let x: i32 = 24; /// let rem = x.rem_euclid(4); /// ``` - #[clippy::version = "1.63.0"] + #[clippy::version = "1.64.0"] pub MANUAL_REM_EUCLID, complexity, "manually reimplementing `rem_euclid`" diff --git a/clippy_lints/src/manual_retain.rs b/clippy_lints/src/manual_retain.rs index f28c37d3dca7e..8476197bd1201 100644 --- a/clippy_lints/src/manual_retain.rs +++ b/clippy_lints/src/manual_retain.rs @@ -43,7 +43,7 @@ declare_clippy_lint! { /// let mut vec = vec![0, 1, 2]; /// vec.retain(|x| x % 2 == 0); /// ``` - #[clippy::version = "1.63.0"] + #[clippy::version = "1.64.0"] pub MANUAL_RETAIN, perf, "`retain()` is simpler and the same functionalitys" From 4d015293d1cb7ebdd0972e620c3e0f1763ad2ec8 Mon Sep 17 00:00:00 2001 From: David Koloski Date: Wed, 21 Sep 2022 13:02:37 -0400 Subject: [PATCH 030/114] Merge commit '7248d06384c6a90de58c04c1f46be88821278d8b' into sync-from-clippy --- CHANGELOG.md | 1 + CONTRIBUTING.md | 25 +- book/src/development/adding_lints.md | 1 + .../development/common_tools_writing_lints.md | 15 +- clippy_dev/src/new_lint.rs | 1 + .../src/almost_complete_letter_range.rs | 2 + .../src/assertions_on_result_states.rs | 22 +- clippy_lints/src/bool_to_int_with_if.rs | 47 +- clippy_lints/src/booleans.rs | 2 +- clippy_lints/src/dereference.rs | 7 +- clippy_lints/src/derivable_impls.rs | 24 +- clippy_lints/src/format.rs | 2 +- clippy_lints/src/format_args.rs | 2 +- clippy_lints/src/large_stack_arrays.rs | 50 +- clippy_lints/src/lib.register_all.rs | 2 +- clippy_lints/src/lib.register_complexity.rs | 1 + clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/lib.register_suspicious.rs | 1 - clippy_lints/src/lib.rs | 5 +- clippy_lints/src/methods/err_expect.rs | 11 +- clippy_lints/src/methods/iter_kv_map.rs | 87 ++ clippy_lints/src/methods/mod.rs | 36 + clippy_lints/src/methods/ok_expect.rs | 11 +- .../src/methods/unnecessary_to_owned.rs | 8 +- clippy_lints/src/module_style.rs | 6 +- clippy_lints/src/nonstandard_macro_braces.rs | 4 + .../src/operators/arithmetic_side_effects.rs | 51 +- clippy_lints/src/renamed_lints.rs | 1 + clippy_lints/src/unused_peekable.rs | 36 +- clippy_lints/src/use_self.rs | 8 +- clippy_lints/src/utils/conf.rs | 2 +- clippy_lints/src/write.rs | 787 ++++++------------ clippy_utils/src/consts.rs | 8 +- clippy_utils/src/macros.rs | 100 +-- clippy_utils/src/sugg.rs | 48 +- clippy_utils/src/ty.rs | 7 + src/docs.rs | 2 +- src/docs/iter_kv_map.txt | 22 + .../positional_named_format_parameters.txt | 15 - src/docs/print_literal.txt | 4 - src/docs/print_stderr.txt | 8 +- src/docs/print_stdout.txt | 8 +- src/docs/write_literal.txt | 4 - .../module_style/fail_mod_remap/Cargo.toml | 9 + .../module_style/fail_mod_remap/src/bad.rs | 1 + .../fail_mod_remap/src/bad/inner.rs | 1 + .../module_style/fail_mod_remap/src/main.rs | 7 + .../fail_mod_remap/src/main.stderr | 11 + .../conf_nonstandard_macro_braces.rs | 1 + .../conf_nonstandard_macro_braces.stderr | 30 +- tests/ui/almost_complete_letter_range.fixed | 13 + tests/ui/almost_complete_letter_range.rs | 13 + tests/ui/almost_complete_letter_range.stderr | 39 +- tests/ui/arithmetic_side_effects.rs | 104 ++- tests/ui/arithmetic_side_effects.stderr | 92 +- tests/ui/assertions_on_result_states.fixed | 6 + tests/ui/assertions_on_result_states.rs | 6 + tests/ui/assertions_on_result_states.stderr | 8 +- tests/ui/auxiliary/macro_rules.rs | 7 + tests/ui/bool_to_int_with_if.fixed | 8 +- tests/ui/bool_to_int_with_if.rs | 14 + tests/ui/bool_to_int_with_if.stderr | 41 +- tests/ui/collapsible_if.fixed | 3 + tests/ui/collapsible_if.rs | 5 + tests/ui/collapsible_if.stderr | 10 +- tests/ui/crashes/ice-9463.rs | 5 + tests/ui/crashes/ice-9463.stderr | 29 + tests/ui/derivable_impls.fixed | 213 +++++ tests/ui/derivable_impls.rs | 4 + tests/ui/derivable_impls.stderr | 56 +- tests/ui/eprint_with_newline.rs | 10 +- tests/ui/eprint_with_newline.stderr | 18 +- tests/ui/explicit_write.fixed | 2 + tests/ui/explicit_write.rs | 2 + tests/ui/explicit_write.stderr | 8 +- tests/ui/format.fixed | 4 - tests/ui/format.rs | 4 - tests/ui/format.stderr | 44 +- tests/ui/iter_kv_map.fixed | 64 ++ tests/ui/iter_kv_map.rs | 64 ++ tests/ui/iter_kv_map.stderr | 136 +++ tests/ui/large_enum_variant.rs | 4 +- tests/ui/large_enum_variant.stderr | 16 +- tests/ui/large_stack_arrays.rs | 6 + tests/ui/large_stack_arrays.stderr | 8 +- tests/ui/len_without_is_empty.rs | 2 +- tests/ui/nonminimal_bool.rs | 6 + tests/ui/nonminimal_bool.stderr | 8 +- .../positional_named_format_parameters.fixed | 56 -- .../ui/positional_named_format_parameters.rs | 56 -- .../positional_named_format_parameters.stderr | 418 ---------- tests/ui/print_literal.rs | 2 + tests/ui/print_literal.stderr | 56 +- tests/ui/print_with_newline.rs | 10 +- tests/ui/print_with_newline.stderr | 18 +- tests/ui/println_empty_string.stderr | 24 +- tests/ui/rename.fixed | 2 + tests/ui/rename.rs | 2 + tests/ui/rename.stderr | 82 +- tests/ui/unnecessary_to_owned.fixed | 9 + tests/ui/unnecessary_to_owned.rs | 9 + tests/ui/unused_peekable.rs | 33 +- tests/ui/use_self.fixed | 9 + tests/ui/use_self.rs | 9 + tests/ui/write_literal.rs | 2 + tests/ui/write_literal.stderr | 56 +- tests/ui/write_literal_2.rs | 9 +- tests/ui/write_literal_2.stderr | 80 +- tests/ui/write_with_newline.rs | 8 + tests/ui/write_with_newline.stderr | 38 +- tests/ui/writeln_empty_string.stderr | 12 +- 111 files changed, 1997 insertions(+), 1631 deletions(-) create mode 100644 clippy_lints/src/methods/iter_kv_map.rs create mode 100644 src/docs/iter_kv_map.txt delete mode 100644 src/docs/positional_named_format_parameters.txt create mode 100644 tests/ui-cargo/module_style/fail_mod_remap/Cargo.toml create mode 100644 tests/ui-cargo/module_style/fail_mod_remap/src/bad.rs create mode 100644 tests/ui-cargo/module_style/fail_mod_remap/src/bad/inner.rs create mode 100644 tests/ui-cargo/module_style/fail_mod_remap/src/main.rs create mode 100644 tests/ui-cargo/module_style/fail_mod_remap/src/main.stderr create mode 100644 tests/ui/crashes/ice-9463.rs create mode 100644 tests/ui/crashes/ice-9463.stderr create mode 100644 tests/ui/derivable_impls.fixed create mode 100644 tests/ui/iter_kv_map.fixed create mode 100644 tests/ui/iter_kv_map.rs create mode 100644 tests/ui/iter_kv_map.stderr delete mode 100644 tests/ui/positional_named_format_parameters.fixed delete mode 100644 tests/ui/positional_named_format_parameters.rs delete mode 100644 tests/ui/positional_named_format_parameters.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index d847e4c749481..044cbff4b78e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3800,6 +3800,7 @@ Released 2018-09-13 [`items_after_statements`]: https://rust-lang.github.io/rust-clippy/master/index.html#items_after_statements [`iter_cloned_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_cloned_collect [`iter_count`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_count +[`iter_kv_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_kv_map [`iter_next_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_loop [`iter_next_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_slice [`iter_not_returning_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_not_returning_iterator diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 28b4cfd5f0995..6c977b2cacab5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -110,23 +110,28 @@ Just make sure to remove the dependencies again before finally making a pull req [IntelliJ_rust_homepage]: https://intellij-rust.github.io/ ### Rust Analyzer -As of [#6869][6869], [`rust-analyzer`][ra_homepage] can understand that Clippy uses compiler-internals -using `extern crate` when `package.metadata.rust-analyzer.rustc_private` is set to `true` in Clippy's `Cargo.toml.` -You will require a `nightly` toolchain with the `rustc-dev` component installed. -Make sure that in the `rust-analyzer` configuration, you set +For [`rust-analyzer`][ra_homepage] to work correctly make sure that in the `rust-analyzer` configuration you set + ```json { "rust-analyzer.rustc.source": "discover" } ``` -and -```json -{ "rust-analyzer.updates.channel": "nightly" } -``` + You should be able to see information on things like `Expr` or `EarlyContext` now if you hover them, also a lot more type hints. -This will work with `rust-analyzer 2021-03-15` shipped in nightly `1.52.0-nightly (107896c32 2021-03-15)` or later. + +To have `rust-analyzer` also work in the `clippy_dev` and `lintcheck` crates, add the following configuration + +```json +{ + "rust-analyzer.linkedProjects": [ + "./Cargo.toml", + "clippy_dev/Cargo.toml", + "lintcheck/Cargo.toml", + ] +} +``` [ra_homepage]: https://rust-analyzer.github.io/ -[6869]: https://github.com/rust-lang/rust-clippy/pull/6869 ## How Clippy works diff --git a/book/src/development/adding_lints.md b/book/src/development/adding_lints.md index da781eb970df7..b1e843bc7f4c8 100644 --- a/book/src/development/adding_lints.md +++ b/book/src/development/adding_lints.md @@ -90,6 +90,7 @@ We start by opening the test file created at `tests/ui/foo_functions.rs`. Update the file with some examples to get started: ```rust +#![allow(unused)] #![warn(clippy::foo_functions)] // Impl methods diff --git a/book/src/development/common_tools_writing_lints.md b/book/src/development/common_tools_writing_lints.md index 2bc275ceff0be..f5aa06e4bf653 100644 --- a/book/src/development/common_tools_writing_lints.md +++ b/book/src/development/common_tools_writing_lints.md @@ -123,7 +123,8 @@ There are three ways to do this, depending on if the target trait has a diagnostic item, lang item or neither. ```rust -use clippy_utils::{implements_trait, is_trait_method, match_trait_method, paths}; +use clippy_utils::ty::implements_trait; +use clippy_utils::is_trait_method; use rustc_span::symbol::sym; impl LateLintPass<'_> for MyStructLint { @@ -143,13 +144,6 @@ impl LateLintPass<'_> for MyStructLint { .map_or(false, |id| implements_trait(cx, ty, id, &[])) { // `expr` implements `Drop` trait } - - // 3. Using the type path with the expression - // we use `match_trait_method` function from Clippy's utils - // (This method should be avoided if possible) - if match_trait_method(cx, expr, &paths::INTO) { - // `expr` implements `Into` trait - } } } ``` @@ -233,8 +227,9 @@ functions to deal with macros: crates ```rust - #[macro_use] - extern crate a_crate_with_macros; + use rustc_middle::lint::in_external_macro; + + use a_crate_with_macros::foo; // `foo` is defined in `a_crate_with_macros` foo!("bar"); diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index 331b76484b8a5..02cb13a1d8afe 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -188,6 +188,7 @@ pub(crate) fn get_stabilization_version() -> String { fn get_test_file_contents(lint_name: &str, header_commands: Option<&str>) -> String { let mut contents = format!( indoc! {" + #![allow(unused)] #![warn(clippy::{})] fn main() {{ diff --git a/clippy_lints/src/almost_complete_letter_range.rs b/clippy_lints/src/almost_complete_letter_range.rs index 59a7c53540069..073e4af1318e3 100644 --- a/clippy_lints/src/almost_complete_letter_range.rs +++ b/clippy_lints/src/almost_complete_letter_range.rs @@ -4,6 +4,7 @@ use clippy_utils::{meets_msrv, msrvs}; use rustc_ast::ast::{Expr, ExprKind, LitKind, Pat, PatKind, RangeEnd, RangeLimits}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::Span; @@ -79,6 +80,7 @@ fn check_range(cx: &EarlyContext<'_>, span: Span, start: &Expr, end: &Expr, sugg (LitKind::Byte(b'a') | LitKind::Char('a'), LitKind::Byte(b'z') | LitKind::Char('z')) | (LitKind::Byte(b'A') | LitKind::Char('A'), LitKind::Byte(b'Z') | LitKind::Char('Z')) ) + && !in_external_macro(cx.sess(), span) { span_lint_and_then( cx, diff --git a/clippy_lints/src/assertions_on_result_states.rs b/clippy_lints/src/assertions_on_result_states.rs index 7cd198ace86c0..656dc5feeb570 100644 --- a/clippy_lints/src/assertions_on_result_states.rs +++ b/clippy_lints/src/assertions_on_result_states.rs @@ -1,9 +1,9 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::macros::{find_assert_args, root_macro_call_first_node, PanicExpn}; -use clippy_utils::path_res; use clippy_utils::source::snippet_with_context; -use clippy_utils::ty::{implements_trait, is_copy, is_type_diagnostic_item}; +use clippy_utils::ty::{has_debug_impl, is_copy, is_type_diagnostic_item}; use clippy_utils::usage::local_used_after_expr; +use clippy_utils::{is_expr_final_block_expr, path_res}; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::{Expr, ExprKind}; @@ -58,6 +58,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates { return; } } + let semicolon = if is_expr_final_block_expr(cx.tcx, e) {";"} else {""}; let mut app = Applicability::MachineApplicable; match method_segment.ident.as_str() { "is_ok" if type_suitable_to_unwrap(cx, substs.type_at(1)) => { @@ -68,8 +69,9 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates { "called `assert!` with `Result::is_ok`", "replace with", format!( - "{}.unwrap()", - snippet_with_context(cx, recv.span, condition.span.ctxt(), "..", &mut app).0 + "{}.unwrap(){}", + snippet_with_context(cx, recv.span, condition.span.ctxt(), "..", &mut app).0, + semicolon ), app, ); @@ -82,8 +84,9 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates { "called `assert!` with `Result::is_err`", "replace with", format!( - "{}.unwrap_err()", - snippet_with_context(cx, recv.span, condition.span.ctxt(), "..", &mut app).0 + "{}.unwrap_err(){}", + snippet_with_context(cx, recv.span, condition.span.ctxt(), "..", &mut app).0, + semicolon ), app, ); @@ -94,13 +97,6 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates { } } -/// This checks whether a given type is known to implement Debug. -fn has_debug_impl<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { - cx.tcx - .get_diagnostic_item(sym::Debug) - .map_or(false, |debug| implements_trait(cx, ty, debug, &[])) -} - fn type_suitable_to_unwrap<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { has_debug_impl(cx, ty) && !ty.is_unit() && !ty.is_never() } diff --git a/clippy_lints/src/bool_to_int_with_if.rs b/clippy_lints/src/bool_to_int_with_if.rs index a4b8cbb0d82aa..51e98cda84519 100644 --- a/clippy_lints/src/bool_to_int_with_if.rs +++ b/clippy_lints/src/bool_to_int_with_if.rs @@ -1,9 +1,9 @@ -use rustc_ast::{ExprPrecedence, LitKind}; +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, source::snippet_block_with_applicability}; +use clippy_utils::{diagnostics::span_lint_and_then, is_else_clause, sugg::Sugg}; use rustc_errors::Applicability; declare_clippy_lint! { @@ -55,27 +55,42 @@ fn check_if_else<'tcx>(ctx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx if let ExprKind::If(check, then, Some(else_)) = expr.kind && let Some(then_lit) = int_literal(then) && let Some(else_lit) = int_literal(else_) - && check_int_literal_equals_val(then_lit, 1) - && check_int_literal_equals_val(else_lit, 0) { + let inverted = if + check_int_literal_equals_val(then_lit, 1) + && check_int_literal_equals_val(else_lit, 0) { + false + } else if + check_int_literal_equals_val(then_lit, 0) + && check_int_literal_equals_val(else_lit, 1) { + true + } else { + // Expression isn't boolean, exit + return; + }; let mut applicability = Applicability::MachineApplicable; - let snippet = snippet_block_with_applicability(ctx, check.span, "..", None, &mut applicability); - let snippet_with_braces = { - let need_parens = should_have_parentheses(check); - let (left_paren, right_paren) = if need_parens {("(", ")")} else {("", "")}; - format!("{left_paren}{snippet}{right_paren}") + let snippet = { + let mut sugg = Sugg::hir_with_applicability(ctx, check, "..", &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 suggestion = { let wrap_in_curly = is_else_clause(ctx.tcx, expr); - let (left_curly, right_curly) = if wrap_in_curly {("{", "}")} else {("", "")}; - format!( - "{left_curly}{ty}::from({snippet}){right_curly}" - ) + let mut s = Sugg::NonParen(format!("{ty}::from({snippet})").into()); + if wrap_in_curly { + s = s.blockify(); + } + s }; // when used in else clause if statement should be wrapped in curly braces + let into_snippet = snippet.clone().maybe_par(); + let as_snippet = snippet.as_ty(ty); + span_lint_and_then(ctx, BOOL_TO_INT_WITH_IF, expr.span, @@ -87,7 +102,7 @@ fn check_if_else<'tcx>(ctx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx suggestion, applicability, ); - diag.note(format!("`{snippet_with_braces} as {ty}` or `{snippet_with_braces}.into()` can also be valid options")); + diag.note(format!("`{as_snippet}` or `{into_snippet}.into()` can also be valid options")); }); }; } @@ -119,7 +134,3 @@ fn check_int_literal_equals_val<'tcx>(expr: &'tcx rustc_hir::Expr<'tcx>, expecte false } } - -fn should_have_parentheses<'tcx>(check: &'tcx rustc_hir::Expr<'tcx>) -> bool { - check.precedence().order() < ExprPrecedence::Cast.order() -} diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 656d639f0efd9..03d262d5a59c6 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -237,7 +237,7 @@ impl<'a, 'tcx, 'v> SuggestContext<'a, 'tcx, 'v> { } }, &Term(n) => { - let snip = snippet_opt(self.cx, self.terminals[n as usize].span)?; + let snip = snippet_opt(self.cx, self.terminals[n as usize].span.source_callsite())?; self.output.push_str(&snip); }, } diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 45b5d79d44522..501f9ef78aebe 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -297,13 +297,10 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { if !is_lint_allowed(cx, EXPLICIT_DEREF_METHODS, expr.hir_id) && position.lint_explicit_deref() => { + let ty_changed_count = usize::from(!deref_method_same_type(expr_ty, typeck.expr_ty(sub_expr))); self.state = Some(( State::DerefMethod { - ty_changed_count: if deref_method_same_type(expr_ty, typeck.expr_ty(sub_expr)) { - 0 - } else { - 1 - }, + ty_changed_count, is_final_ufcs: matches!(expr.kind, ExprKind::Call(..)), target_mut, }, diff --git a/clippy_lints/src/derivable_impls.rs b/clippy_lints/src/derivable_impls.rs index ef9eeecc6a934..06ae5abeaeb9b 100644 --- a/clippy_lints/src/derivable_impls.rs +++ b/clippy_lints/src/derivable_impls.rs @@ -1,5 +1,6 @@ -use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::{is_default_equivalent, peel_blocks}; +use rustc_errors::Applicability; use rustc_hir::{ def::{DefKind, Res}, Body, Expr, ExprKind, GenericArg, Impl, ImplItemKind, Item, ItemKind, Node, PathSegment, QPath, TyKind, @@ -100,15 +101,28 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls { ExprKind::Struct(_, fields, _) => fields.iter().all(|ef| is_default_equivalent(cx, ef.expr)), _ => false, }; + if should_emit { - let path_string = cx.tcx.def_path_str(adt_def.did()); - span_lint_and_help( + let struct_span = cx.tcx.def_span(adt_def.did()); + span_lint_and_then( cx, DERIVABLE_IMPLS, item.span, "this `impl` can be derived", - None, - &format!("try annotating `{}` with `#[derive(Default)]`", path_string), + |diag| { + diag.span_suggestion_hidden( + item.span, + "remove the manual implementation...", + String::new(), + Applicability::MachineApplicable + ); + diag.span_suggestion( + struct_span.shrink_to_lo(), + "...and instead derive it", + "#[derive(Default)]\n".to_string(), + Applicability::MachineApplicable + ); + } ); } } diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index 0c5851cdbed2a..f10d825695360 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -71,12 +71,12 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat { let value = arg.param.value; if_chain! { if format_args.format_string.parts == [kw::Empty]; + if arg.format.is_default(); if match cx.typeck_results().expr_ty(value).peel_refs().kind() { ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(sym::String, adt.did()), ty::Str => true, _ => false, }; - if !arg.format.has_string_formatting(); then { let is_new_string = match value.kind { ExprKind::Binary(..) => true, diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index 2a55c48cf7731..9e1eaf248b73c 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -77,7 +77,7 @@ impl<'tcx> LateLintPass<'tcx> for FormatArgs { if let ExpnKind::Macro(_, name) = outermost_expn_data.kind; then { for arg in &format_args.args { - if arg.format.has_string_formatting() { + if !arg.format.is_default() { continue; } if is_aliased(&format_args, arg.param.value.hir_id) { diff --git a/clippy_lints/src/large_stack_arrays.rs b/clippy_lints/src/large_stack_arrays.rs index 0acbd81aec343..5857d81ab1f20 100644 --- a/clippy_lints/src/large_stack_arrays.rs +++ b/clippy_lints/src/large_stack_arrays.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::snippet; -use if_chain::if_chain; -use rustc_hir::{Expr, ExprKind}; +use rustc_hir::{Expr, ExprKind, Item, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, ConstKind}; @@ -39,29 +38,28 @@ impl_lint_pass!(LargeStackArrays => [LARGE_STACK_ARRAYS]); impl<'tcx> LateLintPass<'tcx> for LargeStackArrays { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { - if_chain! { - if let ExprKind::Repeat(_, _) = expr.kind; - if let ty::Array(element_type, cst) = cx.typeck_results().expr_ty(expr).kind(); - if let ConstKind::Value(ty::ValTree::Leaf(element_count)) = cst.kind(); - if let Ok(element_count) = element_count.try_to_machine_usize(cx.tcx); - if let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes()); - if self.maximum_allowed_size < element_count * element_size; - then { - span_lint_and_help( - cx, - LARGE_STACK_ARRAYS, - expr.span, - &format!( - "allocating a local array larger than {} bytes", - self.maximum_allowed_size - ), - None, - &format!( - "consider allocating on the heap with `vec!{}.into_boxed_slice()`", - snippet(cx, expr.span, "[...]") - ), - ); - } - } + if let ExprKind::Repeat(_, _) = expr.kind + && let ty::Array(element_type, cst) = cx.typeck_results().expr_ty(expr).kind() + && let ConstKind::Value(ty::ValTree::Leaf(element_count)) = cst.kind() + && let Ok(element_count) = element_count.try_to_machine_usize(cx.tcx) + && let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes()) + && !cx.tcx.hir().parent_iter(expr.hir_id) + .any(|(_, node)| matches!(node, Node::Item(Item { kind: ItemKind::Static(..), .. }))) + && self.maximum_allowed_size < element_count * element_size { + span_lint_and_help( + cx, + LARGE_STACK_ARRAYS, + expr.span, + &format!( + "allocating a local array larger than {} bytes", + self.maximum_allowed_size + ), + None, + &format!( + "consider allocating on the heap with `vec!{}.into_boxed_slice()`", + snippet(cx, expr.span, "[...]") + ), + ); + } } } diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index 59d1760fe6064..8718d5fa1da0b 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -171,6 +171,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ 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), @@ -351,7 +352,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(useless_conversion::USELESS_CONVERSION), LintId::of(vec::USELESS_VEC), LintId::of(vec_init_then_push::VEC_INIT_THEN_PUSH), - LintId::of(write::POSITIONAL_NAMED_FORMAT_PARAMETERS), LintId::of(write::PRINTLN_EMPTY_STRING), LintId::of(write::PRINT_LITERAL), LintId::of(write::PRINT_WITH_NEWLINE), diff --git a/clippy_lints/src/lib.register_complexity.rs b/clippy_lints/src/lib.register_complexity.rs index aa247352f88fb..185189a6af5b6 100644 --- a/clippy_lints/src/lib.register_complexity.rs +++ b/clippy_lints/src/lib.register_complexity.rs @@ -40,6 +40,7 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec! 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), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 962e67220069a..02fcc8de50727 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -313,6 +313,7 @@ store.register_lints(&[ 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, @@ -595,7 +596,6 @@ store.register_lints(&[ vec_init_then_push::VEC_INIT_THEN_PUSH, wildcard_imports::ENUM_GLOB_USE, wildcard_imports::WILDCARD_IMPORTS, - write::POSITIONAL_NAMED_FORMAT_PARAMETERS, write::PRINTLN_EMPTY_STRING, write::PRINT_LITERAL, write::PRINT_STDERR, diff --git a/clippy_lints/src/lib.register_suspicious.rs b/clippy_lints/src/lib.register_suspicious.rs index bede91f183e79..6125d0f7a8628 100644 --- a/clippy_lints/src/lib.register_suspicious.rs +++ b/clippy_lints/src/lib.register_suspicious.rs @@ -35,5 +35,4 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec! 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), - LintId::of(write::POSITIONAL_NAMED_FORMAT_PARAMETERS), ]) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index ceaaf5c6d6ed6..298566cb5b625 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -40,7 +40,6 @@ extern crate rustc_lint; extern crate rustc_middle; extern crate rustc_mir_dataflow; extern crate rustc_parse; -extern crate rustc_parse_format; extern crate rustc_session; extern crate rustc_span; extern crate rustc_target; @@ -425,7 +424,6 @@ pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore, sess: &Se }) }); - store.register_pre_expansion_pass(|| Box::new(write::Write::default())); store.register_pre_expansion_pass(move || Box::new(attrs::EarlyAttributes { msrv })); } @@ -524,7 +522,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: #[cfg(feature = "internal")] { if std::env::var("ENABLE_METADATA_COLLECTION").eq(&Ok("1".to_string())) { - store.register_late_pass(|| Box::new(utils::internal_lints::metadata_collector::MetadataCollector::new())); + store.register_late_pass(|_| Box::new(utils::internal_lints::metadata_collector::MetadataCollector::new())); return; } } @@ -879,6 +877,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: ignore_publish: cargo_ignore_publish, }) }); + store.register_late_pass(|_| Box::new(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)); diff --git a/clippy_lints/src/methods/err_expect.rs b/clippy_lints/src/methods/err_expect.rs index 570a1b87358dd..720d9a68c85ee 100644 --- a/clippy_lints/src/methods/err_expect.rs +++ b/clippy_lints/src/methods/err_expect.rs @@ -1,6 +1,6 @@ use super::ERR_EXPECT; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::ty::implements_trait; +use clippy_utils::ty::has_debug_impl; use clippy_utils::{meets_msrv, msrvs, ty::is_type_diagnostic_item}; use rustc_errors::Applicability; use rustc_lint::LateContext; @@ -28,7 +28,7 @@ pub(super) fn check( // Tests if the T type in a `Result` is not None if let Some(data_type) = get_data_type(cx, result_type); // Tests if the T type in a `Result` implements debug - if has_debug_impl(data_type, cx); + if has_debug_impl(cx, data_type); then { span_lint_and_sugg( @@ -51,10 +51,3 @@ fn get_data_type<'a>(cx: &LateContext<'_>, ty: Ty<'a>) -> Option> { _ => None, } } - -/// Given a type, very if the Debug trait has been impl'd -fn has_debug_impl<'tcx>(ty: Ty<'tcx>, cx: &LateContext<'tcx>) -> bool { - cx.tcx - .get_diagnostic_item(sym::Debug) - .map_or(false, |debug| implements_trait(cx, ty, debug, &[])) -} diff --git a/clippy_lints/src/methods/iter_kv_map.rs b/clippy_lints/src/methods/iter_kv_map.rs new file mode 100644 index 0000000000000..a7eecabd68495 --- /dev/null +++ b/clippy_lints/src/methods/iter_kv_map.rs @@ -0,0 +1,87 @@ +#![allow(unused_imports)] + +use super::ITER_KV_MAP; +use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::source::{snippet, snippet_with_applicability}; +use clippy_utils::sugg; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::visitors::is_local_used; +use rustc_hir::{BindingAnnotation, Body, BorrowKind, Expr, ExprKind, Mutability, Pat, PatKind}; +use rustc_lint::{LateContext, LintContext}; +use rustc_middle::ty; +use rustc_span::sym; +use rustc_span::Span; + +/// lint use of: +/// - `hashmap.iter().map(|(_, v)| v)` +/// - `hashmap.into_iter().map(|(_, v)| v)` +/// on `HashMaps` and `BTreeMaps` in std + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + map_type: &'tcx str, // iter / into_iter + expr: &'tcx Expr<'tcx>, // .iter().map(|(_, v_| v)) + recv: &'tcx Expr<'tcx>, // hashmap + m_arg: &'tcx Expr<'tcx>, // |(_, v)| v +) { + if_chain! { + if !expr.span.from_expansion(); + if let ExprKind::Closure(c) = m_arg.kind; + if let Body {params: [p], value: body_expr, generator_kind: _ } = cx.tcx.hir().body(c.body); + if let PatKind::Tuple([key_pat, val_pat], _) = p.pat.kind; + + let (replacement_kind, binded_ident) = match (&key_pat.kind, &val_pat.kind) { + (key, PatKind::Binding(_, _, value, _)) if pat_is_wild(cx, key, m_arg) => ("value", value), + (PatKind::Binding(_, _, key, _), value) if pat_is_wild(cx, value, m_arg) => ("key", key), + _ => return, + }; + + let ty = cx.typeck_results().expr_ty(recv); + if is_type_diagnostic_item(cx, ty, sym::HashMap) || is_type_diagnostic_item(cx, ty, sym::BTreeMap); + + then { + let mut applicability = rustc_errors::Applicability::MachineApplicable; + let recv_snippet = snippet_with_applicability(cx, recv.span, "map", &mut applicability); + let into_prefix = if map_type == "into_iter" {"into_"} else {""}; + + if_chain! { + if let ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) = body_expr.kind; + if let [local_ident] = path.segments; + if local_ident.ident.as_str() == binded_ident.as_str(); + + then { + span_lint_and_sugg( + cx, + ITER_KV_MAP, + expr.span, + &format!("iterating on a map's {}s", replacement_kind), + "try", + format!("{}.{}{}s()", recv_snippet, into_prefix, replacement_kind), + applicability, + ); + } else { + span_lint_and_sugg( + cx, + ITER_KV_MAP, + expr.span, + &format!("iterating on a map's {}s", replacement_kind), + "try", + format!("{}.{}{}s().map(|{}| {})", recv_snippet, into_prefix, replacement_kind, binded_ident, + snippet_with_applicability(cx, body_expr.span, "/* body */", &mut applicability)), + applicability, + ); + } + } + } + } +} + +/// Returns `true` if the pattern is a `PatWild`, or is an ident prefixed with `_` +/// that is not locally used. +fn pat_is_wild<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx PatKind<'_>, body: &'tcx Expr<'_>) -> bool { + match *pat { + PatKind::Wild => true, + PatKind::Binding(_, id, ident, None) if ident.as_str().starts_with('_') => !is_local_used(cx, body, id), + _ => false, + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 41942b20ea163..cdde4c54d6378 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -35,6 +35,7 @@ mod into_iter_on_ref; mod is_digit_ascii_radix; mod iter_cloned_collect; mod iter_count; +mod iter_kv_map; mod iter_next_slice; mod iter_nth; mod iter_nth_zero; @@ -3036,6 +3037,37 @@ declare_clippy_lint! { "use of `File::read_to_end` or `File::read_to_string`" } +declare_clippy_lint! { + /// ### What it does + /// + /// Checks for iterating a map (`HashMap` or `BTreeMap`) and + /// ignoring either the keys or values. + /// + /// ### Why is this bad? + /// + /// Readability. There are `keys` and `values` methods that + /// can be used to express that we only need the keys or the values. + /// + /// ### Example + /// + /// ``` + /// # use std::collections::HashMap; + /// let map: HashMap = HashMap::new(); + /// let values = map.iter().map(|(_, value)| value).collect::>(); + /// ``` + /// + /// Use instead: + /// ``` + /// # use std::collections::HashMap; + /// let map: HashMap = HashMap::new(); + /// let values = map.values().collect::>(); + /// ``` + #[clippy::version = "1.65.0"] + pub ITER_KV_MAP, + complexity, + "iterating on map using `iter` when `keys` or `values` would do" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -3159,6 +3191,7 @@ impl_lint_pass!(Methods => [ UNNECESSARY_SORT_BY, VEC_RESIZE_TO_ZERO, VERBOSE_FILE_READS, + ITER_KV_MAP, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -3498,6 +3531,9 @@ 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) { + iter_kv_map::check(cx, map_name, expr, recv2, m_arg); + } } else { map_err_ignore::check(cx, expr, m_arg); } diff --git a/clippy_lints/src/methods/ok_expect.rs b/clippy_lints/src/methods/ok_expect.rs index d64a9f320d90e..646fc4a7bcf37 100644 --- a/clippy_lints/src/methods/ok_expect.rs +++ b/clippy_lints/src/methods/ok_expect.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; +use clippy_utils::ty::{has_debug_impl, is_type_diagnostic_item}; use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::LateContext; @@ -15,7 +15,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result); let result_type = cx.typeck_results().expr_ty(recv); if let Some(error_type) = get_error_type(cx, result_type); - if has_debug_impl(error_type, cx); + if has_debug_impl(cx, error_type); then { span_lint_and_help( @@ -37,10 +37,3 @@ fn get_error_type<'a>(cx: &LateContext<'_>, ty: Ty<'a>) -> Option> { _ => None, } } - -/// This checks whether a given type is known to implement Debug. -fn has_debug_impl<'tcx>(ty: Ty<'tcx>, cx: &LateContext<'tcx>) -> bool { - cx.tcx - .get_diagnostic_item(sym::Debug) - .map_or(false, |debug| implements_trait(cx, ty, debug, &[])) -} diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index 8d3cede70f70d..79d784c342cac 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -7,7 +7,7 @@ use clippy_utils::visitors::find_all_ret_expressions; use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, return_ty}; use clippy_utils::{meets_msrv, msrvs}; use rustc_errors::Applicability; -use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind, ItemKind, Node}; +use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind, ItemKind, LangItem, Node}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; use rustc_middle::mir::Mutability; @@ -268,7 +268,7 @@ fn check_other_call_arg<'tcx>( // We can't add an `&` when the trait is `Deref` because `Target = &T` won't match // `Target = T`. if n_refs > 0 || is_copy(cx, receiver_ty) || trait_predicate.def_id() != deref_trait_id; - let n_refs = max(n_refs, if is_copy(cx, receiver_ty) { 0 } else { 1 }); + let n_refs = max(n_refs, usize::from(!is_copy(cx, receiver_ty))); if let Some(receiver_snippet) = snippet_opt(cx, receiver.span); then { span_lint_and_sugg( @@ -379,6 +379,10 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< Node::Expr(parent_expr) => { if let Some((callee_def_id, call_substs, recv, call_args)) = get_callee_substs_and_args(cx, parent_expr) { + if cx.tcx.lang_items().require(LangItem::IntoFutureIntoFuture) == Ok(callee_def_id) { + return false; + } + let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder(); if let Some(arg_index) = recv.into_iter().chain(call_args).position(|arg| arg.hir_id == expr.hir_id) && let Some(param_ty) = fn_sig.inputs().get(arg_index) diff --git a/clippy_lints/src/module_style.rs b/clippy_lints/src/module_style.rs index 0a393657267b0..22071ab3044f4 100644 --- a/clippy_lints/src/module_style.rs +++ b/clippy_lints/src/module_style.rs @@ -2,7 +2,7 @@ use rustc_ast::ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_lint::{EarlyContext, EarlyLintPass, Level, LintContext}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::{FileName, RealFileName, SourceFile, Span, SyntaxContext}; +use rustc_span::{FileName, SourceFile, Span, SyntaxContext}; use std::ffi::OsStr; use std::path::{Component, Path}; @@ -79,7 +79,7 @@ impl EarlyLintPass for ModStyle { let files = cx.sess().source_map().files(); - let RealFileName::LocalPath(trim_to_src) = &cx.sess().opts.working_dir else { return }; + let Some(trim_to_src) = cx.sess().opts.working_dir.local_path() else { return }; // `folder_segments` is all unique folder path segments `path/to/foo.rs` gives // `[path, to]` but not foo @@ -90,7 +90,7 @@ impl EarlyLintPass for ModStyle { // `{ foo => path/to/foo.rs, .. } let mut file_map = FxHashMap::default(); for file in files.iter() { - if let FileName::Real(RealFileName::LocalPath(lp)) = &file.name { + if let FileName::Real(name) = &file.name && let Some(lp) = name.local_path() { let path = if lp.is_relative() { lp } else if let Ok(relative) = lp.strip_prefix(trim_to_src) { diff --git a/clippy_lints/src/nonstandard_macro_braces.rs b/clippy_lints/src/nonstandard_macro_braces.rs index 4722c031006be..f86dfb6b8df84 100644 --- a/clippy_lints/src/nonstandard_macro_braces.rs +++ b/clippy_lints/src/nonstandard_macro_braces.rs @@ -184,6 +184,10 @@ fn macro_braces(conf: FxHashSet) -> FxHashMap>(); diff --git a/clippy_lints/src/operators/arithmetic_side_effects.rs b/clippy_lints/src/operators/arithmetic_side_effects.rs index 83b69fbb31164..d24c57c0a4b8a 100644 --- a/clippy_lints/src/operators/arithmetic_side_effects.rs +++ b/clippy_lints/src/operators/arithmetic_side_effects.rs @@ -42,27 +42,30 @@ impl ArithmeticSideEffects { } } - /// Checks assign operators (+=, -=, *=, /=) of integers in a non-constant environment that - /// won't overflow. - fn has_valid_assign_op(op: &Spanned, rhs: &hir::Expr<'_>, rhs_refs: Ty<'_>) -> bool { - if !Self::is_literal_integer(rhs, rhs_refs) { - return false; + /// Assuming that `expr` is a literal integer, checks operators (+=, -=, *, /) in a + /// non-constant environment that won't overflow. + fn has_valid_op(op: &Spanned, expr: &hir::Expr<'_>) -> bool { + if let hir::BinOpKind::Add | hir::BinOpKind::Sub = op.node + && let hir::ExprKind::Lit(ref lit) = expr.kind + && let ast::LitKind::Int(0, _) = lit.node + { + return true; + } + if let hir::BinOpKind::Div | hir::BinOpKind::Rem = op.node + && let hir::ExprKind::Lit(ref lit) = expr.kind + && !matches!(lit.node, ast::LitKind::Int(0, _)) + { + return true; } - if let hir::BinOpKind::Div | hir::BinOpKind::Mul = op.node - && let hir::ExprKind::Lit(ref lit) = rhs.kind - && let ast::LitKind::Int(1, _) = lit.node + if let hir::BinOpKind::Mul = op.node + && let hir::ExprKind::Lit(ref lit) = expr.kind + && let ast::LitKind::Int(0 | 1, _) = lit.node { return true; } false } - /// Checks "raw" binary operators (+, -, *, /) of integers in a non-constant environment - /// already handled by the CTFE. - fn has_valid_bin_op(lhs: &hir::Expr<'_>, lhs_refs: Ty<'_>, rhs: &hir::Expr<'_>, rhs_refs: Ty<'_>) -> bool { - Self::is_literal_integer(lhs, lhs_refs) && Self::is_literal_integer(rhs, rhs_refs) - } - /// Checks if the given `expr` has any of the inner `allowed` elements. fn is_allowed_ty(&self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { self.allowed.contains( @@ -83,7 +86,8 @@ impl ArithmeticSideEffects { } fn issue_lint(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) { - span_lint(cx, ARITHMETIC_SIDE_EFFECTS, expr.span, "arithmetic detected"); + let msg = "arithmetic operation that can potentially result in unexpected side-effects"; + span_lint(cx, ARITHMETIC_SIDE_EFFECTS, expr.span, msg); self.expr_span = Some(expr.span); } @@ -115,13 +119,18 @@ impl ArithmeticSideEffects { if self.is_allowed_ty(cx, lhs) || self.is_allowed_ty(cx, rhs) { return; } - let lhs_refs = cx.typeck_results().expr_ty(lhs).peel_refs(); - let rhs_refs = cx.typeck_results().expr_ty(rhs).peel_refs(); - let has_valid_assign_op = Self::has_valid_assign_op(op, rhs, rhs_refs); - if has_valid_assign_op || Self::has_valid_bin_op(lhs, lhs_refs, rhs, rhs_refs) { - return; + let has_valid_op = match ( + Self::is_literal_integer(lhs, cx.typeck_results().expr_ty(lhs).peel_refs()), + Self::is_literal_integer(rhs, cx.typeck_results().expr_ty(rhs).peel_refs()), + ) { + (true, true) => true, + (true, false) => Self::has_valid_op(op, lhs), + (false, true) => Self::has_valid_op(op, rhs), + (false, false) => false, + }; + if !has_valid_op { + self.issue_lint(cx, expr); } - self.issue_lint(cx, expr); } } diff --git a/clippy_lints/src/renamed_lints.rs b/clippy_lints/src/renamed_lints.rs index 6bea6dc0773d5..d320eea1c377d 100644 --- a/clippy_lints/src/renamed_lints.rs +++ b/clippy_lints/src/renamed_lints.rs @@ -36,6 +36,7 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[ ("clippy::invalid_ref", "invalid_value"), ("clippy::mem_discriminant_non_enum", "enum_intrinsics_non_enums"), ("clippy::panic_params", "non_fmt_panics"), + ("clippy::positional_named_format_parameters", "named_arguments_used_positionally"), ("clippy::temporary_cstring_as_ptr", "temporary_cstring_as_ptr"), ("clippy::unknown_clippy_lints", "unknown_lints"), ("clippy::unused_label", "unused_labels"), diff --git a/clippy_lints/src/unused_peekable.rs b/clippy_lints/src/unused_peekable.rs index cc86564359459..f1cebf0f9923d 100644 --- a/clippy_lints/src/unused_peekable.rs +++ b/clippy_lints/src/unused_peekable.rs @@ -6,6 +6,7 @@ use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::lang_items::LangItem; use rustc_hir::{Block, Expr, ExprKind, HirId, Local, Node, PatKind, PathSegment, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; @@ -109,8 +110,14 @@ impl<'a, 'tcx> PeekableVisitor<'a, 'tcx> { } } -impl<'tcx> Visitor<'_> for PeekableVisitor<'_, 'tcx> { - fn visit_expr(&mut self, ex: &'_ Expr<'_>) { +impl<'tcx> Visitor<'tcx> for PeekableVisitor<'_, 'tcx> { + type NestedFilter = OnlyBodies; + + fn nested_visit_map(&mut self) -> Self::Map { + self.cx.tcx.hir() + } + + fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) { if self.found_peek_call { return; } @@ -136,12 +143,11 @@ impl<'tcx> Visitor<'_> for PeekableVisitor<'_, 'tcx> { return; } - if args.iter().any(|arg| { - matches!(arg.kind, ExprKind::Path(_)) && arg_is_mut_peekable(self.cx, arg) - }) { + if args.iter().any(|arg| arg_is_mut_peekable(self.cx, arg)) { self.found_peek_call = true; - return; } + + return; }, // Catch anything taking a Peekable mutably ExprKind::MethodCall( @@ -190,21 +196,21 @@ impl<'tcx> Visitor<'_> for PeekableVisitor<'_, 'tcx> { Node::Local(Local { init: Some(init), .. }) => { if arg_is_mut_peekable(self.cx, init) { self.found_peek_call = true; - return; } - break; + return; }, - Node::Stmt(stmt) => match stmt.kind { - StmtKind::Expr(_) | StmtKind::Semi(_) => {}, - _ => { - self.found_peek_call = true; - return; - }, + Node::Stmt(stmt) => { + match stmt.kind { + StmtKind::Local(_) | StmtKind::Item(_) => self.found_peek_call = true, + StmtKind::Expr(_) | StmtKind::Semi(_) => {}, + } + + return; }, Node::Block(_) | Node::ExprField(_) => {}, _ => { - break; + return; }, } } diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index 486ea5e5ccfa9..44ab9bca79596 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::ty::same_type_and_consts; -use clippy_utils::{meets_msrv, msrvs}; +use clippy_utils::{is_from_proc_macro, meets_msrv, msrvs}; use if_chain::if_chain; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; @@ -87,7 +87,7 @@ impl_lint_pass!(UseSelf => [USE_SELF]); const SEGMENTS_MSG: &str = "segments should be composed of at least 1 element"; impl<'tcx> LateLintPass<'tcx> for UseSelf { - fn check_item(&mut self, _cx: &LateContext<'_>, item: &Item<'_>) { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &Item<'tcx>) { if matches!(item.kind, ItemKind::OpaqueTy(_)) { // skip over `ItemKind::OpaqueTy` in order to lint `foo() -> impl <..>` return; @@ -103,6 +103,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { if parameters.as_ref().map_or(true, |params| { !params.parenthesized && !params.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_))) }); + if !is_from_proc_macro(cx, item); // expensive, should be last check then { StackItem::Check { impl_id: item.def_id, @@ -213,9 +214,6 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { hir_ty_to_ty(cx.tcx, hir_ty) }; if same_type_and_consts(ty, cx.tcx.type_of(impl_id)); - let hir = cx.tcx.hir(); - // prevents false positive on `#[derive(serde::Deserialize)]` - if !hir.span(hir.get_parent_node(hir_ty.hir_id)).in_derive_expansion(); then { span_lint(cx, hir_ty.span); } diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index a8500beb25747..2be3fa99c811c 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -476,7 +476,7 @@ pub fn format_error(error: Box) -> String { let mut msg = String::from(prefix); for row in 0..rows { - write!(msg, "\n").unwrap(); + writeln!(msg).unwrap(); for (column, column_width) in column_widths.iter().copied().enumerate() { let index = column * rows + row; let field = fields.get(index).copied().unwrap_or_default(); diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index 640a09a7a9123..06e7d70170171 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -1,20 +1,12 @@ -use std::borrow::Cow; -use std::iter; -use std::ops::{Deref, Range}; - -use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability}; -use rustc_ast::ast::{Expr, ExprKind, Impl, Item, ItemKind, MacCall, Path, StrLit, StrStyle}; -use rustc_ast::ptr::P; -use rustc_ast::token::{self, LitKind}; -use rustc_ast::tokenstream::TokenStream; -use rustc_errors::{Applicability, DiagnosticBuilder}; -use rustc_lexer::unescape::{self, EscapeError}; -use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; -use rustc_parse::parser; +use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; +use clippy_utils::macros::{root_macro_call_first_node, FormatArgsExpn, MacroCall}; +use clippy_utils::source::snippet_opt; +use rustc_ast::LitKind; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind, HirIdMap, Impl, Item, ItemKind}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::symbol::{kw, Symbol}; -use rustc_span::{sym, BytePos, InnerSpan, Span, DUMMY_SP}; +use rustc_span::{sym, BytePos, Span}; declare_clippy_lint! { /// ### What it does @@ -74,13 +66,7 @@ declare_clippy_lint! { /// application and might forget to remove those prints afterward. /// /// ### Known problems - /// * Only catches `print!` and `println!` calls. - /// * The lint level is unaffected by crate attributes. The level can still - /// be set for functions, modules and other items. To change the level for - /// the entire crate, please use command line flags. More information and a - /// configuration example can be found in [clippy#6610]. - /// - /// [clippy#6610]: https://github.com/rust-lang/rust-clippy/issues/6610#issuecomment-977120558 + /// Only catches `print!` and `println!` calls. /// /// ### Example /// ```rust @@ -102,13 +88,7 @@ declare_clippy_lint! { /// application and might forget to remove those prints afterward. /// /// ### Known problems - /// * Only catches `eprint!` and `eprintln!` calls. - /// * The lint level is unaffected by crate attributes. The level can still - /// be set for functions, modules and other items. To change the level for - /// the entire crate, please use command line flags. More information and a - /// configuration example can be found in [clippy#6610]. - /// - /// [clippy#6610]: https://github.com/rust-lang/rust-clippy/issues/6610#issuecomment-977120558 + /// Only catches `eprint!` and `eprintln!` calls. /// /// ### Example /// ```rust @@ -149,10 +129,6 @@ declare_clippy_lint! { /// (c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary /// (i.e., just put the literal in the format string) /// - /// ### Known problems - /// Will also warn with macro calls as arguments that expand to literals - /// -- e.g., `println!("{}", env!("FOO"))`. - /// /// ### Example /// ```rust /// println!("{}", "foo"); @@ -234,10 +210,6 @@ declare_clippy_lint! { /// (c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary /// (i.e., just put the literal in the format string) /// - /// ### Known problems - /// Will also warn with macro calls as arguments that expand to literals - /// -- e.g., `writeln!(buf, "{}", env!("FOO"))`. - /// /// ### Example /// ```rust /// # use std::fmt::Write; @@ -257,28 +229,6 @@ declare_clippy_lint! { "writing a literal with a format string" } -declare_clippy_lint! { - /// ### What it does - /// This lint warns when a named parameter in a format string is used as a positional one. - /// - /// ### Why is this bad? - /// It may be confused for an assignment and obfuscates which parameter is being used. - /// - /// ### Example - /// ```rust - /// println!("{}", x = 10); - /// ``` - /// - /// Use instead: - /// ```rust - /// println!("{x}", x = 10); - /// ``` - #[clippy::version = "1.63.0"] - pub POSITIONAL_NAMED_FORMAT_PARAMETERS, - suspicious, - "named parameter in a format string is used positionally" -} - #[derive(Default)] pub struct Write { in_debug_impl: bool, @@ -294,537 +244,308 @@ impl_lint_pass!(Write => [ WRITE_WITH_NEWLINE, WRITELN_EMPTY_STRING, WRITE_LITERAL, - POSITIONAL_NAMED_FORMAT_PARAMETERS, ]); -impl EarlyLintPass for Write { - fn check_item(&mut self, _: &EarlyContext<'_>, item: &Item) { - if let ItemKind::Impl(box Impl { - of_trait: Some(trait_ref), - .. - }) = &item.kind - { - let trait_name = trait_ref - .path - .segments - .iter() - .last() - .expect("path has at least one segment") - .ident - .name; - if trait_name == sym::Debug { - self.in_debug_impl = true; - } +impl<'tcx> LateLintPass<'tcx> for Write { + fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { + if is_debug_impl(cx, item) { + self.in_debug_impl = true; } } - fn check_item_post(&mut self, _: &EarlyContext<'_>, _: &Item) { - self.in_debug_impl = false; + fn check_item_post(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { + if is_debug_impl(cx, item) { + self.in_debug_impl = false; + } } - fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &MacCall) { - fn is_build_script(cx: &EarlyContext<'_>) -> bool { - // Cargo sets the crate name for build scripts to `build_script_build` - cx.sess() - .opts - .crate_name - .as_ref() - .map_or(false, |crate_name| crate_name == "build_script_build") - } + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return }; + let Some(diag_name) = cx.tcx.get_diagnostic_name(macro_call.def_id) else { return }; + let Some(name) = diag_name.as_str().strip_suffix("_macro") else { return }; - if mac.path == sym!(print) { - if !is_build_script(cx) { - span_lint(cx, PRINT_STDOUT, mac.span(), "use of `print!`"); - } - self.lint_print_with_newline(cx, mac); - } else if mac.path == sym!(println) { - if !is_build_script(cx) { - span_lint(cx, PRINT_STDOUT, mac.span(), "use of `println!`"); - } - self.lint_println_empty_string(cx, mac); - } else if mac.path == sym!(eprint) { - span_lint(cx, PRINT_STDERR, mac.span(), "use of `eprint!`"); - self.lint_print_with_newline(cx, mac); - } else if mac.path == sym!(eprintln) { - span_lint(cx, PRINT_STDERR, mac.span(), "use of `eprintln!`"); - self.lint_println_empty_string(cx, mac); - } else if mac.path == sym!(write) { - if let (Some(fmt_str), dest) = self.check_tts(cx, mac.args.inner_tokens(), true) { - if check_newlines(&fmt_str) { - let (nl_span, only_nl) = newline_span(&fmt_str); - let nl_span = match (dest, only_nl) { - // Special case of `write!(buf, "\n")`: Mark everything from the end of - // `buf` for removal so no trailing comma [`writeln!(buf, )`] remains. - (Some(dest_expr), true) => nl_span.with_lo(dest_expr.span.hi()), - _ => nl_span, - }; - span_lint_and_then( - cx, - WRITE_WITH_NEWLINE, - mac.span(), - "using `write!()` with a format string that ends in a single newline", - |err| { - err.multipart_suggestion( - "use `writeln!()` instead", - vec![(mac.path.span, String::from("writeln")), (nl_span, String::new())], - Applicability::MachineApplicable, - ); - }, - ); - } - } - } else if mac.path == sym!(writeln) { - if let (Some(fmt_str), expr) = self.check_tts(cx, mac.args.inner_tokens(), true) { - if fmt_str.symbol == kw::Empty { - let mut applicability = Applicability::MachineApplicable; - let suggestion = if let Some(e) = expr { - snippet_with_applicability(cx, e.span, "v", &mut applicability) - } else { - applicability = Applicability::HasPlaceholders; - Cow::Borrowed("v") - }; - - span_lint_and_sugg( - cx, - WRITELN_EMPTY_STRING, - mac.span(), - format!("using `writeln!({}, \"\")`", suggestion).as_str(), - "replace it with", - format!("writeln!({})", suggestion), - applicability, - ); + let is_build_script = cx + .sess() + .opts + .crate_name + .as_ref() + .map_or(false, |crate_name| crate_name == "build_script_build"); + + match diag_name { + sym::print_macro | sym::println_macro => { + if !is_build_script { + span_lint(cx, PRINT_STDOUT, macro_call.span, &format!("use of `{name}!`")); } - } + }, + sym::eprint_macro | sym::eprintln_macro => { + span_lint(cx, PRINT_STDERR, macro_call.span, &format!("use of `{name}!`")); + }, + sym::write_macro | sym::writeln_macro => {}, + _ => return, } - } -} -/// Given a format string that ends in a newline and its span, calculates the span of the -/// newline, or the format string itself if the format string consists solely of a newline. -/// Return this and a boolean indicating whether it only consisted of a newline. -fn newline_span(fmtstr: &StrLit) -> (Span, bool) { - let sp = fmtstr.span; - let contents = fmtstr.symbol.as_str(); + let Some(format_args) = FormatArgsExpn::find_nested(cx, expr, macro_call.expn) else { return }; - if contents == r"\n" { - return (sp, true); - } - - let newline_sp_hi = sp.hi() - - match fmtstr.style { - StrStyle::Cooked => BytePos(1), - StrStyle::Raw(hashes) => BytePos((1 + hashes).into()), - }; + // ignore `writeln!(w)` and `write!(v, some_macro!())` + if format_args.format_string.span.from_expansion() { + return; + } - let newline_sp_len = if contents.ends_with('\n') { - BytePos(1) - } else if contents.ends_with(r"\n") { - BytePos(2) - } else { - panic!("expected format string to contain a newline"); - }; + match diag_name { + sym::print_macro | sym::eprint_macro | sym::write_macro => { + check_newline(cx, &format_args, ¯o_call, name); + }, + sym::println_macro | sym::eprintln_macro | sym::writeln_macro => { + check_empty_string(cx, &format_args, ¯o_call, name); + }, + _ => {}, + } - (sp.with_lo(newline_sp_hi - newline_sp_len).with_hi(newline_sp_hi), false) -} + check_literal(cx, &format_args, name); -/// Stores a list of replacement spans for each argument, but only if all the replacements used an -/// empty format string. -#[derive(Default)] -struct SimpleFormatArgs { - unnamed: Vec>, - complex_unnamed: Vec>, - named: Vec<(Symbol, Vec)>, + if !self.in_debug_impl { + for arg in &format_args.args { + if arg.format.r#trait == sym::Debug { + span_lint(cx, USE_DEBUG, arg.span, "use of `Debug`-based formatting"); + } + } + } + } } -impl SimpleFormatArgs { - fn get_unnamed(&self) -> impl Iterator { - self.unnamed.iter().map(|x| match x.as_slice() { - // Ignore the dummy span added from out of order format arguments. - [DUMMY_SP] => &[], - x => x, - }) +fn is_debug_impl(cx: &LateContext<'_>, item: &Item<'_>) -> bool { + if let ItemKind::Impl(Impl { of_trait: Some(trait_ref), .. }) = &item.kind + && let Some(trait_id) = trait_ref.trait_def_id() + { + cx.tcx.is_diagnostic_item(sym::Debug, trait_id) + } else { + false } +} - fn get_complex_unnamed(&self) -> impl Iterator { - self.complex_unnamed.iter().map(Vec::as_slice) - } +fn check_newline(cx: &LateContext<'_>, format_args: &FormatArgsExpn<'_>, macro_call: &MacroCall, name: &str) { + let format_string_parts = &format_args.format_string.parts; + let mut format_string_span = format_args.format_string.span; - fn get_named(&self, n: &Path) -> &[Span] { - self.named.iter().find(|x| *n == x.0).map_or(&[], |x| x.1.as_slice()) - } + let Some(last) = format_string_parts.last() else { return }; - fn push(&mut self, arg: rustc_parse_format::Argument<'_>, span: Span) { - use rustc_parse_format::{ - AlignUnknown, ArgumentImplicitlyIs, ArgumentIs, ArgumentNamed, CountImplied, FormatSpec, - }; + let count_vertical_whitespace = || { + format_string_parts + .iter() + .flat_map(|part| part.as_str().chars()) + .filter(|ch| matches!(ch, '\r' | '\n')) + .count() + }; - const SIMPLE: FormatSpec<'_> = FormatSpec { - fill: None, - align: AlignUnknown, - flags: 0, - precision: CountImplied, - precision_span: None, - width: CountImplied, - width_span: None, - ty: "", - ty_span: None, - }; + if last.as_str().ends_with('\n') + // ignore format strings with other internal vertical whitespace + && count_vertical_whitespace() == 1 - match arg.position { - ArgumentIs(n) | ArgumentImplicitlyIs(n) => { - if self.unnamed.len() <= n { - // Use a dummy span to mark all unseen arguments. - self.unnamed.resize_with(n, || vec![DUMMY_SP]); - if arg.format == SIMPLE { - self.unnamed.push(vec![span]); - } else { - self.unnamed.push(Vec::new()); - } - } else { - let args = &mut self.unnamed[n]; - match (args.as_mut_slice(), arg.format == SIMPLE) { - // A non-empty format string has been seen already. - ([], _) => (), - // Replace the dummy span, if it exists. - ([dummy @ DUMMY_SP], true) => *dummy = span, - ([_, ..], true) => args.push(span), - ([_, ..], false) => *args = Vec::new(), - } - } - }, - ArgumentNamed(n) => { - let n = Symbol::intern(n); - if let Some(x) = self.named.iter_mut().find(|x| x.0 == n) { - match x.1.as_slice() { - // A non-empty format string has been seen already. - [] => (), - [_, ..] if arg.format == SIMPLE => x.1.push(span), - [_, ..] => x.1 = Vec::new(), - } - } else if arg.format == SIMPLE { - self.named.push((n, vec![span])); - } else { - self.named.push((n, Vec::new())); - } - }, - }; - } + // ignore trailing arguments: `print!("Issue\n{}", 1265);` + && format_string_parts.len() > format_args.args.len() + { + let lint = if name == "write" { + format_string_span = expand_past_previous_comma(cx, format_string_span); - fn push_to_complex(&mut self, span: Span, position: usize) { - if self.complex_unnamed.len() <= position { - self.complex_unnamed.resize_with(position, Vec::new); - self.complex_unnamed.push(vec![span]); + WRITE_WITH_NEWLINE } else { - let args: &mut Vec = &mut self.complex_unnamed[position]; - args.push(span); - } - } - - fn push_complex( - &mut self, - cx: &EarlyContext<'_>, - arg: rustc_parse_format::Argument<'_>, - str_lit_span: Span, - fmt_span: Span, - ) { - use rustc_parse_format::{ArgumentImplicitlyIs, ArgumentIs, CountIsParam, CountIsStar}; - - let snippet = snippet_opt(cx, fmt_span); - - let end = snippet - .as_ref() - .and_then(|s| s.find(':')) - .or_else(|| fmt_span.hi().0.checked_sub(fmt_span.lo().0 + 1).map(|u| u as usize)); - - if let (ArgumentIs(n) | ArgumentImplicitlyIs(n), Some(end)) = (arg.position, end) { - let span = fmt_span.from_inner(InnerSpan::new(1, end)); - self.push_to_complex(span, n); + PRINT_WITH_NEWLINE }; - if let (CountIsParam(n) | CountIsStar(n), Some(span)) = (arg.format.precision, arg.format.precision_span) { - // We need to do this hack as precision spans should be converted from .* to .foo$ - let hack = if snippet.as_ref().and_then(|s| s.find('*')).is_some() { - 0 - } else { - 1 - }; + span_lint_and_then( + cx, + lint, + macro_call.span, + &format!("using `{name}!()` with a format string that ends in a single newline"), + |diag| { + let name_span = cx.sess().source_map().span_until_char(macro_call.span, '!'); + let Some(format_snippet) = snippet_opt(cx, format_string_span) else { return }; + + if format_string_parts.len() == 1 && last.as_str() == "\n" { + // print!("\n"), write!(f, "\n") + + diag.multipart_suggestion( + &format!("use `{name}ln!` instead"), + vec![(name_span, format!("{name}ln")), (format_string_span, String::new())], + Applicability::MachineApplicable, + ); + } else if format_snippet.ends_with("\\n\"") { + // print!("...\n"), write!(f, "...\n") - let span = str_lit_span.from_inner(InnerSpan { - start: span.start + 1, - end: span.end - hack, - }); - self.push_to_complex(span, n); - }; + let hi = format_string_span.hi(); + let newline_span = format_string_span.with_lo(hi - BytePos(3)).with_hi(hi - BytePos(1)); - if let (CountIsParam(n), Some(span)) = (arg.format.width, arg.format.width_span) { - let span = str_lit_span.from_inner(InnerSpan { - start: span.start, - end: span.end - 1, - }); - self.push_to_complex(span, n); - }; + diag.multipart_suggestion( + &format!("use `{name}ln!` instead"), + vec![(name_span, format!("{name}ln")), (newline_span, String::new())], + Applicability::MachineApplicable, + ); + } + }, + ); } } -impl Write { - /// Parses a format string into a collection of spans for each argument. This only keeps track - /// of empty format arguments. Will also lint usages of debug format strings outside of debug - /// impls. - fn parse_fmt_string(&self, cx: &EarlyContext<'_>, str_lit: &StrLit) -> Option { - use rustc_parse_format::{ParseMode, Parser, Piece}; - - let str_sym = str_lit.symbol_unescaped.as_str(); - let style = match str_lit.style { - StrStyle::Cooked => None, - StrStyle::Raw(n) => Some(n as usize), - }; - - let mut parser = Parser::new(str_sym, style, snippet_opt(cx, str_lit.span), false, ParseMode::Format); - let mut args = SimpleFormatArgs::default(); +fn check_empty_string(cx: &LateContext<'_>, format_args: &FormatArgsExpn<'_>, macro_call: &MacroCall, name: &str) { + if let [part] = &format_args.format_string.parts[..] + && let mut span = format_args.format_string.span + && part.as_str() == "\n" + { + let lint = if name == "writeln" { + span = expand_past_previous_comma(cx, span); - while let Some(arg) = parser.next() { - let arg = match arg { - Piece::String(_) => continue, - Piece::NextArgument(arg) => arg, - }; - let span = parser - .arg_places - .last() - .map_or(DUMMY_SP, |&x| str_lit.span.from_inner(InnerSpan::new(x.start, x.end))); - - if !self.in_debug_impl && arg.format.ty == "?" { - // FIXME: modify rustc's fmt string parser to give us the current span - span_lint(cx, USE_DEBUG, span, "use of `Debug`-based formatting"); - } - args.push(arg, span); - args.push_complex(cx, arg, str_lit.span, span); - } - - parser.errors.is_empty().then_some(args) - } - - /// Checks the arguments of `print[ln]!` and `write[ln]!` calls. It will return a tuple of two - /// `Option`s. The first `Option` of the tuple is the macro's format string. It includes - /// the contents of the string, whether it's a raw string, and the span of the literal in the - /// source. The second `Option` in the tuple is, in the `write[ln]!` case, the expression the - /// `format_str` should be written to. - /// - /// Example: - /// - /// Calling this function on - /// ```rust - /// # use std::fmt::Write; - /// # let mut buf = String::new(); - /// # let something = "something"; - /// writeln!(buf, "string to write: {}", something); - /// ``` - /// will return - /// ```rust,ignore - /// (Some("string to write: {}"), Some(buf)) - /// ``` - fn check_tts<'a>(&self, cx: &EarlyContext<'a>, tts: TokenStream, is_write: bool) -> (Option, Option) { - let mut parser = parser::Parser::new(&cx.sess().parse_sess, tts, false, None); - let expr = if is_write { - match parser - .parse_expr() - .map(rustc_ast::ptr::P::into_inner) - .map_err(DiagnosticBuilder::cancel) - { - // write!(e, ...) - Ok(p) if parser.eat(&token::Comma) => Some(p), - // write!(e) or error - e => return (None, e.ok()), - } + WRITELN_EMPTY_STRING } else { - None + PRINTLN_EMPTY_STRING }; - let fmtstr = match parser.parse_str_lit() { - Ok(fmtstr) => fmtstr, - Err(_) => return (None, expr), - }; + span_lint_and_then( + cx, + lint, + macro_call.span, + &format!("empty string literal in `{name}!`"), + |diag| { + diag.span_suggestion( + span, + "remove the empty string", + String::new(), + Applicability::MachineApplicable, + ); + }, + ); + } +} - let args = match self.parse_fmt_string(cx, &fmtstr) { - Some(args) => args, - None => return (Some(fmtstr), expr), - }; +fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgsExpn<'_>, name: &str) { + let mut counts = HirIdMap::::default(); + for param in format_args.params() { + *counts.entry(param.value.hir_id).or_default() += 1; + } - let lint = if is_write { WRITE_LITERAL } else { PRINT_LITERAL }; - let mut unnamed_args = args.get_unnamed(); - let mut complex_unnamed_args = args.get_complex_unnamed(); - loop { - if !parser.eat(&token::Comma) { - return (Some(fmtstr), expr); - } + for arg in &format_args.args { + let value = arg.param.value; - let comma_span = parser.prev_token.span; - let token_expr = if let Ok(expr) = parser.parse_expr().map_err(DiagnosticBuilder::cancel) { - expr - } else { - return (Some(fmtstr), None); - }; - let complex_unnamed_arg = complex_unnamed_args.next(); - - let (fmt_spans, lit) = match &token_expr.kind { - ExprKind::Lit(lit) => (unnamed_args.next().unwrap_or(&[]), lit), - ExprKind::Assign(lhs, rhs, _) => { - if let Some(span) = complex_unnamed_arg { - for x in span { - Self::report_positional_named_param(cx, *x, lhs, rhs); - } - } - match (&lhs.kind, &rhs.kind) { - (ExprKind::Path(_, p), ExprKind::Lit(lit)) => (args.get_named(p), lit), - _ => continue, + if counts[&value.hir_id] == 1 + && arg.format.is_default() + && let ExprKind::Lit(lit) = &value.kind + && !value.span.from_expansion() + && let Some(value_string) = snippet_opt(cx, value.span) + { + let (replacement, replace_raw) = match lit.node { + LitKind::Str(..) => extract_str_literal(&value_string), + LitKind::Char(ch) => ( + match ch { + '"' => "\\\"", + '\'' => "'", + _ => &value_string[1..value_string.len() - 1], } - }, - _ => { - unnamed_args.next(); - continue; - }, + .to_string(), + false, + ), + LitKind::Bool(b) => (b.to_string(), false), + _ => continue, + }; + + let lint = if name.starts_with("write") { + WRITE_LITERAL + } else { + PRINT_LITERAL }; - let replacement: String = match lit.token_lit.kind { - LitKind::StrRaw(_) | LitKind::ByteStrRaw(_) if matches!(fmtstr.style, StrStyle::Raw(_)) => { - lit.token_lit.symbol.as_str().replace('{', "{{").replace('}', "}}") + let format_string_is_raw = format_args.format_string.style.is_some(); + let replacement = match (format_string_is_raw, replace_raw) { + (false, false) => Some(replacement), + (false, true) => Some(replacement.replace('"', "\\\"").replace('\\', "\\\\")), + (true, false) => match conservative_unescape(&replacement) { + Ok(unescaped) => Some(unescaped), + Err(UnescapeErr::Lint) => None, + Err(UnescapeErr::Ignore) => continue, }, - LitKind::Str | LitKind::ByteStr if matches!(fmtstr.style, StrStyle::Cooked) => { - lit.token_lit.symbol.as_str().replace('{', "{{").replace('}', "}}") + (true, true) => { + if replacement.contains(['#', '"']) { + None + } else { + Some(replacement) + } }, - LitKind::StrRaw(_) - | LitKind::Str - | LitKind::ByteStrRaw(_) - | LitKind::ByteStr - | LitKind::Integer - | LitKind::Float - | LitKind::Err => continue, - LitKind::Byte | LitKind::Char => match lit.token_lit.symbol.as_str() { - "\"" if matches!(fmtstr.style, StrStyle::Cooked) => "\\\"", - "\"" if matches!(fmtstr.style, StrStyle::Raw(0)) => continue, - "\\\\" if matches!(fmtstr.style, StrStyle::Raw(_)) => "\\", - "\\'" => "'", - "{" => "{{", - "}" => "}}", - x if matches!(fmtstr.style, StrStyle::Raw(_)) && x.starts_with('\\') => continue, - x => x, - } - .into(), - LitKind::Bool => lit.token_lit.symbol.as_str().deref().into(), }; - if !fmt_spans.is_empty() { - span_lint_and_then( - cx, - lint, - token_expr.span, - "literal with an empty format string", - |diag| { + span_lint_and_then( + cx, + lint, + value.span, + "literal with an empty format string", + |diag| { + if let Some(replacement) = replacement { + // `format!("{}", "a")`, `format!("{named}", named = "b") + // ~~~~~ ~~~~~~~~~~~~~ + let value_span = expand_past_previous_comma(cx, value.span); + + let replacement = replacement.replace('{', "{{").replace('}', "}}"); diag.multipart_suggestion( "try this", - iter::once((comma_span.to(token_expr.span), String::new())) - .chain(fmt_spans.iter().copied().zip(iter::repeat(replacement))) - .collect(), + vec![(arg.span, replacement), (value_span, String::new())], Applicability::MachineApplicable, ); - }, - ); - } - } - } - - fn report_positional_named_param(cx: &EarlyContext<'_>, span: Span, lhs: &P, _rhs: &P) { - if let ExprKind::Path(_, _p) = &lhs.kind { - let mut applicability = Applicability::MachineApplicable; - let name = snippet_with_applicability(cx, lhs.span, "name", &mut applicability); - // We need to do this hack as precision spans should be converted from .* to .foo$ - let hack = snippet(cx, span, "").contains('*'); - - span_lint_and_sugg( - cx, - POSITIONAL_NAMED_FORMAT_PARAMETERS, - span, - &format!("named parameter {} is used as a positional parameter", name), - "replace it with", - if hack { - format!("{}$", name) - } else { - format!("{}", name) + } }, - applicability, ); - }; - } - - fn lint_println_empty_string(&self, cx: &EarlyContext<'_>, mac: &MacCall) { - if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), false) { - if fmt_str.symbol == kw::Empty { - let name = mac.path.segments[0].ident.name; - span_lint_and_sugg( - cx, - PRINTLN_EMPTY_STRING, - mac.span(), - &format!("using `{}!(\"\")`", name), - "replace it with", - format!("{}!()", name), - Applicability::MachineApplicable, - ); - } - } - } - - fn lint_print_with_newline(&self, cx: &EarlyContext<'_>, mac: &MacCall) { - if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), false) { - if check_newlines(&fmt_str) { - let name = mac.path.segments[0].ident.name; - let suggested = format!("{}ln", name); - span_lint_and_then( - cx, - PRINT_WITH_NEWLINE, - mac.span(), - &format!("using `{}!()` with a format string that ends in a single newline", name), - |err| { - err.multipart_suggestion( - &format!("use `{}!` instead", suggested), - vec![(mac.path.span, suggested), (newline_span(&fmt_str).0, String::new())], - Applicability::MachineApplicable, - ); - }, - ); - } } } } -/// Checks if the format string contains a single newline that terminates it. +/// Removes the raw marker, `#`s and quotes from a str, and returns if the literal is raw /// -/// Literal and escaped newlines are both checked (only literal for raw strings). -fn check_newlines(fmtstr: &StrLit) -> bool { - let mut has_internal_newline = false; - let mut last_was_cr = false; - let mut should_lint = false; - - let contents = fmtstr.symbol.as_str(); - - let mut cb = |r: Range, c: Result| { - let c = match c { - Ok(c) => c, - Err(e) if !e.is_fatal() => return, - Err(e) => panic!("{:?}", e), - }; - - if r.end == contents.len() && c == '\n' && !last_was_cr && !has_internal_newline { - should_lint = true; - } else { - last_was_cr = c == '\r'; - if c == '\n' { - has_internal_newline = true; - } - } +/// `r#"a"#` -> (`a`, true) +/// +/// `"b"` -> (`b`, false) +fn extract_str_literal(literal: &str) -> (String, bool) { + let (literal, raw) = match literal.strip_prefix('r') { + Some(stripped) => (stripped.trim_matches('#'), true), + None => (literal, false), }; - match fmtstr.style { - StrStyle::Cooked => unescape::unescape_literal(contents, unescape::Mode::Str, &mut cb), - StrStyle::Raw(_) => unescape::unescape_literal(contents, unescape::Mode::RawStr, &mut cb), + (literal[1..literal.len() - 1].to_string(), raw) +} + +enum UnescapeErr { + /// Should still be linted, can be manually resolved by author, e.g. + /// + /// ```ignore + /// print!(r"{}", '"'); + /// ``` + Lint, + /// Should not be linted, e.g. + /// + /// ```ignore + /// print!(r"{}", '\r'); + /// ``` + Ignore, +} + +/// Unescape a normal string into a raw string +fn conservative_unescape(literal: &str) -> Result { + let mut unescaped = String::with_capacity(literal.len()); + let mut chars = literal.chars(); + let mut err = false; + + while let Some(ch) = chars.next() { + match ch { + '#' => err = true, + '\\' => match chars.next() { + Some('\\') => unescaped.push('\\'), + Some('"') => err = true, + _ => return Err(UnescapeErr::Ignore), + }, + _ => unescaped.push(ch), + } } - should_lint + if err { Err(UnescapeErr::Lint) } else { Ok(unescaped) } +} + +// Expand from `writeln!(o, "")` to `writeln!(o, "")` +// ^^ ^^^^ +fn expand_past_previous_comma(cx: &LateContext<'_>, span: Span) -> Span { + let extended = cx.sess().source_map().span_extend_to_prev_char(span, ',', true); + extended.with_lo(extended.lo() - BytePos(1)) } diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 96c55111fbaff..1b8a9c05559a9 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -501,8 +501,8 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { BinOpKind::Mul => l.checked_mul(r).map(zext), BinOpKind::Div if r != 0 => l.checked_div(r).map(zext), BinOpKind::Rem if r != 0 => l.checked_rem(r).map(zext), - BinOpKind::Shr => l.checked_shr(r.try_into().expect("invalid shift")).map(zext), - BinOpKind::Shl => l.checked_shl(r.try_into().expect("invalid shift")).map(zext), + BinOpKind::Shr => l.checked_shr(r.try_into().ok()?).map(zext), + BinOpKind::Shl => l.checked_shl(r.try_into().ok()?).map(zext), BinOpKind::BitXor => Some(zext(l ^ r)), BinOpKind::BitOr => Some(zext(l | r)), BinOpKind::BitAnd => Some(zext(l & r)), @@ -521,8 +521,8 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { BinOpKind::Mul => l.checked_mul(r).map(Constant::Int), BinOpKind::Div => l.checked_div(r).map(Constant::Int), BinOpKind::Rem => l.checked_rem(r).map(Constant::Int), - BinOpKind::Shr => l.checked_shr(r.try_into().expect("shift too large")).map(Constant::Int), - BinOpKind::Shl => l.checked_shl(r.try_into().expect("shift too large")).map(Constant::Int), + BinOpKind::Shr => l.checked_shr(r.try_into().ok()?).map(Constant::Int), + BinOpKind::Shl => l.checked_shl(r.try_into().ok()?).map(Constant::Int), BinOpKind::BitXor => Some(Constant::Int(l ^ r)), BinOpKind::BitOr => Some(Constant::Int(l | r)), BinOpKind::BitAnd => Some(Constant::Int(l & r)), diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs index bd89ff977f877..a1808c0972009 100644 --- a/clippy_utils/src/macros.rs +++ b/clippy_utils/src/macros.rs @@ -7,8 +7,8 @@ use crate::visitors::expr_visitor_no_bodies; use arrayvec::ArrayVec; use itertools::{izip, Either, Itertools}; use rustc_ast::ast::LitKind; -use rustc_hir::intravisit::Visitor; -use rustc_hir::{self as hir, Expr, ExprKind, HirId, Node, QPath}; +use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::{self as hir, Expr, ExprField, ExprKind, HirId, Node, QPath}; use rustc_lexer::unescape::unescape_literal; use rustc_lexer::{tokenize, unescape, LiteralKind, TokenKind}; use rustc_lint::LateContext; @@ -485,64 +485,49 @@ struct ParamPosition { precision: Option, } -/// Parses the `fmt` arg of `Arguments::new_v1_formatted(pieces, args, fmt, _)` -fn parse_rt_fmt<'tcx>(fmt_arg: &'tcx Expr<'tcx>) -> Option + 'tcx> { - fn parse_count(expr: &Expr<'_>) -> Option { - // ::core::fmt::rt::v1::Count::Param(1usize), - if let ExprKind::Call(ctor, [val]) = expr.kind - && let ExprKind::Path(QPath::Resolved(_, path)) = ctor.kind - && path.segments.last()?.ident.name == sym::Param - && let ExprKind::Lit(lit) = &val.kind - && let LitKind::Int(pos, _) = lit.node - { - Some(pos as usize) - } else { - None +impl<'tcx> Visitor<'tcx> for ParamPosition { + fn visit_expr_field(&mut self, field: &'tcx ExprField<'tcx>) { + fn parse_count(expr: &Expr<'_>) -> Option { + // ::core::fmt::rt::v1::Count::Param(1usize), + if let ExprKind::Call(ctor, [val]) = expr.kind + && let ExprKind::Path(QPath::Resolved(_, path)) = ctor.kind + && path.segments.last()?.ident.name == sym::Param + && let ExprKind::Lit(lit) = &val.kind + && let LitKind::Int(pos, _) = lit.node + { + Some(pos as usize) + } else { + None + } + } + + match field.ident.name { + sym::position => { + if let ExprKind::Lit(lit) = &field.expr.kind + && let LitKind::Int(pos, _) = lit.node + { + self.value = pos as usize; + } + }, + sym::precision => { + self.precision = parse_count(field.expr); + }, + sym::width => { + self.width = parse_count(field.expr); + }, + _ => walk_expr(self, field.expr), } } +} +/// Parses the `fmt` arg of `Arguments::new_v1_formatted(pieces, args, fmt, _)` +fn parse_rt_fmt<'tcx>(fmt_arg: &'tcx Expr<'tcx>) -> Option + 'tcx> { if let ExprKind::AddrOf(.., array) = fmt_arg.kind && let ExprKind::Array(specs) = array.kind { Some(specs.iter().map(|spec| { let mut position = ParamPosition::default(); - - // ::core::fmt::rt::v1::Argument { - // position: 0usize, - // format: ::core::fmt::rt::v1::FormatSpec { - // .. - // precision: ::core::fmt::rt::v1::Count::Implied, - // width: ::core::fmt::rt::v1::Count::Implied, - // }, - // } - - // TODO: this can be made much nicer next sync with `Visitor::visit_expr_field` - if let ExprKind::Struct(_, fields, _) = spec.kind { - for field in fields { - match (field.ident.name, &field.expr.kind) { - (sym::position, ExprKind::Lit(lit)) => { - if let LitKind::Int(pos, _) = lit.node { - position.value = pos as usize; - } - }, - (sym::format, &ExprKind::Struct(_, spec_fields, _)) => { - for spec_field in spec_fields { - match spec_field.ident.name { - sym::precision => { - position.precision = parse_count(spec_field.expr); - }, - sym::width => { - position.width = parse_count(spec_field.expr); - }, - _ => {}, - } - } - }, - _ => {}, - } - } - } - + position.visit_expr(spec); position })) } else { @@ -711,9 +696,14 @@ impl<'tcx> FormatSpec<'tcx> { }) } - /// Returns true if this format spec would change the contents of a string when formatted - pub fn has_string_formatting(&self) -> bool { - self.r#trait != sym::Display || !self.width.is_implied() || !self.precision.is_implied() + /// Returns true if this format spec is unchanged from the default. e.g. returns true for `{}`, + /// `{foo}` and `{2}`, but false for `{:?}`, `{foo:5}` and `{3:.5}` + pub fn is_default(&self) -> bool { + self.r#trait == sym::Display + && self.width.is_implied() + && self.precision.is_implied() + && self.align == Alignment::AlignUnknown + && self.flags == 0 } } diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index cca71bbf76e28..f08275a4ac76b 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -22,7 +22,7 @@ use std::fmt::{Display, Write as _}; use std::ops::{Add, Neg, Not, Sub}; /// A helper type to build suggestion correctly handling parentheses. -#[derive(Clone, PartialEq)] +#[derive(Clone, Debug, PartialEq)] pub enum Sugg<'a> { /// An expression that never needs parentheses such as `1337` or `[0; 42]`. NonParen(Cow<'a, str>), @@ -155,8 +155,8 @@ impl<'a> Sugg<'a> { | hir::ExprKind::Ret(..) | hir::ExprKind::Struct(..) | hir::ExprKind::Tup(..) - | hir::ExprKind::DropTemps(_) | hir::ExprKind::Err => Sugg::NonParen(get_snippet(expr.span)), + hir::ExprKind::DropTemps(inner) => Self::hir_from_snippet(inner, get_snippet), hir::ExprKind::Assign(lhs, rhs, _) => { Sugg::BinOp(AssocOp::Assign, get_snippet(lhs.span), get_snippet(rhs.span)) }, @@ -177,11 +177,11 @@ impl<'a> Sugg<'a> { pub fn ast(cx: &EarlyContext<'_>, expr: &ast::Expr, default: &'a str) -> Self { use rustc_ast::ast::RangeLimits; - let get_whole_snippet = || { - if expr.span.from_expansion() { - snippet_with_macro_callsite(cx, expr.span, default) + let snippet_without_expansion = |cx, span: Span, default| { + if span.from_expansion() { + snippet_with_macro_callsite(cx, span, default) } else { - snippet(cx, expr.span, default) + snippet(cx, span, default) } }; @@ -192,7 +192,7 @@ impl<'a> Sugg<'a> { | ast::ExprKind::If(..) | ast::ExprKind::Let(..) | ast::ExprKind::Unary(..) - | ast::ExprKind::Match(..) => Sugg::MaybeParen(get_whole_snippet()), + | ast::ExprKind::Match(..) => Sugg::MaybeParen(snippet_without_expansion(cx, expr.span, default)), ast::ExprKind::Async(..) | ast::ExprKind::Block(..) | ast::ExprKind::Break(..) @@ -221,41 +221,45 @@ impl<'a> Sugg<'a> { | ast::ExprKind::Array(..) | ast::ExprKind::While(..) | ast::ExprKind::Await(..) - | ast::ExprKind::Err => Sugg::NonParen(get_whole_snippet()), + | ast::ExprKind::Err => Sugg::NonParen(snippet_without_expansion(cx, expr.span, default)), ast::ExprKind::Range(ref lhs, ref rhs, RangeLimits::HalfOpen) => Sugg::BinOp( AssocOp::DotDot, - lhs.as_ref().map_or("".into(), |lhs| snippet(cx, lhs.span, default)), - rhs.as_ref().map_or("".into(), |rhs| snippet(cx, rhs.span, default)), + lhs.as_ref() + .map_or("".into(), |lhs| snippet_without_expansion(cx, lhs.span, default)), + rhs.as_ref() + .map_or("".into(), |rhs| snippet_without_expansion(cx, rhs.span, default)), ), ast::ExprKind::Range(ref lhs, ref rhs, RangeLimits::Closed) => Sugg::BinOp( AssocOp::DotDotEq, - lhs.as_ref().map_or("".into(), |lhs| snippet(cx, lhs.span, default)), - rhs.as_ref().map_or("".into(), |rhs| snippet(cx, rhs.span, default)), + lhs.as_ref() + .map_or("".into(), |lhs| snippet_without_expansion(cx, lhs.span, default)), + rhs.as_ref() + .map_or("".into(), |rhs| snippet_without_expansion(cx, rhs.span, default)), ), ast::ExprKind::Assign(ref lhs, ref rhs, _) => Sugg::BinOp( AssocOp::Assign, - snippet(cx, lhs.span, default), - snippet(cx, rhs.span, default), + snippet_without_expansion(cx, lhs.span, default), + snippet_without_expansion(cx, rhs.span, default), ), ast::ExprKind::AssignOp(op, ref lhs, ref rhs) => Sugg::BinOp( astbinop2assignop(op), - snippet(cx, lhs.span, default), - snippet(cx, rhs.span, default), + snippet_without_expansion(cx, lhs.span, default), + snippet_without_expansion(cx, rhs.span, default), ), ast::ExprKind::Binary(op, ref lhs, ref rhs) => Sugg::BinOp( AssocOp::from_ast_binop(op.node), - snippet(cx, lhs.span, default), - snippet(cx, rhs.span, default), + snippet_without_expansion(cx, lhs.span, default), + snippet_without_expansion(cx, rhs.span, default), ), ast::ExprKind::Cast(ref lhs, ref ty) => Sugg::BinOp( AssocOp::As, - snippet(cx, lhs.span, default), - snippet(cx, ty.span, default), + snippet_without_expansion(cx, lhs.span, default), + snippet_without_expansion(cx, ty.span, default), ), ast::ExprKind::Type(ref lhs, ref ty) => Sugg::BinOp( AssocOp::Colon, - snippet(cx, lhs.span, default), - snippet(cx, ty.span, default), + snippet_without_expansion(cx, lhs.span, default), + snippet_without_expansion(cx, ty.span, default), ), } } diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 926ecf9659321..56343880320db 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -31,6 +31,13 @@ pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { ty.is_copy_modulo_regions(cx.tcx.at(DUMMY_SP), cx.param_env) } +/// This checks whether a given type is known to implement Debug. +pub fn has_debug_impl<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { + cx.tcx + .get_diagnostic_item(sym::Debug) + .map_or(false, |debug| implements_trait(cx, ty, debug, &[])) +} + /// Checks whether a type can be partially moved. pub fn can_partially_move_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { if has_drop(cx, ty) || is_copy(cx, ty) { diff --git a/src/docs.rs b/src/docs.rs index f3a5048e7fa82..6c89b4dde372d 100644 --- a/src/docs.rs +++ b/src/docs.rs @@ -221,6 +221,7 @@ docs! { "items_after_statements", "iter_cloned_collect", "iter_count", + "iter_kv_map", "iter_next_loop", "iter_next_slice", "iter_not_returning_iterator", @@ -391,7 +392,6 @@ docs! { "partialeq_to_none", "path_buf_push_overwrite", "pattern_type_mismatch", - "positional_named_format_parameters", "possible_missing_comma", "precedence", "print_in_format_impl", diff --git a/src/docs/iter_kv_map.txt b/src/docs/iter_kv_map.txt new file mode 100644 index 0000000000000..a063c8195ef57 --- /dev/null +++ b/src/docs/iter_kv_map.txt @@ -0,0 +1,22 @@ +### What it does + +Checks for iterating a map (`HashMap` or `BTreeMap`) and +ignoring either the keys or values. + +### Why is this bad? + +Readability. There are `keys` and `values` methods that +can be used to express that we only need the keys or the values. + +### Example + +``` +let map: HashMap = HashMap::new(); +let values = map.iter().map(|(_, value)| value).collect::>(); +``` + +Use instead: +``` +let map: HashMap = HashMap::new(); +let values = map.values().collect::>(); +``` \ No newline at end of file diff --git a/src/docs/positional_named_format_parameters.txt b/src/docs/positional_named_format_parameters.txt deleted file mode 100644 index e391d2406677d..0000000000000 --- a/src/docs/positional_named_format_parameters.txt +++ /dev/null @@ -1,15 +0,0 @@ -### What it does -This lint warns when a named parameter in a format string is used as a positional one. - -### Why is this bad? -It may be confused for an assignment and obfuscates which parameter is being used. - -### Example -``` -println!("{}", x = 10); -``` - -Use instead: -``` -println!("{x}", x = 10); -``` \ No newline at end of file diff --git a/src/docs/print_literal.txt b/src/docs/print_literal.txt index 160073414f9af..a6252a68780bb 100644 --- a/src/docs/print_literal.txt +++ b/src/docs/print_literal.txt @@ -6,10 +6,6 @@ Using literals as `println!` args is inefficient (c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary (i.e., just put the literal in the format string) -### Known problems -Will also warn with macro calls as arguments that expand to literals --- e.g., `println!("{}", env!("FOO"))`. - ### Example ``` println!("{}", "foo"); diff --git a/src/docs/print_stderr.txt b/src/docs/print_stderr.txt index fc14511cd6a65..9c6edeeef125d 100644 --- a/src/docs/print_stderr.txt +++ b/src/docs/print_stderr.txt @@ -7,13 +7,7 @@ People often print on *stderr* while debugging an application and might forget to remove those prints afterward. ### Known problems -* Only catches `eprint!` and `eprintln!` calls. -* The lint level is unaffected by crate attributes. The level can still - be set for functions, modules and other items. To change the level for - the entire crate, please use command line flags. More information and a - configuration example can be found in [clippy#6610]. - -[clippy#6610]: https://github.com/rust-lang/rust-clippy/issues/6610#issuecomment-977120558 +Only catches `eprint!` and `eprintln!` calls. ### Example ``` diff --git a/src/docs/print_stdout.txt b/src/docs/print_stdout.txt index 6c9a4b98e1e66..d2cbd811d1b2a 100644 --- a/src/docs/print_stdout.txt +++ b/src/docs/print_stdout.txt @@ -7,13 +7,7 @@ People often print on *stdout* while debugging an application and might forget to remove those prints afterward. ### Known problems -* Only catches `print!` and `println!` calls. -* The lint level is unaffected by crate attributes. The level can still - be set for functions, modules and other items. To change the level for - the entire crate, please use command line flags. More information and a - configuration example can be found in [clippy#6610]. - -[clippy#6610]: https://github.com/rust-lang/rust-clippy/issues/6610#issuecomment-977120558 +Only catches `print!` and `println!` calls. ### Example ``` diff --git a/src/docs/write_literal.txt b/src/docs/write_literal.txt index 9c41a48f9f731..a7a884d087115 100644 --- a/src/docs/write_literal.txt +++ b/src/docs/write_literal.txt @@ -6,10 +6,6 @@ Using literals as `writeln!` args is inefficient (c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary (i.e., just put the literal in the format string) -### Known problems -Will also warn with macro calls as arguments that expand to literals --- e.g., `writeln!(buf, "{}", env!("FOO"))`. - ### Example ``` writeln!(buf, "{}", "foo"); diff --git a/tests/ui-cargo/module_style/fail_mod_remap/Cargo.toml b/tests/ui-cargo/module_style/fail_mod_remap/Cargo.toml new file mode 100644 index 0000000000000..a822fad388f56 --- /dev/null +++ b/tests/ui-cargo/module_style/fail_mod_remap/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "fail-mod-remap" +version = "0.1.0" +edition = "2018" +publish = false + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/tests/ui-cargo/module_style/fail_mod_remap/src/bad.rs b/tests/ui-cargo/module_style/fail_mod_remap/src/bad.rs new file mode 100644 index 0000000000000..509aad18622b5 --- /dev/null +++ b/tests/ui-cargo/module_style/fail_mod_remap/src/bad.rs @@ -0,0 +1 @@ +pub mod inner; diff --git a/tests/ui-cargo/module_style/fail_mod_remap/src/bad/inner.rs b/tests/ui-cargo/module_style/fail_mod_remap/src/bad/inner.rs new file mode 100644 index 0000000000000..8b137891791fe --- /dev/null +++ b/tests/ui-cargo/module_style/fail_mod_remap/src/bad/inner.rs @@ -0,0 +1 @@ + diff --git a/tests/ui-cargo/module_style/fail_mod_remap/src/main.rs b/tests/ui-cargo/module_style/fail_mod_remap/src/main.rs new file mode 100644 index 0000000000000..ba4c8c873dd55 --- /dev/null +++ b/tests/ui-cargo/module_style/fail_mod_remap/src/main.rs @@ -0,0 +1,7 @@ +// compile-flags: --remap-path-prefix {{src-base}}=/remapped + +#![warn(clippy::self_named_module_files)] + +mod bad; + +fn main() {} diff --git a/tests/ui-cargo/module_style/fail_mod_remap/src/main.stderr b/tests/ui-cargo/module_style/fail_mod_remap/src/main.stderr new file mode 100644 index 0000000000000..46991ff662e53 --- /dev/null +++ b/tests/ui-cargo/module_style/fail_mod_remap/src/main.stderr @@ -0,0 +1,11 @@ +error: `mod.rs` files are required, found `bad.rs` + --> /remapped/module_style/fail_mod_remap/src/bad.rs:1:1 + | +LL | pub mod inner; + | ^ + | + = note: `-D clippy::self-named-module-files` implied by `-D warnings` + = help: move `bad.rs` to `bad/mod.rs` + +error: aborting due to previous error + diff --git a/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs b/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs index 5b4adc868dff1..ed8161acc0efb 100644 --- a/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs +++ b/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs @@ -42,6 +42,7 @@ macro_rules! printlnfoo { fn main() { let _ = vec! {1, 2, 3}; let _ = format!["ugh {} stop being such a good compiler", "hello"]; + let _ = matches!{{}, ()}; let _ = quote!(let x = 1;); let _ = quote::quote!(match match match); let _ = test!(); // trigger when macro def is inside our own crate diff --git a/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.stderr b/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.stderr index 039b23b1bdb2f..d80ad49f3086d 100644 --- a/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.stderr +++ b/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.stderr @@ -23,26 +23,38 @@ help: consider writing `format!("ugh () stop being such a good compiler", "hello LL | let _ = format!["ugh {} stop being such a good compiler", "hello"]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: use of irregular braces for `quote!` macro +error: use of irregular braces for `matches!` macro + --> $DIR/conf_nonstandard_macro_braces.rs:45:13 + | +LL | let _ = matches!{{}, ()}; + | ^^^^^^^^^^^^^^^^ + | +help: consider writing `matches!((), ())` --> $DIR/conf_nonstandard_macro_braces.rs:45:13 | +LL | let _ = matches!{{}, ()}; + | ^^^^^^^^^^^^^^^^ + +error: use of irregular braces for `quote!` macro + --> $DIR/conf_nonstandard_macro_braces.rs:46:13 + | LL | let _ = quote!(let x = 1;); | ^^^^^^^^^^^^^^^^^^ | help: consider writing `quote! {let x = 1;}` - --> $DIR/conf_nonstandard_macro_braces.rs:45:13 + --> $DIR/conf_nonstandard_macro_braces.rs:46:13 | LL | let _ = quote!(let x = 1;); | ^^^^^^^^^^^^^^^^^^ error: use of irregular braces for `quote::quote!` macro - --> $DIR/conf_nonstandard_macro_braces.rs:46:13 + --> $DIR/conf_nonstandard_macro_braces.rs:47:13 | LL | let _ = quote::quote!(match match match); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: consider writing `quote::quote! {match match match}` - --> $DIR/conf_nonstandard_macro_braces.rs:46:13 + --> $DIR/conf_nonstandard_macro_braces.rs:47:13 | LL | let _ = quote::quote!(match match match); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -67,28 +79,28 @@ LL | let _ = test!(); // trigger when macro def is inside our own crate = note: this error originates in the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info) error: use of irregular braces for `type_pos!` macro - --> $DIR/conf_nonstandard_macro_braces.rs:55:12 + --> $DIR/conf_nonstandard_macro_braces.rs:56:12 | LL | let _: type_pos!(usize) = vec![]; | ^^^^^^^^^^^^^^^^ | help: consider writing `type_pos![usize]` - --> $DIR/conf_nonstandard_macro_braces.rs:55:12 + --> $DIR/conf_nonstandard_macro_braces.rs:56:12 | LL | let _: type_pos!(usize) = vec![]; | ^^^^^^^^^^^^^^^^ error: use of irregular braces for `eprint!` macro - --> $DIR/conf_nonstandard_macro_braces.rs:57:5 + --> $DIR/conf_nonstandard_macro_braces.rs:58:5 | LL | eprint!("test if user config overrides defaults"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: consider writing `eprint!["test if user config overrides defaults"]` - --> $DIR/conf_nonstandard_macro_braces.rs:57:5 + --> $DIR/conf_nonstandard_macro_braces.rs:58:5 | LL | eprint!("test if user config overrides defaults"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 7 previous errors +error: aborting due to 8 previous errors diff --git a/tests/ui/almost_complete_letter_range.fixed b/tests/ui/almost_complete_letter_range.fixed index e69b40f35f4c6..079b7c000dce1 100644 --- a/tests/ui/almost_complete_letter_range.fixed +++ b/tests/ui/almost_complete_letter_range.fixed @@ -1,5 +1,6 @@ // run-rustfix // edition:2018 +// aux-build:macro_rules.rs #![feature(custom_inner_attributes)] #![feature(exclusive_range_pattern)] @@ -8,12 +9,21 @@ #![allow(ellipsis_inclusive_range_patterns)] #![allow(clippy::needless_parens_on_range_literals)] +#[macro_use] +extern crate macro_rules; + macro_rules! a { () => { 'a' }; } +macro_rules! b { + () => { + let _ = 'a'..='z'; + }; +} + fn main() { #[rustfmt::skip] { @@ -47,6 +57,9 @@ fn main() { 'B'..'Z' => 4, _ => 5, }; + + almost_complete_letter_range!(); + b!(); } fn _under_msrv() { diff --git a/tests/ui/almost_complete_letter_range.rs b/tests/ui/almost_complete_letter_range.rs index f2240981d45fa..a66900a976efa 100644 --- a/tests/ui/almost_complete_letter_range.rs +++ b/tests/ui/almost_complete_letter_range.rs @@ -1,5 +1,6 @@ // run-rustfix // edition:2018 +// aux-build:macro_rules.rs #![feature(custom_inner_attributes)] #![feature(exclusive_range_pattern)] @@ -8,12 +9,21 @@ #![allow(ellipsis_inclusive_range_patterns)] #![allow(clippy::needless_parens_on_range_literals)] +#[macro_use] +extern crate macro_rules; + macro_rules! a { () => { 'a' }; } +macro_rules! b { + () => { + let _ = 'a'..'z'; + }; +} + fn main() { #[rustfmt::skip] { @@ -47,6 +57,9 @@ fn main() { 'B'..'Z' => 4, _ => 5, }; + + almost_complete_letter_range!(); + b!(); } fn _under_msrv() { diff --git a/tests/ui/almost_complete_letter_range.stderr b/tests/ui/almost_complete_letter_range.stderr index 5b5dc40ee54d0..3de44c72c1b9d 100644 --- a/tests/ui/almost_complete_letter_range.stderr +++ b/tests/ui/almost_complete_letter_range.stderr @@ -1,5 +1,5 @@ error: almost complete ascii letter range - --> $DIR/almost_complete_letter_range.rs:20:17 + --> $DIR/almost_complete_letter_range.rs:30:17 | LL | let _ = ('a') ..'z'; | ^^^^^^--^^^ @@ -9,7 +9,7 @@ LL | let _ = ('a') ..'z'; = note: `-D clippy::almost-complete-letter-range` implied by `-D warnings` error: almost complete ascii letter range - --> $DIR/almost_complete_letter_range.rs:21:17 + --> $DIR/almost_complete_letter_range.rs:31:17 | LL | let _ = 'A' .. ('Z'); | ^^^^--^^^^^^ @@ -17,7 +17,7 @@ LL | let _ = 'A' .. ('Z'); | help: use an inclusive range: `..=` error: almost complete ascii letter range - --> $DIR/almost_complete_letter_range.rs:27:13 + --> $DIR/almost_complete_letter_range.rs:37:13 | LL | let _ = (b'a')..(b'z'); | ^^^^^^--^^^^^^ @@ -25,7 +25,7 @@ LL | let _ = (b'a')..(b'z'); | help: use an inclusive range: `..=` error: almost complete ascii letter range - --> $DIR/almost_complete_letter_range.rs:28:13 + --> $DIR/almost_complete_letter_range.rs:38:13 | LL | let _ = b'A'..b'Z'; | ^^^^--^^^^ @@ -33,7 +33,7 @@ LL | let _ = b'A'..b'Z'; | help: use an inclusive range: `..=` error: almost complete ascii letter range - --> $DIR/almost_complete_letter_range.rs:33:13 + --> $DIR/almost_complete_letter_range.rs:43:13 | LL | let _ = a!()..'z'; | ^^^^--^^^ @@ -41,7 +41,7 @@ LL | let _ = a!()..'z'; | help: use an inclusive range: `..=` error: almost complete ascii letter range - --> $DIR/almost_complete_letter_range.rs:36:9 + --> $DIR/almost_complete_letter_range.rs:46:9 | LL | b'a'..b'z' if true => 1, | ^^^^--^^^^ @@ -49,7 +49,7 @@ LL | b'a'..b'z' if true => 1, | help: use an inclusive range: `..=` error: almost complete ascii letter range - --> $DIR/almost_complete_letter_range.rs:37:9 + --> $DIR/almost_complete_letter_range.rs:47:9 | LL | b'A'..b'Z' if true => 2, | ^^^^--^^^^ @@ -57,7 +57,7 @@ LL | b'A'..b'Z' if true => 2, | help: use an inclusive range: `..=` error: almost complete ascii letter range - --> $DIR/almost_complete_letter_range.rs:44:9 + --> $DIR/almost_complete_letter_range.rs:54:9 | LL | 'a'..'z' if true => 1, | ^^^--^^^ @@ -65,7 +65,7 @@ LL | 'a'..'z' if true => 1, | help: use an inclusive range: `..=` error: almost complete ascii letter range - --> $DIR/almost_complete_letter_range.rs:45:9 + --> $DIR/almost_complete_letter_range.rs:55:9 | LL | 'A'..'Z' if true => 2, | ^^^--^^^ @@ -73,7 +73,20 @@ LL | 'A'..'Z' if true => 2, | help: use an inclusive range: `..=` error: almost complete ascii letter range - --> $DIR/almost_complete_letter_range.rs:55:9 + --> $DIR/almost_complete_letter_range.rs:23:17 + | +LL | let _ = 'a'..'z'; + | ^^^--^^^ + | | + | help: use an inclusive range: `..=` +... +LL | b!(); + | ---- in this macro invocation + | + = note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: almost complete ascii letter range + --> $DIR/almost_complete_letter_range.rs:68:9 | LL | 'a'..'z' => 1, | ^^^--^^^ @@ -81,7 +94,7 @@ LL | 'a'..'z' => 1, | help: use an inclusive range: `...` error: almost complete ascii letter range - --> $DIR/almost_complete_letter_range.rs:62:13 + --> $DIR/almost_complete_letter_range.rs:75:13 | LL | let _ = 'a'..'z'; | ^^^--^^^ @@ -89,12 +102,12 @@ LL | let _ = 'a'..'z'; | help: use an inclusive range: `..=` error: almost complete ascii letter range - --> $DIR/almost_complete_letter_range.rs:64:9 + --> $DIR/almost_complete_letter_range.rs:77:9 | LL | 'a'..'z' => 1, | ^^^--^^^ | | | help: use an inclusive range: `..=` -error: aborting due to 12 previous errors +error: aborting due to 13 previous errors diff --git a/tests/ui/arithmetic_side_effects.rs b/tests/ui/arithmetic_side_effects.rs index f5390c7464250..dd24f5aa592b3 100644 --- a/tests/ui/arithmetic_side_effects.rs +++ b/tests/ui/arithmetic_side_effects.rs @@ -1,9 +1,49 @@ -#![allow(clippy::assign_op_pattern, clippy::unnecessary_owned_empty_strings)] +#![allow( + clippy::assign_op_pattern, + clippy::erasing_op, + clippy::identity_op, + clippy::unnecessary_owned_empty_strings, + arithmetic_overflow, + unconditional_panic +)] #![feature(inline_const, saturating_int_impl)] #![warn(clippy::arithmetic_side_effects)] use core::num::{Saturating, Wrapping}; +pub fn association_with_structures_should_not_trigger_the_lint() { + enum Foo { + Bar = -2, + } + + impl Trait for Foo { + const ASSOC: i32 = { + let _: [i32; 1 + 1]; + fn foo() {} + 1 + 1 + }; + } + + struct Baz([i32; 1 + 1]); + + trait Trait { + const ASSOC: i32 = 1 + 1; + } + + type Alias = [i32; 1 + 1]; + + union Qux { + field: [i32; 1 + 1], + } + + let _: [i32; 1 + 1] = [0, 0]; + + let _: [i32; 1 + 1] = { + let a: [i32; 1 + 1] = [0, 0]; + a + }; +} + pub fn hard_coded_allowed() { let _ = 1f32 + 1f32; let _ = 1f64 + 1f64; @@ -26,7 +66,7 @@ pub fn hard_coded_allowed() { } #[rustfmt::skip] -pub fn non_overflowing_ops() { +pub fn const_ops_should_not_trigger_the_lint() { const _: i32 = { let mut n = 1; n += 1; n }; let _ = const { let mut n = 1; n += 1; n }; @@ -37,21 +77,63 @@ pub fn non_overflowing_ops() { let _ = const { let mut n = 1; n = 1 + n; n }; const _: i32 = 1 + 1; - let _ = 1 + 1; let _ = const { 1 + 1 }; - let mut _a = 1; - _a *= 1; - _a /= 1; + const _: i32 = { let mut n = -1; n = -(-1); n = -n; n }; + let _ = const { let mut n = -1; n = -(-1); n = -n; n }; } -#[rustfmt::skip] -pub fn overflowing_ops() { - let mut _a = 1; _a += 1; +pub fn non_overflowing_runtime_ops_or_ops_already_handled_by_the_compiler() { + let mut _n = i32::MAX; + + // Assign + _n += 0; + _n -= 0; + _n /= 99; + _n %= 99; + _n *= 0; + _n *= 1; + + // Binary + _n = _n + 0; + _n = 0 + _n; + _n = _n - 0; + _n = 0 - _n; + _n = _n / 99; + _n = _n % 99; + _n = _n * 0; + _n = 0 * _n; + _n = _n * 1; + _n = 1 * _n; + _n = 23 + 85; + + // Unary + _n = -1; + _n = -(-1); +} + +pub fn overflowing_runtime_ops() { + let mut _n = i32::MAX; + + // Assign + _n += 1; + _n -= 1; + _n /= 0; + _n %= 0; + _n *= 2; - let mut _b = 1; _b = _b + 1; + // Binary + _n = _n + 1; + _n = 1 + _n; + _n = _n - 1; + _n = 1 - _n; + _n = _n / 0; + _n = _n % 0; + _n = _n * 2; + _n = 2 * _n; - let mut _c = 1; _c = 1 + _c; + // Unary + _n = -_n; } fn main() {} diff --git a/tests/ui/arithmetic_side_effects.stderr b/tests/ui/arithmetic_side_effects.stderr index 6c4c8bdec0f05..a2a856efbffc0 100644 --- a/tests/ui/arithmetic_side_effects.stderr +++ b/tests/ui/arithmetic_side_effects.stderr @@ -1,22 +1,88 @@ -error: arithmetic detected - --> $DIR/arithmetic_side_effects.rs:50:21 +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:119:5 | -LL | let mut _a = 1; _a += 1; - | ^^^^^^^ +LL | _n += 1; + | ^^^^^^^ | = note: `-D clippy::arithmetic-side-effects` implied by `-D warnings` -error: arithmetic detected - --> $DIR/arithmetic_side_effects.rs:52:26 +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:120:5 | -LL | let mut _b = 1; _b = _b + 1; - | ^^^^^^ +LL | _n -= 1; + | ^^^^^^^ -error: arithmetic detected - --> $DIR/arithmetic_side_effects.rs:54:26 +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:121:5 | -LL | let mut _c = 1; _c = 1 + _c; - | ^^^^^^ +LL | _n /= 0; + | ^^^^^^^ -error: aborting due to 3 previous errors +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:122:5 + | +LL | _n %= 0; + | ^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:123:5 + | +LL | _n *= 2; + | ^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:126:10 + | +LL | _n = _n + 1; + | ^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:127:10 + | +LL | _n = 1 + _n; + | ^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:128:10 + | +LL | _n = _n - 1; + | ^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:129:10 + | +LL | _n = 1 - _n; + | ^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:130:10 + | +LL | _n = _n / 0; + | ^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:131:10 + | +LL | _n = _n % 0; + | ^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:132:10 + | +LL | _n = _n * 2; + | ^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:133:10 + | +LL | _n = 2 * _n; + | ^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:136:10 + | +LL | _n = -_n; + | ^^^ + +error: aborting due to 14 previous errors diff --git a/tests/ui/assertions_on_result_states.fixed b/tests/ui/assertions_on_result_states.fixed index 795f435f24cd4..2bb755290c508 100644 --- a/tests/ui/assertions_on_result_states.fixed +++ b/tests/ui/assertions_on_result_states.fixed @@ -75,3 +75,9 @@ fn main() { let r: Result = Err(Foo); assert!(r.is_err()); } + +#[allow(dead_code)] +fn issue9450() { + let res: Result = Ok(1); + res.unwrap_err(); +} diff --git a/tests/ui/assertions_on_result_states.rs b/tests/ui/assertions_on_result_states.rs index 1101aec1e1b34..d8a9bd2f1c455 100644 --- a/tests/ui/assertions_on_result_states.rs +++ b/tests/ui/assertions_on_result_states.rs @@ -75,3 +75,9 @@ fn main() { let r: Result = Err(Foo); assert!(r.is_err()); } + +#[allow(dead_code)] +fn issue9450() { + let res: Result = Ok(1); + assert!(res.is_err()) +} diff --git a/tests/ui/assertions_on_result_states.stderr b/tests/ui/assertions_on_result_states.stderr index 97a5f3dfca4a6..298d63c9c34fb 100644 --- a/tests/ui/assertions_on_result_states.stderr +++ b/tests/ui/assertions_on_result_states.stderr @@ -36,5 +36,11 @@ error: called `assert!` with `Result::is_err` LL | assert!(r.is_err()); | ^^^^^^^^^^^^^^^^^^^ help: replace with: `r.unwrap_err()` -error: aborting due to 6 previous errors +error: called `assert!` with `Result::is_err` + --> $DIR/assertions_on_result_states.rs:82:5 + | +LL | assert!(res.is_err()) + | ^^^^^^^^^^^^^^^^^^^^^ help: replace with: `res.unwrap_err();` + +error: aborting due to 7 previous errors diff --git a/tests/ui/auxiliary/macro_rules.rs b/tests/ui/auxiliary/macro_rules.rs index 83a0af6b87aca..ef3ca9aea380c 100644 --- a/tests/ui/auxiliary/macro_rules.rs +++ b/tests/ui/auxiliary/macro_rules.rs @@ -140,3 +140,10 @@ macro_rules! manual_rem_euclid { macro_rules! equatable_if_let { ($a:ident) => {{ if let 2 = $a {} }}; } + +#[macro_export] +macro_rules! almost_complete_letter_range { + () => { + let _ = 'a'..'z'; + }; +} diff --git a/tests/ui/bool_to_int_with_if.fixed b/tests/ui/bool_to_int_with_if.fixed index 9c1098dc4c17a..2c8339cdd7f8a 100644 --- a/tests/ui/bool_to_int_with_if.fixed +++ b/tests/ui/bool_to_int_with_if.fixed @@ -14,6 +14,7 @@ fn main() { // precedence i32::from(a); i32::from(!a); + i32::from(!a); i32::from(a || b); i32::from(cond(a, b)); i32::from(x + y < 4); @@ -21,7 +22,12 @@ fn main() { // if else if if a { 123 - } else {i32::from(b)}; + } else { i32::from(b) }; + + // if else if inverted + if a { + 123 + } else { i32::from(!b) }; // Shouldn't lint diff --git a/tests/ui/bool_to_int_with_if.rs b/tests/ui/bool_to_int_with_if.rs index 0c967dac6e2dd..5d9496f01775f 100644 --- a/tests/ui/bool_to_int_with_if.rs +++ b/tests/ui/bool_to_int_with_if.rs @@ -17,6 +17,11 @@ fn main() { } else { 0 }; + if a { + 0 + } else { + 1 + }; if !a { 1 } else { @@ -47,6 +52,15 @@ fn main() { 0 }; + // if else if inverted + if a { + 123 + } else if b { + 0 + } else { + 1 + }; + // Shouldn't lint if a { diff --git a/tests/ui/bool_to_int_with_if.stderr b/tests/ui/bool_to_int_with_if.stderr index 8647a9cffbede..e695440f6682f 100644 --- a/tests/ui/bool_to_int_with_if.stderr +++ b/tests/ui/bool_to_int_with_if.stderr @@ -14,6 +14,18 @@ LL | | }; error: boolean to int conversion using if --> $DIR/bool_to_int_with_if.rs:20:5 | +LL | / if a { +LL | | 0 +LL | | } else { +LL | | 1 +LL | | }; + | |_____^ help: replace with from: `i32::from(!a)` + | + = note: `!a as i32` or `(!a).into()` can also be valid options + +error: boolean to int conversion using if + --> $DIR/bool_to_int_with_if.rs:25:5 + | LL | / if !a { LL | | 1 LL | | } else { @@ -21,10 +33,10 @@ LL | | 0 LL | | }; | |_____^ help: replace with from: `i32::from(!a)` | - = note: `!a as i32` or `!a.into()` can also be valid options + = note: `!a as i32` or `(!a).into()` can also be valid options error: boolean to int conversion using if - --> $DIR/bool_to_int_with_if.rs:25:5 + --> $DIR/bool_to_int_with_if.rs:30:5 | LL | / if a || b { LL | | 1 @@ -36,7 +48,7 @@ LL | | }; = note: `(a || b) as i32` or `(a || b).into()` can also be valid options error: boolean to int conversion using if - --> $DIR/bool_to_int_with_if.rs:30:5 + --> $DIR/bool_to_int_with_if.rs:35:5 | LL | / if cond(a, b) { LL | | 1 @@ -48,7 +60,7 @@ LL | | }; = note: `cond(a, b) as i32` or `cond(a, b).into()` can also be valid options error: boolean to int conversion using if - --> $DIR/bool_to_int_with_if.rs:35:5 + --> $DIR/bool_to_int_with_if.rs:40:5 | LL | / if x + y < 4 { LL | | 1 @@ -60,7 +72,7 @@ LL | | }; = note: `(x + y < 4) as i32` or `(x + y < 4).into()` can also be valid options error: boolean to int conversion using if - --> $DIR/bool_to_int_with_if.rs:44:12 + --> $DIR/bool_to_int_with_if.rs:49:12 | LL | } else if b { | ____________^ @@ -68,17 +80,30 @@ LL | | 1 LL | | } else { LL | | 0 LL | | }; - | |_____^ help: replace with from: `{i32::from(b)}` + | |_____^ help: replace with from: `{ i32::from(b) }` | = note: `b as i32` or `b.into()` can also be valid options error: boolean to int conversion using if - --> $DIR/bool_to_int_with_if.rs:102:5 + --> $DIR/bool_to_int_with_if.rs:58:12 + | +LL | } else if b { + | ____________^ +LL | | 0 +LL | | } else { +LL | | 1 +LL | | }; + | |_____^ help: replace with from: `{ i32::from(!b) }` + | + = note: `!b as i32` or `(!b).into()` can also be valid options + +error: boolean to int conversion using if + --> $DIR/bool_to_int_with_if.rs:116:5 | LL | if a { 1 } else { 0 } | ^^^^^^^^^^^^^^^^^^^^^ help: replace with from: `u8::from(a)` | = note: `a as u8` or `a.into()` can also be valid options -error: aborting due to 7 previous errors +error: aborting due to 9 previous errors diff --git a/tests/ui/collapsible_if.fixed b/tests/ui/collapsible_if.fixed index 5b0e4a473c4ad..6bb7682bae953 100644 --- a/tests/ui/collapsible_if.fixed +++ b/tests/ui/collapsible_if.fixed @@ -139,6 +139,9 @@ fn main() { // Fix #5962 if matches!(true, true) && matches!(true, true) {} + // Issue #9375 + if matches!(true, true) && truth() && matches!(true, true) {} + if true { #[cfg(not(teehee))] if true { diff --git a/tests/ui/collapsible_if.rs b/tests/ui/collapsible_if.rs index cd231a5d7abb0..e216a9ee54c90 100644 --- a/tests/ui/collapsible_if.rs +++ b/tests/ui/collapsible_if.rs @@ -155,6 +155,11 @@ fn main() { if matches!(true, true) {} } + // Issue #9375 + if matches!(true, true) && truth() { + if matches!(true, true) {} + } + if true { #[cfg(not(teehee))] if true { diff --git a/tests/ui/collapsible_if.stderr b/tests/ui/collapsible_if.stderr index 6749612388fe3..6327444df21d7 100644 --- a/tests/ui/collapsible_if.stderr +++ b/tests/ui/collapsible_if.stderr @@ -126,5 +126,13 @@ LL | | if matches!(true, true) {} LL | | } | |_____^ help: collapse nested if block: `if matches!(true, true) && matches!(true, true) {}` -error: aborting due to 8 previous errors +error: this `if` statement can be collapsed + --> $DIR/collapsible_if.rs:159:5 + | +LL | / if matches!(true, true) && truth() { +LL | | if matches!(true, true) {} +LL | | } + | |_____^ help: collapse nested if block: `if matches!(true, true) && truth() && matches!(true, true) {}` + +error: aborting due to 9 previous errors diff --git a/tests/ui/crashes/ice-9463.rs b/tests/ui/crashes/ice-9463.rs new file mode 100644 index 0000000000000..41ef930d3233d --- /dev/null +++ b/tests/ui/crashes/ice-9463.rs @@ -0,0 +1,5 @@ +#![deny(arithmetic_overflow, const_err)] +fn main() { + let _x = -1_i32 >> -1; + let _y = 1u32 >> 10000000000000u32; +} diff --git a/tests/ui/crashes/ice-9463.stderr b/tests/ui/crashes/ice-9463.stderr new file mode 100644 index 0000000000000..7daa08aeb6c94 --- /dev/null +++ b/tests/ui/crashes/ice-9463.stderr @@ -0,0 +1,29 @@ +error: this arithmetic operation will overflow + --> $DIR/ice-9463.rs:3:14 + | +LL | let _x = -1_i32 >> -1; + | ^^^^^^^^^^^^ attempt to shift right by `-1_i32`, which would overflow + | +note: the lint level is defined here + --> $DIR/ice-9463.rs:1:9 + | +LL | #![deny(arithmetic_overflow, const_err)] + | ^^^^^^^^^^^^^^^^^^^ + +error: this arithmetic operation will overflow + --> $DIR/ice-9463.rs:4:14 + | +LL | let _y = 1u32 >> 10000000000000u32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to shift right by `1316134912_u32`, which would overflow + +error: literal out of range for `u32` + --> $DIR/ice-9463.rs:4:22 + | +LL | let _y = 1u32 >> 10000000000000u32; + | ^^^^^^^^^^^^^^^^^ + | + = note: `#[deny(overflowing_literals)]` on by default + = note: the literal `10000000000000u32` does not fit into the type `u32` whose range is `0..=4294967295` + +error: aborting due to 3 previous errors + diff --git a/tests/ui/derivable_impls.fixed b/tests/ui/derivable_impls.fixed new file mode 100644 index 0000000000000..7dcdfb0937e89 --- /dev/null +++ b/tests/ui/derivable_impls.fixed @@ -0,0 +1,213 @@ +// run-rustfix + +#![allow(dead_code)] + +use std::collections::HashMap; + +#[derive(Default)] +struct FooDefault<'a> { + a: bool, + b: i32, + c: u64, + d: Vec, + e: FooND1, + f: FooND2, + g: HashMap, + h: (i32, Vec), + i: [Vec; 3], + j: [i32; 5], + k: Option, + l: &'a [i32], +} + + + +#[derive(Default)] +struct TupleDefault(bool, i32, u64); + + + +struct FooND1 { + a: bool, +} + +impl std::default::Default for FooND1 { + fn default() -> Self { + Self { a: true } + } +} + +struct FooND2 { + a: i32, +} + +impl std::default::Default for FooND2 { + fn default() -> Self { + Self { a: 5 } + } +} + +struct FooNDNew { + a: bool, +} + +impl FooNDNew { + fn new() -> Self { + Self { a: true } + } +} + +impl Default for FooNDNew { + fn default() -> Self { + Self::new() + } +} + +struct FooNDVec(Vec); + +impl Default for FooNDVec { + fn default() -> Self { + Self(vec![5, 12]) + } +} + +#[derive(Default)] +struct StrDefault<'a>(&'a str); + + + +#[derive(Default)] +struct AlreadyDerived(i32, bool); + +macro_rules! mac { + () => { + 0 + }; + ($e:expr) => { + struct X(u32); + impl Default for X { + fn default() -> Self { + Self($e) + } + } + }; +} + +mac!(0); + +#[derive(Default)] +struct Y(u32); + + +struct RustIssue26925 { + a: Option, +} + +// We should watch out for cases where a manual impl is needed because a +// derive adds different type bounds (https://github.com/rust-lang/rust/issues/26925). +// For example, a struct with Option does not require T: Default, but a derive adds +// that type bound anyways. So until #26925 get fixed we should disable lint +// for the following case +impl Default for RustIssue26925 { + fn default() -> Self { + Self { a: None } + } +} + +struct SpecializedImpl { + a: A, + b: B, +} + +impl Default for SpecializedImpl { + fn default() -> Self { + Self { + a: T::default(), + b: T::default(), + } + } +} + +#[derive(Default)] +struct WithoutSelfCurly { + a: bool, +} + + + +#[derive(Default)] +struct WithoutSelfParan(bool); + + + +// https://github.com/rust-lang/rust-clippy/issues/7655 + +pub struct SpecializedImpl2 { + v: Vec, +} + +impl Default for SpecializedImpl2 { + fn default() -> Self { + Self { v: Vec::new() } + } +} + +// https://github.com/rust-lang/rust-clippy/issues/7654 + +pub struct Color { + pub r: u8, + pub g: u8, + pub b: u8, +} + +/// `#000000` +impl Default for Color { + fn default() -> Self { + Color { r: 0, g: 0, b: 0 } + } +} + +pub struct Color2 { + pub r: u8, + pub g: u8, + pub b: u8, +} + +impl Default for Color2 { + /// `#000000` + fn default() -> Self { + Self { r: 0, g: 0, b: 0 } + } +} + +#[derive(Default)] +pub struct RepeatDefault1 { + a: [i8; 32], +} + + + +pub struct RepeatDefault2 { + a: [i8; 33], +} + +impl Default for RepeatDefault2 { + fn default() -> Self { + RepeatDefault2 { a: [0; 33] } + } +} + +// https://github.com/rust-lang/rust-clippy/issues/7753 + +pub enum IntOrString { + Int(i32), + String(String), +} + +impl Default for IntOrString { + fn default() -> Self { + IntOrString::Int(0) + } +} + +fn main() {} diff --git a/tests/ui/derivable_impls.rs b/tests/ui/derivable_impls.rs index a6412004726d3..625cbcdde230a 100644 --- a/tests/ui/derivable_impls.rs +++ b/tests/ui/derivable_impls.rs @@ -1,3 +1,7 @@ +// run-rustfix + +#![allow(dead_code)] + use std::collections::HashMap; struct FooDefault<'a> { diff --git a/tests/ui/derivable_impls.stderr b/tests/ui/derivable_impls.stderr index 49fb471a21962..c1db5a58b1f51 100644 --- a/tests/ui/derivable_impls.stderr +++ b/tests/ui/derivable_impls.stderr @@ -1,5 +1,5 @@ error: this `impl` can be derived - --> $DIR/derivable_impls.rs:18:1 + --> $DIR/derivable_impls.rs:22:1 | LL | / impl std::default::Default for FooDefault<'_> { LL | | fn default() -> Self { @@ -11,10 +11,14 @@ LL | | } | |_^ | = note: `-D clippy::derivable-impls` implied by `-D warnings` - = help: try annotating `FooDefault` with `#[derive(Default)]` + = help: remove the manual implementation... +help: ...and instead derive it + | +LL | #[derive(Default)] + | error: this `impl` can be derived - --> $DIR/derivable_impls.rs:39:1 + --> $DIR/derivable_impls.rs:43:1 | LL | / impl std::default::Default for TupleDefault { LL | | fn default() -> Self { @@ -23,10 +27,14 @@ LL | | } LL | | } | |_^ | - = help: try annotating `TupleDefault` with `#[derive(Default)]` + = help: remove the manual implementation... +help: ...and instead derive it + | +LL | #[derive(Default)] + | error: this `impl` can be derived - --> $DIR/derivable_impls.rs:91:1 + --> $DIR/derivable_impls.rs:95:1 | LL | / impl Default for StrDefault<'_> { LL | | fn default() -> Self { @@ -35,10 +43,14 @@ LL | | } LL | | } | |_^ | - = help: try annotating `StrDefault` with `#[derive(Default)]` + = help: remove the manual implementation... +help: ...and instead derive it + | +LL | #[derive(Default)] + | error: this `impl` can be derived - --> $DIR/derivable_impls.rs:117:1 + --> $DIR/derivable_impls.rs:121:1 | LL | / impl Default for Y { LL | | fn default() -> Self { @@ -47,10 +59,14 @@ LL | | } LL | | } | |_^ | - = help: try annotating `Y` with `#[derive(Default)]` + = help: remove the manual implementation... +help: ...and instead derive it + | +LL | #[derive(Default)] + | error: this `impl` can be derived - --> $DIR/derivable_impls.rs:156:1 + --> $DIR/derivable_impls.rs:160:1 | LL | / impl Default for WithoutSelfCurly { LL | | fn default() -> Self { @@ -59,10 +75,14 @@ LL | | } LL | | } | |_^ | - = help: try annotating `WithoutSelfCurly` with `#[derive(Default)]` + = help: remove the manual implementation... +help: ...and instead derive it + | +LL | #[derive(Default)] + | error: this `impl` can be derived - --> $DIR/derivable_impls.rs:164:1 + --> $DIR/derivable_impls.rs:168:1 | LL | / impl Default for WithoutSelfParan { LL | | fn default() -> Self { @@ -71,10 +91,14 @@ LL | | } LL | | } | |_^ | - = help: try annotating `WithoutSelfParan` with `#[derive(Default)]` + = help: remove the manual implementation... +help: ...and instead derive it + | +LL | #[derive(Default)] + | error: this `impl` can be derived - --> $DIR/derivable_impls.rs:214:1 + --> $DIR/derivable_impls.rs:218:1 | LL | / impl Default for RepeatDefault1 { LL | | fn default() -> Self { @@ -83,7 +107,11 @@ LL | | } LL | | } | |_^ | - = help: try annotating `RepeatDefault1` with `#[derive(Default)]` + = help: remove the manual implementation... +help: ...and instead derive it + | +LL | #[derive(Default)] + | error: aborting due to 7 previous errors diff --git a/tests/ui/eprint_with_newline.rs b/tests/ui/eprint_with_newline.rs index 8df32649ad948..de5e121be8774 100644 --- a/tests/ui/eprint_with_newline.rs +++ b/tests/ui/eprint_with_newline.rs @@ -45,5 +45,13 @@ fn main() { eprint!("\r\n"); eprint!("foo\r\n"); eprint!("\\r\n"); //~ ERROR - eprint!("foo\rbar\n") // ~ ERROR + eprint!("foo\rbar\n"); + + // Ignore expanded format strings + macro_rules! newline { + () => { + "\n" + }; + } + eprint!(newline!()); } diff --git a/tests/ui/eprint_with_newline.stderr b/tests/ui/eprint_with_newline.stderr index f137787bff0c7..0eefb9f0ca978 100644 --- a/tests/ui/eprint_with_newline.stderr +++ b/tests/ui/eprint_with_newline.stderr @@ -83,7 +83,7 @@ LL | | ); help: use `eprintln!` instead | LL ~ eprintln!( -LL ~ "" +LL ~ | error: using `eprint!()` with a format string that ends in a single newline @@ -98,7 +98,7 @@ LL | | ); help: use `eprintln!` instead | LL ~ eprintln!( -LL ~ r"" +LL ~ | error: using `eprint!()` with a format string that ends in a single newline @@ -113,17 +113,5 @@ LL - eprint!("/r/n"); //~ ERROR LL + eprintln!("/r"); //~ ERROR | -error: using `eprint!()` with a format string that ends in a single newline - --> $DIR/eprint_with_newline.rs:48:5 - | -LL | eprint!("foo/rbar/n") // ~ ERROR - | ^^^^^^^^^^^^^^^^^^^^^ - | -help: use `eprintln!` instead - | -LL - eprint!("foo/rbar/n") // ~ ERROR -LL + eprintln!("foo/rbar") // ~ ERROR - | - -error: aborting due to 10 previous errors +error: aborting due to 9 previous errors diff --git a/tests/ui/explicit_write.fixed b/tests/ui/explicit_write.fixed index 74d0e5290282a..35283725619ae 100644 --- a/tests/ui/explicit_write.fixed +++ b/tests/ui/explicit_write.fixed @@ -36,6 +36,8 @@ fn main() { eprintln!("with {} {}", 2, value); eprintln!("with {value}"); eprintln!("macro arg {}", one!()); + let width = 2; + eprintln!("{:w$}", value, w = width); } // these should not warn, different destination { diff --git a/tests/ui/explicit_write.rs b/tests/ui/explicit_write.rs index e7a698d3e012d..be864a55b663f 100644 --- a/tests/ui/explicit_write.rs +++ b/tests/ui/explicit_write.rs @@ -36,6 +36,8 @@ fn main() { writeln!(std::io::stderr(), "with {} {}", 2, value).unwrap(); writeln!(std::io::stderr(), "with {value}").unwrap(); writeln!(std::io::stderr(), "macro arg {}", one!()).unwrap(); + let width = 2; + writeln!(std::io::stderr(), "{:w$}", value, w = width).unwrap(); } // these should not warn, different destination { diff --git a/tests/ui/explicit_write.stderr b/tests/ui/explicit_write.stderr index 29ae0cdece249..ff05f4343d77d 100644 --- a/tests/ui/explicit_write.stderr +++ b/tests/ui/explicit_write.stderr @@ -72,5 +72,11 @@ error: use of `writeln!(stderr(), ...).unwrap()` LL | writeln!(std::io::stderr(), "macro arg {}", one!()).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprintln!("macro arg {}", one!())` -error: aborting due to 12 previous errors +error: use of `writeln!(stderr(), ...).unwrap()` + --> $DIR/explicit_write.rs:40:9 + | +LL | writeln!(std::io::stderr(), "{:w$}", value, w = width).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprintln!("{:w$}", value, w = width)` + +error: aborting due to 13 previous errors diff --git a/tests/ui/format.fixed b/tests/ui/format.fixed index b56d6aec508d3..e0c5f692740a1 100644 --- a/tests/ui/format.fixed +++ b/tests/ui/format.fixed @@ -28,8 +28,6 @@ fn main() { format!("{:?}", "foo"); // Don't warn about `Debug`. format!("{:8}", "foo"); format!("{:width$}", "foo", width = 8); - "foo".to_string(); // Warn when the format makes no difference. - "foo".to_string(); // Warn when the format makes no difference. format!("foo {}", "bar"); format!("{} bar", "foo"); @@ -38,8 +36,6 @@ fn main() { format!("{:?}", arg); // Don't warn about debug. format!("{:8}", arg); format!("{:width$}", arg, width = 8); - arg.to_string(); // Warn when the format makes no difference. - arg.to_string(); // Warn when the format makes no difference. format!("foo {}", arg); format!("{} bar", arg); diff --git a/tests/ui/format.rs b/tests/ui/format.rs index 4c1a3a840ed96..ff83cd64bf09c 100644 --- a/tests/ui/format.rs +++ b/tests/ui/format.rs @@ -30,8 +30,6 @@ fn main() { format!("{:?}", "foo"); // Don't warn about `Debug`. format!("{:8}", "foo"); format!("{:width$}", "foo", width = 8); - format!("{:+}", "foo"); // Warn when the format makes no difference. - format!("{:<}", "foo"); // Warn when the format makes no difference. format!("foo {}", "bar"); format!("{} bar", "foo"); @@ -40,8 +38,6 @@ fn main() { format!("{:?}", arg); // Don't warn about debug. format!("{:8}", arg); format!("{:width$}", arg, width = 8); - format!("{:+}", arg); // Warn when the format makes no difference. - format!("{:<}", arg); // Warn when the format makes no difference. format!("foo {}", arg); format!("{} bar", arg); diff --git a/tests/ui/format.stderr b/tests/ui/format.stderr index 6c35caeb034d0..0ef0ac655d394 100644 --- a/tests/ui/format.stderr +++ b/tests/ui/format.stderr @@ -46,82 +46,58 @@ LL | format!("{}", "foo"); | ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()` error: useless use of `format!` - --> $DIR/format.rs:33:5 - | -LL | format!("{:+}", "foo"); // Warn when the format makes no difference. - | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()` - -error: useless use of `format!` - --> $DIR/format.rs:34:5 - | -LL | format!("{:<}", "foo"); // Warn when the format makes no difference. - | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()` - -error: useless use of `format!` - --> $DIR/format.rs:39:5 + --> $DIR/format.rs:37:5 | LL | format!("{}", arg); | ^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()` error: useless use of `format!` - --> $DIR/format.rs:43:5 - | -LL | format!("{:+}", arg); // Warn when the format makes no difference. - | ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()` - -error: useless use of `format!` - --> $DIR/format.rs:44:5 - | -LL | format!("{:<}", arg); // Warn when the format makes no difference. - | ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()` - -error: useless use of `format!` - --> $DIR/format.rs:71:5 + --> $DIR/format.rs:67:5 | LL | format!("{}", 42.to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `42.to_string()` error: useless use of `format!` - --> $DIR/format.rs:73:5 + --> $DIR/format.rs:69:5 | LL | format!("{}", x.display().to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.display().to_string()` error: useless use of `format!` - --> $DIR/format.rs:77:18 + --> $DIR/format.rs:73:18 | LL | let _ = Some(format!("{}", a + "bar")); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `a + "bar"` error: useless use of `format!` - --> $DIR/format.rs:81:22 + --> $DIR/format.rs:77:22 | LL | let _s: String = format!("{}", &*v.join("/n")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `(&*v.join("/n")).to_string()` error: useless use of `format!` - --> $DIR/format.rs:87:13 + --> $DIR/format.rs:83:13 | LL | let _ = format!("{x}"); | ^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()` error: useless use of `format!` - --> $DIR/format.rs:89:13 + --> $DIR/format.rs:85:13 | LL | let _ = format!("{y}", y = x); | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()` error: useless use of `format!` - --> $DIR/format.rs:93:13 + --> $DIR/format.rs:89:13 | LL | let _ = format!("{abc}"); | ^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `abc.to_string()` error: useless use of `format!` - --> $DIR/format.rs:95:13 + --> $DIR/format.rs:91:13 | LL | let _ = format!("{xx}"); | ^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `xx.to_string()` -error: aborting due to 19 previous errors +error: aborting due to 15 previous errors diff --git a/tests/ui/iter_kv_map.fixed b/tests/ui/iter_kv_map.fixed new file mode 100644 index 0000000000000..83fee04080fa7 --- /dev/null +++ b/tests/ui/iter_kv_map.fixed @@ -0,0 +1,64 @@ +// run-rustfix + +#![warn(clippy::iter_kv_map)] +#![allow(clippy::redundant_clone)] +#![allow(clippy::suspicious_map)] +#![allow(clippy::map_identity)] + +use std::collections::{BTreeMap, HashMap}; + +fn main() { + let get_key = |(key, _val)| key; + + let map: HashMap = HashMap::new(); + + let _ = map.keys().collect::>(); + let _ = map.values().collect::>(); + let _ = map.values().map(|v| v + 2).collect::>(); + + let _ = map.clone().into_keys().collect::>(); + let _ = map.clone().into_keys().map(|key| key + 2).collect::>(); + + let _ = map.clone().into_values().collect::>(); + let _ = map.clone().into_values().map(|val| val + 2).collect::>(); + + let _ = map.clone().values().collect::>(); + let _ = map.keys().filter(|x| *x % 2 == 0).count(); + + // Don't lint + let _ = map.iter().filter(|(_, val)| *val % 2 == 0).map(|(key, _)| key).count(); + let _ = map.iter().map(get_key).collect::>(); + + // Linting the following could be an improvement to the lint + // map.iter().filter_map(|(_, val)| (val % 2 == 0).then(val * 17)).count(); + + // Lint + let _ = map.keys().map(|key| key * 9).count(); + let _ = map.values().map(|value| value * 17).count(); + + let map: BTreeMap = BTreeMap::new(); + + let _ = map.keys().collect::>(); + let _ = map.values().collect::>(); + let _ = map.values().map(|v| v + 2).collect::>(); + + let _ = map.clone().into_keys().collect::>(); + let _ = map.clone().into_keys().map(|key| key + 2).collect::>(); + + let _ = map.clone().into_values().collect::>(); + let _ = map.clone().into_values().map(|val| val + 2).collect::>(); + + let _ = map.clone().values().collect::>(); + let _ = map.keys().filter(|x| *x % 2 == 0).count(); + + // Don't lint + let _ = map.iter().filter(|(_, val)| *val % 2 == 0).map(|(key, _)| key).count(); + let _ = map.iter().map(get_key).collect::>(); + + // Linting the following could be an improvement to the lint + // map.iter().filter_map(|(_, val)| (val % 2 == 0).then(val * 17)).count(); + + // Lint + let _ = map.keys().map(|key| key * 9).count(); + let _ = map.values().map(|value| value * 17).count(); +} diff --git a/tests/ui/iter_kv_map.rs b/tests/ui/iter_kv_map.rs new file mode 100644 index 0000000000000..7a1f1fb0198c7 --- /dev/null +++ b/tests/ui/iter_kv_map.rs @@ -0,0 +1,64 @@ +// run-rustfix + +#![warn(clippy::iter_kv_map)] +#![allow(clippy::redundant_clone)] +#![allow(clippy::suspicious_map)] +#![allow(clippy::map_identity)] + +use std::collections::{BTreeMap, HashMap}; + +fn main() { + let get_key = |(key, _val)| key; + + let map: HashMap = HashMap::new(); + + let _ = map.iter().map(|(key, _)| key).collect::>(); + let _ = map.iter().map(|(_, value)| value).collect::>(); + let _ = map.iter().map(|(_, v)| v + 2).collect::>(); + + let _ = map.clone().into_iter().map(|(key, _)| key).collect::>(); + let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::>(); + + let _ = map.clone().into_iter().map(|(_, val)| val).collect::>(); + let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::>(); + + let _ = map.clone().iter().map(|(_, val)| val).collect::>(); + let _ = map.iter().map(|(key, _)| key).filter(|x| *x % 2 == 0).count(); + + // Don't lint + let _ = map.iter().filter(|(_, val)| *val % 2 == 0).map(|(key, _)| key).count(); + let _ = map.iter().map(get_key).collect::>(); + + // Linting the following could be an improvement to the lint + // map.iter().filter_map(|(_, val)| (val % 2 == 0).then(val * 17)).count(); + + // Lint + let _ = map.iter().map(|(key, _value)| key * 9).count(); + let _ = map.iter().map(|(_key, value)| value * 17).count(); + + let map: BTreeMap = BTreeMap::new(); + + let _ = map.iter().map(|(key, _)| key).collect::>(); + let _ = map.iter().map(|(_, value)| value).collect::>(); + let _ = map.iter().map(|(_, v)| v + 2).collect::>(); + + let _ = map.clone().into_iter().map(|(key, _)| key).collect::>(); + let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::>(); + + let _ = map.clone().into_iter().map(|(_, val)| val).collect::>(); + let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::>(); + + let _ = map.clone().iter().map(|(_, val)| val).collect::>(); + let _ = map.iter().map(|(key, _)| key).filter(|x| *x % 2 == 0).count(); + + // Don't lint + let _ = map.iter().filter(|(_, val)| *val % 2 == 0).map(|(key, _)| key).count(); + let _ = map.iter().map(get_key).collect::>(); + + // Linting the following could be an improvement to the lint + // map.iter().filter_map(|(_, val)| (val % 2 == 0).then(val * 17)).count(); + + // Lint + let _ = map.iter().map(|(key, _value)| key * 9).count(); + let _ = map.iter().map(|(_key, value)| value * 17).count(); +} diff --git a/tests/ui/iter_kv_map.stderr b/tests/ui/iter_kv_map.stderr new file mode 100644 index 0000000000000..9b9b04c97d81e --- /dev/null +++ b/tests/ui/iter_kv_map.stderr @@ -0,0 +1,136 @@ +error: iterating on a map's keys + --> $DIR/iter_kv_map.rs:15:13 + | +LL | let _ = map.iter().map(|(key, _)| key).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()` + | + = note: `-D clippy::iter-kv-map` implied by `-D warnings` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:16:13 + | +LL | let _ = map.iter().map(|(_, value)| value).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values()` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:17:13 + | +LL | let _ = map.iter().map(|(_, v)| v + 2).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)` + +error: iterating on a map's keys + --> $DIR/iter_kv_map.rs:19:13 + | +LL | let _ = map.clone().into_iter().map(|(key, _)| key).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys()` + +error: iterating on a map's keys + --> $DIR/iter_kv_map.rs:20:13 + | +LL | let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys().map(|key| key + 2)` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:22:13 + | +LL | let _ = map.clone().into_iter().map(|(_, val)| val).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:23:13 + | +LL | let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|val| val + 2)` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:25:13 + | +LL | let _ = map.clone().iter().map(|(_, val)| val).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().values()` + +error: iterating on a map's keys + --> $DIR/iter_kv_map.rs:26:13 + | +LL | let _ = map.iter().map(|(key, _)| key).filter(|x| *x % 2 == 0).count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()` + +error: iterating on a map's keys + --> $DIR/iter_kv_map.rs:36:13 + | +LL | let _ = map.iter().map(|(key, _value)| key * 9).count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys().map(|key| key * 9)` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:37:13 + | +LL | let _ = map.iter().map(|(_key, value)| value * 17).count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|value| value * 17)` + +error: iterating on a map's keys + --> $DIR/iter_kv_map.rs:41:13 + | +LL | let _ = map.iter().map(|(key, _)| key).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:42:13 + | +LL | let _ = map.iter().map(|(_, value)| value).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values()` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:43:13 + | +LL | let _ = map.iter().map(|(_, v)| v + 2).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)` + +error: iterating on a map's keys + --> $DIR/iter_kv_map.rs:45:13 + | +LL | let _ = map.clone().into_iter().map(|(key, _)| key).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys()` + +error: iterating on a map's keys + --> $DIR/iter_kv_map.rs:46:13 + | +LL | let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys().map(|key| key + 2)` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:48:13 + | +LL | let _ = map.clone().into_iter().map(|(_, val)| val).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:49:13 + | +LL | let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|val| val + 2)` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:51:13 + | +LL | let _ = map.clone().iter().map(|(_, val)| val).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().values()` + +error: iterating on a map's keys + --> $DIR/iter_kv_map.rs:52:13 + | +LL | let _ = map.iter().map(|(key, _)| key).filter(|x| *x % 2 == 0).count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()` + +error: iterating on a map's keys + --> $DIR/iter_kv_map.rs:62:13 + | +LL | let _ = map.iter().map(|(key, _value)| key * 9).count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys().map(|key| key * 9)` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:63:13 + | +LL | let _ = map.iter().map(|(_key, value)| value * 17).count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|value| value * 17)` + +error: aborting due to 22 previous errors + diff --git a/tests/ui/large_enum_variant.rs b/tests/ui/large_enum_variant.rs index 717009e4c4cca..3b96f09d7b1d6 100644 --- a/tests/ui/large_enum_variant.rs +++ b/tests/ui/large_enum_variant.rs @@ -101,12 +101,12 @@ struct Struct2 { #[derive(Copy, Clone)] enum CopyableLargeEnum { A(bool), - B([u128; 4000]), + B([u64; 8000]), } enum ManuallyCopyLargeEnum { A(bool), - B([u128; 4000]), + B([u64; 8000]), } impl Clone for ManuallyCopyLargeEnum { diff --git a/tests/ui/large_enum_variant.stderr b/tests/ui/large_enum_variant.stderr index c6ed97487c0e3..709972b4a6e49 100644 --- a/tests/ui/large_enum_variant.stderr +++ b/tests/ui/large_enum_variant.stderr @@ -167,8 +167,8 @@ error: large size difference between variants LL | / enum CopyableLargeEnum { LL | | A(bool), | | ------- the second-largest variant contains at least 1 bytes -LL | | B([u128; 4000]), - | | --------------- the largest variant contains at least 64000 bytes +LL | | B([u64; 8000]), + | | -------------- the largest variant contains at least 64000 bytes LL | | } | |_^ the entire enum is at least 64008 bytes | @@ -180,8 +180,8 @@ LL | enum CopyableLargeEnum { help: consider boxing the large fields to reduce the total size of the enum --> $DIR/large_enum_variant.rs:104:5 | -LL | B([u128; 4000]), - | ^^^^^^^^^^^^^^^ +LL | B([u64; 8000]), + | ^^^^^^^^^^^^^^ error: large size difference between variants --> $DIR/large_enum_variant.rs:107:1 @@ -189,8 +189,8 @@ error: large size difference between variants LL | / enum ManuallyCopyLargeEnum { LL | | A(bool), | | ------- the second-largest variant contains at least 1 bytes -LL | | B([u128; 4000]), - | | --------------- the largest variant contains at least 64000 bytes +LL | | B([u64; 8000]), + | | -------------- the largest variant contains at least 64000 bytes LL | | } | |_^ the entire enum is at least 64008 bytes | @@ -202,8 +202,8 @@ LL | enum ManuallyCopyLargeEnum { help: consider boxing the large fields to reduce the total size of the enum --> $DIR/large_enum_variant.rs:109:5 | -LL | B([u128; 4000]), - | ^^^^^^^^^^^^^^^ +LL | B([u64; 8000]), + | ^^^^^^^^^^^^^^ error: large size difference between variants --> $DIR/large_enum_variant.rs:120:1 diff --git a/tests/ui/large_stack_arrays.rs b/tests/ui/large_stack_arrays.rs index d9161bfcf1543..6790765f803e0 100644 --- a/tests/ui/large_stack_arrays.rs +++ b/tests/ui/large_stack_arrays.rs @@ -12,6 +12,12 @@ enum E { T(u32), } +pub static DOESNOTLINT: [u8; 512_001] = [0; 512_001]; +pub static DOESNOTLINT2: [u8; 512_001] = { + let x = 0; + [x; 512_001] +}; + fn main() { let bad = ( [0u32; 20_000_000], diff --git a/tests/ui/large_stack_arrays.stderr b/tests/ui/large_stack_arrays.stderr index 58c0a77c1c841..0d91b65b42840 100644 --- a/tests/ui/large_stack_arrays.stderr +++ b/tests/ui/large_stack_arrays.stderr @@ -1,5 +1,5 @@ error: allocating a local array larger than 512000 bytes - --> $DIR/large_stack_arrays.rs:17:9 + --> $DIR/large_stack_arrays.rs:23:9 | LL | [0u32; 20_000_000], | ^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | [0u32; 20_000_000], = help: consider allocating on the heap with `vec![0u32; 20_000_000].into_boxed_slice()` error: allocating a local array larger than 512000 bytes - --> $DIR/large_stack_arrays.rs:18:9 + --> $DIR/large_stack_arrays.rs:24:9 | LL | [S { data: [0; 32] }; 5000], | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | [S { data: [0; 32] }; 5000], = help: consider allocating on the heap with `vec![S { data: [0; 32] }; 5000].into_boxed_slice()` error: allocating a local array larger than 512000 bytes - --> $DIR/large_stack_arrays.rs:19:9 + --> $DIR/large_stack_arrays.rs:25:9 | LL | [Some(""); 20_000_000], | ^^^^^^^^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL | [Some(""); 20_000_000], = help: consider allocating on the heap with `vec![Some(""); 20_000_000].into_boxed_slice()` error: allocating a local array larger than 512000 bytes - --> $DIR/large_stack_arrays.rs:20:9 + --> $DIR/large_stack_arrays.rs:26:9 | LL | [E::T(0); 5000], | ^^^^^^^^^^^^^^^ diff --git a/tests/ui/len_without_is_empty.rs b/tests/ui/len_without_is_empty.rs index 1e938e72b5777..78397c2af346b 100644 --- a/tests/ui/len_without_is_empty.rs +++ b/tests/ui/len_without_is_empty.rs @@ -274,7 +274,7 @@ impl AsyncLen { } pub async fn len(&self) -> usize { - if self.async_task().await { 0 } else { 1 } + usize::from(!self.async_task().await) } pub async fn is_empty(&self) -> bool { diff --git a/tests/ui/nonminimal_bool.rs b/tests/ui/nonminimal_bool.rs index 24ae62bb05884..e9b4367ca653c 100644 --- a/tests/ui/nonminimal_bool.rs +++ b/tests/ui/nonminimal_bool.rs @@ -57,3 +57,9 @@ fn check_expect() { #[expect(clippy::nonminimal_bool)] let _ = !!a; } + +fn issue9428() { + if matches!(true, true) && true { + println!("foo"); + } +} diff --git a/tests/ui/nonminimal_bool.stderr b/tests/ui/nonminimal_bool.stderr index fc6a5ce1dc2ee..91b5805aa97ab 100644 --- a/tests/ui/nonminimal_bool.stderr +++ b/tests/ui/nonminimal_bool.stderr @@ -107,5 +107,11 @@ LL | let _ = !(a == b || c == d); LL | let _ = a != b && c != d; | ~~~~~~~~~~~~~~~~ -error: aborting due to 12 previous errors +error: this boolean expression can be simplified + --> $DIR/nonminimal_bool.rs:62:8 + | +LL | if matches!(true, true) && true { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(true, true)` + +error: aborting due to 13 previous errors diff --git a/tests/ui/positional_named_format_parameters.fixed b/tests/ui/positional_named_format_parameters.fixed deleted file mode 100644 index 4170e10982045..0000000000000 --- a/tests/ui/positional_named_format_parameters.fixed +++ /dev/null @@ -1,56 +0,0 @@ -// run-rustfix -#![allow(unused_must_use)] -#![allow(named_arguments_used_positionally)] // Unstable at time of writing. -#![warn(clippy::positional_named_format_parameters)] - -use std::io::Write; - -fn main() { - let mut v = Vec::new(); - let hello = "Hello"; - - println!("{hello:.foo$}", foo = 2); - writeln!(v, "{hello:.foo$}", foo = 2); - - // Warnings - println!("{zero} {one:?}", zero = 0, one = 1); - println!("This is a test {zero} {one:?}", zero = 0, one = 1); - println!("Hello {one} is {two:.zero$}", zero = 5, one = hello, two = 0.01); - println!("Hello {one:zero$}!", zero = 5, one = 1); - println!("Hello {zero:one$}!", zero = 4, one = 1); - println!("Hello {zero:0one$}!", zero = 4, one = 1); - println!("Hello is {one:.zero$}", zero = 5, one = 0.01); - println!("Hello is {one:<6.zero$}", zero = 5, one = 0.01); - println!("{zero}, `{two:>8.one$}` has 3", zero = hello, one = 3, two = hello); - println!("Hello {one} is {two:.zero$}", zero = 5, one = hello, two = 0.01); - println!("Hello {world} {world}!", world = 5); - - writeln!(v, "{zero} {one:?}", zero = 0, one = 1); - writeln!(v, "This is a test {zero} {one:?}", zero = 0, one = 1); - writeln!(v, "Hello {one} is {two:.zero$}", zero = 5, one = hello, two = 0.01); - writeln!(v, "Hello {one:zero$}!", zero = 4, one = 1); - writeln!(v, "Hello {zero:one$}!", zero = 4, one = 1); - writeln!(v, "Hello {zero:0one$}!", zero = 4, one = 1); - writeln!(v, "Hello is {one:.zero$}", zero = 3, one = 0.01); - writeln!(v, "Hello is {one:<6.zero$}", zero = 2, one = 0.01); - writeln!(v, "{zero}, `{two:>8.one$}` has 3", zero = hello, one = 3, two = hello); - writeln!(v, "Hello {one} is {two:.zero$}", zero = 1, one = hello, two = 0.01); - writeln!(v, "Hello {world} {world}!", world = 0); - - // Tests from other files - println!("{w:w$}", w = 1); - println!("{p:.p$}", p = 1); - println!("{v}", v = 1); - println!("{v:v$}", v = 1); - println!("{v:v$}", v = 1); - println!("{v:v$.v$}", v = 1); - println!("{v:v$.v$}", v = 1); - println!("{v:v$.v$}", v = 1); - println!("{v:v$.v$}", v = 1); - println!("{v:v$.v$}", v = 1); - println!("{v:v$.v$}", v = 1); - println!("{v:v$.v$}", v = 1); - println!("{w:w$}", w = 1); - println!("{p:.p$}", p = 1); - println!("{:p$.w$}", 1, w = 1, p = 1); -} diff --git a/tests/ui/positional_named_format_parameters.rs b/tests/ui/positional_named_format_parameters.rs deleted file mode 100644 index 553d8494ecc04..0000000000000 --- a/tests/ui/positional_named_format_parameters.rs +++ /dev/null @@ -1,56 +0,0 @@ -// run-rustfix -#![allow(unused_must_use)] -#![allow(named_arguments_used_positionally)] // Unstable at time of writing. -#![warn(clippy::positional_named_format_parameters)] - -use std::io::Write; - -fn main() { - let mut v = Vec::new(); - let hello = "Hello"; - - println!("{hello:.foo$}", foo = 2); - writeln!(v, "{hello:.foo$}", foo = 2); - - // Warnings - println!("{} {1:?}", zero = 0, one = 1); - println!("This is a test { } {000001:?}", zero = 0, one = 1); - println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01); - println!("Hello {1:0$}!", zero = 5, one = 1); - println!("Hello {0:1$}!", zero = 4, one = 1); - println!("Hello {0:01$}!", zero = 4, one = 1); - println!("Hello is {1:.*}", zero = 5, one = 0.01); - println!("Hello is {:<6.*}", zero = 5, one = 0.01); - println!("{}, `{two:>8.*}` has 3", zero = hello, one = 3, two = hello); - println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01); - println!("Hello {world} {}!", world = 5); - - writeln!(v, "{} {1:?}", zero = 0, one = 1); - writeln!(v, "This is a test { } {000001:?}", zero = 0, one = 1); - writeln!(v, "Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01); - writeln!(v, "Hello {1:0$}!", zero = 4, one = 1); - writeln!(v, "Hello {0:1$}!", zero = 4, one = 1); - writeln!(v, "Hello {0:01$}!", zero = 4, one = 1); - writeln!(v, "Hello is {1:.*}", zero = 3, one = 0.01); - writeln!(v, "Hello is {:<6.*}", zero = 2, one = 0.01); - writeln!(v, "{}, `{two:>8.*}` has 3", zero = hello, one = 3, two = hello); - writeln!(v, "Hello {1} is {2:.0$}", zero = 1, one = hello, two = 0.01); - writeln!(v, "Hello {world} {}!", world = 0); - - // Tests from other files - println!("{:w$}", w = 1); - println!("{:.p$}", p = 1); - println!("{}", v = 1); - println!("{:0$}", v = 1); - println!("{0:0$}", v = 1); - println!("{:0$.0$}", v = 1); - println!("{0:0$.0$}", v = 1); - println!("{0:0$.v$}", v = 1); - println!("{0:v$.0$}", v = 1); - println!("{v:0$.0$}", v = 1); - println!("{v:v$.0$}", v = 1); - println!("{v:0$.v$}", v = 1); - println!("{:w$}", w = 1); - println!("{:.p$}", p = 1); - println!("{:p$.w$}", 1, w = 1, p = 1); -} diff --git a/tests/ui/positional_named_format_parameters.stderr b/tests/ui/positional_named_format_parameters.stderr deleted file mode 100644 index 48ddb6d67ad24..0000000000000 --- a/tests/ui/positional_named_format_parameters.stderr +++ /dev/null @@ -1,418 +0,0 @@ -error: named parameter zero is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:16:16 - | -LL | println!("{} {1:?}", zero = 0, one = 1); - | ^ help: replace it with: `zero` - | - = note: `-D clippy::positional-named-format-parameters` implied by `-D warnings` - -error: named parameter one is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:16:19 - | -LL | println!("{} {1:?}", zero = 0, one = 1); - | ^ help: replace it with: `one` - -error: named parameter zero is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:17:31 - | -LL | println!("This is a test { } {000001:?}", zero = 0, one = 1); - | ^ help: replace it with: `zero` - -error: named parameter one is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:17:35 - | -LL | println!("This is a test { } {000001:?}", zero = 0, one = 1); - | ^^^^^^ help: replace it with: `one` - -error: named parameter zero is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:18:32 - | -LL | println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01); - | ^ help: replace it with: `zero` - -error: named parameter one is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:18:22 - | -LL | println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01); - | ^ help: replace it with: `one` - -error: named parameter two is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:18:29 - | -LL | println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01); - | ^ help: replace it with: `two` - -error: named parameter zero is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:19:24 - | -LL | println!("Hello {1:0$}!", zero = 5, one = 1); - | ^ help: replace it with: `zero` - -error: named parameter one is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:19:22 - | -LL | println!("Hello {1:0$}!", zero = 5, one = 1); - | ^ help: replace it with: `one` - -error: named parameter zero is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:20:22 - | -LL | println!("Hello {0:1$}!", zero = 4, one = 1); - | ^ help: replace it with: `zero` - -error: named parameter one is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:20:24 - | -LL | println!("Hello {0:1$}!", zero = 4, one = 1); - | ^ help: replace it with: `one` - -error: named parameter zero is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:21:22 - | -LL | println!("Hello {0:01$}!", zero = 4, one = 1); - | ^ help: replace it with: `zero` - -error: named parameter one is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:21:25 - | -LL | println!("Hello {0:01$}!", zero = 4, one = 1); - | ^ help: replace it with: `one` - -error: named parameter zero is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:22:28 - | -LL | println!("Hello is {1:.*}", zero = 5, one = 0.01); - | ^ help: replace it with: `zero$` - -error: named parameter one is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:22:25 - | -LL | println!("Hello is {1:.*}", zero = 5, one = 0.01); - | ^ help: replace it with: `one` - -error: named parameter zero is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:23:29 - | -LL | println!("Hello is {:<6.*}", zero = 5, one = 0.01); - | ^ help: replace it with: `zero$` - -error: named parameter one is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:23:25 - | -LL | println!("Hello is {:<6.*}", zero = 5, one = 0.01); - | ^ help: replace it with: `one` - -error: named parameter zero is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:24:16 - | -LL | println!("{}, `{two:>8.*}` has 3", zero = hello, one = 3, two = hello); - | ^ help: replace it with: `zero` - -error: named parameter one is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:24:28 - | -LL | println!("{}, `{two:>8.*}` has 3", zero = hello, one = 3, two = hello); - | ^ help: replace it with: `one$` - -error: named parameter zero is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:25:32 - | -LL | println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01); - | ^ help: replace it with: `zero` - -error: named parameter one is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:25:22 - | -LL | println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01); - | ^ help: replace it with: `one` - -error: named parameter two is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:25:29 - | -LL | println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01); - | ^ help: replace it with: `two` - -error: named parameter world is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:26:30 - | -LL | println!("Hello {world} {}!", world = 5); - | ^ help: replace it with: `world` - -error: named parameter zero is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:28:19 - | -LL | writeln!(v, "{} {1:?}", zero = 0, one = 1); - | ^ help: replace it with: `zero` - -error: named parameter one is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:28:22 - | -LL | writeln!(v, "{} {1:?}", zero = 0, one = 1); - | ^ help: replace it with: `one` - -error: named parameter zero is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:29:34 - | -LL | writeln!(v, "This is a test { } {000001:?}", zero = 0, one = 1); - | ^ help: replace it with: `zero` - -error: named parameter one is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:29:38 - | -LL | writeln!(v, "This is a test { } {000001:?}", zero = 0, one = 1); - | ^^^^^^ help: replace it with: `one` - -error: named parameter zero is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:30:35 - | -LL | writeln!(v, "Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01); - | ^ help: replace it with: `zero` - -error: named parameter one is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:30:25 - | -LL | writeln!(v, "Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01); - | ^ help: replace it with: `one` - -error: named parameter two is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:30:32 - | -LL | writeln!(v, "Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01); - | ^ help: replace it with: `two` - -error: named parameter zero is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:31:27 - | -LL | writeln!(v, "Hello {1:0$}!", zero = 4, one = 1); - | ^ help: replace it with: `zero` - -error: named parameter one is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:31:25 - | -LL | writeln!(v, "Hello {1:0$}!", zero = 4, one = 1); - | ^ help: replace it with: `one` - -error: named parameter zero is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:32:25 - | -LL | writeln!(v, "Hello {0:1$}!", zero = 4, one = 1); - | ^ help: replace it with: `zero` - -error: named parameter one is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:32:27 - | -LL | writeln!(v, "Hello {0:1$}!", zero = 4, one = 1); - | ^ help: replace it with: `one` - -error: named parameter zero is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:33:25 - | -LL | writeln!(v, "Hello {0:01$}!", zero = 4, one = 1); - | ^ help: replace it with: `zero` - -error: named parameter one is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:33:28 - | -LL | writeln!(v, "Hello {0:01$}!", zero = 4, one = 1); - | ^ help: replace it with: `one` - -error: named parameter zero is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:34:31 - | -LL | writeln!(v, "Hello is {1:.*}", zero = 3, one = 0.01); - | ^ help: replace it with: `zero$` - -error: named parameter one is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:34:28 - | -LL | writeln!(v, "Hello is {1:.*}", zero = 3, one = 0.01); - | ^ help: replace it with: `one` - -error: named parameter zero is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:35:32 - | -LL | writeln!(v, "Hello is {:<6.*}", zero = 2, one = 0.01); - | ^ help: replace it with: `zero$` - -error: named parameter one is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:35:28 - | -LL | writeln!(v, "Hello is {:<6.*}", zero = 2, one = 0.01); - | ^ help: replace it with: `one` - -error: named parameter zero is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:36:19 - | -LL | writeln!(v, "{}, `{two:>8.*}` has 3", zero = hello, one = 3, two = hello); - | ^ help: replace it with: `zero` - -error: named parameter one is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:36:31 - | -LL | writeln!(v, "{}, `{two:>8.*}` has 3", zero = hello, one = 3, two = hello); - | ^ help: replace it with: `one$` - -error: named parameter zero is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:37:35 - | -LL | writeln!(v, "Hello {1} is {2:.0$}", zero = 1, one = hello, two = 0.01); - | ^ help: replace it with: `zero` - -error: named parameter one is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:37:25 - | -LL | writeln!(v, "Hello {1} is {2:.0$}", zero = 1, one = hello, two = 0.01); - | ^ help: replace it with: `one` - -error: named parameter two is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:37:32 - | -LL | writeln!(v, "Hello {1} is {2:.0$}", zero = 1, one = hello, two = 0.01); - | ^ help: replace it with: `two` - -error: named parameter world is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:38:33 - | -LL | writeln!(v, "Hello {world} {}!", world = 0); - | ^ help: replace it with: `world` - -error: named parameter w is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:41:16 - | -LL | println!("{:w$}", w = 1); - | ^ help: replace it with: `w` - -error: named parameter p is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:42:16 - | -LL | println!("{:.p$}", p = 1); - | ^ help: replace it with: `p` - -error: named parameter v is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:43:16 - | -LL | println!("{}", v = 1); - | ^ help: replace it with: `v` - -error: named parameter v is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:44:16 - | -LL | println!("{:0$}", v = 1); - | ^ help: replace it with: `v` - -error: named parameter v is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:44:17 - | -LL | println!("{:0$}", v = 1); - | ^ help: replace it with: `v` - -error: named parameter v is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:45:16 - | -LL | println!("{0:0$}", v = 1); - | ^ help: replace it with: `v` - -error: named parameter v is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:45:18 - | -LL | println!("{0:0$}", v = 1); - | ^ help: replace it with: `v` - -error: named parameter v is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:46:16 - | -LL | println!("{:0$.0$}", v = 1); - | ^ help: replace it with: `v` - -error: named parameter v is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:46:20 - | -LL | println!("{:0$.0$}", v = 1); - | ^ help: replace it with: `v` - -error: named parameter v is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:46:17 - | -LL | println!("{:0$.0$}", v = 1); - | ^ help: replace it with: `v` - -error: named parameter v is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:47:16 - | -LL | println!("{0:0$.0$}", v = 1); - | ^ help: replace it with: `v` - -error: named parameter v is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:47:21 - | -LL | println!("{0:0$.0$}", v = 1); - | ^ help: replace it with: `v` - -error: named parameter v is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:47:18 - | -LL | println!("{0:0$.0$}", v = 1); - | ^ help: replace it with: `v` - -error: named parameter v is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:48:16 - | -LL | println!("{0:0$.v$}", v = 1); - | ^ help: replace it with: `v` - -error: named parameter v is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:48:18 - | -LL | println!("{0:0$.v$}", v = 1); - | ^ help: replace it with: `v` - -error: named parameter v is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:49:16 - | -LL | println!("{0:v$.0$}", v = 1); - | ^ help: replace it with: `v` - -error: named parameter v is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:49:21 - | -LL | println!("{0:v$.0$}", v = 1); - | ^ help: replace it with: `v` - -error: named parameter v is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:50:21 - | -LL | println!("{v:0$.0$}", v = 1); - | ^ help: replace it with: `v` - -error: named parameter v is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:50:18 - | -LL | println!("{v:0$.0$}", v = 1); - | ^ help: replace it with: `v` - -error: named parameter v is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:51:21 - | -LL | println!("{v:v$.0$}", v = 1); - | ^ help: replace it with: `v` - -error: named parameter v is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:52:18 - | -LL | println!("{v:0$.v$}", v = 1); - | ^ help: replace it with: `v` - -error: named parameter w is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:53:16 - | -LL | println!("{:w$}", w = 1); - | ^ help: replace it with: `w` - -error: named parameter p is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:54:16 - | -LL | println!("{:.p$}", p = 1); - | ^ help: replace it with: `p` - -error: aborting due to 69 previous errors - diff --git a/tests/ui/print_literal.rs b/tests/ui/print_literal.rs index 8665a3bb28ae1..3f6639c14585a 100644 --- a/tests/ui/print_literal.rs +++ b/tests/ui/print_literal.rs @@ -20,11 +20,13 @@ fn main() { println!("{} of {:b} people know binary, the other half doesn't", 1, 2); println!("10 / 4 is {}", 2.5); println!("2 + 1 = {}", 3); + println!("From expansion {}", stringify!(not a string literal)); // these should throw warnings print!("Hello {}", "world"); println!("Hello {} {}", world, "world"); println!("Hello {}", "world"); + println!("{} {:.4}", "a literal", 5); // positional args don't change the fact // that we're using a literal -- this should diff --git a/tests/ui/print_literal.stderr b/tests/ui/print_literal.stderr index 72aae0756033a..23e6dbc3e341f 100644 --- a/tests/ui/print_literal.stderr +++ b/tests/ui/print_literal.stderr @@ -1,5 +1,5 @@ error: literal with an empty format string - --> $DIR/print_literal.rs:25:24 + --> $DIR/print_literal.rs:26:24 | LL | print!("Hello {}", "world"); | ^^^^^^^ @@ -12,7 +12,7 @@ LL + print!("Hello world"); | error: literal with an empty format string - --> $DIR/print_literal.rs:26:36 + --> $DIR/print_literal.rs:27:36 | LL | println!("Hello {} {}", world, "world"); | ^^^^^^^ @@ -24,7 +24,7 @@ LL + println!("Hello {} world", world); | error: literal with an empty format string - --> $DIR/print_literal.rs:27:26 + --> $DIR/print_literal.rs:28:26 | LL | println!("Hello {}", "world"); | ^^^^^^^ @@ -36,7 +36,19 @@ LL + println!("Hello world"); | error: literal with an empty format string - --> $DIR/print_literal.rs:32:25 + --> $DIR/print_literal.rs:29:26 + | +LL | println!("{} {:.4}", "a literal", 5); + | ^^^^^^^^^^^ + | +help: try this + | +LL - println!("{} {:.4}", "a literal", 5); +LL + println!("a literal {:.4}", 5); + | + +error: literal with an empty format string + --> $DIR/print_literal.rs:34:25 | LL | println!("{0} {1}", "hello", "world"); | ^^^^^^^ @@ -48,7 +60,7 @@ LL + println!("hello {1}", "world"); | error: literal with an empty format string - --> $DIR/print_literal.rs:32:34 + --> $DIR/print_literal.rs:34:34 | LL | println!("{0} {1}", "hello", "world"); | ^^^^^^^ @@ -60,34 +72,34 @@ LL + println!("{0} world", "hello"); | error: literal with an empty format string - --> $DIR/print_literal.rs:33:25 + --> $DIR/print_literal.rs:35:34 | LL | println!("{1} {0}", "hello", "world"); - | ^^^^^^^ + | ^^^^^^^ | help: try this | LL - println!("{1} {0}", "hello", "world"); -LL + println!("{1} hello", "world"); +LL + println!("world {0}", "hello"); | error: literal with an empty format string - --> $DIR/print_literal.rs:33:34 + --> $DIR/print_literal.rs:35:25 | LL | println!("{1} {0}", "hello", "world"); - | ^^^^^^^ + | ^^^^^^^ | help: try this | LL - println!("{1} {0}", "hello", "world"); -LL + println!("world {0}", "hello"); +LL + println!("{1} hello", "world"); | error: literal with an empty format string - --> $DIR/print_literal.rs:36:29 + --> $DIR/print_literal.rs:38:35 | LL | println!("{foo} {bar}", foo = "hello", bar = "world"); - | ^^^^^^^^^^^^^ + | ^^^^^^^ | help: try this | @@ -96,10 +108,10 @@ LL + println!("hello {bar}", bar = "world"); | error: literal with an empty format string - --> $DIR/print_literal.rs:36:44 + --> $DIR/print_literal.rs:38:50 | LL | println!("{foo} {bar}", foo = "hello", bar = "world"); - | ^^^^^^^^^^^^^ + | ^^^^^^^ | help: try this | @@ -108,28 +120,28 @@ LL + println!("{foo} world", foo = "hello"); | error: literal with an empty format string - --> $DIR/print_literal.rs:37:29 + --> $DIR/print_literal.rs:39:50 | LL | println!("{bar} {foo}", foo = "hello", bar = "world"); - | ^^^^^^^^^^^^^ + | ^^^^^^^ | help: try this | LL - println!("{bar} {foo}", foo = "hello", bar = "world"); -LL + println!("{bar} hello", bar = "world"); +LL + println!("world {foo}", foo = "hello"); | error: literal with an empty format string - --> $DIR/print_literal.rs:37:44 + --> $DIR/print_literal.rs:39:35 | LL | println!("{bar} {foo}", foo = "hello", bar = "world"); - | ^^^^^^^^^^^^^ + | ^^^^^^^ | help: try this | LL - println!("{bar} {foo}", foo = "hello", bar = "world"); -LL + println!("world {foo}", foo = "hello"); +LL + println!("{bar} hello", bar = "world"); | -error: aborting due to 11 previous errors +error: aborting due to 12 previous errors diff --git a/tests/ui/print_with_newline.rs b/tests/ui/print_with_newline.rs index a43a1fc4f5241..b8c29d207adae 100644 --- a/tests/ui/print_with_newline.rs +++ b/tests/ui/print_with_newline.rs @@ -48,5 +48,13 @@ fn main() { print!("\r\n"); print!("foo\r\n"); print!("\\r\n"); //~ ERROR - print!("foo\rbar\n") // ~ ERROR + print!("foo\rbar\n"); + + // Ignore expanded format strings + macro_rules! newline { + () => { + "\n" + }; + } + print!(newline!()); } diff --git a/tests/ui/print_with_newline.stderr b/tests/ui/print_with_newline.stderr index edbaa1cdf979f..b9f5675faec73 100644 --- a/tests/ui/print_with_newline.stderr +++ b/tests/ui/print_with_newline.stderr @@ -83,7 +83,7 @@ LL | | ); help: use `println!` instead | LL ~ println!( -LL ~ "" +LL ~ | error: using `print!()` with a format string that ends in a single newline @@ -98,7 +98,7 @@ LL | | ); help: use `println!` instead | LL ~ println!( -LL ~ r"" +LL ~ | error: using `print!()` with a format string that ends in a single newline @@ -113,17 +113,5 @@ LL - print!("/r/n"); //~ ERROR LL + println!("/r"); //~ ERROR | -error: using `print!()` with a format string that ends in a single newline - --> $DIR/print_with_newline.rs:51:5 - | -LL | print!("foo/rbar/n") // ~ ERROR - | ^^^^^^^^^^^^^^^^^^^^ - | -help: use `println!` instead - | -LL - print!("foo/rbar/n") // ~ ERROR -LL + println!("foo/rbar") // ~ ERROR - | - -error: aborting due to 10 previous errors +error: aborting due to 9 previous errors diff --git a/tests/ui/println_empty_string.stderr b/tests/ui/println_empty_string.stderr index 17fe4ea74790c..3cc8bb947bd35 100644 --- a/tests/ui/println_empty_string.stderr +++ b/tests/ui/println_empty_string.stderr @@ -1,28 +1,36 @@ -error: using `println!("")` +error: empty string literal in `println!` --> $DIR/println_empty_string.rs:6:5 | LL | println!(""); - | ^^^^^^^^^^^^ help: replace it with: `println!()` + | ^^^^^^^^^--^ + | | + | help: remove the empty string | = note: `-D clippy::println-empty-string` implied by `-D warnings` -error: using `println!("")` +error: empty string literal in `println!` --> $DIR/println_empty_string.rs:9:14 | LL | _ => println!(""), - | ^^^^^^^^^^^^ help: replace it with: `println!()` + | ^^^^^^^^^--^ + | | + | help: remove the empty string -error: using `eprintln!("")` +error: empty string literal in `eprintln!` --> $DIR/println_empty_string.rs:13:5 | LL | eprintln!(""); - | ^^^^^^^^^^^^^ help: replace it with: `eprintln!()` + | ^^^^^^^^^^--^ + | | + | help: remove the empty string -error: using `eprintln!("")` +error: empty string literal in `eprintln!` --> $DIR/println_empty_string.rs:16:14 | LL | _ => eprintln!(""), - | ^^^^^^^^^^^^^ help: replace it with: `eprintln!()` + | ^^^^^^^^^^--^ + | | + | help: remove the empty string error: aborting due to 4 previous errors diff --git a/tests/ui/rename.fixed b/tests/ui/rename.fixed index 9cbad2269a099..a6e7bdba77c65 100644 --- a/tests/ui/rename.fixed +++ b/tests/ui/rename.fixed @@ -32,6 +32,7 @@ #![allow(invalid_value)] #![allow(enum_intrinsics_non_enums)] #![allow(non_fmt_panics)] +#![allow(named_arguments_used_positionally)] #![allow(temporary_cstring_as_ptr)] #![allow(unknown_lints)] #![allow(unused_labels)] @@ -69,6 +70,7 @@ #![warn(invalid_value)] #![warn(enum_intrinsics_non_enums)] #![warn(non_fmt_panics)] +#![warn(named_arguments_used_positionally)] #![warn(temporary_cstring_as_ptr)] #![warn(unknown_lints)] #![warn(unused_labels)] diff --git a/tests/ui/rename.rs b/tests/ui/rename.rs index 9153c0dab0290..e8f57597d02b5 100644 --- a/tests/ui/rename.rs +++ b/tests/ui/rename.rs @@ -32,6 +32,7 @@ #![allow(invalid_value)] #![allow(enum_intrinsics_non_enums)] #![allow(non_fmt_panics)] +#![allow(named_arguments_used_positionally)] #![allow(temporary_cstring_as_ptr)] #![allow(unknown_lints)] #![allow(unused_labels)] @@ -69,6 +70,7 @@ #![warn(clippy::invalid_ref)] #![warn(clippy::mem_discriminant_non_enum)] #![warn(clippy::panic_params)] +#![warn(clippy::positional_named_format_parameters)] #![warn(clippy::temporary_cstring_as_ptr)] #![warn(clippy::unknown_clippy_lints)] #![warn(clippy::unused_label)] diff --git a/tests/ui/rename.stderr b/tests/ui/rename.stderr index 9c03ea914bb65..31865a7f66d60 100644 --- a/tests/ui/rename.stderr +++ b/tests/ui/rename.stderr @@ -1,5 +1,5 @@ error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names` - --> $DIR/rename.rs:38:9 + --> $DIR/rename.rs:39:9 | LL | #![warn(clippy::blacklisted_name)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names` @@ -7,220 +7,226 @@ LL | #![warn(clippy::blacklisted_name)] = note: `-D renamed-and-removed-lints` implied by `-D warnings` error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions` - --> $DIR/rename.rs:39:9 + --> $DIR/rename.rs:40:9 | LL | #![warn(clippy::block_in_if_condition_expr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions` - --> $DIR/rename.rs:40:9 + --> $DIR/rename.rs:41:9 | LL | #![warn(clippy::block_in_if_condition_stmt)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` error: lint `clippy::box_vec` has been renamed to `clippy::box_collection` - --> $DIR/rename.rs:41:9 + --> $DIR/rename.rs:42:9 | LL | #![warn(clippy::box_vec)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection` error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes` - --> $DIR/rename.rs:42:9 + --> $DIR/rename.rs:43:9 | LL | #![warn(clippy::const_static_lifetime)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes` error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity` - --> $DIR/rename.rs:43:9 + --> $DIR/rename.rs:44:9 | LL | #![warn(clippy::cyclomatic_complexity)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity` error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods` - --> $DIR/rename.rs:44:9 + --> $DIR/rename.rs:45:9 | LL | #![warn(clippy::disallowed_method)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods` error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types` - --> $DIR/rename.rs:45:9 + --> $DIR/rename.rs:46:9 | LL | #![warn(clippy::disallowed_type)] | ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types` error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression` - --> $DIR/rename.rs:46:9 + --> $DIR/rename.rs:47:9 | LL | #![warn(clippy::eval_order_dependence)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression` error: lint `clippy::for_loop_over_option` has been renamed to `clippy::for_loops_over_fallibles` - --> $DIR/rename.rs:47:9 + --> $DIR/rename.rs:48:9 | LL | #![warn(clippy::for_loop_over_option)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles` error: lint `clippy::for_loop_over_result` has been renamed to `clippy::for_loops_over_fallibles` - --> $DIR/rename.rs:48:9 + --> $DIR/rename.rs:49:9 | LL | #![warn(clippy::for_loop_over_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles` error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion` - --> $DIR/rename.rs:49:9 + --> $DIR/rename.rs:50:9 | LL | #![warn(clippy::identity_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion` error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok` - --> $DIR/rename.rs:50:9 + --> $DIR/rename.rs:51:9 | LL | #![warn(clippy::if_let_some_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok` error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr` - --> $DIR/rename.rs:51:9 + --> $DIR/rename.rs:52:9 | LL | #![warn(clippy::logic_bug)] | ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr` error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default` - --> $DIR/rename.rs:52:9 + --> $DIR/rename.rs:53:9 | LL | #![warn(clippy::new_without_default_derive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default` error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map` - --> $DIR/rename.rs:53:9 + --> $DIR/rename.rs:54:9 | LL | #![warn(clippy::option_and_then_some)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map` error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used` - --> $DIR/rename.rs:54:9 + --> $DIR/rename.rs:55:9 | LL | #![warn(clippy::option_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:55:9 + --> $DIR/rename.rs:56:9 | LL | #![warn(clippy::option_map_unwrap_or)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:56:9 + --> $DIR/rename.rs:57:9 | LL | #![warn(clippy::option_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used` - --> $DIR/rename.rs:57:9 + --> $DIR/rename.rs:58:9 | LL | #![warn(clippy::option_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow` - --> $DIR/rename.rs:58:9 + --> $DIR/rename.rs:59:9 | LL | #![warn(clippy::ref_in_deref)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow` error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used` - --> $DIR/rename.rs:59:9 + --> $DIR/rename.rs:60:9 | LL | #![warn(clippy::result_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:60:9 + --> $DIR/rename.rs:61:9 | LL | #![warn(clippy::result_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used` - --> $DIR/rename.rs:61:9 + --> $DIR/rename.rs:62:9 | LL | #![warn(clippy::result_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str` - --> $DIR/rename.rs:62:9 + --> $DIR/rename.rs:63:9 | LL | #![warn(clippy::single_char_push_str)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str` error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions` - --> $DIR/rename.rs:63:9 + --> $DIR/rename.rs:64:9 | LL | #![warn(clippy::stutter)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions` error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl` - --> $DIR/rename.rs:64:9 + --> $DIR/rename.rs:65:9 | LL | #![warn(clippy::to_string_in_display)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl` error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters` - --> $DIR/rename.rs:65:9 + --> $DIR/rename.rs:66:9 | LL | #![warn(clippy::zero_width_space)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters` error: lint `clippy::drop_bounds` has been renamed to `drop_bounds` - --> $DIR/rename.rs:66:9 + --> $DIR/rename.rs:67:9 | LL | #![warn(clippy::drop_bounds)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds` error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter` - --> $DIR/rename.rs:67:9 + --> $DIR/rename.rs:68:9 | LL | #![warn(clippy::into_iter_on_array)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter` error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering` - --> $DIR/rename.rs:68:9 + --> $DIR/rename.rs:69:9 | LL | #![warn(clippy::invalid_atomic_ordering)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering` error: lint `clippy::invalid_ref` has been renamed to `invalid_value` - --> $DIR/rename.rs:69:9 + --> $DIR/rename.rs:70:9 | LL | #![warn(clippy::invalid_ref)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value` error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums` - --> $DIR/rename.rs:70:9 + --> $DIR/rename.rs:71:9 | LL | #![warn(clippy::mem_discriminant_non_enum)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums` error: lint `clippy::panic_params` has been renamed to `non_fmt_panics` - --> $DIR/rename.rs:71:9 + --> $DIR/rename.rs:72:9 | LL | #![warn(clippy::panic_params)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics` +error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally` + --> $DIR/rename.rs:73:9 + | +LL | #![warn(clippy::positional_named_format_parameters)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally` + error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr` - --> $DIR/rename.rs:72:9 + --> $DIR/rename.rs:74:9 | LL | #![warn(clippy::temporary_cstring_as_ptr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr` error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints` - --> $DIR/rename.rs:73:9 + --> $DIR/rename.rs:75:9 | LL | #![warn(clippy::unknown_clippy_lints)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints` error: lint `clippy::unused_label` has been renamed to `unused_labels` - --> $DIR/rename.rs:74:9 + --> $DIR/rename.rs:76:9 | LL | #![warn(clippy::unused_label)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels` -error: aborting due to 37 previous errors +error: aborting due to 38 previous errors diff --git a/tests/ui/unnecessary_to_owned.fixed b/tests/ui/unnecessary_to_owned.fixed index a920c63b199c1..f97583aa22f9a 100644 --- a/tests/ui/unnecessary_to_owned.fixed +++ b/tests/ui/unnecessary_to_owned.fixed @@ -417,3 +417,12 @@ mod issue_9351 { predicates_are_satisfied(id("abc".to_string())); } } + +mod issue_9504 { + #![allow(dead_code)] + + async fn foo>(_: S) {} + async fn bar() { + foo(std::path::PathBuf::new().to_string_lossy().to_string()).await; + } +} diff --git a/tests/ui/unnecessary_to_owned.rs b/tests/ui/unnecessary_to_owned.rs index 2128bdacddadf..aa5394a565790 100644 --- a/tests/ui/unnecessary_to_owned.rs +++ b/tests/ui/unnecessary_to_owned.rs @@ -417,3 +417,12 @@ mod issue_9351 { predicates_are_satisfied(id("abc".to_string())); } } + +mod issue_9504 { + #![allow(dead_code)] + + async fn foo>(_: S) {} + async fn bar() { + foo(std::path::PathBuf::new().to_string_lossy().to_string()).await; + } +} diff --git a/tests/ui/unused_peekable.rs b/tests/ui/unused_peekable.rs index 153457e367165..7374dfdf92e87 100644 --- a/tests/ui/unused_peekable.rs +++ b/tests/ui/unused_peekable.rs @@ -57,12 +57,22 @@ fn valid() { impl PeekableConsumer { fn consume(&self, _: Peekable>) {} fn consume_mut_ref(&self, _: &mut Peekable>) {} + fn consume_assoc(_: Peekable>) {} + fn consume_assoc_mut_ref(_: &mut Peekable>) {} } - let peekable_consumer = PeekableConsumer; - let mut passed_along_to_method = std::iter::empty::().peekable(); - peekable_consumer.consume_mut_ref(&mut passed_along_to_method); - peekable_consumer.consume(passed_along_to_method); + + let peekable = std::iter::empty::().peekable(); + peekable_consumer.consume(peekable); + + let mut peekable = std::iter::empty::().peekable(); + peekable_consumer.consume_mut_ref(&mut peekable); + + let peekable = std::iter::empty::().peekable(); + PeekableConsumer::consume_assoc(peekable); + + let mut peekable = std::iter::empty::().peekable(); + PeekableConsumer::consume_assoc_mut_ref(&mut peekable); // `peek` called in another block let mut peekable_in_block = std::iter::empty::().peekable(); @@ -141,4 +151,19 @@ fn valid() { { peekable_last_expr.peek(); } + + let mut peek_in_closure = std::iter::empty::().peekable(); + let _ = || { + let _ = peek_in_closure.peek(); + }; + + trait PeekTrait {} + impl PeekTrait for Peekable where I: Iterator {} + + let mut peekable = std::iter::empty::().peekable(); + let _dyn = &mut peekable as &mut dyn PeekTrait; + + fn takes_dyn(_: &mut dyn PeekTrait) {} + let mut peekable = std::iter::empty::().peekable(); + takes_dyn(&mut peekable); } diff --git a/tests/ui/use_self.fixed b/tests/ui/use_self.fixed index 4f80aaecc902d..37986187da179 100644 --- a/tests/ui/use_self.fixed +++ b/tests/ui/use_self.fixed @@ -608,3 +608,12 @@ mod issue8845 { } } } + +mod issue6902 { + use serde::Serialize; + + #[derive(Serialize)] + pub enum Foo { + Bar = 1, + } +} diff --git a/tests/ui/use_self.rs b/tests/ui/use_self.rs index 52da72db53ce3..1b2b3337c92ed 100644 --- a/tests/ui/use_self.rs +++ b/tests/ui/use_self.rs @@ -608,3 +608,12 @@ mod issue8845 { } } } + +mod issue6902 { + use serde::Serialize; + + #[derive(Serialize)] + pub enum Foo { + Bar = 1, + } +} diff --git a/tests/ui/write_literal.rs b/tests/ui/write_literal.rs index 4466917441162..5892818aa9a61 100644 --- a/tests/ui/write_literal.rs +++ b/tests/ui/write_literal.rs @@ -25,11 +25,13 @@ fn main() { writeln!(v, "{} of {:b} people know binary, the other half doesn't", 1, 2); writeln!(v, "10 / 4 is {}", 2.5); writeln!(v, "2 + 1 = {}", 3); + writeln!(v, "From expansion {}", stringify!(not a string literal)); // these should throw warnings write!(v, "Hello {}", "world"); writeln!(v, "Hello {} {}", world, "world"); writeln!(v, "Hello {}", "world"); + writeln!(v, "{} {:.4}", "a literal", 5); // positional args don't change the fact // that we're using a literal -- this should diff --git a/tests/ui/write_literal.stderr b/tests/ui/write_literal.stderr index 3c5ec91d3e0fb..1e306ae28a263 100644 --- a/tests/ui/write_literal.stderr +++ b/tests/ui/write_literal.stderr @@ -1,5 +1,5 @@ error: literal with an empty format string - --> $DIR/write_literal.rs:30:27 + --> $DIR/write_literal.rs:31:27 | LL | write!(v, "Hello {}", "world"); | ^^^^^^^ @@ -12,7 +12,7 @@ LL + write!(v, "Hello world"); | error: literal with an empty format string - --> $DIR/write_literal.rs:31:39 + --> $DIR/write_literal.rs:32:39 | LL | writeln!(v, "Hello {} {}", world, "world"); | ^^^^^^^ @@ -24,7 +24,7 @@ LL + writeln!(v, "Hello {} world", world); | error: literal with an empty format string - --> $DIR/write_literal.rs:32:29 + --> $DIR/write_literal.rs:33:29 | LL | writeln!(v, "Hello {}", "world"); | ^^^^^^^ @@ -36,7 +36,19 @@ LL + writeln!(v, "Hello world"); | error: literal with an empty format string - --> $DIR/write_literal.rs:37:28 + --> $DIR/write_literal.rs:34:29 + | +LL | writeln!(v, "{} {:.4}", "a literal", 5); + | ^^^^^^^^^^^ + | +help: try this + | +LL - writeln!(v, "{} {:.4}", "a literal", 5); +LL + writeln!(v, "a literal {:.4}", 5); + | + +error: literal with an empty format string + --> $DIR/write_literal.rs:39:28 | LL | writeln!(v, "{0} {1}", "hello", "world"); | ^^^^^^^ @@ -48,7 +60,7 @@ LL + writeln!(v, "hello {1}", "world"); | error: literal with an empty format string - --> $DIR/write_literal.rs:37:37 + --> $DIR/write_literal.rs:39:37 | LL | writeln!(v, "{0} {1}", "hello", "world"); | ^^^^^^^ @@ -60,34 +72,34 @@ LL + writeln!(v, "{0} world", "hello"); | error: literal with an empty format string - --> $DIR/write_literal.rs:38:28 + --> $DIR/write_literal.rs:40:37 | LL | writeln!(v, "{1} {0}", "hello", "world"); - | ^^^^^^^ + | ^^^^^^^ | help: try this | LL - writeln!(v, "{1} {0}", "hello", "world"); -LL + writeln!(v, "{1} hello", "world"); +LL + writeln!(v, "world {0}", "hello"); | error: literal with an empty format string - --> $DIR/write_literal.rs:38:37 + --> $DIR/write_literal.rs:40:28 | LL | writeln!(v, "{1} {0}", "hello", "world"); - | ^^^^^^^ + | ^^^^^^^ | help: try this | LL - writeln!(v, "{1} {0}", "hello", "world"); -LL + writeln!(v, "world {0}", "hello"); +LL + writeln!(v, "{1} hello", "world"); | error: literal with an empty format string - --> $DIR/write_literal.rs:41:32 + --> $DIR/write_literal.rs:43:38 | LL | writeln!(v, "{foo} {bar}", foo = "hello", bar = "world"); - | ^^^^^^^^^^^^^ + | ^^^^^^^ | help: try this | @@ -96,10 +108,10 @@ LL + writeln!(v, "hello {bar}", bar = "world"); | error: literal with an empty format string - --> $DIR/write_literal.rs:41:47 + --> $DIR/write_literal.rs:43:53 | LL | writeln!(v, "{foo} {bar}", foo = "hello", bar = "world"); - | ^^^^^^^^^^^^^ + | ^^^^^^^ | help: try this | @@ -108,28 +120,28 @@ LL + writeln!(v, "{foo} world", foo = "hello"); | error: literal with an empty format string - --> $DIR/write_literal.rs:42:32 + --> $DIR/write_literal.rs:44:53 | LL | writeln!(v, "{bar} {foo}", foo = "hello", bar = "world"); - | ^^^^^^^^^^^^^ + | ^^^^^^^ | help: try this | LL - writeln!(v, "{bar} {foo}", foo = "hello", bar = "world"); -LL + writeln!(v, "{bar} hello", bar = "world"); +LL + writeln!(v, "world {foo}", foo = "hello"); | error: literal with an empty format string - --> $DIR/write_literal.rs:42:47 + --> $DIR/write_literal.rs:44:38 | LL | writeln!(v, "{bar} {foo}", foo = "hello", bar = "world"); - | ^^^^^^^^^^^^^ + | ^^^^^^^ | help: try this | LL - writeln!(v, "{bar} {foo}", foo = "hello", bar = "world"); -LL + writeln!(v, "world {foo}", foo = "hello"); +LL + writeln!(v, "{bar} hello", bar = "world"); | -error: aborting due to 11 previous errors +error: aborting due to 12 previous errors diff --git a/tests/ui/write_literal_2.rs b/tests/ui/write_literal_2.rs index ba0d7be5eaa68..55a11daa1d344 100644 --- a/tests/ui/write_literal_2.rs +++ b/tests/ui/write_literal_2.rs @@ -10,7 +10,7 @@ fn main() { writeln!(v, r"{}", r"{hello}"); writeln!(v, "{}", '\''); writeln!(v, "{}", '"'); - writeln!(v, r"{}", '"'); // don't lint + writeln!(v, r"{}", '"'); writeln!(v, r"{}", '\''); writeln!( v, @@ -24,4 +24,11 @@ fn main() { {} \\ {}", "1", "2", "3", ); + writeln!(v, "{}", "\\"); + writeln!(v, r"{}", "\\"); + writeln!(v, r#"{}"#, "\\"); + writeln!(v, "{}", r"\"); + writeln!(v, "{}", "\r"); + writeln!(v, r#"{}{}"#, '#', '"'); // hard mode + writeln!(v, r"{}", "\r"); // should not lint } diff --git a/tests/ui/write_literal_2.stderr b/tests/ui/write_literal_2.stderr index 9ff297069c402..d5956db9ff0b4 100644 --- a/tests/ui/write_literal_2.stderr +++ b/tests/ui/write_literal_2.stderr @@ -47,6 +47,12 @@ LL - writeln!(v, "{}", '"'); LL + writeln!(v, "/""); | +error: literal with an empty format string + --> $DIR/write_literal_2.rs:13:24 + | +LL | writeln!(v, r"{}", '"'); + | ^^^ + error: literal with an empty format string --> $DIR/write_literal_2.rs:14:24 | @@ -108,5 +114,77 @@ LL ~ {} / 3", LL ~ "1", "2", | -error: aborting due to 9 previous errors +error: literal with an empty format string + --> $DIR/write_literal_2.rs:27:23 + | +LL | writeln!(v, "{}", "/"); + | ^^^^ + | +help: try this + | +LL - writeln!(v, "{}", "/"); +LL + writeln!(v, "/"); + | + +error: literal with an empty format string + --> $DIR/write_literal_2.rs:28:24 + | +LL | writeln!(v, r"{}", "/"); + | ^^^^ + | +help: try this + | +LL - writeln!(v, r"{}", "/"); +LL + writeln!(v, r"/"); + | + +error: literal with an empty format string + --> $DIR/write_literal_2.rs:29:26 + | +LL | writeln!(v, r#"{}"#, "/"); + | ^^^^ + | +help: try this + | +LL - writeln!(v, r#"{}"#, "/"); +LL + writeln!(v, r#"/"#); + | + +error: literal with an empty format string + --> $DIR/write_literal_2.rs:30:23 + | +LL | writeln!(v, "{}", r"/"); + | ^^^^ + | +help: try this + | +LL - writeln!(v, "{}", r"/"); +LL + writeln!(v, "/"); + | + +error: literal with an empty format string + --> $DIR/write_literal_2.rs:31:23 + | +LL | writeln!(v, "{}", "/r"); + | ^^^^ + | +help: try this + | +LL - writeln!(v, "{}", "/r"); +LL + writeln!(v, "/r"); + | + +error: literal with an empty format string + --> $DIR/write_literal_2.rs:32:28 + | +LL | writeln!(v, r#"{}{}"#, '#', '"'); // hard mode + | ^^^ + +error: literal with an empty format string + --> $DIR/write_literal_2.rs:32:33 + | +LL | writeln!(v, r#"{}{}"#, '#', '"'); // hard mode + | ^^^ + +error: aborting due to 17 previous errors diff --git a/tests/ui/write_with_newline.rs b/tests/ui/write_with_newline.rs index 446d6914d3461..b79364c8758c5 100644 --- a/tests/ui/write_with_newline.rs +++ b/tests/ui/write_with_newline.rs @@ -56,4 +56,12 @@ fn main() { write!(v, "foo\r\n"); write!(v, "\\r\n"); //~ ERROR write!(v, "foo\rbar\n"); + + // Ignore expanded format strings + macro_rules! newline { + () => { + "\n" + }; + } + write!(v, newline!()); } diff --git a/tests/ui/write_with_newline.stderr b/tests/ui/write_with_newline.stderr index 5f55431be0bd9..2baaea166d8ef 100644 --- a/tests/ui/write_with_newline.stderr +++ b/tests/ui/write_with_newline.stderr @@ -5,7 +5,7 @@ LL | write!(v, "Hello/n"); | ^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::write-with-newline` implied by `-D warnings` -help: use `writeln!()` instead +help: use `writeln!` instead | LL - write!(v, "Hello/n"); LL + writeln!(v, "Hello"); @@ -17,7 +17,7 @@ error: using `write!()` with a format string that ends in a single newline LL | write!(v, "Hello {}/n", "world"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: use `writeln!()` instead +help: use `writeln!` instead | LL - write!(v, "Hello {}/n", "world"); LL + writeln!(v, "Hello {}", "world"); @@ -29,7 +29,7 @@ error: using `write!()` with a format string that ends in a single newline LL | write!(v, "Hello {} {}/n", "world", "#2"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: use `writeln!()` instead +help: use `writeln!` instead | LL - write!(v, "Hello {} {}/n", "world", "#2"); LL + writeln!(v, "Hello {} {}", "world", "#2"); @@ -41,7 +41,7 @@ error: using `write!()` with a format string that ends in a single newline LL | write!(v, "{}/n", 1265); | ^^^^^^^^^^^^^^^^^^^^^^^ | -help: use `writeln!()` instead +help: use `writeln!` instead | LL - write!(v, "{}/n", 1265); LL + writeln!(v, "{}", 1265); @@ -53,7 +53,7 @@ error: using `write!()` with a format string that ends in a single newline LL | write!(v, "/n"); | ^^^^^^^^^^^^^^^ | -help: use `writeln!()` instead +help: use `writeln!` instead | LL - write!(v, "/n"); LL + writeln!(v); @@ -65,7 +65,7 @@ error: using `write!()` with a format string that ends in a single newline LL | write!(v, "//n"); // should fail | ^^^^^^^^^^^^^^^^^ | -help: use `writeln!()` instead +help: use `writeln!` instead | LL - write!(v, "//n"); // should fail LL + writeln!(v, "/"); // should fail @@ -81,11 +81,10 @@ LL | | " LL | | ); | |_____^ | -help: use `writeln!()` instead +help: use `writeln!` instead | LL ~ writeln!( -LL | v, -LL ~ "" +LL ~ v | error: using `write!()` with a format string that ends in a single newline @@ -98,11 +97,10 @@ LL | | " LL | | ); | |_____^ | -help: use `writeln!()` instead +help: use `writeln!` instead | LL ~ writeln!( -LL | v, -LL ~ r"" +LL ~ v | error: using `write!()` with a format string that ends in a single newline @@ -111,23 +109,11 @@ error: using `write!()` with a format string that ends in a single newline LL | write!(v, "/r/n"); //~ ERROR | ^^^^^^^^^^^^^^^^^^ | -help: use `writeln!()` instead +help: use `writeln!` instead | LL - write!(v, "/r/n"); //~ ERROR LL + writeln!(v, "/r"); //~ ERROR | -error: using `write!()` with a format string that ends in a single newline - --> $DIR/write_with_newline.rs:58:5 - | -LL | write!(v, "foo/rbar/n"); - | ^^^^^^^^^^^^^^^^^^^^^^^ - | -help: use `writeln!()` instead - | -LL - write!(v, "foo/rbar/n"); -LL + writeln!(v, "foo/rbar"); - | - -error: aborting due to 10 previous errors +error: aborting due to 9 previous errors diff --git a/tests/ui/writeln_empty_string.stderr b/tests/ui/writeln_empty_string.stderr index ac65aadfc0e89..25e69ec48e7e2 100644 --- a/tests/ui/writeln_empty_string.stderr +++ b/tests/ui/writeln_empty_string.stderr @@ -1,16 +1,20 @@ -error: using `writeln!(v, "")` +error: empty string literal in `writeln!` --> $DIR/writeln_empty_string.rs:11:5 | LL | writeln!(v, ""); - | ^^^^^^^^^^^^^^^ help: replace it with: `writeln!(v)` + | ^^^^^^^^^^----^ + | | + | help: remove the empty string | = note: `-D clippy::writeln-empty-string` implied by `-D warnings` -error: using `writeln!(suggestion, "")` +error: empty string literal in `writeln!` --> $DIR/writeln_empty_string.rs:14:5 | LL | writeln!(suggestion, ""); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `writeln!(suggestion)` + | ^^^^^^^^^^^^^^^^^^^----^ + | | + | help: remove the empty string error: aborting due to 2 previous errors From 4c5f23082aff7c55d32de9869c0c40df94eeae37 Mon Sep 17 00:00:00 2001 From: Caio Date: Wed, 21 Sep 2022 15:02:37 -0300 Subject: [PATCH 031/114] [arithmetic-side-effects] Consider references --- .../src/operators/arithmetic_side_effects.rs | 59 +++++---- tests/ui/arithmetic_side_effects.rs | 40 +++++- tests/ui/arithmetic_side_effects.stderr | 114 +++++++++++++++--- 3 files changed, 172 insertions(+), 41 deletions(-) diff --git a/clippy_lints/src/operators/arithmetic_side_effects.rs b/clippy_lints/src/operators/arithmetic_side_effects.rs index d24c57c0a4b8a..c8a374d90b559 100644 --- a/clippy_lints/src/operators/arithmetic_side_effects.rs +++ b/clippy_lints/src/operators/arithmetic_side_effects.rs @@ -9,7 +9,6 @@ use rustc_ast as ast; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::Ty; use rustc_session::impl_lint_pass; use rustc_span::source_map::{Span, Spanned}; @@ -78,28 +77,47 @@ impl ArithmeticSideEffects { ) } - /// Explicit integers like `1` or `i32::MAX`. Does not take into consideration references. - fn is_literal_integer(expr: &hir::Expr<'_>, expr_refs: Ty<'_>) -> bool { - let is_integral = expr_refs.is_integral(); - let is_literal = matches!(expr.kind, hir::ExprKind::Lit(_)); - is_integral && is_literal - } - + // Common entry-point to avoid code duplication. fn issue_lint(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) { let msg = "arithmetic operation that can potentially result in unexpected side-effects"; span_lint(cx, ARITHMETIC_SIDE_EFFECTS, expr.span, msg); self.expr_span = Some(expr.span); } + /// * If `expr` is a literal integer like `1` or `i32::MAX`, returns itself. + /// * Is `expr` is a literal integer reference like `&199`, returns the literal integer without + /// references. + /// * If `expr` is anything else, returns `None`. + fn literal_integer<'expr, 'tcx>( + cx: &LateContext<'tcx>, + expr: &'expr hir::Expr<'tcx>, + ) -> Option<&'expr hir::Expr<'tcx>> { + let expr_refs = cx.typeck_results().expr_ty(expr).peel_refs(); + + if !expr_refs.is_integral() { + return None; + } + + if matches!(expr.kind, hir::ExprKind::Lit(_)) { + return Some(expr); + } + + if let hir::ExprKind::AddrOf(.., inn) = expr.kind && let hir::ExprKind::Lit(_) = inn.kind { + return Some(inn) + } + + None + } + /// Manages when the lint should be triggered. Operations in constant environments, hard coded /// types, custom allowed types and non-constant operations that won't overflow are ignored. - fn manage_bin_ops( + fn manage_bin_ops<'tcx>( &mut self, - cx: &LateContext<'_>, - expr: &hir::Expr<'_>, + cx: &LateContext<'tcx>, + expr: &hir::Expr<'tcx>, op: &Spanned, - lhs: &hir::Expr<'_>, - rhs: &hir::Expr<'_>, + lhs: &hir::Expr<'tcx>, + rhs: &hir::Expr<'tcx>, ) { if constant_simple(cx, cx.typeck_results(), expr).is_some() { return; @@ -119,14 +137,11 @@ impl ArithmeticSideEffects { if self.is_allowed_ty(cx, lhs) || self.is_allowed_ty(cx, rhs) { return; } - let has_valid_op = match ( - Self::is_literal_integer(lhs, cx.typeck_results().expr_ty(lhs).peel_refs()), - Self::is_literal_integer(rhs, cx.typeck_results().expr_ty(rhs).peel_refs()), - ) { - (true, true) => true, - (true, false) => Self::has_valid_op(op, lhs), - (false, true) => Self::has_valid_op(op, rhs), - (false, false) => false, + let has_valid_op = match (Self::literal_integer(cx, lhs), Self::literal_integer(cx, rhs)) { + (None, None) => false, + (None, Some(local_expr)) => Self::has_valid_op(op, local_expr), + (Some(local_expr), None) => Self::has_valid_op(op, local_expr), + (Some(_), Some(_)) => true, }; if !has_valid_op { self.issue_lint(cx, expr); @@ -135,7 +150,7 @@ impl ArithmeticSideEffects { } impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { + 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)) { return; } diff --git a/tests/ui/arithmetic_side_effects.rs b/tests/ui/arithmetic_side_effects.rs index dd24f5aa592b3..6741e1485472c 100644 --- a/tests/ui/arithmetic_side_effects.rs +++ b/tests/ui/arithmetic_side_effects.rs @@ -2,11 +2,12 @@ clippy::assign_op_pattern, clippy::erasing_op, clippy::identity_op, + clippy::op_ref, clippy::unnecessary_owned_empty_strings, arithmetic_overflow, unconditional_panic )] -#![feature(inline_const, saturating_int_impl)] +#![feature(const_mut_refs, inline_const, saturating_int_impl)] #![warn(clippy::arithmetic_side_effects)] use core::num::{Saturating, Wrapping}; @@ -79,33 +80,50 @@ pub fn const_ops_should_not_trigger_the_lint() { const _: i32 = 1 + 1; let _ = const { 1 + 1 }; - const _: i32 = { let mut n = -1; n = -(-1); n = -n; n }; - let _ = const { let mut n = -1; n = -(-1); n = -n; n }; + const _: i32 = { let mut n = 1; n = -1; n = -(-1); n = -n; n }; + let _ = const { let mut n = 1; n = -1; n = -(-1); n = -n; n }; } -pub fn non_overflowing_runtime_ops_or_ops_already_handled_by_the_compiler() { +pub fn non_overflowing_ops_or_ops_already_handled_by_the_compiler_should_not_trigger_the_lint() { let mut _n = i32::MAX; // Assign _n += 0; + _n += &0; _n -= 0; + _n -= &0; _n /= 99; + _n /= &99; _n %= 99; + _n %= &99; _n *= 0; + _n *= &0; _n *= 1; + _n *= &1; // Binary _n = _n + 0; + _n = _n + &0; _n = 0 + _n; + _n = &0 + _n; _n = _n - 0; + _n = _n - &0; _n = 0 - _n; + _n = &0 - _n; _n = _n / 99; + _n = _n / &99; _n = _n % 99; + _n = _n % &99; _n = _n * 0; + _n = _n * &0; _n = 0 * _n; + _n = &0 * _n; _n = _n * 1; + _n = _n * &1; _n = 1 * _n; + _n = &1 * _n; _n = 23 + 85; + _n = &23 + &85; // Unary _n = -1; @@ -117,23 +135,37 @@ pub fn overflowing_runtime_ops() { // Assign _n += 1; + _n += &1; _n -= 1; + _n -= &1; _n /= 0; + _n /= &0; _n %= 0; + _n %= &0; _n *= 2; + _n *= &2; // Binary _n = _n + 1; + _n = _n + &1; _n = 1 + _n; + _n = &1 + _n; _n = _n - 1; + _n = _n - &1; _n = 1 - _n; + _n = &1 - _n; _n = _n / 0; + _n = _n / &0; _n = _n % 0; + _n = _n % &0; _n = _n * 2; + _n = _n * &2; _n = 2 * _n; + _n = &2 * _n; // Unary _n = -_n; + _n = -&_n; } fn main() {} diff --git a/tests/ui/arithmetic_side_effects.stderr b/tests/ui/arithmetic_side_effects.stderr index a2a856efbffc0..4dce13b624b4a 100644 --- a/tests/ui/arithmetic_side_effects.stderr +++ b/tests/ui/arithmetic_side_effects.stderr @@ -1,5 +1,5 @@ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:119:5 + --> $DIR/arithmetic_side_effects.rs:137:5 | LL | _n += 1; | ^^^^^^^ @@ -7,82 +7,166 @@ LL | _n += 1; = note: `-D clippy::arithmetic-side-effects` implied by `-D warnings` error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:120:5 + --> $DIR/arithmetic_side_effects.rs:138:5 + | +LL | _n += &1; + | ^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:139:5 | LL | _n -= 1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:121:5 + --> $DIR/arithmetic_side_effects.rs:140:5 + | +LL | _n -= &1; + | ^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:141:5 | LL | _n /= 0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:122:5 + --> $DIR/arithmetic_side_effects.rs:142:5 + | +LL | _n /= &0; + | ^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:143:5 | LL | _n %= 0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:123:5 + --> $DIR/arithmetic_side_effects.rs:144:5 + | +LL | _n %= &0; + | ^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:145:5 | LL | _n *= 2; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:126:10 + --> $DIR/arithmetic_side_effects.rs:146:5 + | +LL | _n *= &2; + | ^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:149:10 | LL | _n = _n + 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:127:10 + --> $DIR/arithmetic_side_effects.rs:150:10 + | +LL | _n = _n + &1; + | ^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:151:10 | LL | _n = 1 + _n; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:128:10 + --> $DIR/arithmetic_side_effects.rs:152:10 + | +LL | _n = &1 + _n; + | ^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:153:10 | LL | _n = _n - 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:129:10 + --> $DIR/arithmetic_side_effects.rs:154:10 + | +LL | _n = _n - &1; + | ^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:155:10 | LL | _n = 1 - _n; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:130:10 + --> $DIR/arithmetic_side_effects.rs:156:10 + | +LL | _n = &1 - _n; + | ^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:157:10 | LL | _n = _n / 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:131:10 + --> $DIR/arithmetic_side_effects.rs:158:10 + | +LL | _n = _n / &0; + | ^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:159:10 | LL | _n = _n % 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:132:10 + --> $DIR/arithmetic_side_effects.rs:160:10 + | +LL | _n = _n % &0; + | ^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:161:10 | LL | _n = _n * 2; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:133:10 + --> $DIR/arithmetic_side_effects.rs:162:10 + | +LL | _n = _n * &2; + | ^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:163:10 | LL | _n = 2 * _n; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:136:10 + --> $DIR/arithmetic_side_effects.rs:164:10 + | +LL | _n = &2 * _n; + | ^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:167:10 | LL | _n = -_n; | ^^^ -error: aborting due to 14 previous errors +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:168:10 + | +LL | _n = -&_n; + | ^^^^ + +error: aborting due to 28 previous errors From 033dae9ecc676a1a6d7fa43665ebff3861f2fa15 Mon Sep 17 00:00:00 2001 From: Michael Schubart Date: Wed, 21 Sep 2022 19:04:31 +0100 Subject: [PATCH 032/114] Actually use the sorted vector --- clippy_dev/src/update_lints.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs index b95061bf81a25..e77c70b67818a 100644 --- a/clippy_dev/src/update_lints.rs +++ b/clippy_dev/src/update_lints.rs @@ -45,9 +45,8 @@ fn generate_lint_files( renamed_lints: &[RenamedLint], ) { let internal_lints = Lint::internal_lints(lints); - let usable_lints = Lint::usable_lints(lints); - let mut sorted_usable_lints = usable_lints.clone(); - sorted_usable_lints.sort_by_key(|lint| lint.name.clone()); + let mut usable_lints = Lint::usable_lints(lints); + usable_lints.sort_by_key(|lint| lint.name.clone()); replace_region_in_file( update_mode, From 09b1e8ff3494a6fa92922ef992fb8fe861c87b28 Mon Sep 17 00:00:00 2001 From: Steve Heindel Date: Wed, 21 Sep 2022 19:45:57 -0400 Subject: [PATCH 033/114] Add note to clippy::non_expressive_names doc --- clippy_lints/src/non_expressive_names.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index b96af06b8d7c6..a7cd1f6d0652b 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -15,6 +15,10 @@ declare_clippy_lint! { /// ### What it does /// Checks for names that are very similar and thus confusing. /// + /// Note: this lint looks for similar names throughout each + /// scope. To allow it, you need to allow it on the scope + /// level, not on the name that is reported. + /// /// ### Why is this bad? /// It's hard to distinguish between names that differ only /// by a single character. From adc7e3e679ff18653fe646326ff0f27eaccd5f70 Mon Sep 17 00:00:00 2001 From: b-naber Date: Mon, 19 Sep 2022 19:46:53 +0200 Subject: [PATCH 034/114] introduce mir::Unevaluated --- clippy_lints/src/non_copy_const.rs | 2 +- clippy_utils/src/consts.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 72c86f28bbc6c..85024b0b05c8f 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -195,7 +195,7 @@ fn is_value_unfrozen_expr<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId, def_id: D let result = cx.tcx.const_eval_resolve( cx.param_env, - ty::Unevaluated::new(ty::WithOptConstParam::unknown(def_id), substs), + mir::Unevaluated::new(ty::WithOptConstParam::unknown(def_id), substs), None, ); is_value_unfrozen_raw(cx, result, ty) diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 1b8a9c05559a9..ac5bac3714f0e 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -424,7 +424,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { .tcx .const_eval_resolve( self.param_env, - ty::Unevaluated::new(ty::WithOptConstParam::unknown(def_id), substs), + mir::Unevaluated::new(ty::WithOptConstParam::unknown(def_id), substs), None, ) .ok() From a390115c6f0e40001e87a8fd6fdaf864ddd81cf4 Mon Sep 17 00:00:00 2001 From: kraktus Date: Mon, 19 Sep 2022 18:08:28 +0200 Subject: [PATCH 035/114] [`nonstandard_macro_braces`] Do not modify macro arguments Also simplify the lint by not caring about code format which should be `rustfmt` job, and turn the lint into machine Applicable --- clippy_lints/src/nonstandard_macro_braces.rs | 71 ++++++++-------- .../conf_nonstandard_macro_braces.fixed | 62 ++++++++++++++ .../conf_nonstandard_macro_braces.rs | 1 + .../conf_nonstandard_macro_braces.stderr | 81 ++++--------------- 4 files changed, 111 insertions(+), 104 deletions(-) create mode 100644 tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.fixed diff --git a/clippy_lints/src/nonstandard_macro_braces.rs b/clippy_lints/src/nonstandard_macro_braces.rs index f86dfb6b8df84..5e38a95c40b3d 100644 --- a/clippy_lints/src/nonstandard_macro_braces.rs +++ b/clippy_lints/src/nonstandard_macro_braces.rs @@ -3,16 +3,17 @@ use std::{ hash::{Hash, Hasher}, }; -use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; use if_chain::if_chain; use rustc_ast::ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_errors::Applicability; use rustc_hir::def_id::DefId; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::hygiene::{ExpnKind, MacroKind}; -use rustc_span::{Span, Symbol}; +use rustc_span::Span; use serde::{de, Deserialize}; declare_clippy_lint! { @@ -39,8 +40,8 @@ declare_clippy_lint! { const BRACES: &[(&str, &str)] = &[("(", ")"), ("{", "}"), ("[", "]")]; -/// The (name, (open brace, close brace), source snippet) -type MacroInfo<'a> = (Symbol, &'a (String, String), String); +/// The (callsite span, (open brace, close brace), source snippet) +type MacroInfo<'a> = (Span, &'a (String, String), String); #[derive(Clone, Debug, Default)] pub struct MacroBraces { @@ -62,33 +63,29 @@ impl_lint_pass!(MacroBraces => [NONSTANDARD_MACRO_BRACES]); impl EarlyLintPass for MacroBraces { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) { - if let Some((name, braces, snip)) = is_offending_macro(cx, item.span, self) { - let span = item.span.ctxt().outer_expn_data().call_site; - emit_help(cx, snip, braces, name, span); + if let Some((span, braces, snip)) = is_offending_macro(cx, item.span, self) { + emit_help(cx, &snip, braces, span); self.done.insert(span); } } fn check_stmt(&mut self, cx: &EarlyContext<'_>, stmt: &ast::Stmt) { - if let Some((name, braces, snip)) = is_offending_macro(cx, stmt.span, self) { - let span = stmt.span.ctxt().outer_expn_data().call_site; - emit_help(cx, snip, braces, name, span); + if let Some((span, braces, snip)) = is_offending_macro(cx, stmt.span, self) { + emit_help(cx, &snip, braces, span); self.done.insert(span); } } fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) { - if let Some((name, braces, snip)) = is_offending_macro(cx, expr.span, self) { - let span = expr.span.ctxt().outer_expn_data().call_site; - emit_help(cx, snip, braces, name, span); + if let Some((span, braces, snip)) = is_offending_macro(cx, expr.span, self) { + emit_help(cx, &snip, braces, span); self.done.insert(span); } } fn check_ty(&mut self, cx: &EarlyContext<'_>, ty: &ast::Ty) { - if let Some((name, braces, snip)) = is_offending_macro(cx, ty.span, self) { - let span = ty.span.ctxt().outer_expn_data().call_site; - emit_help(cx, snip, braces, name, span); + if let Some((span, braces, snip)) = is_offending_macro(cx, ty.span, self) { + emit_help(cx, &snip, braces, span); self.done.insert(span); } } @@ -102,11 +99,12 @@ fn is_offending_macro<'a>(cx: &EarlyContext<'_>, span: Span, mac_braces: &'a Mac .last() .map_or(false, |e| e.macro_def_id.map_or(false, DefId::is_local)) }; + let span_call_site = span.ctxt().outer_expn_data().call_site; if_chain! { if let ExpnKind::Macro(MacroKind::Bang, mac_name) = span.ctxt().outer_expn_data().kind; let name = mac_name.as_str(); if let Some(braces) = mac_braces.macro_braces.get(name); - if let Some(snip) = snippet_opt(cx, span.ctxt().outer_expn_data().call_site); + if let Some(snip) = snippet_opt(cx, span_call_site); // we must check only invocation sites // https://github.com/rust-lang/rust-clippy/issues/7422 if snip.starts_with(&format!("{}!", name)); @@ -114,36 +112,31 @@ fn is_offending_macro<'a>(cx: &EarlyContext<'_>, span: Span, mac_braces: &'a Mac // make formatting consistent let c = snip.replace(' ', ""); if !c.starts_with(&format!("{}!{}", name, braces.0)); - if !mac_braces.done.contains(&span.ctxt().outer_expn_data().call_site); + if !mac_braces.done.contains(&span_call_site); then { - Some((mac_name, braces, snip)) + Some((span_call_site, braces, snip)) } else { None } } } -fn emit_help(cx: &EarlyContext<'_>, snip: String, braces: &(String, String), name: Symbol, span: Span) { - let with_space = &format!("! {}", braces.0); - let without_space = &format!("!{}", braces.0); - let mut help = snip; - for b in BRACES.iter().filter(|b| b.0 != braces.0) { - help = help.replace(b.0, &braces.0).replace(b.1, &braces.1); - // Only `{` traditionally has space before the brace - if braces.0 != "{" && help.contains(with_space) { - help = help.replace(with_space, without_space); - } else if braces.0 == "{" && help.contains(without_space) { - help = help.replace(without_space, with_space); - } +fn emit_help(cx: &EarlyContext<'_>, snip: &str, braces: &(String, String), span: Span) { + if let Some((macro_name, macro_args_str)) = snip.split_once('!') { + let mut macro_args = macro_args_str.trim().to_string(); + // now remove the wrong braces + macro_args.remove(0); + macro_args.pop(); + span_lint_and_sugg( + cx, + NONSTANDARD_MACRO_BRACES, + span, + &format!("use of irregular braces for `{}!` macro", macro_name), + "consider writing", + format!("{}!{}{}{}", macro_name, braces.0, macro_args, braces.1), + Applicability::MachineApplicable, + ); } - span_lint_and_help( - cx, - NONSTANDARD_MACRO_BRACES, - span, - &format!("use of irregular braces for `{}!` macro", name), - Some(span), - &format!("consider writing `{}`", help), - ); } fn macro_braces(conf: FxHashSet) -> FxHashMap { diff --git a/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.fixed b/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.fixed new file mode 100644 index 0000000000000..01d135764dffd --- /dev/null +++ b/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.fixed @@ -0,0 +1,62 @@ +// aux-build:proc_macro_derive.rs +// run-rustfix + +#![warn(clippy::nonstandard_macro_braces)] + +extern crate proc_macro_derive; +extern crate quote; + +use quote::quote; + +#[derive(proc_macro_derive::DeriveSomething)] +pub struct S; + +proc_macro_derive::foo_bar!(); + +#[rustfmt::skip] +macro_rules! test { + () => { + vec![0, 0, 0] + }; +} + +#[rustfmt::skip] +macro_rules! test2 { + ($($arg:tt)*) => { + format_args!($($arg)*) + }; +} + +macro_rules! type_pos { + ($what:ty) => { + Vec<$what> + }; +} + +macro_rules! printlnfoo { + ($thing:expr) => { + println!("{}", $thing) + }; +} + +#[rustfmt::skip] +fn main() { + let _ = vec![1, 2, 3]; + let _ = format!("ugh {} stop being such a good compiler", "hello"); + let _ = matches!({}, ()); + let _ = quote!{let x = 1;}; + let _ = quote::quote!{match match match}; + let _ = test!(); // trigger when macro def is inside our own crate + let _ = vec![1,2,3]; + + let _ = quote::quote! {true || false}; + let _ = vec! [0 ,0 ,0]; + let _ = format!("fds{}fds", 10); + let _ = test2!["{}{}{}", 1, 2, 3]; + + let _: type_pos![usize] = vec![]; + + eprint!["test if user config overrides defaults"]; + + printlnfoo!["test if printlnfoo is triggered by println"]; +} diff --git a/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs b/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs index ed8161acc0efb..72883e8270c3b 100644 --- a/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs +++ b/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs @@ -1,4 +1,5 @@ // aux-build:proc_macro_derive.rs +// run-rustfix #![warn(clippy::nonstandard_macro_braces)] diff --git a/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.stderr b/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.stderr index d80ad49f3086d..7ae3815978c77 100644 --- a/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.stderr +++ b/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.stderr @@ -1,106 +1,57 @@ error: use of irregular braces for `vec!` macro - --> $DIR/conf_nonstandard_macro_braces.rs:43:13 + --> $DIR/conf_nonstandard_macro_braces.rs:44:13 | LL | let _ = vec! {1, 2, 3}; - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ help: consider writing: `vec![1, 2, 3]` | = note: `-D clippy::nonstandard-macro-braces` implied by `-D warnings` -help: consider writing `vec![1, 2, 3]` - --> $DIR/conf_nonstandard_macro_braces.rs:43:13 - | -LL | let _ = vec! {1, 2, 3}; - | ^^^^^^^^^^^^^^ error: use of irregular braces for `format!` macro - --> $DIR/conf_nonstandard_macro_braces.rs:44:13 - | -LL | let _ = format!["ugh {} stop being such a good compiler", "hello"]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: consider writing `format!("ugh () stop being such a good compiler", "hello")` - --> $DIR/conf_nonstandard_macro_braces.rs:44:13 + --> $DIR/conf_nonstandard_macro_braces.rs:45:13 | LL | let _ = format!["ugh {} stop being such a good compiler", "hello"]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `format!("ugh {} stop being such a good compiler", "hello")` error: use of irregular braces for `matches!` macro - --> $DIR/conf_nonstandard_macro_braces.rs:45:13 - | -LL | let _ = matches!{{}, ()}; - | ^^^^^^^^^^^^^^^^ - | -help: consider writing `matches!((), ())` - --> $DIR/conf_nonstandard_macro_braces.rs:45:13 + --> $DIR/conf_nonstandard_macro_braces.rs:46:13 | LL | let _ = matches!{{}, ()}; - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ help: consider writing: `matches!({}, ())` error: use of irregular braces for `quote!` macro - --> $DIR/conf_nonstandard_macro_braces.rs:46:13 - | -LL | let _ = quote!(let x = 1;); - | ^^^^^^^^^^^^^^^^^^ - | -help: consider writing `quote! {let x = 1;}` - --> $DIR/conf_nonstandard_macro_braces.rs:46:13 + --> $DIR/conf_nonstandard_macro_braces.rs:47:13 | LL | let _ = quote!(let x = 1;); - | ^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ help: consider writing: `quote!{let x = 1;}` error: use of irregular braces for `quote::quote!` macro - --> $DIR/conf_nonstandard_macro_braces.rs:47:13 + --> $DIR/conf_nonstandard_macro_braces.rs:48:13 | LL | let _ = quote::quote!(match match match); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: consider writing `quote::quote! {match match match}` - --> $DIR/conf_nonstandard_macro_braces.rs:47:13 - | -LL | let _ = quote::quote!(match match match); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `quote::quote!{match match match}` error: use of irregular braces for `vec!` macro - --> $DIR/conf_nonstandard_macro_braces.rs:18:9 + --> $DIR/conf_nonstandard_macro_braces.rs:19:9 | LL | vec!{0, 0, 0} - | ^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ help: consider writing: `vec![0, 0, 0]` ... LL | let _ = test!(); // trigger when macro def is inside our own crate | ------- in this macro invocation | -help: consider writing `vec![0, 0, 0]` - --> $DIR/conf_nonstandard_macro_braces.rs:18:9 - | -LL | vec!{0, 0, 0} - | ^^^^^^^^^^^^^ -... -LL | let _ = test!(); // trigger when macro def is inside our own crate - | ------- in this macro invocation = note: this error originates in the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info) error: use of irregular braces for `type_pos!` macro - --> $DIR/conf_nonstandard_macro_braces.rs:56:12 + --> $DIR/conf_nonstandard_macro_braces.rs:57:12 | LL | let _: type_pos!(usize) = vec![]; - | ^^^^^^^^^^^^^^^^ - | -help: consider writing `type_pos![usize]` - --> $DIR/conf_nonstandard_macro_braces.rs:56:12 - | -LL | let _: type_pos!(usize) = vec![]; - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ help: consider writing: `type_pos![usize]` error: use of irregular braces for `eprint!` macro - --> $DIR/conf_nonstandard_macro_braces.rs:58:5 - | -LL | eprint!("test if user config overrides defaults"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: consider writing `eprint!["test if user config overrides defaults"]` - --> $DIR/conf_nonstandard_macro_braces.rs:58:5 + --> $DIR/conf_nonstandard_macro_braces.rs:59:5 | LL | eprint!("test if user config overrides defaults"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `eprint!["test if user config overrides defaults"]` error: aborting due to 8 previous errors From cda754739471869a12d7055466180e4fec702dba Mon Sep 17 00:00:00 2001 From: kraktus Date: Thu, 22 Sep 2022 16:33:14 +0200 Subject: [PATCH 036/114] Make `semicolon_span` code more refactor-tolerant --- clippy_lints/src/returns.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index f7ceb415a798c..f758f4cff8ba1 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -9,7 +9,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; 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::source_map::{Span, DUMMY_SP}; +use rustc_span::source_map::Span; declare_clippy_lint! { /// ### What it does @@ -182,8 +182,10 @@ fn check_block_return<'tcx>(cx: &LateContext<'tcx>, expr_kind: &ExprKind<'tcx>, StmtKind::Semi(semi_expr) => { let mut semi_spans_and_this_one = semi_spans; // we only want the span containing the semicolon so we can remove it later. From `entry.rs:382` - semi_spans_and_this_one.push(stmt.span.trim_start(semi_expr.span).unwrap_or(DUMMY_SP)); - check_final_expr(cx, semi_expr, semi_spans_and_this_one, RetReplacement::Empty); + if let Some(semicolon_span) = stmt.span.trim_start(semi_expr.span) { + semi_spans_and_this_one.push(semicolon_span); + check_final_expr(cx, semi_expr, semi_spans_and_this_one, RetReplacement::Empty); + } }, _ => (), } From b33364597105dc60555957a4ae59bb780eb15147 Mon Sep 17 00:00:00 2001 From: kraktus Date: Thu, 22 Sep 2022 16:44:21 +0200 Subject: [PATCH 037/114] Add test with `unsafe` block to check #9503 is fixed too s --- tests/ui/needless_return.fixed | 10 ++++++++++ tests/ui/needless_return.rs | 10 ++++++++++ tests/ui/needless_return.stderr | 18 +++++++++++++++++- 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/tests/ui/needless_return.fixed b/tests/ui/needless_return.fixed index a5e28b9b1a447..112a2f57b419e 100644 --- a/tests/ui/needless_return.fixed +++ b/tests/ui/needless_return.fixed @@ -260,4 +260,14 @@ fn issue9192() -> i32 { } } +fn issue9503(x: usize) -> isize { + unsafe { + if x > 12 { + *(x as *const isize) + } else { + !*(x as *const isize) + } + } +} + fn main() {} diff --git a/tests/ui/needless_return.rs b/tests/ui/needless_return.rs index 49fd49c72936e..22aa2e11fadb1 100644 --- a/tests/ui/needless_return.rs +++ b/tests/ui/needless_return.rs @@ -260,4 +260,14 @@ fn issue9192() -> i32 { }; } +fn issue9503(x: usize) -> isize { + unsafe { + if x > 12 { + return *(x as *const isize); + } else { + return !*(x as *const isize); + }; + }; +} + fn main() {} diff --git a/tests/ui/needless_return.stderr b/tests/ui/needless_return.stderr index d8dba766bf4ae..45090dbe2064e 100644 --- a/tests/ui/needless_return.stderr +++ b/tests/ui/needless_return.stderr @@ -335,5 +335,21 @@ LL | return 0; | = help: remove `return` -error: aborting due to 42 previous errors +error: unneeded `return` statement + --> $DIR/needless_return.rs:266:13 + | +LL | return *(x as *const isize); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: remove `return` + +error: unneeded `return` statement + --> $DIR/needless_return.rs:268:13 + | +LL | return !*(x as *const isize); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: remove `return` + +error: aborting due to 44 previous errors From 49319b4206cbde83e0113c024b09275677ab8d74 Mon Sep 17 00:00:00 2001 From: Alessandro Decina Date: Fri, 23 Sep 2022 00:06:13 +0100 Subject: [PATCH 038/114] uninit_vec: special case set_len(0) set_len(0) does not create uninitialized elements. Fixes a false positive with the following pattern: fn copy_slice_into_vec(dst: &mut Vec, src: &[u8]) { dst.reserve(src.len().saturating_sub(dst.len())); unsafe { dst.set_len(0); std::ptr::copy_nonoverlapping(src.as_ptr(), dst.as_mut_ptr(), src.len()); dst.set_len(src.len()); } } --- clippy_lints/src/uninit_vec.rs | 18 ++++++++++++++++-- tests/ui/uninit_vec.rs | 6 ++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/uninit_vec.rs b/clippy_lints/src/uninit_vec.rs index 3f99bd3f31567..bde7c318f448c 100644 --- a/clippy_lints/src/uninit_vec.rs +++ b/clippy_lints/src/uninit_vec.rs @@ -2,6 +2,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::higher::{get_vec_init_kind, VecInitKind}; use clippy_utils::ty::{is_type_diagnostic_item, is_uninit_value_valid_for_ty}; use clippy_utils::{is_lint_allowed, path_to_local_id, peel_hir_expr_while, SpanlessEq}; +use rustc_ast::ast::LitKind; use rustc_hir::{Block, Expr, ExprKind, HirId, PatKind, PathSegment, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; @@ -211,9 +212,12 @@ fn extract_set_len_self<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Opt } }); match expr.kind { - ExprKind::MethodCall(path, self_expr, [_], _) => { + ExprKind::MethodCall(path, self_expr, [arg], _) => { let self_type = cx.typeck_results().expr_ty(self_expr).peel_refs(); - if is_type_diagnostic_item(cx, self_type, sym::Vec) && path.ident.name.as_str() == "set_len" { + if is_type_diagnostic_item(cx, self_type, sym::Vec) + && path.ident.name.as_str() == "set_len" + && !is_literal_zero(arg) + { Some((self_expr, expr.span)) } else { None @@ -222,3 +226,13 @@ fn extract_set_len_self<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Opt _ => None, } } + +fn is_literal_zero(arg: &Expr<'_>) -> bool { + if let ExprKind::Lit(lit) = &arg.kind + && let LitKind::Int(0, _) = lit.node + { + true + } else { + false + } +} diff --git a/tests/ui/uninit_vec.rs b/tests/ui/uninit_vec.rs index dc150cf28f2cc..194e4fc157ef1 100644 --- a/tests/ui/uninit_vec.rs +++ b/tests/ui/uninit_vec.rs @@ -91,4 +91,10 @@ fn main() { vec1.set_len(200); vec2.set_len(200); } + + // set_len(0) should not be detected + let mut vec: Vec = Vec::with_capacity(1000); + unsafe { + vec.set_len(0); + } } From 628a854ae215f7ce2a68294467c40febfa6650b9 Mon Sep 17 00:00:00 2001 From: Samuel Moelius Date: Fri, 23 Sep 2022 05:53:42 -0400 Subject: [PATCH 039/114] Upgrade `copiletest-rs` dependency --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index d648cd7945ef2..5e960fdbcf118 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ tempfile = { version = "3.2", optional = true } termize = "0.1" [dev-dependencies] -compiletest_rs = { version = "0.8", features = ["tmp"] } +compiletest_rs = { version = "0.9", features = ["tmp"] } tester = "0.9" regex = "1.5" toml = "0.5" From 26861fbd7f5fa80928f2ccad750ec2cc9726862c Mon Sep 17 00:00:00 2001 From: b-naber Date: Thu, 22 Sep 2022 12:34:23 +0200 Subject: [PATCH 040/114] rename Unevaluated to UnevaluatedConst --- clippy_lints/src/non_copy_const.rs | 2 +- clippy_utils/src/consts.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 85024b0b05c8f..b15884527321c 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -195,7 +195,7 @@ fn is_value_unfrozen_expr<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId, def_id: D let result = cx.tcx.const_eval_resolve( cx.param_env, - mir::Unevaluated::new(ty::WithOptConstParam::unknown(def_id), substs), + mir::UnevaluatedConst::new(ty::WithOptConstParam::unknown(def_id), substs), None, ); is_value_unfrozen_raw(cx, result, ty) diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index ac5bac3714f0e..fa6766f7cfe19 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -424,7 +424,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { .tcx .const_eval_resolve( self.param_env, - mir::Unevaluated::new(ty::WithOptConstParam::unknown(def_id), substs), + mir::UnevaluatedConst::new(ty::WithOptConstParam::unknown(def_id), substs), None, ) .ok() From 781e45c224e2ae2f2d7876d2ebb3d0390db45a6c Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 22 Sep 2022 19:39:38 +0200 Subject: [PATCH 041/114] Bless clippy. --- tests/ui/inefficient_to_string.stderr | 8 ++++---- tests/ui/suspicious_to_owned.stderr | 8 ++++---- tests/ui/transmute_ptr_to_ref.stderr | 4 ++-- tests/ui/useless_conversion.stderr | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/ui/inefficient_to_string.stderr b/tests/ui/inefficient_to_string.stderr index 4be46161e8b74..1c0490ffa44cc 100644 --- a/tests/ui/inefficient_to_string.stderr +++ b/tests/ui/inefficient_to_string.stderr @@ -35,21 +35,21 @@ LL | let _: String = rrrstring.to_string(); | = help: `&&std::string::String` implements `ToString` through a slower blanket impl, but `std::string::String` has a fast specialization of `ToString` -error: calling `to_string` on `&&std::borrow::Cow` +error: calling `to_string` on `&&std::borrow::Cow<'_, str>` --> $DIR/inefficient_to_string.rs:29:21 | LL | let _: String = rrcow.to_string(); | ^^^^^^^^^^^^^^^^^ help: try dereferencing the receiver: `(*rrcow).to_string()` | - = help: `&std::borrow::Cow` implements `ToString` through a slower blanket impl, but `std::borrow::Cow` has a fast specialization of `ToString` + = help: `&std::borrow::Cow<'_, str>` implements `ToString` through a slower blanket impl, but `std::borrow::Cow<'_, str>` has a fast specialization of `ToString` -error: calling `to_string` on `&&&std::borrow::Cow` +error: calling `to_string` on `&&&std::borrow::Cow<'_, str>` --> $DIR/inefficient_to_string.rs:30:21 | LL | let _: String = rrrcow.to_string(); | ^^^^^^^^^^^^^^^^^^ help: try dereferencing the receiver: `(**rrrcow).to_string()` | - = help: `&&std::borrow::Cow` implements `ToString` through a slower blanket impl, but `std::borrow::Cow` has a fast specialization of `ToString` + = help: `&&std::borrow::Cow<'_, str>` implements `ToString` through a slower blanket impl, but `std::borrow::Cow<'_, str>` has a fast specialization of `ToString` error: aborting due to 6 previous errors diff --git a/tests/ui/suspicious_to_owned.stderr b/tests/ui/suspicious_to_owned.stderr index 92e1024bf1f4e..ae1aec34d82e0 100644 --- a/tests/ui/suspicious_to_owned.stderr +++ b/tests/ui/suspicious_to_owned.stderr @@ -1,4 +1,4 @@ -error: this `to_owned` call clones the std::borrow::Cow itself and does not cause the std::borrow::Cow contents to become owned +error: this `to_owned` call clones the std::borrow::Cow<'_, str> itself and does not cause the std::borrow::Cow<'_, str> contents to become owned --> $DIR/suspicious_to_owned.rs:16:13 | LL | let _ = cow.to_owned(); @@ -6,19 +6,19 @@ LL | let _ = cow.to_owned(); | = note: `-D clippy::suspicious-to-owned` implied by `-D warnings` -error: this `to_owned` call clones the std::borrow::Cow<[char; 3]> itself and does not cause the std::borrow::Cow<[char; 3]> contents to become owned +error: this `to_owned` call clones the std::borrow::Cow<'_, [char; 3]> itself and does not cause the std::borrow::Cow<'_, [char; 3]> contents to become owned --> $DIR/suspicious_to_owned.rs:26:13 | LL | let _ = cow.to_owned(); | ^^^^^^^^^^^^^^ help: consider using, depending on intent: `cow.clone()` or `cow.into_owned()` -error: this `to_owned` call clones the std::borrow::Cow> itself and does not cause the std::borrow::Cow> contents to become owned +error: this `to_owned` call clones the std::borrow::Cow<'_, std::vec::Vec> itself and does not cause the std::borrow::Cow<'_, std::vec::Vec> contents to become owned --> $DIR/suspicious_to_owned.rs:36:13 | LL | let _ = cow.to_owned(); | ^^^^^^^^^^^^^^ help: consider using, depending on intent: `cow.clone()` or `cow.into_owned()` -error: this `to_owned` call clones the std::borrow::Cow itself and does not cause the std::borrow::Cow contents to become owned +error: this `to_owned` call clones the std::borrow::Cow<'_, str> itself and does not cause the std::borrow::Cow<'_, str> contents to become owned --> $DIR/suspicious_to_owned.rs:46:13 | LL | let _ = cow.to_owned(); diff --git a/tests/ui/transmute_ptr_to_ref.stderr b/tests/ui/transmute_ptr_to_ref.stderr index 2993e5e7b0c91..10117ee9182ab 100644 --- a/tests/ui/transmute_ptr_to_ref.stderr +++ b/tests/ui/transmute_ptr_to_ref.stderr @@ -42,13 +42,13 @@ error: transmute from a pointer type (`*mut U`) to a reference type (`&T`) LL | let _: &T = std::mem::transmute(om); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(om as *const T)` -error: transmute from a pointer type (`*const i32`) to a reference type (`&_issue1231::Foo`) +error: transmute from a pointer type (`*const i32`) to a reference type (`&_issue1231::Foo<'_, u8>`) --> $DIR/transmute_ptr_to_ref.rs:36:32 | LL | let _: &Foo = unsafe { std::mem::transmute::<_, &Foo<_>>(raw) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*raw.cast::>()` -error: transmute from a pointer type (`*const i32`) to a reference type (`&_issue1231::Foo<&u8>`) +error: transmute from a pointer type (`*const i32`) to a reference type (`&_issue1231::Foo<'_, &u8>`) --> $DIR/transmute_ptr_to_ref.rs:38:33 | LL | let _: &Foo<&u8> = unsafe { std::mem::transmute::<_, &Foo<&_>>(raw) }; diff --git a/tests/ui/useless_conversion.stderr b/tests/ui/useless_conversion.stderr index e6760f700f342..65ee3807fa9d9 100644 --- a/tests/ui/useless_conversion.stderr +++ b/tests/ui/useless_conversion.stderr @@ -46,7 +46,7 @@ error: useless conversion to the same type: `std::string::String` LL | let _ = String::from(format!("A: {:04}", 123)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `format!("A: {:04}", 123)` -error: useless conversion to the same type: `std::str::Lines` +error: useless conversion to the same type: `std::str::Lines<'_>` --> $DIR/useless_conversion.rs:65:13 | LL | let _ = "".lines().into_iter(); From e67b2bf732876eeb26e0d2fbc4b6c55e1a9f9317 Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Fri, 23 Sep 2022 13:42:59 -0400 Subject: [PATCH 042/114] Apply uninlined_format-args to clippy_lints This change is needed for the uninlined_format-args lint to be merged. See https://github.com/rust-lang/rust-clippy/pull/9233 --- clippy_lints/src/approx_const.rs | 4 +- clippy_lints/src/asm_syntax.rs | 2 +- clippy_lints/src/assertions_on_constants.rs | 4 +- .../src/assertions_on_result_states.rs | 10 ++--- clippy_lints/src/attrs.rs | 7 +--- clippy_lints/src/bool_assert_comparison.rs | 4 +- clippy_lints/src/booleans.rs | 5 +-- clippy_lints/src/cargo/common_metadata.rs | 2 +- clippy_lints/src/cargo/feature_name.rs | 4 +- clippy_lints/src/cargo/mod.rs | 4 +- .../src/cargo/multiple_crate_versions.rs | 2 +- clippy_lints/src/casts/borrow_as_ptr.rs | 2 +- clippy_lints/src/casts/cast_lossless.rs | 12 ++---- .../src/casts/cast_possible_truncation.rs | 16 +++----- clippy_lints/src/casts/cast_possible_wrap.rs | 5 +-- clippy_lints/src/casts/cast_ptr_alignment.rs | 4 +- clippy_lints/src/casts/cast_sign_loss.rs | 5 +-- .../src/casts/cast_slice_different_sizes.rs | 4 +- clippy_lints/src/casts/char_lit_as_u8.rs | 2 +- clippy_lints/src/casts/fn_to_numeric_cast.rs | 4 +- .../src/casts/fn_to_numeric_cast_any.rs | 4 +- .../fn_to_numeric_cast_with_truncation.rs | 7 +--- clippy_lints/src/casts/ptr_as_ptr.rs | 4 +- clippy_lints/src/casts/unnecessary_cast.rs | 9 ++--- clippy_lints/src/checked_conversions.rs | 2 +- clippy_lints/src/cognitive_complexity.rs | 3 +- clippy_lints/src/default.rs | 17 ++++---- clippy_lints/src/default_numeric_fallback.rs | 4 +- clippy_lints/src/dereference.rs | 14 +++---- clippy_lints/src/disallowed_methods.rs | 2 +- clippy_lints/src/disallowed_script_idents.rs | 3 +- clippy_lints/src/disallowed_types.rs | 4 +- clippy_lints/src/doc.rs | 2 +- clippy_lints/src/drop_forget_ref.rs | 2 +- clippy_lints/src/entry.rs | 28 ++++--------- clippy_lints/src/enum_variants.rs | 7 ++-- clippy_lints/src/equatable_if_let.rs | 3 +- clippy_lints/src/eta_reduction.rs | 4 +- clippy_lints/src/exhaustive_items.rs | 2 +- clippy_lints/src/explicit_write.rs | 8 ++-- clippy_lints/src/float_literal.rs | 6 +-- clippy_lints/src/floating_point_arithmetic.rs | 7 ++-- clippy_lints/src/format.rs | 2 +- clippy_lints/src/format_args.rs | 17 +++----- clippy_lints/src/format_impl.rs | 6 +-- clippy_lints/src/formatting.rs | 25 +++++------- clippy_lints/src/from_str_radix_10.rs | 2 +- clippy_lints/src/functions/must_use.rs | 2 +- .../src/functions/too_many_arguments.rs | 5 +-- clippy_lints/src/functions/too_many_lines.rs | 5 +-- clippy_lints/src/if_then_some_else_none.rs | 9 ++--- clippy_lints/src/implicit_hasher.rs | 7 ++-- clippy_lints/src/implicit_return.rs | 4 +- clippy_lints/src/implicit_saturating_sub.rs | 2 +- .../src/inconsistent_struct_constructor.rs | 6 +-- clippy_lints/src/index_refutable_slice.rs | 4 +- clippy_lints/src/inherent_to_string.rs | 12 ++---- clippy_lints/src/inline_fn_without_body.rs | 2 +- clippy_lints/src/int_plus_one.rs | 4 +- .../src/iter_not_returning_iterator.rs | 5 +-- clippy_lints/src/len_zero.rs | 35 +++++++--------- clippy_lints/src/let_if_seq.rs | 3 +- clippy_lints/src/lib.rs | 11 ++--- clippy_lints/src/literal_representation.rs | 2 +- .../src/loops/explicit_counter_loop.rs | 14 +++---- clippy_lints/src/loops/explicit_iter_loop.rs | 2 +- clippy_lints/src/loops/for_kv_map.rs | 4 +- clippy_lints/src/loops/manual_flatten.rs | 2 +- clippy_lints/src/loops/manual_memcpy.rs | 13 +----- clippy_lints/src/loops/needless_collect.rs | 6 +-- clippy_lints/src/loops/needless_range_loop.rs | 10 ++--- clippy_lints/src/loops/never_loop.rs | 6 +-- clippy_lints/src/loops/same_item_push.rs | 5 +-- clippy_lints/src/loops/utils.rs | 3 +- .../src/loops/while_let_on_iterator.rs | 2 +- clippy_lints/src/macro_use.rs | 6 +-- clippy_lints/src/manual_async_fn.rs | 6 +-- clippy_lints/src/manual_non_exhaustive.rs | 4 +- clippy_lints/src/manual_retain.rs | 14 +++---- clippy_lints/src/manual_strip.rs | 9 ++--- clippy_lints/src/map_unit_fn.rs | 5 +-- clippy_lints/src/match_result_ok.rs | 6 +-- clippy_lints/src/matches/manual_map.rs | 14 +++---- clippy_lints/src/matches/manual_unwrap_or.rs | 6 +-- clippy_lints/src/matches/match_as_ref.rs | 6 +-- .../src/matches/match_like_matches.rs | 5 +-- clippy_lints/src/matches/match_same_arms.rs | 2 +- .../src/matches/match_single_binding.rs | 28 +++++-------- .../src/matches/match_str_case_mismatch.rs | 4 +- .../src/matches/match_wild_err_arm.rs | 2 +- .../src/matches/redundant_pattern_match.rs | 8 ++-- .../matches/significant_drop_in_scrutinee.rs | 6 +-- clippy_lints/src/matches/single_match.rs | 6 +-- clippy_lints/src/matches/try_err.rs | 4 +- .../src/methods/bind_instead_of_map.rs | 2 +- clippy_lints/src/methods/bytes_nth.rs | 2 +- clippy_lints/src/methods/chars_cmp.rs | 5 +-- .../src/methods/chars_cmp_with_unwrap.rs | 5 +-- clippy_lints/src/methods/clone_on_copy.rs | 13 +++--- clippy_lints/src/methods/clone_on_ref_ptr.rs | 2 +- clippy_lints/src/methods/expect_fun_call.rs | 11 ++--- clippy_lints/src/methods/filetype_is_file.rs | 4 +- clippy_lints/src/methods/filter_map_next.rs | 2 +- clippy_lints/src/methods/filter_next.rs | 2 +- .../methods/from_iter_instead_of_collect.rs | 6 +-- clippy_lints/src/methods/get_first.rs | 4 +- clippy_lints/src/methods/get_unwrap.rs | 11 ++--- clippy_lints/src/methods/implicit_clone.rs | 6 +-- .../src/methods/inefficient_to_string.rs | 7 ++-- clippy_lints/src/methods/into_iter_on_ref.rs | 3 +- .../src/methods/is_digit_ascii_radix.rs | 7 ++-- .../src/methods/iter_cloned_collect.rs | 4 +- clippy_lints/src/methods/iter_count.rs | 2 +- clippy_lints/src/methods/iter_kv_map.rs | 8 ++-- clippy_lints/src/methods/iter_next_slice.rs | 2 +- clippy_lints/src/methods/iter_nth.rs | 4 +- clippy_lints/src/methods/iter_with_drain.rs | 2 +- clippy_lints/src/methods/manual_ok_or.rs | 4 +- .../methods/manual_saturating_arithmetic.rs | 5 +-- clippy_lints/src/methods/manual_str_repeat.rs | 2 +- clippy_lints/src/methods/map_clone.rs | 5 +-- clippy_lints/src/methods/map_flatten.rs | 9 ++--- clippy_lints/src/methods/map_identity.rs | 2 +- clippy_lints/src/methods/map_unwrap_or.rs | 2 +- .../src/methods/option_as_ref_deref.rs | 9 ++--- .../src/methods/option_map_or_none.rs | 6 +-- .../src/methods/option_map_unwrap_or.rs | 9 ++--- clippy_lints/src/methods/or_fun_call.rs | 10 ++--- clippy_lints/src/methods/search_is_some.rs | 14 +++---- .../src/methods/single_char_insert_string.rs | 2 +- .../src/methods/single_char_push_string.rs | 2 +- .../src/methods/stable_sort_primitive.rs | 4 +- .../src/methods/string_extend_chars.rs | 3 +- clippy_lints/src/methods/suspicious_splitn.rs | 4 +- .../src/methods/suspicious_to_owned.rs | 4 +- .../src/methods/unnecessary_filter_map.rs | 2 +- clippy_lints/src/methods/unnecessary_fold.rs | 7 +--- .../src/methods/unnecessary_iter_cloned.rs | 2 +- .../src/methods/unnecessary_lazy_eval.rs | 4 +- .../src/methods/unnecessary_to_owned.rs | 21 +++++----- clippy_lints/src/methods/useless_asref.rs | 2 +- .../src/methods/wrong_self_convention.rs | 15 ++++--- clippy_lints/src/misc.rs | 18 ++++----- clippy_lints/src/misc_early/literal_suffix.rs | 8 ++-- clippy_lints/src/misc_early/mod.rs | 5 +-- .../src/misc_early/unneeded_field_pattern.rs | 4 +- .../src/mismatching_type_param_order.rs | 7 ++-- clippy_lints/src/missing_doc.rs | 2 +- .../src/missing_enforced_import_rename.rs | 4 +- clippy_lints/src/missing_inline.rs | 2 +- clippy_lints/src/mut_reference.rs | 2 +- clippy_lints/src/mutable_debug_assertion.rs | 5 +-- clippy_lints/src/mutex_atomic.rs | 5 +-- clippy_lints/src/needless_continue.rs | 14 ++----- clippy_lints/src/needless_late_init.rs | 10 ++--- clippy_lints/src/needless_pass_by_value.rs | 4 +- clippy_lints/src/needless_question_mark.rs | 2 +- clippy_lints/src/neg_multiply.rs | 4 +- clippy_lints/src/new_without_default.rs | 7 ++-- clippy_lints/src/non_expressive_names.rs | 5 +-- clippy_lints/src/nonstandard_macro_braces.rs | 12 +++--- clippy_lints/src/octal_escapes.rs | 2 +- .../operators/absurd_extreme_comparisons.rs | 5 +-- .../src/operators/assign_op_pattern.rs | 2 +- clippy_lints/src/operators/bit_mask.rs | 40 ++++--------------- clippy_lints/src/operators/cmp_owned.rs | 10 ++--- clippy_lints/src/operators/duration_subsec.rs | 7 ++-- clippy_lints/src/operators/eq_op.rs | 2 +- .../src/operators/misrefactored_assign_op.rs | 12 ++---- .../src/operators/needless_bitwise_bool.rs | 2 +- clippy_lints/src/operators/ptr_eq.rs | 2 +- clippy_lints/src/operators/self_assignment.rs | 2 +- .../src/operators/verbose_bit_mask.rs | 2 +- clippy_lints/src/option_if_let_else.rs | 2 +- clippy_lints/src/pass_by_ref_or_value.rs | 4 +- clippy_lints/src/ptr.rs | 2 +- clippy_lints/src/ptr_offset_with_cast.rs | 4 +- clippy_lints/src/question_mark.rs | 7 ++-- clippy_lints/src/ranges.rs | 16 ++++---- clippy_lints/src/read_zero_byte_vec.rs | 3 +- clippy_lints/src/redundant_pub_crate.rs | 2 +- clippy_lints/src/redundant_slicing.rs | 8 ++-- .../src/redundant_static_lifetimes.rs | 2 +- clippy_lints/src/regex.rs | 4 +- clippy_lints/src/same_name_method.rs | 4 +- .../src/semicolon_if_nothing_returned.rs | 2 +- .../src/slow_vector_initialization.rs | 2 +- clippy_lints/src/strings.rs | 6 +-- clippy_lints/src/strlen_on_c_strings.rs | 2 +- .../src/suspicious_operation_groupings.rs | 9 ++--- clippy_lints/src/swap.rs | 19 ++++----- clippy_lints/src/swap_ptr_to_ref.rs | 2 +- clippy_lints/src/to_digit_is_some.rs | 4 +- clippy_lints/src/trait_bounds.rs | 3 +- .../src/transmute/crosspointer_transmute.rs | 10 +---- .../src/transmute/transmute_float_to_int.rs | 4 +- .../src/transmute/transmute_int_to_bool.rs | 2 +- .../src/transmute/transmute_int_to_char.rs | 4 +- .../src/transmute/transmute_int_to_float.rs | 4 +- .../src/transmute/transmute_num_to_bytes.rs | 4 +- .../src/transmute/transmute_ptr_to_ref.rs | 18 ++++----- .../src/transmute/transmute_ref_to_ref.rs | 2 +- .../src/transmute/transmute_undefined_repr.rs | 23 +++++------ .../transmutes_expressible_as_ptr_casts.rs | 5 +-- .../transmute/unsound_collection_transmute.rs | 5 +-- .../src/transmute/useless_transmute.rs | 2 +- clippy_lints/src/transmute/wrong_transmute.rs | 2 +- clippy_lints/src/types/borrowed_box.rs | 6 +-- clippy_lints/src/types/box_collection.rs | 2 +- clippy_lints/src/types/rc_buffer.rs | 4 +- .../src/types/redundant_allocation.rs | 29 +++++--------- clippy_lints/src/unit_return_expecting_ord.rs | 6 +-- clippy_lints/src/unit_types/unit_arg.rs | 7 ++-- clippy_lints/src/unit_types/unit_cmp.rs | 7 ++-- clippy_lints/src/unnecessary_self_imports.rs | 2 +- clippy_lints/src/unnecessary_wraps.rs | 7 +--- clippy_lints/src/unsafe_removed_from_name.rs | 5 +-- clippy_lints/src/unused_rounding.rs | 4 +- clippy_lints/src/unwrap.rs | 7 +--- clippy_lints/src/upper_case_acronyms.rs | 2 +- clippy_lints/src/useless_conversion.rs | 10 ++--- clippy_lints/src/utils/author.rs | 2 +- clippy_lints/src/utils/conf.rs | 9 ++--- clippy_lints/src/wildcard_imports.rs | 2 +- clippy_lints/src/zero_div_zero.rs | 3 +- 225 files changed, 557 insertions(+), 842 deletions(-) diff --git a/clippy_lints/src/approx_const.rs b/clippy_lints/src/approx_const.rs index 159f3b0cd014a..724490fb49592 100644 --- a/clippy_lints/src/approx_const.rs +++ b/clippy_lints/src/approx_const.rs @@ -92,7 +92,7 @@ impl ApproxConstant { cx, APPROX_CONSTANT, e.span, - &format!("approximate value of `{}::consts::{}` found", module, &name), + &format!("approximate value of `{module}::consts::{}` found", &name), None, "consider using the constant directly", ); @@ -126,7 +126,7 @@ fn is_approx_const(constant: f64, value: &str, min_digits: usize) -> bool { // The value is a truncated constant true } else { - let round_const = format!("{:.*}", value.len() - 2, constant); + let round_const = format!("{constant:.*}", value.len() - 2); value == round_const } } diff --git a/clippy_lints/src/asm_syntax.rs b/clippy_lints/src/asm_syntax.rs index f419781dbc82f..ad31d708f64d5 100644 --- a/clippy_lints/src/asm_syntax.rs +++ b/clippy_lints/src/asm_syntax.rs @@ -44,7 +44,7 @@ fn check_expr_asm_syntax(lint: &'static Lint, cx: &EarlyContext<'_>, expr: &Expr cx, lint, expr.span, - &format!("{} x86 assembly syntax used", style), + &format!("{style} x86 assembly syntax used"), None, &format!("use {} x86 assembly syntax", !style), ); diff --git a/clippy_lints/src/assertions_on_constants.rs b/clippy_lints/src/assertions_on_constants.rs index 2705ffffdcbff..a36df55d0bdaf 100644 --- a/clippy_lints/src/assertions_on_constants.rs +++ b/clippy_lints/src/assertions_on_constants.rs @@ -60,9 +60,9 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants { cx, ASSERTIONS_ON_CONSTANTS, macro_call.span, - &format!("`assert!(false{})` should probably be replaced", assert_arg), + &format!("`assert!(false{assert_arg})` should probably be replaced"), None, - &format!("use `panic!({})` or `unreachable!({0})`", panic_arg), + &format!("use `panic!({panic_arg})` or `unreachable!({panic_arg})`"), ); } } diff --git a/clippy_lints/src/assertions_on_result_states.rs b/clippy_lints/src/assertions_on_result_states.rs index 656dc5feeb570..f6d6c23bb6ed2 100644 --- a/clippy_lints/src/assertions_on_result_states.rs +++ b/clippy_lints/src/assertions_on_result_states.rs @@ -69,9 +69,8 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates { "called `assert!` with `Result::is_ok`", "replace with", format!( - "{}.unwrap(){}", - snippet_with_context(cx, recv.span, condition.span.ctxt(), "..", &mut app).0, - semicolon + "{}.unwrap(){semicolon}", + snippet_with_context(cx, recv.span, condition.span.ctxt(), "..", &mut app).0 ), app, ); @@ -84,9 +83,8 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates { "called `assert!` with `Result::is_err`", "replace with", format!( - "{}.unwrap_err(){}", - snippet_with_context(cx, recv.span, condition.span.ctxt(), "..", &mut app).0, - semicolon + "{}.unwrap_err(){semicolon}", + snippet_with_context(cx, recv.span, condition.span.ctxt(), "..", &mut app).0 ), app, ); diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 732dc2b433091..5f45c69d7f98d 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -541,10 +541,7 @@ fn check_attrs(cx: &LateContext<'_>, span: Span, name: Symbol, attrs: &[Attribut cx, INLINE_ALWAYS, attr.span, - &format!( - "you have declared `#[inline(always)]` on `{}`. This is usually a bad idea", - name - ), + &format!("you have declared `#[inline(always)]` on `{name}`. This is usually a bad idea"), ); } } @@ -720,7 +717,7 @@ fn check_mismatched_target_os(cx: &EarlyContext<'_>, attr: &Attribute) { let mut unix_suggested = false; for (os, span) in mismatched { - let sugg = format!("target_os = \"{}\"", os); + let sugg = format!("target_os = \"{os}\""); diag.span_suggestion(span, "try", sugg, Applicability::MaybeIncorrect); if !unix_suggested && is_unix(os) { diff --git a/clippy_lints/src/bool_assert_comparison.rs b/clippy_lints/src/bool_assert_comparison.rs index 95abe8aa59fbe..4bd55c1429c3b 100644 --- a/clippy_lints/src/bool_assert_comparison.rs +++ b/clippy_lints/src/bool_assert_comparison.rs @@ -98,9 +98,9 @@ impl<'tcx> LateLintPass<'tcx> for BoolAssertComparison { cx, BOOL_ASSERT_COMPARISON, macro_call.span, - &format!("used `{}!` with a literal bool", macro_name), + &format!("used `{macro_name}!` with a literal bool"), "replace it with", - format!("{}!(..)", non_eq_mac), + format!("{non_eq_mac}!(..)"), Applicability::MaybeIncorrect, ); } diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 03d262d5a59c6..2a15cbc7a3c3b 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -263,9 +263,8 @@ fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { } .and_then(|op| { Some(format!( - "{}{}{}", + "{}{op}{}", snippet_opt(cx, lhs.span)?, - op, snippet_opt(cx, rhs.span)? )) }) @@ -285,7 +284,7 @@ fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { let path: &str = path.ident.name.as_str(); a == path }) - .and_then(|(_, neg_method)| Some(format!("{}.{}()", snippet_opt(cx, receiver.span)?, neg_method))) + .and_then(|(_, neg_method)| Some(format!("{}.{neg_method}()", snippet_opt(cx, receiver.span)?))) }, _ => None, } diff --git a/clippy_lints/src/cargo/common_metadata.rs b/clippy_lints/src/cargo/common_metadata.rs index e0442dda479d7..805121bcced3b 100644 --- a/clippy_lints/src/cargo/common_metadata.rs +++ b/clippy_lints/src/cargo/common_metadata.rs @@ -40,7 +40,7 @@ pub(super) fn check(cx: &LateContext<'_>, metadata: &Metadata, ignore_publish: b } fn missing_warning(cx: &LateContext<'_>, package: &cargo_metadata::Package, field: &str) { - let message = format!("package `{}` is missing `{}` metadata", package.name, field); + let message = format!("package `{}` is missing `{field}` metadata", package.name); span_lint(cx, CARGO_COMMON_METADATA, DUMMY_SP, &message); } diff --git a/clippy_lints/src/cargo/feature_name.rs b/clippy_lints/src/cargo/feature_name.rs index 79a469a4258bb..37c169dbd95e3 100644 --- a/clippy_lints/src/cargo/feature_name.rs +++ b/clippy_lints/src/cargo/feature_name.rs @@ -57,10 +57,8 @@ fn lint(cx: &LateContext<'_>, feature: &str, substring: &str, is_prefix: bool) { }, DUMMY_SP, &format!( - "the \"{}\" {} in the feature name \"{}\" is {}", - substring, + "the \"{substring}\" {} in the feature name \"{feature}\" is {}", if is_prefix { "prefix" } else { "suffix" }, - feature, if is_negative { "negative" } else { "redundant" } ), None, diff --git a/clippy_lints/src/cargo/mod.rs b/clippy_lints/src/cargo/mod.rs index 9f45db86a0913..3a872e54c9a2b 100644 --- a/clippy_lints/src/cargo/mod.rs +++ b/clippy_lints/src/cargo/mod.rs @@ -196,7 +196,7 @@ impl LateLintPass<'_> for Cargo { }, Err(e) => { for lint in NO_DEPS_LINTS { - span_lint(cx, lint, DUMMY_SP, &format!("could not read cargo metadata: {}", e)); + span_lint(cx, lint, DUMMY_SP, &format!("could not read cargo metadata: {e}")); } }, } @@ -212,7 +212,7 @@ impl LateLintPass<'_> for Cargo { }, Err(e) => { for lint in WITH_DEPS_LINTS { - span_lint(cx, lint, DUMMY_SP, &format!("could not read cargo metadata: {}", e)); + span_lint(cx, lint, DUMMY_SP, &format!("could not read cargo metadata: {e}")); } }, } diff --git a/clippy_lints/src/cargo/multiple_crate_versions.rs b/clippy_lints/src/cargo/multiple_crate_versions.rs index 76fd0819a39a5..f9b17d45e9fba 100644 --- a/clippy_lints/src/cargo/multiple_crate_versions.rs +++ b/clippy_lints/src/cargo/multiple_crate_versions.rs @@ -37,7 +37,7 @@ pub(super) fn check(cx: &LateContext<'_>, metadata: &Metadata) { cx, MULTIPLE_CRATE_VERSIONS, DUMMY_SP, - &format!("multiple versions for dependency `{}`: {}", name, versions), + &format!("multiple versions for dependency `{name}`: {versions}"), ); } } diff --git a/clippy_lints/src/casts/borrow_as_ptr.rs b/clippy_lints/src/casts/borrow_as_ptr.rs index 6e1f8cd64f077..294d22d34de95 100644 --- a/clippy_lints/src/casts/borrow_as_ptr.rs +++ b/clippy_lints/src/casts/borrow_as_ptr.rs @@ -30,7 +30,7 @@ pub(super) fn check<'tcx>( expr.span, "borrow as raw pointer", "try", - format!("{}::ptr::{}!({})", core_or_std, macro_name, snip), + format!("{core_or_std}::ptr::{macro_name}!({snip})"), Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/casts/cast_lossless.rs b/clippy_lints/src/casts/cast_lossless.rs index 938458e30cadc..13c403234dad5 100644 --- a/clippy_lints/src/casts/cast_lossless.rs +++ b/clippy_lints/src/casts/cast_lossless.rs @@ -41,15 +41,9 @@ pub(super) fn check( ); let message = if cast_from.is_bool() { - format!( - "casting `{0:}` to `{1:}` is more cleanly stated with `{1:}::from(_)`", - cast_from, cast_to - ) + format!("casting `{cast_from:}` to `{cast_to:}` is more cleanly stated with `{cast_to:}::from(_)`") } else { - format!( - "casting `{}` to `{}` may become silently lossy if you later change the type", - cast_from, cast_to - ) + format!("casting `{cast_from}` to `{cast_to}` may become silently lossy if you later change the type") }; span_lint_and_sugg( @@ -58,7 +52,7 @@ pub(super) fn check( expr.span, &message, "try", - format!("{}::from({})", cast_to, sugg), + format!("{cast_to}::from({sugg})"), applicability, ); } diff --git a/clippy_lints/src/casts/cast_possible_truncation.rs b/clippy_lints/src/casts/cast_possible_truncation.rs index 406547a4454e6..88deb4565eb21 100644 --- a/clippy_lints/src/casts/cast_possible_truncation.rs +++ b/clippy_lints/src/casts/cast_possible_truncation.rs @@ -103,10 +103,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, return; } - format!( - "casting `{}` to `{}` may truncate the value{}", - cast_from, cast_to, suffix, - ) + format!("casting `{cast_from}` to `{cast_to}` may truncate the value{suffix}",) }, (ty::Adt(def, _), true) if def.is_enum() => { @@ -142,20 +139,17 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, CAST_ENUM_TRUNCATION, expr.span, &format!( - "casting `{}::{}` to `{}` will truncate the value{}", - cast_from, variant.name, cast_to, suffix, + "casting `{cast_from}::{}` to `{cast_to}` will truncate the value{suffix}", + variant.name, ), ); return; } - format!( - "casting `{}` to `{}` may truncate the value{}", - cast_from, cast_to, suffix, - ) + format!("casting `{cast_from}` to `{cast_to}` may truncate the value{suffix}",) }, (ty::Float(_), true) => { - format!("casting `{}` to `{}` may truncate the value", cast_from, cast_to) + format!("casting `{cast_from}` to `{cast_to}` may truncate the value") }, (ty::Float(FloatTy::F64), false) if matches!(cast_to.kind(), &ty::Float(FloatTy::F32)) => { diff --git a/clippy_lints/src/casts/cast_possible_wrap.rs b/clippy_lints/src/casts/cast_possible_wrap.rs index 2c5c1d7cb4654..28ecdea7ea06c 100644 --- a/clippy_lints/src/casts/cast_possible_wrap.rs +++ b/clippy_lints/src/casts/cast_possible_wrap.rs @@ -35,10 +35,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, ca cx, CAST_POSSIBLE_WRAP, expr.span, - &format!( - "casting `{}` to `{}` may wrap around the value{}", - cast_from, cast_to, suffix, - ), + &format!("casting `{cast_from}` to `{cast_to}` may wrap around the value{suffix}",), ); } } diff --git a/clippy_lints/src/casts/cast_ptr_alignment.rs b/clippy_lints/src/casts/cast_ptr_alignment.rs index da7b12f67266a..97054a0d10154 100644 --- a/clippy_lints/src/casts/cast_ptr_alignment.rs +++ b/clippy_lints/src/casts/cast_ptr_alignment.rs @@ -49,9 +49,7 @@ fn lint_cast_ptr_alignment<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, cast_f CAST_PTR_ALIGNMENT, expr.span, &format!( - "casting from `{}` to a more-strictly-aligned pointer (`{}`) ({} < {} bytes)", - cast_from, - cast_to, + "casting from `{cast_from}` to a more-strictly-aligned pointer (`{cast_to}`) ({} < {} bytes)", from_layout.align.abi.bytes(), to_layout.align.abi.bytes(), ), diff --git a/clippy_lints/src/casts/cast_sign_loss.rs b/clippy_lints/src/casts/cast_sign_loss.rs index 5b59350be042c..a20a97d4e56da 100644 --- a/clippy_lints/src/casts/cast_sign_loss.rs +++ b/clippy_lints/src/casts/cast_sign_loss.rs @@ -14,10 +14,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_op: &Expr<'_>, c cx, CAST_SIGN_LOSS, expr.span, - &format!( - "casting `{}` to `{}` may lose the sign of the value", - cast_from, cast_to - ), + &format!("casting `{cast_from}` to `{cast_to}` may lose the sign of the value"), ); } } diff --git a/clippy_lints/src/casts/cast_slice_different_sizes.rs b/clippy_lints/src/casts/cast_slice_different_sizes.rs index 027c660ce3b24..d31d10d22b92b 100644 --- a/clippy_lints/src/casts/cast_slice_different_sizes.rs +++ b/clippy_lints/src/casts/cast_slice_different_sizes.rs @@ -35,8 +35,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: Optio CAST_SLICE_DIFFERENT_SIZES, expr.span, &format!( - "casting between raw pointers to `[{}]` (element size {}) and `[{}]` (element size {}) does not adjust the count", - start_ty.ty, from_size, end_ty.ty, to_size, + "casting between raw pointers to `[{}]` (element size {from_size}) and `[{}]` (element size {to_size}) does not adjust the count", + start_ty.ty, end_ty.ty, ), |diag| { let ptr_snippet = source::snippet(cx, left_cast.span, ".."); diff --git a/clippy_lints/src/casts/char_lit_as_u8.rs b/clippy_lints/src/casts/char_lit_as_u8.rs index 7cc406018dbe0..82e07c98a7e01 100644 --- a/clippy_lints/src/casts/char_lit_as_u8.rs +++ b/clippy_lints/src/casts/char_lit_as_u8.rs @@ -31,7 +31,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { diag.span_suggestion( expr.span, "use a byte literal instead", - format!("b{}", snippet), + format!("b{snippet}"), applicability, ); } diff --git a/clippy_lints/src/casts/fn_to_numeric_cast.rs b/clippy_lints/src/casts/fn_to_numeric_cast.rs index 35350d8a25b86..a26bfab4e7c15 100644 --- a/clippy_lints/src/casts/fn_to_numeric_cast.rs +++ b/clippy_lints/src/casts/fn_to_numeric_cast.rs @@ -25,9 +25,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cx, FN_TO_NUMERIC_CAST, expr.span, - &format!("casting function pointer `{}` to `{}`", from_snippet, cast_to), + &format!("casting function pointer `{from_snippet}` to `{cast_to}`"), "try", - format!("{} as usize", from_snippet), + format!("{from_snippet} as usize"), applicability, ); } diff --git a/clippy_lints/src/casts/fn_to_numeric_cast_any.rs b/clippy_lints/src/casts/fn_to_numeric_cast_any.rs index 03621887a34a6..75654129408e6 100644 --- a/clippy_lints/src/casts/fn_to_numeric_cast_any.rs +++ b/clippy_lints/src/casts/fn_to_numeric_cast_any.rs @@ -23,9 +23,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cx, FN_TO_NUMERIC_CAST_ANY, expr.span, - &format!("casting function pointer `{}` to `{}`", from_snippet, cast_to), + &format!("casting function pointer `{from_snippet}` to `{cast_to}`"), "did you mean to invoke the function?", - format!("{}() as {}", from_snippet, cast_to), + format!("{from_snippet}() as {cast_to}"), applicability, ); }, diff --git a/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs b/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs index 6287f479b5bfe..556be1d150665 100644 --- a/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs +++ b/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs @@ -24,12 +24,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cx, FN_TO_NUMERIC_CAST_WITH_TRUNCATION, expr.span, - &format!( - "casting function pointer `{}` to `{}`, which truncates the value", - from_snippet, cast_to - ), + &format!("casting function pointer `{from_snippet}` to `{cast_to}`, which truncates the value"), "try", - format!("{} as usize", from_snippet), + format!("{from_snippet} as usize"), applicability, ); } diff --git a/clippy_lints/src/casts/ptr_as_ptr.rs b/clippy_lints/src/casts/ptr_as_ptr.rs index 46d45d09661ae..c2b9253ec35dc 100644 --- a/clippy_lints/src/casts/ptr_as_ptr.rs +++ b/clippy_lints/src/casts/ptr_as_ptr.rs @@ -33,7 +33,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: Option Cow::Borrowed(""), TyKind::Ptr(mut_ty) if matches!(mut_ty.ty.kind, TyKind::Infer) => Cow::Borrowed(""), - _ => Cow::Owned(format!("::<{}>", to_pointee_ty)), + _ => Cow::Owned(format!("::<{to_pointee_ty}>")), }; span_lint_and_sugg( cx, @@ -41,7 +41,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: Option( cx, UNNECESSARY_CAST, expr.span, - &format!( - "casting to the same type is unnecessary (`{}` -> `{}`)", - cast_from, cast_to - ), + &format!("casting to the same type is unnecessary (`{cast_from}` -> `{cast_to}`)"), "try", literal_str, Applicability::MachineApplicable, @@ -101,9 +98,9 @@ fn lint_unnecessary_cast(cx: &LateContext<'_>, expr: &Expr<'_>, literal_str: &st cx, UNNECESSARY_CAST, expr.span, - &format!("casting {} literal to `{}` is unnecessary", literal_kind_name, cast_to), + &format!("casting {literal_kind_name} literal to `{cast_to}` is unnecessary"), "try", - format!("{}_{}", matchless.trim_end_matches('.'), cast_to), + format!("{}_{cast_to}", matchless.trim_end_matches('.')), Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs index 37b2fdcff09ff..1d113c7cbee6c 100644 --- a/clippy_lints/src/checked_conversions.rs +++ b/clippy_lints/src/checked_conversions.rs @@ -82,7 +82,7 @@ impl<'tcx> LateLintPass<'tcx> for CheckedConversions { item.span, "checked cast can be simplified", "try", - format!("{}::try_from({}).is_ok()", to_type, snippet), + format!("{to_type}::try_from({snippet}).is_ok()"), applicability, ); } diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs index 33c44f8b2dba9..fed04ae7f3d59 100644 --- a/clippy_lints/src/cognitive_complexity.rs +++ b/clippy_lints/src/cognitive_complexity.rs @@ -107,8 +107,7 @@ impl CognitiveComplexity { COGNITIVE_COMPLEXITY, fn_span, &format!( - "the function has a cognitive complexity of ({}/{})", - rust_cc, + "the function has a cognitive complexity of ({rust_cc}/{})", self.limit.limit() ), None, diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs index 74f7df611778e..cb6800c8ba2a2 100644 --- a/clippy_lints/src/default.rs +++ b/clippy_lints/src/default.rs @@ -105,7 +105,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { cx, DEFAULT_TRAIT_ACCESS, expr.span, - &format!("calling `{}` is more clear than this expression", replacement), + &format!("calling `{replacement}` is more clear than this expression"), "try", replacement, Applicability::Unspecified, // First resolve the TODO above @@ -210,7 +210,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { .map(|(field, rhs)| { // extract and store the assigned value for help message let value_snippet = snippet_with_macro_callsite(cx, rhs.span, ".."); - format!("{}: {}", field, value_snippet) + format!("{field}: {value_snippet}") }) .collect::>() .join(", "); @@ -227,7 +227,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { .map(ToString::to_string) .collect::>() .join(", "); - format!("{}::<{}>", adt_def_ty_name, &tys_str) + format!("{adt_def_ty_name}::<{}>", &tys_str) } else { binding_type.to_string() } @@ -235,12 +235,12 @@ impl<'tcx> LateLintPass<'tcx> for Default { let sugg = if ext_with_default { if field_list.is_empty() { - format!("{}::default()", binding_type) + format!("{binding_type}::default()") } else { - format!("{} {{ {}, ..Default::default() }}", binding_type, field_list) + format!("{binding_type} {{ {field_list}, ..Default::default() }}") } } else { - format!("{} {{ {} }}", binding_type, field_list) + format!("{binding_type} {{ {field_list} }}") }; // span lint once per statement that binds default @@ -250,10 +250,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { first_assign.unwrap().span, "field assignment outside of initializer for an instance created with Default::default()", Some(local.span), - &format!( - "consider initializing the variable with `{}` and removing relevant reassignments", - sugg - ), + &format!("consider initializing the variable with `{sugg}` and removing relevant reassignments"), ); self.reassigned_linted.insert(span); } diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs index be02f328e989a..3ed9cd36a2292 100644 --- a/clippy_lints/src/default_numeric_fallback.rs +++ b/clippy_lints/src/default_numeric_fallback.rs @@ -95,8 +95,8 @@ impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> { src } else { match lit.node { - LitKind::Int(src, _) => format!("{}", src), - LitKind::Float(src, _) => format!("{}", src), + LitKind::Int(src, _) => format!("{src}"), + LitKind::Float(src, _) => format!("{src}"), _ => return, } }; diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index b965d27afce35..e272283152d8e 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -1308,7 +1308,7 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data }; let expr_str = if !expr_is_macro_call && is_final_ufcs && expr.precedence().order() < PREC_PREFIX { - format!("({})", expr_str) + format!("({expr_str})") } else { expr_str.into_owned() }; @@ -1322,7 +1322,7 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data Mutability::Mut => "explicit `deref_mut` method call", }, "try this", - format!("{}{}{}", addr_of_str, deref_str, expr_str), + format!("{addr_of_str}{deref_str}{expr_str}"), app, ); }, @@ -1336,7 +1336,7 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data && !has_enclosing_paren(&snip) && (expr.precedence().order() < data.position.precedence() || calls_field) { - format!("({})", snip) + format!("({snip})") } else { snip.into() }; @@ -1379,9 +1379,9 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data let (snip, snip_is_macro) = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app); let sugg = if !snip_is_macro && expr.precedence().order() < precedence && !has_enclosing_paren(&snip) { - format!("{}({})", prefix, snip) + format!("{prefix}({snip})") } else { - format!("{}{}", prefix, snip) + format!("{prefix}{snip}") }; diag.span_suggestion(data.span, "try this", sugg, app); }, @@ -1460,14 +1460,14 @@ impl Dereferencing { } else { pat.always_deref = false; let snip = snippet_with_context(cx, e.span, parent.span.ctxt(), "..", &mut pat.app).0; - pat.replacements.push((e.span, format!("&{}", snip))); + pat.replacements.push((e.span, format!("&{snip}"))); } }, _ if !e.span.from_expansion() => { // Double reference might be needed at this point. pat.always_deref = false; let snip = snippet_with_applicability(cx, e.span, "..", &mut pat.app); - pat.replacements.push((e.span, format!("&{}", snip))); + pat.replacements.push((e.span, format!("&{snip}"))); }, // Edge case for macros. The span of the identifier will usually match the context of the // binding, but not if the identifier was created in a macro. e.g. `concat_idents` and proc diff --git a/clippy_lints/src/disallowed_methods.rs b/clippy_lints/src/disallowed_methods.rs index 53973ab792a91..b02f87c07db73 100644 --- a/clippy_lints/src/disallowed_methods.rs +++ b/clippy_lints/src/disallowed_methods.rs @@ -106,7 +106,7 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods { reason: Some(reason), .. } = conf { - diag.note(&format!("{} (from clippy.toml)", reason)); + diag.note(&format!("{reason} (from clippy.toml)")); } }); } diff --git a/clippy_lints/src/disallowed_script_idents.rs b/clippy_lints/src/disallowed_script_idents.rs index 0c27c3f9255f2..084190f00132c 100644 --- a/clippy_lints/src/disallowed_script_idents.rs +++ b/clippy_lints/src/disallowed_script_idents.rs @@ -99,8 +99,7 @@ impl EarlyLintPass for DisallowedScriptIdents { DISALLOWED_SCRIPT_IDENTS, span, &format!( - "identifier `{}` has a Unicode script that is not allowed by configuration: {}", - symbol_str, + "identifier `{symbol_str}` has a Unicode script that is not allowed by configuration: {}", script.full_name() ), ); diff --git a/clippy_lints/src/disallowed_types.rs b/clippy_lints/src/disallowed_types.rs index 14f89edce615d..53451238d9acb 100644 --- a/clippy_lints/src/disallowed_types.rs +++ b/clippy_lints/src/disallowed_types.rs @@ -92,7 +92,7 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedTypes { conf::DisallowedType::Simple(path) => (path, None), conf::DisallowedType::WithReason { path, reason } => ( path, - reason.as_ref().map(|reason| format!("{} (from clippy.toml)", reason)), + reason.as_ref().map(|reason| format!("{reason} (from clippy.toml)")), ), }; let segs: Vec<_> = path.split("::").collect(); @@ -130,7 +130,7 @@ fn emit(cx: &LateContext<'_>, name: &str, span: Span, reason: Option<&str>) { cx, DISALLOWED_TYPES, span, - &format!("`{}` is not allowed according to config", name), + &format!("`{name}` is not allowed according to config"), |diag| { if let Some(reason) = reason { diag.note(reason); diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index eb158d850fa72..fa50a2d1a2c6e 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -790,7 +790,7 @@ fn check_word(cx: &LateContext<'_>, word: &str, span: Span) { diag.span_suggestion_with_style( span, "try", - format!("`{}`", snippet), + format!("`{snippet}`"), applicability, // always show the suggestion in a separate line, since the // inline presentation adds another pair of backticks diff --git a/clippy_lints/src/drop_forget_ref.rs b/clippy_lints/src/drop_forget_ref.rs index b35f0b8ca52da..0ee07fbcc754a 100644 --- a/clippy_lints/src/drop_forget_ref.rs +++ b/clippy_lints/src/drop_forget_ref.rs @@ -236,7 +236,7 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef { expr.span, msg, Some(arg.span), - &format!("argument has type `{}`", arg_ty), + &format!("argument has type `{arg_ty}`"), ); } } diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index e70df3f53c75d..9c834cf014485 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -113,13 +113,8 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass { ), }; format!( - "if let {}::{} = {}.entry({}) {} else {}", + "if let {}::{entry_kind} = {map_str}.entry({key_str}) {then_str} else {else_str}", map_ty.entry_path(), - entry_kind, - map_str, - key_str, - then_str, - else_str, ) } else { // if .. { insert } else { insert } @@ -137,16 +132,11 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass { let indent_str = snippet_indent(cx, expr.span); let indent_str = indent_str.as_deref().unwrap_or(""); format!( - "match {}.entry({}) {{\n{indent} {entry}::{} => {}\n\ - {indent} {entry}::{} => {}\n{indent}}}", - map_str, - key_str, - then_entry, + "match {map_str}.entry({key_str}) {{\n{indent_str} {entry}::{then_entry} => {}\n\ + {indent_str} {entry}::{else_entry} => {}\n{indent_str}}}", reindent_multiline(then_str.into(), true, Some(4 + indent_str.len())), - else_entry, reindent_multiline(else_str.into(), true, Some(4 + indent_str.len())), entry = map_ty.entry_path(), - indent = indent_str, ) } } else { @@ -163,20 +153,16 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass { then_search.snippet_occupied(cx, then_expr.span, &mut app) }; format!( - "if let {}::{} = {}.entry({}) {}", + "if let {}::{entry_kind} = {map_str}.entry({key_str}) {body_str}", map_ty.entry_path(), - entry_kind, - map_str, - key_str, - body_str, ) } else if let Some(insertion) = then_search.as_single_insertion() { let value_str = snippet_with_context(cx, insertion.value.span, then_expr.span.ctxt(), "..", &mut app).0; if contains_expr.negated { if insertion.value.can_have_side_effects() { - format!("{}.entry({}).or_insert_with(|| {});", map_str, key_str, value_str) + format!("{map_str}.entry({key_str}).or_insert_with(|| {value_str});") } else { - format!("{}.entry({}).or_insert({});", map_str, key_str, value_str) + format!("{map_str}.entry({key_str}).or_insert({value_str});") } } else { // TODO: suggest using `if let Some(v) = map.get_mut(k) { .. }` here. @@ -186,7 +172,7 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass { } else { let block_str = then_search.snippet_closure(cx, then_expr.span, &mut app); if contains_expr.negated { - format!("{}.entry({}).or_insert_with(|| {});", map_str, key_str, block_str) + format!("{map_str}.entry({key_str}).or_insert_with(|| {block_str});") } else { // TODO: suggest using `if let Some(v) = map.get_mut(k) { .. }` here. // This would need to be a different lint. diff --git a/clippy_lints/src/enum_variants.rs b/clippy_lints/src/enum_variants.rs index cd36f9fcd729e..d8c6b4e39aef9 100644 --- a/clippy_lints/src/enum_variants.rs +++ b/clippy_lints/src/enum_variants.rs @@ -202,12 +202,11 @@ fn check_variant(cx: &LateContext<'_>, threshold: u64, def: &EnumDef<'_>, item_n cx, ENUM_VARIANT_NAMES, span, - &format!("all variants have the same {}fix: `{}`", what, value), + &format!("all variants have the same {what}fix: `{value}`"), None, &format!( - "remove the {}fixes and use full paths to \ - the variants instead of glob imports", - what + "remove the {what}fixes and use full paths to \ + the variants instead of glob imports" ), ); } diff --git a/clippy_lints/src/equatable_if_let.rs b/clippy_lints/src/equatable_if_let.rs index fdfb821ac7895..7917d83c0b9e8 100644 --- a/clippy_lints/src/equatable_if_let.rs +++ b/clippy_lints/src/equatable_if_let.rs @@ -91,9 +91,8 @@ impl<'tcx> LateLintPass<'tcx> for PatternEquality { "this pattern matching can be expressed using equality", "try", format!( - "{} == {}", + "{} == {pat_str}", snippet_with_context(cx, let_expr.init.span, expr.span.ctxt(), "..", &mut applicability).0, - pat_str, ), applicability, ); diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index 53bc617a4f5b7..0f9f94a6b5460 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -130,7 +130,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction { then { // Mutable closure is used after current expr; we cannot consume it. - snippet = format!("&mut {}", snippet); + snippet = format!("&mut {snippet}"); } } diag.span_suggestion( @@ -158,7 +158,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction { diag.span_suggestion( expr.span, "replace the closure with the method itself", - format!("{}::{}", name, path.ident.name), + format!("{name}::{}", path.ident.name), Applicability::MachineApplicable, ); }) diff --git a/clippy_lints/src/exhaustive_items.rs b/clippy_lints/src/exhaustive_items.rs index 173d41b4b0506..218e40f2b5ffb 100644 --- a/clippy_lints/src/exhaustive_items.rs +++ b/clippy_lints/src/exhaustive_items.rs @@ -97,7 +97,7 @@ impl LateLintPass<'_> for ExhaustiveItems { item.span, msg, |diag| { - let sugg = format!("#[non_exhaustive]\n{}", indent); + let sugg = format!("#[non_exhaustive]\n{indent}"); diag.span_suggestion(suggestion_span, "try adding #[non_exhaustive]", sugg, diff --git a/clippy_lints/src/explicit_write.rs b/clippy_lints/src/explicit_write.rs index b9ed4af02190b..c0ea6f338a230 100644 --- a/clippy_lints/src/explicit_write.rs +++ b/clippy_lints/src/explicit_write.rs @@ -80,12 +80,12 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { // used. let (used, sugg_mac) = if let Some(macro_name) = calling_macro { ( - format!("{}!({}(), ...)", macro_name, dest_name), + format!("{macro_name}!({dest_name}(), ...)"), macro_name.replace("write", "print"), ) } else { ( - format!("{}().write_fmt(...)", dest_name), + format!("{dest_name}().write_fmt(...)"), "print".into(), ) }; @@ -100,9 +100,9 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { cx, EXPLICIT_WRITE, expr.span, - &format!("use of `{}.unwrap()`", used), + &format!("use of `{used}.unwrap()`"), "try this", - format!("{}{}!({})", prefix, sugg_mac, inputs_snippet), + format!("{prefix}{sugg_mac}!({inputs_snippet})"), applicability, ) } diff --git a/clippy_lints/src/float_literal.rs b/clippy_lints/src/float_literal.rs index f2e0798096378..6fee7fb308ce7 100644 --- a/clippy_lints/src/float_literal.rs +++ b/clippy_lints/src/float_literal.rs @@ -173,9 +173,9 @@ impl FloatFormat { T: fmt::UpperExp + fmt::LowerExp + fmt::Display, { match self { - Self::LowerExp => format!("{:e}", f), - Self::UpperExp => format!("{:E}", f), - Self::Normal => format!("{}", f), + Self::LowerExp => format!("{f:e}"), + Self::UpperExp => format!("{f:E}"), + Self::Normal => format!("{f}"), } } } diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index ba53a9678801c..e71afec12a77c 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -142,8 +142,7 @@ fn prepare_receiver_sugg<'a>(cx: &LateContext<'_>, mut expr: &'a Expr<'a>) -> Su if let ast::LitKind::Float(sym, ast::LitFloatType::Unsuffixed) = lit.node; then { let op = format!( - "{}{}{}", - suggestion, + "{suggestion}{}{}", // Check for float literals without numbers following the decimal // separator such as `2.` and adds a trailing zero if sym.as_str().ends_with('.') { @@ -172,7 +171,7 @@ fn check_log_base(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, ar expr.span, "logarithm for bases 2, 10 and e can be computed more accurately", "consider using", - format!("{}.{}()", Sugg::hir(cx, receiver, "..").maybe_par(), method), + format!("{}.{method}()", Sugg::hir(cx, receiver, "..").maybe_par()), Applicability::MachineApplicable, ); } @@ -251,7 +250,7 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: expr.span, "exponent for bases 2 and e can be computed more accurately", "consider using", - format!("{}.{}()", prepare_receiver_sugg(cx, &args[0]), method), + format!("{}.{method}()", prepare_receiver_sugg(cx, &args[0])), Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index f10d825695360..bc0c68f535a96 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -62,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat { [_] => { // Simulate macro expansion, converting {{ and }} to { and }. let s_expand = format_args.format_string.snippet.replace("{{", "{").replace("}}", "}"); - let sugg = format!("{}.to_string()", s_expand); + let sugg = format!("{s_expand}.to_string()"); span_useless_format(cx, call_site, sugg, applicability); }, [..] => {}, diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index e1c46fd0bfd4f..192f6258aa59c 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -112,11 +112,10 @@ fn check_format_in_format_args(cx: &LateContext<'_>, call_site: Span, name: Symb cx, FORMAT_IN_FORMAT_ARGS, call_site, - &format!("`format!` in `{}!` args", name), + &format!("`format!` in `{name}!` args"), |diag| { diag.help(&format!( - "combine the `format!(..)` arguments with the outer `{}!(..)` call", - name + "combine the `format!(..)` arguments with the outer `{name}!(..)` call" )); diag.help("or consider changing `format!` to `format_args!`"); }, @@ -144,8 +143,7 @@ fn check_to_string_in_format_args(cx: &LateContext<'_>, name: Symbol, value: &Ex TO_STRING_IN_FORMAT_ARGS, value.span.with_lo(receiver.span.hi()), &format!( - "`to_string` applied to a type that implements `Display` in `{}!` args", - name + "`to_string` applied to a type that implements `Display` in `{name}!` args" ), "remove this", String::new(), @@ -157,16 +155,13 @@ fn check_to_string_in_format_args(cx: &LateContext<'_>, name: Symbol, value: &Ex TO_STRING_IN_FORMAT_ARGS, value.span, &format!( - "`to_string` applied to a type that implements `Display` in `{}!` args", - name + "`to_string` applied to a type that implements `Display` in `{name}!` args" ), "use this", format!( - "{}{:*>width$}{}", + "{}{:*>n_needed_derefs$}{receiver_snippet}", if needs_ref { "&" } else { "" }, - "", - receiver_snippet, - width = n_needed_derefs + "" ), Applicability::MachineApplicable, ); diff --git a/clippy_lints/src/format_impl.rs b/clippy_lints/src/format_impl.rs index b628fd9f75814..ed1342a546543 100644 --- a/clippy_lints/src/format_impl.rs +++ b/clippy_lints/src/format_impl.rs @@ -214,12 +214,12 @@ fn check_print_in_format_impl(cx: &LateContext<'_>, expr: &Expr<'_>, impl_trait: cx, PRINT_IN_FORMAT_IMPL, macro_call.span, - &format!("use of `{}!` in `{}` impl", name, impl_trait.name), + &format!("use of `{name}!` in `{}` impl", impl_trait.name), "replace with", if let Some(formatter_name) = impl_trait.formatter_name { - format!("{}!({}, ..)", replacement, formatter_name) + format!("{replacement}!({formatter_name}, ..)") } else { - format!("{}!(..)", replacement) + format!("{replacement}!(..)") }, Applicability::HasPlaceholders, ); diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index 01cefe4af8532..a866a68987d02 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -154,11 +154,10 @@ fn check_assign(cx: &EarlyContext<'_>, expr: &Expr) { eqop_span, &format!( "this looks like you are trying to use `.. {op}= ..`, but you \ - really are doing `.. = ({op} ..)`", - op = op + really are doing `.. = ({op} ..)`" ), None, - &format!("to remove this lint, use either `{op}=` or `= {op}`", op = op), + &format!("to remove this lint, use either `{op}=` or `= {op}`"), ); } } @@ -191,16 +190,12 @@ fn check_unop(cx: &EarlyContext<'_>, expr: &Expr) { SUSPICIOUS_UNARY_OP_FORMATTING, eqop_span, &format!( - "by not having a space between `{binop}` and `{unop}` it looks like \ - `{binop}{unop}` is a single operator", - binop = binop_str, - unop = unop_str + "by not having a space between `{binop_str}` and `{unop_str}` it looks like \ + `{binop_str}{unop_str}` is a single operator" ), None, &format!( - "put a space between `{binop}` and `{unop}` and remove the space after `{unop}`", - binop = binop_str, - unop = unop_str + "put a space between `{binop_str}` and `{unop_str}` and remove the space after `{unop_str}`" ), ); } @@ -246,12 +241,11 @@ fn check_else(cx: &EarlyContext<'_>, expr: &Expr) { cx, SUSPICIOUS_ELSE_FORMATTING, else_span, - &format!("this is an `else {}` but the formatting might hide it", else_desc), + &format!("this is an `else {else_desc}` but the formatting might hide it"), None, &format!( "to remove this lint, remove the `else` or remove the new line between \ - `else` and `{}`", - else_desc, + `else` and `{else_desc}`", ), ); } @@ -320,11 +314,10 @@ fn check_missing_else(cx: &EarlyContext<'_>, first: &Expr, second: &Expr) { cx, SUSPICIOUS_ELSE_FORMATTING, else_span, - &format!("this looks like {} but the `else` is missing", looks_like), + &format!("this looks like {looks_like} but the `else` is missing"), None, &format!( - "to remove this lint, add the missing `else` or add a new line before {}", - next_thing, + "to remove this lint, add the missing `else` or add a new line before {next_thing}", ), ); } diff --git a/clippy_lints/src/from_str_radix_10.rs b/clippy_lints/src/from_str_radix_10.rs index 74941d817be36..2a82473be8c5e 100644 --- a/clippy_lints/src/from_str_radix_10.rs +++ b/clippy_lints/src/from_str_radix_10.rs @@ -88,7 +88,7 @@ impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 { exp.span, "this call to `from_str_radix` can be replaced with a call to `str::parse`", "try", - format!("{}.parse::<{}>()", sugg, prim_ty.name_str()), + format!("{sugg}.parse::<{}>()", prim_ty.name_str()), Applicability::MaybeIncorrect ); } diff --git a/clippy_lints/src/functions/must_use.rs b/clippy_lints/src/functions/must_use.rs index 00a4937763eb5..09b97bacd6520 100644 --- a/clippy_lints/src/functions/must_use.rs +++ b/clippy_lints/src/functions/must_use.rs @@ -143,7 +143,7 @@ fn check_must_use_candidate<'tcx>( diag.span_suggestion( fn_span, "add the attribute", - format!("#[must_use] {}", snippet), + format!("#[must_use] {snippet}"), Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/functions/too_many_arguments.rs b/clippy_lints/src/functions/too_many_arguments.rs index 5c8d8b8e7552c..1e08922a61664 100644 --- a/clippy_lints/src/functions/too_many_arguments.rs +++ b/clippy_lints/src/functions/too_many_arguments.rs @@ -59,10 +59,7 @@ fn check_arg_number(cx: &LateContext<'_>, decl: &hir::FnDecl<'_>, fn_span: Span, cx, TOO_MANY_ARGUMENTS, fn_span, - &format!( - "this function has too many arguments ({}/{})", - args, too_many_arguments_threshold - ), + &format!("this function has too many arguments ({args}/{too_many_arguments_threshold})"), ); } } diff --git a/clippy_lints/src/functions/too_many_lines.rs b/clippy_lints/src/functions/too_many_lines.rs index 54bdea7ea25d6..f83f8b40f94b7 100644 --- a/clippy_lints/src/functions/too_many_lines.rs +++ b/clippy_lints/src/functions/too_many_lines.rs @@ -78,10 +78,7 @@ pub(super) fn check_fn( cx, TOO_MANY_LINES, span, - &format!( - "this function has too many lines ({}/{})", - line_count, too_many_lines_threshold - ), + &format!("this function has too many lines ({line_count}/{too_many_lines_threshold})"), ); } } diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs index 11c43247868ca..0800e0644f7f3 100644 --- a/clippy_lints/src/if_then_some_else_none.rs +++ b/clippy_lints/src/if_then_some_else_none.rs @@ -84,7 +84,7 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { { let cond_snip = snippet_with_macro_callsite(cx, cond.span, "[condition]"); let cond_snip = if matches!(cond.kind, ExprKind::Unary(_, _) | ExprKind::Binary(_, _, _)) { - format!("({})", cond_snip) + format!("({cond_snip})") } else { cond_snip.into_owned() }; @@ -92,7 +92,7 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { let mut method_body = if then_block.stmts.is_empty() { arg_snip.into_owned() } else { - format!("{{ /* snippet */ {} }}", arg_snip) + format!("{{ /* snippet */ {arg_snip} }}") }; let method_name = if switch_to_eager_eval(cx, expr) && meets_msrv(self.msrv, msrvs::BOOL_THEN_SOME) { "then_some" @@ -102,14 +102,13 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { }; let help = format!( - "consider using `bool::{}` like: `{}.{}({})`", - method_name, cond_snip, method_name, method_body, + "consider using `bool::{method_name}` like: `{cond_snip}.{method_name}({method_body})`", ); span_lint_and_help( cx, IF_THEN_SOME_ELSE_NONE, expr.span, - &format!("this could be simplified with `bool::{}`", method_name), + &format!("this could be simplified with `bool::{method_name}`"), None, &help, ); diff --git a/clippy_lints/src/implicit_hasher.rs b/clippy_lints/src/implicit_hasher.rs index 4f9680f60fe8b..067af79152fd2 100644 --- a/clippy_lints/src/implicit_hasher.rs +++ b/clippy_lints/src/implicit_hasher.rs @@ -89,8 +89,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher { ( generics_suggestion_span, format!( - "<{}{}S: ::std::hash::BuildHasher{}>", - generics_snip, + "<{generics_snip}{}S: ::std::hash::BuildHasher{}>", if generics_snip.is_empty() { "" } else { ", " }, if vis.suggestions.is_empty() { "" @@ -263,8 +262,8 @@ impl<'tcx> ImplicitHasherType<'tcx> { fn type_arguments(&self) -> String { match *self { - ImplicitHasherType::HashMap(.., ref k, ref v) => format!("{}, {}", k, v), - ImplicitHasherType::HashSet(.., ref t) => format!("{}", t), + ImplicitHasherType::HashMap(.., ref k, ref v) => format!("{k}, {v}"), + ImplicitHasherType::HashSet(.., ref t) => format!("{t}"), } } diff --git a/clippy_lints/src/implicit_return.rs b/clippy_lints/src/implicit_return.rs index feec8ec2e23f8..cfc988da2335d 100644 --- a/clippy_lints/src/implicit_return.rs +++ b/clippy_lints/src/implicit_return.rs @@ -53,7 +53,7 @@ fn lint_return(cx: &LateContext<'_>, emission_place: HirId, span: Span) { span, "missing `return` statement", |diag| { - diag.span_suggestion(span, "add `return` as shown", format!("return {}", snip), app); + diag.span_suggestion(span, "add `return` as shown", format!("return {snip}"), app); }, ); } @@ -71,7 +71,7 @@ fn lint_break(cx: &LateContext<'_>, emission_place: HirId, break_span: Span, exp diag.span_suggestion( break_span, "change `break` to `return` as shown", - format!("return {}", snip), + format!("return {snip}"), app, ); }, diff --git a/clippy_lints/src/implicit_saturating_sub.rs b/clippy_lints/src/implicit_saturating_sub.rs index 46654bc61e0f1..f0dbe17d83a5c 100644 --- a/clippy_lints/src/implicit_saturating_sub.rs +++ b/clippy_lints/src/implicit_saturating_sub.rs @@ -170,7 +170,7 @@ fn print_lint_and_sugg(cx: &LateContext<'_>, var_name: &str, expr: &Expr<'_>) { expr.span, "implicitly performing saturating subtraction", "try", - format!("{} = {}.saturating_sub({});", var_name, var_name, '1'), + format!("{var_name} = {var_name}.saturating_sub({});", '1'), Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/inconsistent_struct_constructor.rs b/clippy_lints/src/inconsistent_struct_constructor.rs index 14b22d2b50d05..e2f2d3d42e695 100644 --- a/clippy_lints/src/inconsistent_struct_constructor.rs +++ b/clippy_lints/src/inconsistent_struct_constructor.rs @@ -90,7 +90,7 @@ impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor { let mut fields_snippet = String::new(); let (last_ident, idents) = ordered_fields.split_last().unwrap(); for ident in idents { - let _ = write!(fields_snippet, "{}, ", ident); + let _ = write!(fields_snippet, "{ident}, "); } fields_snippet.push_str(&last_ident.to_string()); @@ -100,10 +100,8 @@ impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor { String::new() }; - let sugg = format!("{} {{ {}{} }}", + let sugg = format!("{} {{ {fields_snippet}{base_snippet} }}", snippet(cx, qpath.span(), ".."), - fields_snippet, - base_snippet, ); span_lint_and_sugg( diff --git a/clippy_lints/src/index_refutable_slice.rs b/clippy_lints/src/index_refutable_slice.rs index 0dd7f5bf000d2..c7b5badaae51b 100644 --- a/clippy_lints/src/index_refutable_slice.rs +++ b/clippy_lints/src/index_refutable_slice.rs @@ -139,14 +139,14 @@ fn lint_slice(cx: &LateContext<'_>, slice: &SliceLintInformation) { .map(|(index, _)| *index) .collect::>(); - let value_name = |index| format!("{}_{}", slice.ident.name, index); + let value_name = |index| format!("{}_{index}", slice.ident.name); if let Some(max_index) = used_indices.iter().max() { let opt_ref = if slice.needs_ref { "ref " } else { "" }; let pat_sugg_idents = (0..=*max_index) .map(|index| { if used_indices.contains(&index) { - format!("{}{}", opt_ref, value_name(index)) + format!("{opt_ref}{}", value_name(index)) } else { "_".to_string() } diff --git a/clippy_lints/src/inherent_to_string.rs b/clippy_lints/src/inherent_to_string.rs index 17d867aacb533..f171ae2649d4f 100644 --- a/clippy_lints/src/inherent_to_string.rs +++ b/clippy_lints/src/inherent_to_string.rs @@ -131,23 +131,19 @@ fn show_lint(cx: &LateContext<'_>, item: &ImplItem<'_>) { INHERENT_TO_STRING_SHADOW_DISPLAY, item.span, &format!( - "type `{}` implements inherent method `to_string(&self) -> String` which shadows the implementation of `Display`", - self_type + "type `{self_type}` implements inherent method `to_string(&self) -> String` which shadows the implementation of `Display`" ), None, - &format!("remove the inherent method from type `{}`", self_type), + &format!("remove the inherent method from type `{self_type}`"), ); } else { span_lint_and_help( cx, INHERENT_TO_STRING, item.span, - &format!( - "implementation of inherent method `to_string(&self) -> String` for type `{}`", - self_type - ), + &format!("implementation of inherent method `to_string(&self) -> String` for type `{self_type}`"), None, - &format!("implement trait `Display` for type `{}` instead", self_type), + &format!("implement trait `Display` for type `{self_type}` instead"), ); } } diff --git a/clippy_lints/src/inline_fn_without_body.rs b/clippy_lints/src/inline_fn_without_body.rs index dd7177e0131ca..d609a5ca4d465 100644 --- a/clippy_lints/src/inline_fn_without_body.rs +++ b/clippy_lints/src/inline_fn_without_body.rs @@ -51,7 +51,7 @@ fn check_attrs(cx: &LateContext<'_>, name: Symbol, attrs: &[Attribute]) { cx, INLINE_FN_WITHOUT_BODY, attr.span, - &format!("use of `#[inline]` on trait method `{}` which has no body", name), + &format!("use of `#[inline]` on trait method `{name}` which has no body"), |diag| { diag.suggest_remove_item(cx, attr.span, "remove", Applicability::MachineApplicable); }, diff --git a/clippy_lints/src/int_plus_one.rs b/clippy_lints/src/int_plus_one.rs index 9a944def3eb22..33491da3fc5af 100644 --- a/clippy_lints/src/int_plus_one.rs +++ b/clippy_lints/src/int_plus_one.rs @@ -138,8 +138,8 @@ impl IntPlusOne { if let Some(snippet) = snippet_opt(cx, node.span) { if let Some(other_side_snippet) = snippet_opt(cx, other_side.span) { let rec = match side { - Side::Lhs => Some(format!("{} {} {}", snippet, binop_string, other_side_snippet)), - Side::Rhs => Some(format!("{} {} {}", other_side_snippet, binop_string, snippet)), + Side::Lhs => Some(format!("{snippet} {binop_string} {other_side_snippet}")), + Side::Rhs => Some(format!("{other_side_snippet} {binop_string} {snippet}")), }; return rec; } diff --git a/clippy_lints/src/iter_not_returning_iterator.rs b/clippy_lints/src/iter_not_returning_iterator.rs index b56d87c5348c2..78815ea5a0a0f 100644 --- a/clippy_lints/src/iter_not_returning_iterator.rs +++ b/clippy_lints/src/iter_not_returning_iterator.rs @@ -80,10 +80,7 @@ fn check_sig(cx: &LateContext<'_>, name: &str, sig: &FnSig<'_>, fn_id: LocalDefI cx, ITER_NOT_RETURNING_ITERATOR, sig.span, - &format!( - "this method is named `{}` but its return type does not implement `Iterator`", - name - ), + &format!("this method is named `{name}` but its return type does not implement `Iterator`"), ); } } diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 7ae8ef830faea..e94292b9fac03 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -278,15 +278,13 @@ impl<'tcx> LenOutput<'tcx> { _ => "", }; match self { - Self::Integral => format!("expected signature: `({}self) -> bool`", self_ref), - Self::Option(_) => format!( - "expected signature: `({}self) -> bool` or `({}self) -> Option", - self_ref, self_ref - ), - Self::Result(..) => format!( - "expected signature: `({}self) -> bool` or `({}self) -> Result", - self_ref, self_ref - ), + Self::Integral => format!("expected signature: `({self_ref}self) -> bool`"), + Self::Option(_) => { + format!("expected signature: `({self_ref}self) -> bool` or `({self_ref}self) -> Option") + }, + Self::Result(..) => { + format!("expected signature: `({self_ref}self) -> bool` or `({self_ref}self) -> Result") + }, } } } @@ -326,8 +324,7 @@ fn check_for_is_empty<'tcx>( let (msg, is_empty_span, self_kind) = match is_empty { None => ( format!( - "{} `{}` has a public `len` method, but no `is_empty` method", - item_kind, + "{item_kind} `{}` has a public `len` method, but no `is_empty` method", item_name.as_str(), ), None, @@ -335,8 +332,7 @@ fn check_for_is_empty<'tcx>( ), Some(is_empty) if !cx.access_levels.is_exported(is_empty.def_id.expect_local()) => ( format!( - "{} `{}` has a public `len` method, but a private `is_empty` method", - item_kind, + "{item_kind} `{}` has a public `len` method, but a private `is_empty` method", item_name.as_str(), ), Some(cx.tcx.def_span(is_empty.def_id)), @@ -348,8 +344,7 @@ fn check_for_is_empty<'tcx>( { ( format!( - "{} `{}` has a public `len` method, but the `is_empty` method has an unexpected signature", - item_kind, + "{item_kind} `{}` has a public `len` method, but the `is_empty` method has an unexpected signature", item_name.as_str(), ), Some(cx.tcx.def_span(is_empty.def_id)), @@ -419,10 +414,9 @@ fn check_len( LEN_ZERO, span, &format!("length comparison to {}", if compare_to == 0 { "zero" } else { "one" }), - &format!("using `{}is_empty` is clearer and more explicit", op), + &format!("using `{op}is_empty` is clearer and more explicit"), format!( - "{}{}.is_empty()", - op, + "{op}{}.is_empty()", snippet_with_applicability(cx, receiver.span, "_", &mut applicability) ), applicability, @@ -439,10 +433,9 @@ fn check_empty_expr(cx: &LateContext<'_>, span: Span, lit1: &Expr<'_>, lit2: &Ex COMPARISON_TO_EMPTY, span, "comparison to empty slice", - &format!("using `{}is_empty` is clearer and more explicit", op), + &format!("using `{op}is_empty` is clearer and more explicit"), format!( - "{}{}.is_empty()", - op, + "{op}{}.is_empty()", snippet_with_applicability(cx, lit1.span, "_", &mut applicability) ), applicability, diff --git a/clippy_lints/src/let_if_seq.rs b/clippy_lints/src/let_if_seq.rs index 10fc0f4018efd..13071d64441a0 100644 --- a/clippy_lints/src/let_if_seq.rs +++ b/clippy_lints/src/let_if_seq.rs @@ -106,8 +106,7 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq { // use mutably after the `if` let sug = format!( - "let {mut}{name} = if {cond} {{{then} {value} }} else {{{else} {default} }};", - mut=mutability, + "let {mutability}{name} = if {cond} {{{then} {value} }} else {{{else} {default} }};", name=ident.name, cond=snippet(cx, cond.span, "_"), then=if then.stmts.len() > 1 { " ..;" } else { "" }, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 83fdc15c9f02c..8a2a1682eca26 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -417,8 +417,7 @@ pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore, sess: &Se let msrv = conf.msrv.as_ref().and_then(|s| { parse_msrv(s, None, None).or_else(|| { sess.err(&format!( - "error reading Clippy's configuration file. `{}` is not a valid Rust version", - s + "error reading Clippy's configuration file. `{s}` is not a valid Rust version" )); None }) @@ -434,8 +433,7 @@ fn read_msrv(conf: &Conf, sess: &Session) -> Option { let clippy_msrv = conf.msrv.as_ref().and_then(|s| { parse_msrv(s, None, None).or_else(|| { sess.err(&format!( - "error reading Clippy's configuration file. `{}` is not a valid Rust version", - s + "error reading Clippy's configuration file. `{s}` is not a valid Rust version" )); None }) @@ -446,8 +444,7 @@ fn read_msrv(conf: &Conf, sess: &Session) -> Option { // if both files have an msrv, let's compare them and emit a warning if they differ if clippy_msrv != cargo_msrv { sess.warn(&format!( - "the MSRV in `clippy.toml` and `Cargo.toml` differ; using `{}` from `clippy.toml`", - clippy_msrv + "the MSRV in `clippy.toml` and `Cargo.toml` differ; using `{clippy_msrv}` from `clippy.toml`" )); } @@ -466,7 +463,7 @@ pub fn read_conf(sess: &Session) -> Conf { Ok(Some(path)) => path, Ok(None) => return Conf::default(), Err(error) => { - sess.struct_err(&format!("error finding Clippy's configuration file: {}", error)) + sess.struct_err(&format!("error finding Clippy's configuration file: {error}")) .emit(); return Conf::default(); }, diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index fb2104861c87f..25f19b9c6e6c7 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -478,7 +478,7 @@ impl DecimalLiteralRepresentation { if num_lit.radix == Radix::Decimal; if val >= u128::from(self.threshold); then { - let hex = format!("{:#X}", val); + let hex = format!("{val:#X}"); let num_lit = NumericLiteral::new(&hex, num_lit.suffix, false); let _ = Self::do_lint(num_lit.integer).map_err(|warning_type| { warning_type.display(num_lit.format(), cx, lit.span); diff --git a/clippy_lints/src/loops/explicit_counter_loop.rs b/clippy_lints/src/loops/explicit_counter_loop.rs index 8e3ab26a947f1..14f2234813277 100644 --- a/clippy_lints/src/loops/explicit_counter_loop.rs +++ b/clippy_lints/src/loops/explicit_counter_loop.rs @@ -44,11 +44,10 @@ pub(super) fn check<'tcx>( cx, EXPLICIT_COUNTER_LOOP, span, - &format!("the variable `{}` is used as a loop counter", name), + &format!("the variable `{name}` is used as a loop counter"), "consider using", format!( - "for ({}, {}) in {}.enumerate()", - name, + "for ({name}, {}) in {}.enumerate()", snippet_with_applicability(cx, pat.span, "item", &mut applicability), make_iterator_snippet(cx, arg, &mut applicability), ), @@ -65,24 +64,21 @@ pub(super) fn check<'tcx>( cx, EXPLICIT_COUNTER_LOOP, span, - &format!("the variable `{}` is used as a loop counter", name), + &format!("the variable `{name}` is used as a loop counter"), |diag| { diag.span_suggestion( span, "consider using", format!( - "for ({}, {}) in (0_{}..).zip({})", - name, + "for ({name}, {}) in (0_{int_name}..).zip({})", snippet_with_applicability(cx, pat.span, "item", &mut applicability), - int_name, make_iterator_snippet(cx, arg, &mut applicability), ), applicability, ); diag.note(&format!( - "`{}` is of type `{}`, making it ineligible for `Iterator::enumerate`", - name, int_name + "`{name}` is of type `{int_name}`, making it ineligible for `Iterator::enumerate`" )); }, ); diff --git a/clippy_lints/src/loops/explicit_iter_loop.rs b/clippy_lints/src/loops/explicit_iter_loop.rs index 5f5beccd030c1..b1f2941622abb 100644 --- a/clippy_lints/src/loops/explicit_iter_loop.rs +++ b/clippy_lints/src/loops/explicit_iter_loop.rs @@ -41,7 +41,7 @@ pub(super) fn check(cx: &LateContext<'_>, self_arg: &Expr<'_>, arg: &Expr<'_>, m "it is more concise to loop over references to containers instead of using explicit \ iteration methods", "to write this more concisely, try", - format!("&{}{}", muta, object), + format!("&{muta}{object}"), applicability, ); } diff --git a/clippy_lints/src/loops/for_kv_map.rs b/clippy_lints/src/loops/for_kv_map.rs index bee0e1d76831a..ed620460dbe66 100644 --- a/clippy_lints/src/loops/for_kv_map.rs +++ b/clippy_lints/src/loops/for_kv_map.rs @@ -38,7 +38,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, arg: &'tcx cx, FOR_KV_MAP, arg_span, - &format!("you seem to want to iterate on a map's {}s", kind), + &format!("you seem to want to iterate on a map's {kind}s"), |diag| { let map = sugg::Sugg::hir(cx, arg, "map"); multispan_sugg( @@ -46,7 +46,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, arg: &'tcx "use the corresponding method", vec![ (pat_span, snippet(cx, new_pat_span, kind).into_owned()), - (arg_span, format!("{}.{}s{}()", map.maybe_par(), kind, mutbl)), + (arg_span, format!("{}.{kind}s{mutbl}()", map.maybe_par())), ], ); }, diff --git a/clippy_lints/src/loops/manual_flatten.rs b/clippy_lints/src/loops/manual_flatten.rs index 1d6ddf4b99f7b..1b36d452647ed 100644 --- a/clippy_lints/src/loops/manual_flatten.rs +++ b/clippy_lints/src/loops/manual_flatten.rs @@ -38,7 +38,7 @@ pub(super) fn check<'tcx>( then { let if_let_type = if some_ctor { "Some" } else { "Ok" }; // Prepare the error message - let msg = format!("unnecessary `if let` since only the `{}` variant of the iterator element is used", if_let_type); + let msg = format!("unnecessary `if let` since only the `{if_let_type}` variant of the iterator element is used"); // Prepare the help message let mut applicability = Applicability::MaybeIncorrect; diff --git a/clippy_lints/src/loops/manual_memcpy.rs b/clippy_lints/src/loops/manual_memcpy.rs index 3fc569af89ecb..c87fc4f90e216 100644 --- a/clippy_lints/src/loops/manual_memcpy.rs +++ b/clippy_lints/src/loops/manual_memcpy.rs @@ -177,13 +177,7 @@ fn build_manual_memcpy_suggestion<'tcx>( let dst = if dst_offset == sugg::EMPTY && dst_limit == sugg::EMPTY { dst_base_str } else { - format!( - "{}[{}..{}]", - dst_base_str, - dst_offset.maybe_par(), - dst_limit.maybe_par() - ) - .into() + format!("{dst_base_str}[{}..{}]", dst_offset.maybe_par(), dst_limit.maybe_par()).into() }; let method_str = if is_copy(cx, elem_ty) { @@ -193,10 +187,7 @@ fn build_manual_memcpy_suggestion<'tcx>( }; format!( - "{}.{}(&{}[{}..{}]);", - dst, - method_str, - src_base_str, + "{dst}.{method_str}(&{src_base_str}[{}..{}]);", src_offset.maybe_par(), src_limit.maybe_par() ) diff --git a/clippy_lints/src/loops/needless_collect.rs b/clippy_lints/src/loops/needless_collect.rs index 6e6faa79adc9e..66f9e28596e87 100644 --- a/clippy_lints/src/loops/needless_collect.rs +++ b/clippy_lints/src/loops/needless_collect.rs @@ -45,7 +45,7 @@ fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCont let (arg, pred) = contains_arg .strip_prefix('&') .map_or(("&x", &*contains_arg), |s| ("x", s)); - format!("any(|{}| x == {})", arg, pred) + format!("any(|{arg}| x == {pred})") } _ => return, } @@ -141,9 +141,9 @@ impl IterFunction { IterFunctionKind::Contains(span) => { let s = snippet(cx, *span, ".."); if let Some(stripped) = s.strip_prefix('&') { - format!(".any(|x| x == {})", stripped) + format!(".any(|x| x == {stripped})") } else { - format!(".any(|x| x == *{})", s) + format!(".any(|x| x == *{s})") } }, } diff --git a/clippy_lints/src/loops/needless_range_loop.rs b/clippy_lints/src/loops/needless_range_loop.rs index 8ab640051b635..00cfc6d49f19a 100644 --- a/clippy_lints/src/loops/needless_range_loop.rs +++ b/clippy_lints/src/loops/needless_range_loop.rs @@ -145,7 +145,7 @@ pub(super) fn check<'tcx>( cx, NEEDLESS_RANGE_LOOP, arg.span, - &format!("the loop variable `{}` is used to index `{}`", ident.name, indexed), + &format!("the loop variable `{}` is used to index `{indexed}`", ident.name), |diag| { multispan_sugg( diag, @@ -154,7 +154,7 @@ pub(super) fn check<'tcx>( (pat.span, format!("({}, )", ident.name)), ( arg.span, - format!("{}.{}().enumerate(){}{}", indexed, method, method_1, method_2), + format!("{indexed}.{method}().enumerate(){method_1}{method_2}"), ), ], ); @@ -162,16 +162,16 @@ pub(super) fn check<'tcx>( ); } else { let repl = if starts_at_zero && take_is_empty { - format!("&{}{}", ref_mut, indexed) + format!("&{ref_mut}{indexed}") } else { - format!("{}.{}(){}{}", indexed, method, method_1, method_2) + format!("{indexed}.{method}(){method_1}{method_2}") }; span_lint_and_then( cx, NEEDLESS_RANGE_LOOP, arg.span, - &format!("the loop variable `{}` is only used to index `{}`", ident.name, indexed), + &format!("the loop variable `{}` is only used to index `{indexed}`", ident.name), |diag| { multispan_sugg( diag, diff --git a/clippy_lints/src/loops/never_loop.rs b/clippy_lints/src/loops/never_loop.rs index 2386f4f4f4ee5..16b00ad663787 100644 --- a/clippy_lints/src/loops/never_loop.rs +++ b/clippy_lints/src/loops/never_loop.rs @@ -222,9 +222,5 @@ fn for_to_if_let_sugg(cx: &LateContext<'_>, iterator: &Expr<'_>, pat: &Pat<'_>) let pat_snippet = snippet(cx, pat.span, "_"); let iter_snippet = make_iterator_snippet(cx, iterator, &mut Applicability::Unspecified); - format!( - "if let Some({pat}) = {iter}.next()", - pat = pat_snippet, - iter = iter_snippet - ) + format!("if let Some({pat_snippet}) = {iter_snippet}.next()") } diff --git a/clippy_lints/src/loops/same_item_push.rs b/clippy_lints/src/loops/same_item_push.rs index aeefe6e33fbe9..07edee46fa657 100644 --- a/clippy_lints/src/loops/same_item_push.rs +++ b/clippy_lints/src/loops/same_item_push.rs @@ -30,10 +30,7 @@ pub(super) fn check<'tcx>( vec.span, "it looks like the same item is being pushed into this Vec", None, - &format!( - "try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})", - item_str, vec_str, item_str - ), + &format!("try using vec![{item_str};SIZE] or {vec_str}.resize(NEW_SIZE, {item_str})"), ); } diff --git a/clippy_lints/src/loops/utils.rs b/clippy_lints/src/loops/utils.rs index 4801a84eb92ce..b332e8a923ba7 100644 --- a/clippy_lints/src/loops/utils.rs +++ b/clippy_lints/src/loops/utils.rs @@ -344,9 +344,8 @@ pub(super) fn make_iterator_snippet(cx: &LateContext<'_>, arg: &Expr<'_>, applic _ => arg, }; format!( - "{}.{}()", + "{}.{method_name}()", sugg::Sugg::hir_with_applicability(cx, caller, "_", applic_ref).maybe_par(), - method_name, ) }, _ => format!( diff --git a/clippy_lints/src/loops/while_let_on_iterator.rs b/clippy_lints/src/loops/while_let_on_iterator.rs index deb21894f36a9..1c6f0264cb543 100644 --- a/clippy_lints/src/loops/while_let_on_iterator.rs +++ b/clippy_lints/src/loops/while_let_on_iterator.rs @@ -67,7 +67,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { expr.span.with_hi(scrutinee_expr.span.hi()), "this loop could be written as a `for` loop", "try", - format!("for {} in {}{}", loop_var, iterator, by_ref), + format!("for {loop_var} in {iterator}{by_ref}"), applicability, ); } diff --git a/clippy_lints/src/macro_use.rs b/clippy_lints/src/macro_use.rs index 6b78c16206522..f5617a905ff87 100644 --- a/clippy_lints/src/macro_use.rs +++ b/clippy_lints/src/macro_use.rs @@ -190,9 +190,9 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports { let mut suggestions = vec![]; for ((root, span, hir_id), path) in used { if path.len() == 1 { - suggestions.push((span, format!("{}::{}", root, path[0]), hir_id)); + suggestions.push((span, format!("{root}::{}", path[0]), hir_id)); } else { - suggestions.push((span, format!("{}::{{{}}}", root, path.join(", ")), hir_id)); + suggestions.push((span, format!("{root}::{{{}}}", path.join(", ")), hir_id)); } } @@ -200,7 +200,7 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports { // such as `std::prelude::v1::foo` or some other macro that expands to an import. if self.mac_refs.is_empty() { for (span, import, hir_id) in suggestions { - let help = format!("use {};", import); + let help = format!("use {import};"); span_lint_hir_and_then( cx, MACRO_USE_IMPORTS, diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index 2502c8f880ddc..ddd9f34cbc457 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -74,11 +74,11 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn { if let Some(ret_pos) = position_before_rarrow(&header_snip); if let Some((ret_sugg, ret_snip)) = suggested_ret(cx, output); then { - let help = format!("make the function `async` and {}", ret_sugg); + let help = format!("make the function `async` and {ret_sugg}"); diag.span_suggestion( header_span, &help, - format!("async {}{}", &header_snip[..ret_pos], ret_snip), + format!("async {}{ret_snip}", &header_snip[..ret_pos]), Applicability::MachineApplicable ); @@ -196,7 +196,7 @@ fn suggested_ret(cx: &LateContext<'_>, output: &Ty<'_>) -> Option<(&'static str, }, _ => { let sugg = "return the output of the future directly"; - snippet_opt(cx, output.span).map(|snip| (sugg, format!(" -> {}", snip))) + snippet_opt(cx, output.span).map(|snip| (sugg, format!(" -> {snip}"))) }, } } diff --git a/clippy_lints/src/manual_non_exhaustive.rs b/clippy_lints/src/manual_non_exhaustive.rs index 2b04475c7a9de..7d4f0b0211205 100644 --- a/clippy_lints/src/manual_non_exhaustive.rs +++ b/clippy_lints/src/manual_non_exhaustive.rs @@ -133,7 +133,7 @@ impl EarlyLintPass for ManualNonExhaustiveStruct { diag.span_suggestion( header_span, "add the attribute", - format!("#[non_exhaustive] {}", snippet), + format!("#[non_exhaustive] {snippet}"), Applicability::Unspecified, ); } @@ -207,7 +207,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum { diag.span_suggestion( header_span, "add the attribute", - format!("#[non_exhaustive] {}", snippet), + format!("#[non_exhaustive] {snippet}"), Applicability::Unspecified, ); } diff --git a/clippy_lints/src/manual_retain.rs b/clippy_lints/src/manual_retain.rs index 8476197bd1201..570fe73681830 100644 --- a/clippy_lints/src/manual_retain.rs +++ b/clippy_lints/src/manual_retain.rs @@ -153,7 +153,7 @@ fn suggest(cx: &LateContext<'_>, parent_expr: &hir::Expr<'_>, left_expr: &hir::E && let [filter_params] = filter_body.params && let Some(sugg) = match filter_params.pat.kind { hir::PatKind::Binding(_, _, filter_param_ident, None) => { - Some(format!("{}.retain(|{}| {})", snippet(cx, left_expr.span, ".."), filter_param_ident, snippet(cx, filter_body.value.span, ".."))) + Some(format!("{}.retain(|{filter_param_ident}| {})", snippet(cx, left_expr.span, ".."), snippet(cx, filter_body.value.span, ".."))) }, hir::PatKind::Tuple([key_pat, value_pat], _) => { make_sugg(cx, key_pat, value_pat, left_expr, filter_body) @@ -161,7 +161,7 @@ fn suggest(cx: &LateContext<'_>, parent_expr: &hir::Expr<'_>, left_expr: &hir::E hir::PatKind::Ref(pat, _) => { match pat.kind { hir::PatKind::Binding(_, _, filter_param_ident, None) => { - Some(format!("{}.retain(|{}| {})", snippet(cx, left_expr.span, ".."), filter_param_ident, snippet(cx, filter_body.value.span, ".."))) + Some(format!("{}.retain(|{filter_param_ident}| {})", snippet(cx, left_expr.span, ".."), snippet(cx, filter_body.value.span, ".."))) }, _ => None } @@ -190,23 +190,19 @@ fn make_sugg( match (&key_pat.kind, &value_pat.kind) { (hir::PatKind::Binding(_, _, key_param_ident, None), hir::PatKind::Binding(_, _, value_param_ident, None)) => { Some(format!( - "{}.retain(|{}, &mut {}| {})", + "{}.retain(|{key_param_ident}, &mut {value_param_ident}| {})", snippet(cx, left_expr.span, ".."), - key_param_ident, - value_param_ident, snippet(cx, filter_body.value.span, "..") )) }, (hir::PatKind::Binding(_, _, key_param_ident, None), hir::PatKind::Wild) => Some(format!( - "{}.retain(|{}, _| {})", + "{}.retain(|{key_param_ident}, _| {})", snippet(cx, left_expr.span, ".."), - key_param_ident, snippet(cx, filter_body.value.span, "..") )), (hir::PatKind::Wild, hir::PatKind::Binding(_, _, value_param_ident, None)) => Some(format!( - "{}.retain(|_, &mut {}| {})", + "{}.retain(|_, &mut {value_param_ident}| {})", snippet(cx, left_expr.span, ".."), - value_param_ident, snippet(cx, filter_body.value.span, "..") )), _ => None, diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index 7941c8c9c7e39..0976940afac35 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -108,15 +108,14 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip { }; let test_span = expr.span.until(then.span); - span_lint_and_then(cx, MANUAL_STRIP, strippings[0], &format!("stripping a {} manually", kind_word), |diag| { - diag.span_note(test_span, &format!("the {} was tested here", kind_word)); + span_lint_and_then(cx, MANUAL_STRIP, strippings[0], &format!("stripping a {kind_word} manually"), |diag| { + diag.span_note(test_span, &format!("the {kind_word} was tested here")); multispan_sugg( diag, - &format!("try using the `strip_{}` method", kind_word), + &format!("try using the `strip_{kind_word}` method"), vec![(test_span, - format!("if let Some() = {}.strip_{}({}) ", + format!("if let Some() = {}.strip_{kind_word}({}) ", snippet(cx, target_arg.span, ".."), - kind_word, snippet(cx, pattern.span, "..")))] .into_iter().chain(strippings.into_iter().map(|span| (span, "".into()))), ); diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs index 33d744815299f..df5684541e907 100644 --- a/clippy_lints/src/map_unit_fn.rs +++ b/clippy_lints/src/map_unit_fn.rs @@ -194,10 +194,7 @@ fn let_binding_name(cx: &LateContext<'_>, var_arg: &hir::Expr<'_>) -> String { #[must_use] fn suggestion_msg(function_type: &str, map_type: &str) -> String { - format!( - "called `map(f)` on an `{0}` value where `f` is a {1} that returns the unit type `()`", - map_type, function_type - ) + format!("called `map(f)` on an `{map_type}` value where `f` is a {function_type} that returns the unit type `()`") } fn lint_map_unit_fn( diff --git a/clippy_lints/src/match_result_ok.rs b/clippy_lints/src/match_result_ok.rs index 8588ab1ed8db7..a020282d234f9 100644 --- a/clippy_lints/src/match_result_ok.rs +++ b/clippy_lints/src/match_result_ok.rs @@ -70,9 +70,7 @@ impl<'tcx> LateLintPass<'tcx> for MatchResultOk { let some_expr_string = snippet_with_applicability(cx, y[0].span, "", &mut applicability); let trimmed_ok = snippet_with_applicability(cx, let_expr.span.until(ok_path.ident.span), "", &mut applicability); let sugg = format!( - "{} let Ok({}) = {}", - ifwhile, - some_expr_string, + "{ifwhile} let Ok({some_expr_string}) = {}", trimmed_ok.trim().trim_end_matches('.'), ); span_lint_and_sugg( @@ -80,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for MatchResultOk { MATCH_RESULT_OK, expr.span.with_hi(let_expr.span.hi()), "matching on `Some` with `ok()` is redundant", - &format!("consider matching on `Ok({})` and removing the call to `ok` instead", some_expr_string), + &format!("consider matching on `Ok({some_expr_string})` and removing the call to `ok` instead"), sugg, applicability, ); diff --git a/clippy_lints/src/matches/manual_map.rs b/clippy_lints/src/matches/manual_map.rs index b0198e856d5b6..96b8339550cee 100644 --- a/clippy_lints/src/matches/manual_map.rs +++ b/clippy_lints/src/matches/manual_map.rs @@ -144,7 +144,7 @@ fn check<'tcx>( let scrutinee = peel_hir_expr_refs(scrutinee).0; let (scrutinee_str, _) = snippet_with_context(cx, scrutinee.span, expr_ctxt, "..", &mut app); let scrutinee_str = if scrutinee.span.ctxt() == expr.span.ctxt() && scrutinee.precedence().order() < PREC_POSTFIX { - format!("({})", scrutinee_str) + format!("({scrutinee_str})") } else { scrutinee_str.into() }; @@ -172,9 +172,9 @@ fn check<'tcx>( }; let expr_snip = snippet_with_context(cx, some_expr.expr.span, expr_ctxt, "..", &mut app).0; if some_expr.needs_unsafe_block { - format!("|{}{}| unsafe {{ {} }}", annotation, some_binding, expr_snip) + format!("|{annotation}{some_binding}| unsafe {{ {expr_snip} }}") } else { - format!("|{}{}| {}", annotation, some_binding, expr_snip) + format!("|{annotation}{some_binding}| {expr_snip}") } } } @@ -183,9 +183,9 @@ fn check<'tcx>( let pat_snip = snippet_with_context(cx, some_pat.span, expr_ctxt, "..", &mut app).0; let expr_snip = snippet_with_context(cx, some_expr.expr.span, expr_ctxt, "..", &mut app).0; if some_expr.needs_unsafe_block { - format!("|{}| unsafe {{ {} }}", pat_snip, expr_snip) + format!("|{pat_snip}| unsafe {{ {expr_snip} }}") } else { - format!("|{}| {}", pat_snip, expr_snip) + format!("|{pat_snip}| {expr_snip}") } } else { // Refutable bindings and mixed reference annotations can't be handled by `map`. @@ -199,9 +199,9 @@ fn check<'tcx>( "manual implementation of `Option::map`", "try this", if else_pat.is_none() && is_else_clause(cx.tcx, expr) { - format!("{{ {}{}.map({}) }}", scrutinee_str, as_ref_str, body_str) + format!("{{ {scrutinee_str}{as_ref_str}.map({body_str}) }}") } else { - format!("{}{}.map({})", scrutinee_str, as_ref_str, body_str) + format!("{scrutinee_str}{as_ref_str}.map({body_str})") }, app, ); diff --git a/clippy_lints/src/matches/manual_unwrap_or.rs b/clippy_lints/src/matches/manual_unwrap_or.rs index e1111c80f2fe2..2fe7fe98a2e8f 100644 --- a/clippy_lints/src/matches/manual_unwrap_or.rs +++ b/clippy_lints/src/matches/manual_unwrap_or.rs @@ -42,12 +42,10 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, scrutinee: span_lint_and_sugg( cx, MANUAL_UNWRAP_OR, expr.span, - &format!("this pattern reimplements `{}::unwrap_or`", ty_name), + &format!("this pattern reimplements `{ty_name}::unwrap_or`"), "replace with", format!( - "{}.unwrap_or({})", - suggestion, - reindented_or_body, + "{suggestion}.unwrap_or({reindented_or_body})", ), Applicability::MachineApplicable, ); diff --git a/clippy_lints/src/matches/match_as_ref.rs b/clippy_lints/src/matches/match_as_ref.rs index 91d17f481e2df..39d30212f36a3 100644 --- a/clippy_lints/src/matches/match_as_ref.rs +++ b/clippy_lints/src/matches/match_as_ref.rs @@ -45,13 +45,11 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: cx, MATCH_AS_REF, expr.span, - &format!("use `{}()` instead", suggestion), + &format!("use `{suggestion}()` instead"), "try this", format!( - "{}.{}(){}", + "{}.{suggestion}(){cast}", snippet_with_applicability(cx, ex.span, "_", &mut applicability), - suggestion, - cast, ), applicability, ); diff --git a/clippy_lints/src/matches/match_like_matches.rs b/clippy_lints/src/matches/match_like_matches.rs index 34cc082687ec2..107fad32393cf 100644 --- a/clippy_lints/src/matches/match_like_matches.rs +++ b/clippy_lints/src/matches/match_like_matches.rs @@ -112,7 +112,7 @@ where .join(" | ") }; let pat_and_guard = if let Some(Guard::If(g)) = first_guard { - format!("{} if {}", pat, snippet_with_applicability(cx, g.span, "..", &mut applicability)) + format!("{pat} if {}", snippet_with_applicability(cx, g.span, "..", &mut applicability)) } else { pat }; @@ -131,10 +131,9 @@ where &format!("{} expression looks like `matches!` macro", if is_if_let { "if let .. else" } else { "match" }), "try this", format!( - "{}matches!({}, {})", + "{}matches!({}, {pat_and_guard})", if b0 { "" } else { "!" }, snippet_with_applicability(cx, ex_new.span, "..", &mut applicability), - pat_and_guard, ), applicability, ); diff --git a/clippy_lints/src/matches/match_same_arms.rs b/clippy_lints/src/matches/match_same_arms.rs index e32ef9933afe5..3e11016602b8c 100644 --- a/clippy_lints/src/matches/match_same_arms.rs +++ b/clippy_lints/src/matches/match_same_arms.rs @@ -135,7 +135,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) { diag.span_suggestion( keep_arm.pat.span, "try merging the arm patterns", - format!("{} | {}", keep_pat_snip, move_pat_snip), + format!("{keep_pat_snip} | {move_pat_snip}"), Applicability::MaybeIncorrect, ) .help("or try changing either arm body") diff --git a/clippy_lints/src/matches/match_single_binding.rs b/clippy_lints/src/matches/match_single_binding.rs index 5ae4a65acaf33..68682cedf1de4 100644 --- a/clippy_lints/src/matches/match_single_binding.rs +++ b/clippy_lints/src/matches/match_single_binding.rs @@ -75,12 +75,11 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e Some(AssignmentExpr::Local { span, pat_span }) => ( span, format!( - "let {} = {};\n{}let {} = {};", + "let {} = {};\n{}let {} = {snippet_body};", snippet_with_applicability(cx, bind_names, "..", &mut applicability), snippet_with_applicability(cx, matched_vars, "..", &mut applicability), " ".repeat(indent_of(cx, expr.span).unwrap_or(0)), - snippet_with_applicability(cx, pat_span, "..", &mut applicability), - snippet_body + snippet_with_applicability(cx, pat_span, "..", &mut applicability) ), ), None => { @@ -110,10 +109,8 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e if ex.can_have_side_effects() { let indent = " ".repeat(indent_of(cx, expr.span).unwrap_or(0)); let sugg = format!( - "{};\n{}{}", - snippet_with_applicability(cx, ex.span, "..", &mut applicability), - indent, - snippet_body + "{};\n{indent}{snippet_body}", + snippet_with_applicability(cx, ex.span, "..", &mut applicability) ); span_lint_and_sugg( @@ -178,10 +175,10 @@ fn sugg_with_curlies<'a>( let (mut cbrace_start, mut cbrace_end) = (String::new(), String::new()); if let Some(parent_expr) = get_parent_expr(cx, match_expr) { if let ExprKind::Closure { .. } = parent_expr.kind { - cbrace_end = format!("\n{}}}", indent); + cbrace_end = format!("\n{indent}}}"); // Fix body indent due to the closure indent = " ".repeat(indent_of(cx, bind_names).unwrap_or(0)); - cbrace_start = format!("{{\n{}", indent); + cbrace_start = format!("{{\n{indent}"); } } @@ -190,10 +187,10 @@ fn sugg_with_curlies<'a>( let parent_node_id = cx.tcx.hir().get_parent_node(match_expr.hir_id); if let Node::Arm(arm) = &cx.tcx.hir().get(parent_node_id) { if let ExprKind::Match(..) = arm.body.kind { - cbrace_end = format!("\n{}}}", indent); + cbrace_end = format!("\n{indent}}}"); // Fix body indent due to the match indent = " ".repeat(indent_of(cx, bind_names).unwrap_or(0)); - cbrace_start = format!("{{\n{}", indent); + cbrace_start = format!("{{\n{indent}"); } } @@ -204,13 +201,8 @@ fn sugg_with_curlies<'a>( }); format!( - "{}let {} = {};\n{}{}{}{}", - cbrace_start, + "{cbrace_start}let {} = {};\n{indent}{assignment_str}{snippet_body}{cbrace_end}", snippet_with_applicability(cx, bind_names, "..", applicability), - snippet_with_applicability(cx, matched_vars, "..", applicability), - indent, - assignment_str, - snippet_body, - cbrace_end + snippet_with_applicability(cx, matched_vars, "..", applicability) ) } diff --git a/clippy_lints/src/matches/match_str_case_mismatch.rs b/clippy_lints/src/matches/match_str_case_mismatch.rs index 1e80b6cf2d838..6647322caa37a 100644 --- a/clippy_lints/src/matches/match_str_case_mismatch.rs +++ b/clippy_lints/src/matches/match_str_case_mismatch.rs @@ -118,8 +118,8 @@ fn lint(cx: &LateContext<'_>, case_method: &CaseMethod, bad_case_span: Span, bad MATCH_STR_CASE_MISMATCH, bad_case_span, "this `match` arm has a differing case than its expression", - &format!("consider changing the case of this arm to respect `{}`", method_str), - format!("\"{}\"", suggestion), + &format!("consider changing the case of this arm to respect `{method_str}`"), + format!("\"{suggestion}\""), Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/matches/match_wild_err_arm.rs b/clippy_lints/src/matches/match_wild_err_arm.rs index a3aa2e4b389af..42f1e2629d41a 100644 --- a/clippy_lints/src/matches/match_wild_err_arm.rs +++ b/clippy_lints/src/matches/match_wild_err_arm.rs @@ -38,7 +38,7 @@ pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm<' span_lint_and_note(cx, MATCH_WILD_ERR_ARM, arm.pat.span, - &format!("`Err({})` matches all errors", ident_bind_name), + &format!("`Err({ident_bind_name})` matches all errors"), None, "match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable", ); diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs index f7443471e31dd..343b1d058b44e 100644 --- a/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/clippy_lints/src/matches/redundant_pattern_match.rs @@ -138,7 +138,7 @@ fn find_sugg_for_if_let<'tcx>( cx, REDUNDANT_PATTERN_MATCHING, let_pat.span, - &format!("redundant pattern matching, consider using `{}`", good_method), + &format!("redundant pattern matching, consider using `{good_method}`"), |diag| { // if/while let ... = ... { ... } // ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -162,7 +162,7 @@ fn find_sugg_for_if_let<'tcx>( .maybe_par() .to_string(); - diag.span_suggestion(span, "try this", format!("{} {}.{}", keyword, sugg, good_method), app); + diag.span_suggestion(span, "try this", format!("{keyword} {sugg}.{good_method}"), app); if needs_drop { diag.note("this will change drop order of the result, as well as all temporaries"); @@ -252,12 +252,12 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op cx, REDUNDANT_PATTERN_MATCHING, expr.span, - &format!("redundant pattern matching, consider using `{}`", good_method), + &format!("redundant pattern matching, consider using `{good_method}`"), |diag| { diag.span_suggestion( span, "try this", - format!("{}.{}", snippet(cx, result_expr.span, "_"), good_method), + format!("{}.{good_method}", snippet(cx, result_expr.span, "_")), Applicability::MaybeIncorrect, // snippet ); }, diff --git a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs index 86a9df034979b..85269e533a066 100644 --- a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs +++ b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs @@ -50,13 +50,13 @@ fn set_diagnostic<'tcx>(diag: &mut Diagnostic, cx: &LateContext<'tcx>, expr: &'t let trailing_indent = " ".repeat(indent_of(cx, found.found_span).unwrap_or(0)); let replacement = if found.lint_suggestion == LintSuggestion::MoveAndDerefToCopy { - format!("let value = *{};\n{}", original, trailing_indent) + format!("let value = *{original};\n{trailing_indent}") } else if found.is_unit_return_val { // If the return value of the expression to be moved is unit, then we don't need to // capture the result in a temporary -- we can just replace it completely with `()`. - format!("{};\n{}", original, trailing_indent) + format!("{original};\n{trailing_indent}") } else { - format!("let value = {};\n{}", original, trailing_indent) + format!("let value = {original};\n{trailing_indent}") }; let suggestion_message = if found.lint_suggestion == LintSuggestion::MoveOnly { diff --git a/clippy_lints/src/matches/single_match.rs b/clippy_lints/src/matches/single_match.rs index 38df69eeb379b..6314959f818ea 100644 --- a/clippy_lints/src/matches/single_match.rs +++ b/clippy_lints/src/matches/single_match.rs @@ -99,23 +99,21 @@ fn report_single_pattern( let msg = "you seem to be trying to use `match` for an equality check. Consider using `if`"; let sugg = format!( - "if {} == {}{} {}{}", + "if {} == {}{} {}{els_str}", snippet(cx, ex.span, ".."), // PartialEq for different reference counts may not exist. "&".repeat(ref_count_diff), snippet(cx, arms[0].pat.span, ".."), expr_block(cx, arms[0].body, None, "..", Some(expr.span)), - els_str, ); (msg, sugg) } else { let msg = "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"; let sugg = format!( - "if let {} = {} {}{}", + "if let {} = {} {}{els_str}", snippet(cx, arms[0].pat.span, ".."), snippet(cx, ex.span, ".."), expr_block(cx, arms[0].body, None, "..", Some(expr.span)), - els_str, ); (msg, sugg) } diff --git a/clippy_lints/src/matches/try_err.rs b/clippy_lints/src/matches/try_err.rs index 663277d11365f..a3ec1ff24820c 100644 --- a/clippy_lints/src/matches/try_err.rs +++ b/clippy_lints/src/matches/try_err.rs @@ -61,9 +61,9 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, scrutine "return " }; let suggestion = if err_ty == expr_err_ty { - format!("{}{}{}{}", ret_prefix, prefix, origin_snippet, suffix) + format!("{ret_prefix}{prefix}{origin_snippet}{suffix}") } else { - format!("{}{}{}.into(){}", ret_prefix, prefix, origin_snippet, suffix) + format!("{ret_prefix}{prefix}{origin_snippet}.into(){suffix}") }; span_lint_and_sugg( diff --git a/clippy_lints/src/methods/bind_instead_of_map.rs b/clippy_lints/src/methods/bind_instead_of_map.rs index 22f5635a5bccb..cc26b0f7fa82d 100644 --- a/clippy_lints/src/methods/bind_instead_of_map.rs +++ b/clippy_lints/src/methods/bind_instead_of_map.rs @@ -85,7 +85,7 @@ pub(crate) trait BindInsteadOfMap { let closure_args_snip = snippet(cx, closure_args_span, ".."); let option_snip = snippet(cx, recv.span, ".."); - let note = format!("{}.{}({} {})", option_snip, Self::GOOD_METHOD_NAME, closure_args_snip, some_inner_snip); + let note = format!("{option_snip}.{}({closure_args_snip} {some_inner_snip})", Self::GOOD_METHOD_NAME); span_lint_and_sugg( cx, BIND_INSTEAD_OF_MAP, diff --git a/clippy_lints/src/methods/bytes_nth.rs b/clippy_lints/src/methods/bytes_nth.rs index 44857d61fef8f..2e96346be977e 100644 --- a/clippy_lints/src/methods/bytes_nth.rs +++ b/clippy_lints/src/methods/bytes_nth.rs @@ -22,7 +22,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E cx, BYTES_NTH, expr.span, - &format!("called `.bytes().nth()` on a `{}`", caller_type), + &format!("called `.bytes().nth()` on a `{caller_type}`"), "try", format!( "{}.as_bytes().get({})", diff --git a/clippy_lints/src/methods/chars_cmp.rs b/clippy_lints/src/methods/chars_cmp.rs index b2bc1ad5c9ed0..56b7fbb9d4bc8 100644 --- a/clippy_lints/src/methods/chars_cmp.rs +++ b/clippy_lints/src/methods/chars_cmp.rs @@ -33,12 +33,11 @@ pub(super) fn check( cx, lint, info.expr.span, - &format!("you should use the `{}` method", suggest), + &format!("you should use the `{suggest}` method"), "like this", - format!("{}{}.{}({})", + format!("{}{}.{suggest}({})", if info.eq { "" } else { "!" }, snippet_with_applicability(cx, args[0].0.span, "..", &mut applicability), - suggest, snippet_with_applicability(cx, arg_char.span, "..", &mut applicability)), applicability, ); diff --git a/clippy_lints/src/methods/chars_cmp_with_unwrap.rs b/clippy_lints/src/methods/chars_cmp_with_unwrap.rs index b85bfec2b12ba..7e808760663a1 100644 --- a/clippy_lints/src/methods/chars_cmp_with_unwrap.rs +++ b/clippy_lints/src/methods/chars_cmp_with_unwrap.rs @@ -26,12 +26,11 @@ pub(super) fn check<'tcx>( cx, lint, info.expr.span, - &format!("you should use the `{}` method", suggest), + &format!("you should use the `{suggest}` method"), "like this", - format!("{}{}.{}('{}')", + format!("{}{}.{suggest}('{}')", if info.eq { "" } else { "!" }, snippet_with_applicability(cx, args[0].0.span, "..", &mut applicability), - suggest, c.escape_default()), applicability, ); diff --git a/clippy_lints/src/methods/clone_on_copy.rs b/clippy_lints/src/methods/clone_on_copy.rs index 7ab6b84c20749..7c7938dd2e8b0 100644 --- a/clippy_lints/src/methods/clone_on_copy.rs +++ b/clippy_lints/src/methods/clone_on_copy.rs @@ -49,8 +49,7 @@ pub(super) fn check( expr.span, &format!( "using `clone` on a double-reference; \ - this will copy the reference of type `{}` instead of cloning the inner type", - ty + this will copy the reference of type `{ty}` instead of cloning the inner type" ), |diag| { if let Some(snip) = sugg::Sugg::hir_opt(cx, arg) { @@ -62,11 +61,11 @@ pub(super) fn check( } let refs = "&".repeat(n + 1); let derefs = "*".repeat(n); - let explicit = format!("<{}{}>::clone({})", refs, ty, snip); + let explicit = format!("<{refs}{ty}>::clone({snip})"); diag.span_suggestion( expr.span, "try dereferencing it", - format!("{}({}{}).clone()", refs, derefs, snip.deref()), + format!("{refs}({derefs}{}).clone()", snip.deref()), Applicability::MaybeIncorrect, ); diag.span_suggestion( @@ -121,16 +120,16 @@ pub(super) fn check( let (help, sugg) = if deref_count == 0 { ("try removing the `clone` call", snip.into()) } else if parent_is_suffix_expr { - ("try dereferencing it", format!("({}{})", "*".repeat(deref_count), snip)) + ("try dereferencing it", format!("({}{snip})", "*".repeat(deref_count))) } else { - ("try dereferencing it", format!("{}{}", "*".repeat(deref_count), snip)) + ("try dereferencing it", format!("{}{snip}", "*".repeat(deref_count))) }; span_lint_and_sugg( cx, CLONE_ON_COPY, expr.span, - &format!("using `clone` on type `{}` which implements the `Copy` trait", ty), + &format!("using `clone` on type `{ty}` which implements the `Copy` trait"), help, sugg, app, diff --git a/clippy_lints/src/methods/clone_on_ref_ptr.rs b/clippy_lints/src/methods/clone_on_ref_ptr.rs index f82ca89120061..355f53532e268 100644 --- a/clippy_lints/src/methods/clone_on_ref_ptr.rs +++ b/clippy_lints/src/methods/clone_on_ref_ptr.rs @@ -41,7 +41,7 @@ pub(super) fn check( expr.span, "using `.clone()` on a ref-counted pointer", "try this", - format!("{}::<{}>::clone(&{})", caller_type, subst.type_at(0), snippet), + format!("{caller_type}::<{}>::clone(&{snippet})", subst.type_at(0)), Applicability::Unspecified, // Sometimes unnecessary ::<_> after Rc/Arc/Weak ); } diff --git a/clippy_lints/src/methods/expect_fun_call.rs b/clippy_lints/src/methods/expect_fun_call.rs index bd846d71d4668..d0cf411dfd34c 100644 --- a/clippy_lints/src/methods/expect_fun_call.rs +++ b/clippy_lints/src/methods/expect_fun_call.rs @@ -143,9 +143,9 @@ pub(super) fn check<'tcx>( cx, EXPECT_FUN_CALL, span_replace_word, - &format!("use of `{}` followed by a function call", name), + &format!("use of `{name}` followed by a function call"), "try this", - format!("unwrap_or_else({} panic!({}))", closure_args, sugg), + format!("unwrap_or_else({closure_args} panic!({sugg}))"), applicability, ); return; @@ -160,12 +160,9 @@ pub(super) fn check<'tcx>( cx, EXPECT_FUN_CALL, span_replace_word, - &format!("use of `{}` followed by a function call", name), + &format!("use of `{name}` followed by a function call"), "try this", - format!( - "unwrap_or_else({} {{ panic!(\"{{}}\", {}) }})", - closure_args, arg_root_snippet - ), + format!("unwrap_or_else({closure_args} {{ panic!(\"{{}}\", {arg_root_snippet}) }})"), applicability, ); } diff --git a/clippy_lints/src/methods/filetype_is_file.rs b/clippy_lints/src/methods/filetype_is_file.rs index 7b2967feb0fe9..60f8283c3e09d 100644 --- a/clippy_lints/src/methods/filetype_is_file.rs +++ b/clippy_lints/src/methods/filetype_is_file.rs @@ -35,7 +35,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr span = expr.span; } } - let lint_msg = format!("`{}FileType::is_file()` only {} regular files", lint_unary, verb); - let help_msg = format!("use `{}FileType::is_dir()` instead", help_unary); + let lint_msg = format!("`{lint_unary}FileType::is_file()` only {verb} regular files"); + let help_msg = format!("use `{help_unary}FileType::is_dir()` instead"); span_lint_and_help(cx, FILETYPE_IS_FILE, span, &lint_msg, None, &help_msg); } diff --git a/clippy_lints/src/methods/filter_map_next.rs b/clippy_lints/src/methods/filter_map_next.rs index 38ec4d8e3ab8f..ddf8a1f09b87d 100644 --- a/clippy_lints/src/methods/filter_map_next.rs +++ b/clippy_lints/src/methods/filter_map_next.rs @@ -32,7 +32,7 @@ pub(super) fn check<'tcx>( expr.span, msg, "try this", - format!("{}.find_map({})", iter_snippet, filter_snippet), + format!("{iter_snippet}.find_map({filter_snippet})"), Applicability::MachineApplicable, ); } else { diff --git a/clippy_lints/src/methods/filter_next.rs b/clippy_lints/src/methods/filter_next.rs index bcf8d93b602ef..edcec0fc1015e 100644 --- a/clippy_lints/src/methods/filter_next.rs +++ b/clippy_lints/src/methods/filter_next.rs @@ -32,7 +32,7 @@ pub(super) fn check<'tcx>( expr.span, msg, "try this", - format!("{}.find({})", iter_snippet, filter_snippet), + format!("{iter_snippet}.find({filter_snippet})"), Applicability::MachineApplicable, ); } else { diff --git a/clippy_lints/src/methods/from_iter_instead_of_collect.rs b/clippy_lints/src/methods/from_iter_instead_of_collect.rs index 6436e28a63c52..66dfce3682b59 100644 --- a/clippy_lints/src/methods/from_iter_instead_of_collect.rs +++ b/clippy_lints/src/methods/from_iter_instead_of_collect.rs @@ -23,7 +23,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Exp // `expr` implements `FromIterator` trait let iter_expr = sugg::Sugg::hir(cx, &args[0], "..").maybe_par(); let turbofish = extract_turbofish(cx, expr, ty); - let sugg = format!("{}.collect::<{}>()", iter_expr, turbofish); + let sugg = format!("{iter_expr}.collect::<{turbofish}>()"); span_lint_and_sugg( cx, FROM_ITER_INSTEAD_OF_COLLECT, @@ -63,7 +63,7 @@ fn extract_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ty: Ty<'_>) -> if e == type_specifier { None } else { Some((*e).to_string()) } }).collect::>(); // join and add the type specifier at the end (i.e.: `collections::BTreeSet`) - format!("{}{}", without_ts.join("::"), type_specifier) + format!("{}{type_specifier}", without_ts.join("::")) } else { // type is not explicitly specified so wildcards are needed // i.e.: 2 wildcards in `std::collections::BTreeMap<&i32, &char>` @@ -72,7 +72,7 @@ fn extract_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ty: Ty<'_>) -> let end = ty_str.find('>').unwrap_or(ty_str.len()); let nb_wildcard = ty_str[start..end].split(',').count(); let wildcards = format!("_{}", ", _".repeat(nb_wildcard - 1)); - format!("{}<{}>", elements.join("::"), wildcards) + format!("{}<{wildcards}>", elements.join("::")) } } } diff --git a/clippy_lints/src/methods/get_first.rs b/clippy_lints/src/methods/get_first.rs index 4de77de740421..cb17af608a3f0 100644 --- a/clippy_lints/src/methods/get_first.rs +++ b/clippy_lints/src/methods/get_first.rs @@ -29,9 +29,9 @@ pub(super) fn check<'tcx>( cx, GET_FIRST, expr.span, - &format!("accessing first element with `{0}.get(0)`", slice_name), + &format!("accessing first element with `{slice_name}.get(0)`"), "try", - format!("{}.first()", slice_name), + format!("{slice_name}.first()"), app, ); } diff --git a/clippy_lints/src/methods/get_unwrap.rs b/clippy_lints/src/methods/get_unwrap.rs index 18e08d6ee2320..ffc3a4d780e5d 100644 --- a/clippy_lints/src/methods/get_unwrap.rs +++ b/clippy_lints/src/methods/get_unwrap.rs @@ -71,16 +71,11 @@ pub(super) fn check<'tcx>( cx, GET_UNWRAP, span, - &format!( - "called `.get{0}().unwrap()` on a {1}. Using `[]` is more clear and more concise", - mut_str, caller_type - ), + &format!("called `.get{mut_str}().unwrap()` on a {caller_type}. Using `[]` is more clear and more concise"), "try this", format!( - "{}{}[{}]", - borrow_str, - snippet_with_applicability(cx, recv.span, "..", &mut applicability), - get_args_str + "{borrow_str}{}[{get_args_str}]", + snippet_with_applicability(cx, recv.span, "..", &mut applicability) ), applicability, ); diff --git a/clippy_lints/src/methods/implicit_clone.rs b/clippy_lints/src/methods/implicit_clone.rs index 9651a52be4e72..429cdc1918d79 100644 --- a/clippy_lints/src/methods/implicit_clone.rs +++ b/clippy_lints/src/methods/implicit_clone.rs @@ -26,12 +26,12 @@ pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv cx, IMPLICIT_CLONE, expr.span, - &format!("implicitly cloning a `{}` by calling `{}` on its dereferenced type", ty_name, method_name), + &format!("implicitly cloning a `{ty_name}` by calling `{method_name}` on its dereferenced type"), "consider using", if ref_count > 1 { - format!("({}{}).clone()", "*".repeat(ref_count - 1), recv_snip) + format!("({}{recv_snip}).clone()", "*".repeat(ref_count - 1)) } else { - format!("{}.clone()", recv_snip) + format!("{recv_snip}.clone()") }, app, ); diff --git a/clippy_lints/src/methods/inefficient_to_string.rs b/clippy_lints/src/methods/inefficient_to_string.rs index e1c9b5248a8a4..e5dc3711b0b47 100644 --- a/clippy_lints/src/methods/inefficient_to_string.rs +++ b/clippy_lints/src/methods/inefficient_to_string.rs @@ -34,18 +34,17 @@ pub fn check<'tcx>( cx, INEFFICIENT_TO_STRING, expr.span, - &format!("calling `to_string` on `{}`", arg_ty), + &format!("calling `to_string` on `{arg_ty}`"), |diag| { diag.help(&format!( - "`{}` implements `ToString` through a slower blanket impl, but `{}` has a fast specialization of `ToString`", - self_ty, deref_self_ty + "`{self_ty}` implements `ToString` through a slower blanket impl, but `{deref_self_ty}` has a fast specialization of `ToString`" )); let mut applicability = Applicability::MachineApplicable; let arg_snippet = snippet_with_applicability(cx, receiver.span, "..", &mut applicability); diag.span_suggestion( expr.span, "try dereferencing the receiver", - format!("({}{}).to_string()", "*".repeat(deref_count), arg_snippet), + format!("({}{arg_snippet}).to_string()", "*".repeat(deref_count)), applicability, ); }, diff --git a/clippy_lints/src/methods/into_iter_on_ref.rs b/clippy_lints/src/methods/into_iter_on_ref.rs index 11e76841e9f05..be56b63506a4b 100644 --- a/clippy_lints/src/methods/into_iter_on_ref.rs +++ b/clippy_lints/src/methods/into_iter_on_ref.rs @@ -30,8 +30,7 @@ pub(super) fn check( INTO_ITER_ON_REF, method_span, &format!( - "this `.into_iter()` call is equivalent to `.{}()` and will not consume the `{}`", - method_name, kind, + "this `.into_iter()` call is equivalent to `.{method_name}()` and will not consume the `{kind}`", ), "call directly", method_name.to_string(), diff --git a/clippy_lints/src/methods/is_digit_ascii_radix.rs b/clippy_lints/src/methods/is_digit_ascii_radix.rs index aa176dcc8b4af..304024e80666f 100644 --- a/clippy_lints/src/methods/is_digit_ascii_radix.rs +++ b/clippy_lints/src/methods/is_digit_ascii_radix.rs @@ -37,12 +37,11 @@ pub(super) fn check<'tcx>( cx, IS_DIGIT_ASCII_RADIX, expr.span, - &format!("use of `char::is_digit` with literal radix of {}", num), + &format!("use of `char::is_digit` with literal radix of {num}"), "try", format!( - "{}.{}()", - snippet_with_applicability(cx, self_arg.span, "..", &mut applicability), - replacement + "{}.{replacement}()", + snippet_with_applicability(cx, self_arg.span, "..", &mut applicability) ), applicability, ); diff --git a/clippy_lints/src/methods/iter_cloned_collect.rs b/clippy_lints/src/methods/iter_cloned_collect.rs index 30d56113c6c10..bde6f92b076eb 100644 --- a/clippy_lints/src/methods/iter_cloned_collect.rs +++ b/clippy_lints/src/methods/iter_cloned_collect.rs @@ -20,8 +20,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, method_name: &str, expr: &hir: cx, ITER_CLONED_COLLECT, to_replace, - &format!("called `iter().{}().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and \ - more readable", method_name), + &format!("called `iter().{method_name}().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and \ + more readable"), "try", ".to_vec()".to_string(), Applicability::MachineApplicable, diff --git a/clippy_lints/src/methods/iter_count.rs b/clippy_lints/src/methods/iter_count.rs index 052be3d8ee7ca..bcddc7c786a50 100644 --- a/clippy_lints/src/methods/iter_count.rs +++ b/clippy_lints/src/methods/iter_count.rs @@ -37,7 +37,7 @@ pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E cx, ITER_COUNT, expr.span, - &format!("called `.{}().count()` on a `{}`", iter_method, caller_type), + &format!("called `.{iter_method}().count()` on a `{caller_type}`"), "try", format!( "{}.len()", diff --git a/clippy_lints/src/methods/iter_kv_map.rs b/clippy_lints/src/methods/iter_kv_map.rs index a7eecabd68495..2244ebfb12927 100644 --- a/clippy_lints/src/methods/iter_kv_map.rs +++ b/clippy_lints/src/methods/iter_kv_map.rs @@ -54,9 +54,9 @@ pub(super) fn check<'tcx>( cx, ITER_KV_MAP, expr.span, - &format!("iterating on a map's {}s", replacement_kind), + &format!("iterating on a map's {replacement_kind}s"), "try", - format!("{}.{}{}s()", recv_snippet, into_prefix, replacement_kind), + format!("{recv_snippet}.{into_prefix}{replacement_kind}s()"), applicability, ); } else { @@ -64,9 +64,9 @@ pub(super) fn check<'tcx>( cx, ITER_KV_MAP, expr.span, - &format!("iterating on a map's {}s", replacement_kind), + &format!("iterating on a map's {replacement_kind}s"), "try", - format!("{}.{}{}s().map(|{}| {})", recv_snippet, into_prefix, replacement_kind, binded_ident, + format!("{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{binded_ident}| {})", snippet_with_applicability(cx, body_expr.span, "/* body */", &mut applicability)), applicability, ); diff --git a/clippy_lints/src/methods/iter_next_slice.rs b/clippy_lints/src/methods/iter_next_slice.rs index b8d1dabe00764..83c1bf203467a 100644 --- a/clippy_lints/src/methods/iter_next_slice.rs +++ b/clippy_lints/src/methods/iter_next_slice.rs @@ -37,7 +37,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, cal let suggest = if start_idx == 0 { format!("{}.first()", snippet_with_applicability(cx, caller_var.span, "..", &mut applicability)) } else { - format!("{}.get({})", snippet_with_applicability(cx, caller_var.span, "..", &mut applicability), start_idx) + format!("{}.get({start_idx})", snippet_with_applicability(cx, caller_var.span, "..", &mut applicability)) }; span_lint_and_sugg( cx, diff --git a/clippy_lints/src/methods/iter_nth.rs b/clippy_lints/src/methods/iter_nth.rs index 80ca4c94219f8..ceee12784cbb7 100644 --- a/clippy_lints/src/methods/iter_nth.rs +++ b/clippy_lints/src/methods/iter_nth.rs @@ -32,8 +32,8 @@ pub(super) fn check<'tcx>( cx, ITER_NTH, expr.span, - &format!("called `.iter{0}().nth()` on a {1}", mut_str, caller_type), + &format!("called `.iter{mut_str}().nth()` on a {caller_type}"), None, - &format!("calling `.get{}()` is both faster and more readable", mut_str), + &format!("calling `.get{mut_str}()` is both faster and more readable"), ); } diff --git a/clippy_lints/src/methods/iter_with_drain.rs b/clippy_lints/src/methods/iter_with_drain.rs index a669cbbbcc602..3da230e12d7fe 100644 --- a/clippy_lints/src/methods/iter_with_drain.rs +++ b/clippy_lints/src/methods/iter_with_drain.rs @@ -22,7 +22,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span cx, ITER_WITH_DRAIN, span.with_hi(expr.span.hi()), - &format!("`drain(..)` used on a `{}`", ty_name), + &format!("`drain(..)` used on a `{ty_name}`"), "try this", "into_iter()".to_string(), Applicability::MaybeIncorrect, diff --git a/clippy_lints/src/methods/manual_ok_or.rs b/clippy_lints/src/methods/manual_ok_or.rs index ffd2f4a38b8ac..c5c0ace7729c4 100644 --- a/clippy_lints/src/methods/manual_ok_or.rs +++ b/clippy_lints/src/methods/manual_ok_or.rs @@ -37,9 +37,7 @@ pub(super) fn check<'tcx>( "this pattern reimplements `Option::ok_or`", "replace with", format!( - "{}.ok_or({})", - recv_snippet, - reindented_err_arg_snippet + "{recv_snippet}.ok_or({reindented_err_arg_snippet})" ), Applicability::MachineApplicable, ); diff --git a/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/clippy_lints/src/methods/manual_saturating_arithmetic.rs index 0fe510beaa07e..ec694cf6882e5 100644 --- a/clippy_lints/src/methods/manual_saturating_arithmetic.rs +++ b/clippy_lints/src/methods/manual_saturating_arithmetic.rs @@ -57,11 +57,10 @@ pub fn check( super::MANUAL_SATURATING_ARITHMETIC, expr.span, "manual saturating arithmetic", - &format!("try using `saturating_{}`", arith), + &format!("try using `saturating_{arith}`"), format!( - "{}.saturating_{}({})", + "{}.saturating_{arith}({})", snippet_with_applicability(cx, arith_lhs.span, "..", &mut applicability), - arith, snippet_with_applicability(cx, arith_rhs.span, "..", &mut applicability), ), applicability, diff --git a/clippy_lints/src/methods/manual_str_repeat.rs b/clippy_lints/src/methods/manual_str_repeat.rs index 46d2fc493f81e..67e504af161cd 100644 --- a/clippy_lints/src/methods/manual_str_repeat.rs +++ b/clippy_lints/src/methods/manual_str_repeat.rs @@ -91,7 +91,7 @@ pub(super) fn check( collect_expr.span, "manual implementation of `str::repeat` using iterators", "try this", - format!("{}.repeat({})", val_str, count_snip), + format!("{val_str}.repeat({count_snip})"), app ) } diff --git a/clippy_lints/src/methods/map_clone.rs b/clippy_lints/src/methods/map_clone.rs index 8261ef5e1ce34..7ce14ec080b15 100644 --- a/clippy_lints/src/methods/map_clone.rs +++ b/clippy_lints/src/methods/map_clone.rs @@ -111,11 +111,10 @@ fn lint_explicit_closure(cx: &LateContext<'_>, replace: Span, root: Span, is_cop MAP_CLONE, replace, message, - &format!("consider calling the dedicated `{}` method", sugg_method), + &format!("consider calling the dedicated `{sugg_method}` method"), format!( - "{}.{}()", + "{}.{sugg_method}()", snippet_with_applicability(cx, root, "..", &mut applicability), - sugg_method, ), applicability, ); diff --git a/clippy_lints/src/methods/map_flatten.rs b/clippy_lints/src/methods/map_flatten.rs index 13853dec99de8..361ffcb5ef3fb 100644 --- a/clippy_lints/src/methods/map_flatten.rs +++ b/clippy_lints/src/methods/map_flatten.rs @@ -20,12 +20,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, map_ cx, MAP_FLATTEN, expr.span.with_lo(map_span.lo()), - &format!("called `map(..).flatten()` on `{}`", caller_ty_name), - &format!( - "try replacing `map` with `{}` and remove the `.flatten()`", - method_to_use - ), - format!("{}({})", method_to_use, closure_snippet), + &format!("called `map(..).flatten()` on `{caller_ty_name}`"), + &format!("try replacing `map` with `{method_to_use}` and remove the `.flatten()`"), + format!("{method_to_use}({closure_snippet})"), applicability, ); } diff --git a/clippy_lints/src/methods/map_identity.rs b/clippy_lints/src/methods/map_identity.rs index 862a9578e6ff2..0f25ef82ed42a 100644 --- a/clippy_lints/src/methods/map_identity.rs +++ b/clippy_lints/src/methods/map_identity.rs @@ -30,7 +30,7 @@ pub(super) fn check( MAP_IDENTITY, sugg_span, "unnecessary map of the identity function", - &format!("remove the call to `{}`", name), + &format!("remove the call to `{name}`"), String::new(), Applicability::MachineApplicable, ) diff --git a/clippy_lints/src/methods/map_unwrap_or.rs b/clippy_lints/src/methods/map_unwrap_or.rs index 4a8e7ce4ddbbd..74fdead216b0a 100644 --- a/clippy_lints/src/methods/map_unwrap_or.rs +++ b/clippy_lints/src/methods/map_unwrap_or.rs @@ -65,7 +65,7 @@ pub(super) fn check<'tcx>( expr.span, msg, "try this", - format!("{}.map_or_else({}, {})", var_snippet, unwrap_snippet, map_snippet), + format!("{var_snippet}.map_or_else({unwrap_snippet}, {map_snippet})"), Applicability::MachineApplicable, ); return true; diff --git a/clippy_lints/src/methods/option_as_ref_deref.rs b/clippy_lints/src/methods/option_as_ref_deref.rs index c409268de769d..6fb92d1c663cf 100644 --- a/clippy_lints/src/methods/option_as_ref_deref.rs +++ b/clippy_lints/src/methods/option_as_ref_deref.rs @@ -98,13 +98,12 @@ pub(super) fn check<'tcx>( format!(".as_ref().map({})", snippet(cx, map_arg.span, "..")) }; let method_hint = if is_mut { "as_deref_mut" } else { "as_deref" }; - let hint = format!("{}.{}()", snippet(cx, as_ref_recv.span, ".."), method_hint); - let suggestion = format!("try using {} instead", method_hint); + let hint = format!("{}.{method_hint}()", snippet(cx, as_ref_recv.span, "..")); + let suggestion = format!("try using {method_hint} instead"); let msg = format!( - "called `{0}` on an Option value. This can be done more directly \ - by calling `{1}` instead", - current_method, hint + "called `{current_method}` on an Option value. This can be done more directly \ + by calling `{hint}` instead" ); span_lint_and_sugg( cx, diff --git a/clippy_lints/src/methods/option_map_or_none.rs b/clippy_lints/src/methods/option_map_or_none.rs index 6657cdccd010c..76572425346b0 100644 --- a/clippy_lints/src/methods/option_map_or_none.rs +++ b/clippy_lints/src/methods/option_map_or_none.rs @@ -87,7 +87,7 @@ pub(super) fn check<'tcx>( expr.span, msg, "try using `map` instead", - format!("{0}.map({1} {2})", self_snippet, arg_snippet,func_snippet), + format!("{self_snippet}.map({arg_snippet} {func_snippet})"), Applicability::MachineApplicable, ); } @@ -102,7 +102,7 @@ pub(super) fn check<'tcx>( expr.span, msg, "try using `and_then` instead", - format!("{0}.and_then({1})", self_snippet, func_snippet), + format!("{self_snippet}.and_then({func_snippet})"), Applicability::MachineApplicable, ); } else if f_arg_is_some { @@ -115,7 +115,7 @@ pub(super) fn check<'tcx>( expr.span, msg, "try using `ok` instead", - format!("{0}.ok()", self_snippet), + format!("{self_snippet}.ok()"), Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs index 3c4002a3aef99..30421a6dd5afb 100644 --- a/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -65,9 +65,8 @@ pub(super) fn check<'tcx>( "map_or(, )" }; let msg = &format!( - "called `map().unwrap_or({})` on an `Option` value. \ - This can be done more directly by calling `{}` instead", - arg, suggest + "called `map().unwrap_or({arg})` on an `Option` value. \ + This can be done more directly by calling `{suggest}` instead" ); span_lint_and_then(cx, MAP_UNWRAP_OR, expr.span, msg, |diag| { @@ -82,10 +81,10 @@ pub(super) fn check<'tcx>( ]; if !unwrap_snippet_none { - suggestion.push((map_arg_span.with_hi(map_arg_span.lo()), format!("{}, ", unwrap_snippet))); + suggestion.push((map_arg_span.with_hi(map_arg_span.lo()), format!("{unwrap_snippet}, "))); } - diag.multipart_suggestion(&format!("use `{}` instead", suggest), suggestion, applicability); + diag.multipart_suggestion(&format!("use `{suggest}` instead"), suggestion, applicability); }); } } diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index b43b9258c471d..6a35024d03612 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -62,9 +62,9 @@ pub(super) fn check<'tcx>( cx, OR_FUN_CALL, method_span.with_hi(span.hi()), - &format!("use of `{}` followed by a call to `{}`", name, path), + &format!("use of `{name}` followed by a call to `{path}`"), "try this", - format!("{}()", sugg), + format!("{sugg}()"), Applicability::MachineApplicable, ); @@ -131,7 +131,7 @@ pub(super) fn check<'tcx>( if use_lambda { let l_arg = if fn_has_arguments { "_" } else { "" }; - format!("|{}| {}", l_arg, snippet).into() + format!("|{l_arg}| {snippet}").into() } else { snippet } @@ -141,9 +141,9 @@ pub(super) fn check<'tcx>( cx, OR_FUN_CALL, span_replace_word, - &format!("use of `{}` followed by a function call", name), + &format!("use of `{name}` followed by a function call"), "try this", - format!("{}_{}({})", name, suffix, sugg), + format!("{name}_{suffix}({sugg})"), Applicability::HasPlaceholders, ); } diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs index 7572ba3fe9a94..324c9c17b5a9a 100644 --- a/clippy_lints/src/methods/search_is_some.rs +++ b/clippy_lints/src/methods/search_is_some.rs @@ -30,10 +30,7 @@ pub(super) fn check<'tcx>( let option_check_method = if is_some { "is_some" } else { "is_none" }; // lint if caller of search is an Iterator if is_trait_method(cx, is_some_recv, sym::Iterator) { - let msg = format!( - "called `{}()` after searching an `Iterator` with `{}`", - option_check_method, search_method - ); + let msg = format!("called `{option_check_method}()` after searching an `Iterator` with `{search_method}`"); let search_snippet = snippet(cx, search_arg.span, ".."); if search_snippet.lines().count() <= 1 { // suggest `any(|x| ..)` instead of `any(|&x| ..)` for `find(|&x| ..).is_some()` @@ -86,8 +83,7 @@ pub(super) fn check<'tcx>( &msg, "use `!_.any()` instead", format!( - "!{}.any({})", - iter, + "!{iter}.any({})", any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str) ), applicability, @@ -119,7 +115,7 @@ pub(super) fn check<'tcx>( if is_string_or_str_slice(search_recv); if is_string_or_str_slice(search_arg); then { - let msg = format!("called `{}()` after calling `find()` on a string", option_check_method); + let msg = format!("called `{option_check_method}()` after calling `find()` on a string"); match option_check_method { "is_some" => { let mut applicability = Applicability::MachineApplicable; @@ -130,7 +126,7 @@ pub(super) fn check<'tcx>( method_span.with_hi(expr.span.hi()), &msg, "use `contains()` instead", - format!("contains({})", find_arg), + format!("contains({find_arg})"), applicability, ); }, @@ -144,7 +140,7 @@ pub(super) fn check<'tcx>( expr.span, &msg, "use `!_.contains()` instead", - format!("!{}.contains({})", string, find_arg), + format!("!{string}.contains({find_arg})"), applicability, ); }, diff --git a/clippy_lints/src/methods/single_char_insert_string.rs b/clippy_lints/src/methods/single_char_insert_string.rs index 18b6b5be175d1..44a7ad394fa0c 100644 --- a/clippy_lints/src/methods/single_char_insert_string.rs +++ b/clippy_lints/src/methods/single_char_insert_string.rs @@ -14,7 +14,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir:: let base_string_snippet = snippet_with_applicability(cx, receiver.span.source_callsite(), "_", &mut applicability); let pos_arg = snippet_with_applicability(cx, args[0].span, "..", &mut applicability); - let sugg = format!("{}.insert({}, {})", base_string_snippet, pos_arg, extension_string); + let sugg = format!("{base_string_snippet}.insert({pos_arg}, {extension_string})"); span_lint_and_sugg( cx, SINGLE_CHAR_ADD_STR, diff --git a/clippy_lints/src/methods/single_char_push_string.rs b/clippy_lints/src/methods/single_char_push_string.rs index 9ea6751956abb..0698bd6a0c523 100644 --- a/clippy_lints/src/methods/single_char_push_string.rs +++ b/clippy_lints/src/methods/single_char_push_string.rs @@ -13,7 +13,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir:: if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[0], &mut applicability) { let base_string_snippet = snippet_with_applicability(cx, receiver.span.source_callsite(), "..", &mut applicability); - let sugg = format!("{}.push({})", base_string_snippet, extension_string); + let sugg = format!("{base_string_snippet}.push({extension_string})"); span_lint_and_sugg( cx, SINGLE_CHAR_ADD_STR, diff --git a/clippy_lints/src/methods/stable_sort_primitive.rs b/clippy_lints/src/methods/stable_sort_primitive.rs index 91951c65bb309..09c8ca4cbe44c 100644 --- a/clippy_lints/src/methods/stable_sort_primitive.rs +++ b/clippy_lints/src/methods/stable_sort_primitive.rs @@ -17,11 +17,11 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, recv: &'tcx cx, STABLE_SORT_PRIMITIVE, e.span, - &format!("used `sort` on primitive type `{}`", slice_type), + &format!("used `sort` on primitive type `{slice_type}`"), |diag| { let mut app = Applicability::MachineApplicable; let recv_snip = snippet_with_context(cx, recv.span, e.span.ctxt(), "..", &mut app).0; - diag.span_suggestion(e.span, "try", format!("{}.sort_unstable()", recv_snip), app); + diag.span_suggestion(e.span, "try", format!("{recv_snip}.sort_unstable()"), app); diag.note( "an unstable sort typically performs faster without any observable difference for this data type", ); diff --git a/clippy_lints/src/methods/string_extend_chars.rs b/clippy_lints/src/methods/string_extend_chars.rs index 143dcee350521..6974260f70dbd 100644 --- a/clippy_lints/src/methods/string_extend_chars.rs +++ b/clippy_lints/src/methods/string_extend_chars.rs @@ -34,9 +34,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr "calling `.extend(_.chars())`", "try this", format!( - "{}.push_str({}{})", + "{}.push_str({ref_str}{})", snippet_with_applicability(cx, recv.span, "..", &mut applicability), - ref_str, snippet_with_applicability(cx, target.span, "..", &mut applicability) ), applicability, diff --git a/clippy_lints/src/methods/suspicious_splitn.rs b/clippy_lints/src/methods/suspicious_splitn.rs index 55567d8625e52..219a9edd65768 100644 --- a/clippy_lints/src/methods/suspicious_splitn.rs +++ b/clippy_lints/src/methods/suspicious_splitn.rs @@ -24,10 +24,10 @@ pub(super) fn check(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, se } let (msg, note_msg) = if count == 0 { - (format!("`{}` called with `0` splits", method_name), + (format!("`{method_name}` called with `0` splits"), "the resulting iterator will always return `None`") } else { - (format!("`{}` called with `1` split", method_name), + (format!("`{method_name}` called with `1` split"), if self_ty.is_slice() { "the resulting iterator will always return the entire slice followed by `None`" } else { diff --git a/clippy_lints/src/methods/suspicious_to_owned.rs b/clippy_lints/src/methods/suspicious_to_owned.rs index 6b306fbf00855..15c1c618c5137 100644 --- a/clippy_lints/src/methods/suspicious_to_owned.rs +++ b/clippy_lints/src/methods/suspicious_to_owned.rs @@ -24,9 +24,9 @@ pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) - cx, SUSPICIOUS_TO_OWNED, expr.span, - &format!("this `to_owned` call clones the {0} itself and does not cause the {0} contents to become owned", input_type), + &format!("this `to_owned` call clones the {input_type} itself and does not cause the {input_type} contents to become owned"), "consider using, depending on intent", - format!("{0}.clone()` or `{0}.into_owned()", recv_snip), + format!("{recv_snip}.clone()` or `{recv_snip}.into_owned()"), app, ); return true; diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs index 4e8c201f470ba..ee16982d52487 100644 --- a/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -54,7 +54,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr< UNNECESSARY_FIND_MAP }, expr.span, - &format!("this `.{}` can be written more simply using `.{}`", name, sugg), + &format!("this `.{name}` can be written more simply using `.{sugg}`"), ); } } diff --git a/clippy_lints/src/methods/unnecessary_fold.rs b/clippy_lints/src/methods/unnecessary_fold.rs index c17ef6809f912..aa87dead38f01 100644 --- a/clippy_lints/src/methods/unnecessary_fold.rs +++ b/clippy_lints/src/methods/unnecessary_fold.rs @@ -49,15 +49,12 @@ pub(super) fn check( let mut applicability = Applicability::MachineApplicable; let sugg = if replacement_has_args { format!( - "{replacement}(|{s}| {r})", - replacement = replacement_method_name, - s = second_arg_ident, + "{replacement_method_name}(|{second_arg_ident}| {r})", r = snippet_with_applicability(cx, right_expr.span, "EXPR", &mut applicability), ) } else { format!( - "{replacement}()", - replacement = replacement_method_name, + "{replacement_method_name}()", ) }; diff --git a/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/clippy_lints/src/methods/unnecessary_iter_cloned.rs index 95138c0e25b03..1966a85f7a735 100644 --- a/clippy_lints/src/methods/unnecessary_iter_cloned.rs +++ b/clippy_lints/src/methods/unnecessary_iter_cloned.rs @@ -68,7 +68,7 @@ pub fn check_for_loop_iter( cx, UNNECESSARY_TO_OWNED, expr.span, - &format!("unnecessary use of `{}`", method_name), + &format!("unnecessary use of `{method_name}`"), |diag| { // If `check_into_iter_call_arg` called `check_for_loop_iter` because a call to // a `to_owned`-like function was removed, then the next suggestion may be diff --git a/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/clippy_lints/src/methods/unnecessary_lazy_eval.rs index a187a8d6016f8..ec9859fa298b6 100644 --- a/clippy_lints/src/methods/unnecessary_lazy_eval.rs +++ b/clippy_lints/src/methods/unnecessary_lazy_eval.rs @@ -58,8 +58,8 @@ pub(super) fn check<'tcx>( span_lint_and_then(cx, UNNECESSARY_LAZY_EVALUATIONS, expr.span, msg, |diag| { diag.span_suggestion( span, - &format!("use `{}(..)` instead", simplify_using), - format!("{}({})", simplify_using, snippet(cx, body_expr.span, "..")), + &format!("use `{simplify_using}(..)` instead"), + format!("{simplify_using}({})", snippet(cx, body_expr.span, "..")), applicability, ); }); diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index 8e9ed33e00991..d27831327acf8 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -133,12 +133,11 @@ fn check_addr_of_expr( cx, UNNECESSARY_TO_OWNED, parent.span, - &format!("unnecessary use of `{}`", method_name), + &format!("unnecessary use of `{method_name}`"), "use", format!( - "{:&>width$}{}", + "{:&>width$}{receiver_snippet}", "", - receiver_snippet, width = n_target_refs - n_receiver_refs ), Applicability::MachineApplicable, @@ -155,7 +154,7 @@ fn check_addr_of_expr( cx, UNNECESSARY_TO_OWNED, parent.span, - &format!("unnecessary use of `{}`", method_name), + &format!("unnecessary use of `{method_name}`"), "use", receiver_snippet, Applicability::MachineApplicable, @@ -165,7 +164,7 @@ fn check_addr_of_expr( cx, UNNECESSARY_TO_OWNED, expr.span.with_lo(receiver.span.hi()), - &format!("unnecessary use of `{}`", method_name), + &format!("unnecessary use of `{method_name}`"), "remove this", String::new(), Applicability::MachineApplicable, @@ -182,9 +181,9 @@ fn check_addr_of_expr( cx, UNNECESSARY_TO_OWNED, parent.span, - &format!("unnecessary use of `{}`", method_name), + &format!("unnecessary use of `{method_name}`"), "use", - format!("{}.as_ref()", receiver_snippet), + format!("{receiver_snippet}.as_ref()"), Applicability::MachineApplicable, ); return true; @@ -229,9 +228,9 @@ fn check_into_iter_call_arg( cx, UNNECESSARY_TO_OWNED, parent.span, - &format!("unnecessary use of `{}`", method_name), + &format!("unnecessary use of `{method_name}`"), "use", - format!("{}.iter().{}()", receiver_snippet, cloned_or_copied), + format!("{receiver_snippet}.iter().{cloned_or_copied}()"), Applicability::MaybeIncorrect, ); return true; @@ -276,9 +275,9 @@ fn check_other_call_arg<'tcx>( cx, UNNECESSARY_TO_OWNED, maybe_arg.span, - &format!("unnecessary use of `{}`", method_name), + &format!("unnecessary use of `{method_name}`"), "use", - format!("{:&>width$}{}", "", receiver_snippet, width = n_refs), + format!("{:&>n_refs$}{receiver_snippet}", ""), Applicability::MachineApplicable, ); return true; diff --git a/clippy_lints/src/methods/useless_asref.rs b/clippy_lints/src/methods/useless_asref.rs index ca5d33ee8b07f..0380a82411ae1 100644 --- a/clippy_lints/src/methods/useless_asref.rs +++ b/clippy_lints/src/methods/useless_asref.rs @@ -35,7 +35,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, cx, USELESS_ASREF, expr.span, - &format!("this call to `{}` does nothing", call_name), + &format!("this call to `{call_name}` does nothing"), "try this", snippet_with_applicability(cx, recvr.span, "..", &mut applicability).to_string(), applicability, diff --git a/clippy_lints/src/methods/wrong_self_convention.rs b/clippy_lints/src/methods/wrong_self_convention.rs index 4b368d3ffae25..1fbf783b8860e 100644 --- a/clippy_lints/src/methods/wrong_self_convention.rs +++ b/clippy_lints/src/methods/wrong_self_convention.rs @@ -61,20 +61,20 @@ impl Convention { impl fmt::Display for Convention { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { match *self { - Self::Eq(this) => format!("`{}`", this).fmt(f), - Self::StartsWith(this) => format!("`{}*`", this).fmt(f), - Self::EndsWith(this) => format!("`*{}`", this).fmt(f), - Self::NotEndsWith(this) => format!("`~{}`", this).fmt(f), + Self::Eq(this) => format!("`{this}`").fmt(f), + Self::StartsWith(this) => format!("`{this}*`").fmt(f), + Self::EndsWith(this) => format!("`*{this}`").fmt(f), + Self::NotEndsWith(this) => format!("`~{this}`").fmt(f), Self::IsSelfTypeCopy(is_true) => { format!("`self` type is{} `Copy`", if is_true { "" } else { " not" }).fmt(f) }, Self::ImplementsTrait(is_true) => { let (negation, s_suffix) = if is_true { ("", "s") } else { (" does not", "") }; - format!("method{} implement{} a trait", negation, s_suffix).fmt(f) + format!("method{negation} implement{s_suffix} a trait").fmt(f) }, Self::IsTraitItem(is_true) => { let suffix = if is_true { " is" } else { " is not" }; - format!("method{} a trait item", suffix).fmt(f) + format!("method{suffix} a trait item").fmt(f) }, } } @@ -138,8 +138,7 @@ pub(super) fn check<'tcx>( WRONG_SELF_CONVENTION, first_arg_span, &format!( - "{} usually take {}", - suggestion, + "{suggestion} usually take {}", &self_kinds .iter() .map(|k| k.description()) diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index ea245edd77040..381458b91e679 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -178,7 +178,7 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints { ("", sugg_init.addr()) }; let tyopt = if let Some(ty) = local.ty { - format!(": &{mutopt}{ty}", mutopt=mutopt, ty=snippet(cx, ty.span, "..")) + format!(": &{mutopt}{ty}", ty=snippet(cx, ty.span, "..")) } else { String::new() }; @@ -195,8 +195,6 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints { format!( "let {name}{tyopt} = {initref};", name=snippet(cx, name.span, ".."), - tyopt=tyopt, - initref=initref, ), Applicability::MachineApplicable, ); @@ -222,8 +220,7 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints { stmt.span, "replace it with", format!( - "if {} {{ {}; }}", - sugg, + "if {sugg} {{ {}; }}", &snippet(cx, b.span, ".."), ), Applicability::MachineApplicable, // snippet @@ -275,9 +272,8 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints { USED_UNDERSCORE_BINDING, expr.span, &format!( - "used binding `{}` which is prefixed with an underscore. A leading \ - underscore signals that a binding will not be used", - binding + "used binding `{binding}` which is prefixed with an underscore. A leading \ + underscore signals that a binding will not be used" ), ); } @@ -328,12 +324,12 @@ fn check_cast(cx: &LateContext<'_>, span: Span, e: &Expr<'_>, ty: &hir::Ty<'_>) }; let (sugg, appl) = if let TyKind::Infer = mut_ty.ty.kind { - (format!("{}()", sugg_fn), Applicability::MachineApplicable) + (format!("{sugg_fn}()"), Applicability::MachineApplicable) } else if let Some(mut_ty_snip) = snippet_opt(cx, mut_ty.ty.span) { - (format!("{}::<{}>()", sugg_fn, mut_ty_snip), Applicability::MachineApplicable) + (format!("{sugg_fn}::<{mut_ty_snip}>()"), Applicability::MachineApplicable) } else { // `MaybeIncorrect` as type inference may not work with the suggested code - (format!("{}()", sugg_fn), Applicability::MaybeIncorrect) + (format!("{sugg_fn}()"), Applicability::MaybeIncorrect) }; span_lint_and_sugg(cx, ZERO_PTR, span, msg, "try", sugg, appl); } diff --git a/clippy_lints/src/misc_early/literal_suffix.rs b/clippy_lints/src/misc_early/literal_suffix.rs index 1165c19a0cf0b..62c6ca32d31a9 100644 --- a/clippy_lints/src/misc_early/literal_suffix.rs +++ b/clippy_lints/src/misc_early/literal_suffix.rs @@ -18,9 +18,9 @@ pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, lit_snip: &str, suffix: &s cx, SEPARATED_LITERAL_SUFFIX, lit.span, - &format!("{} type suffix should not be separated by an underscore", sugg_type), + &format!("{sugg_type} type suffix should not be separated by an underscore"), "remove the underscore", - format!("{}{}", &lit_snip[..maybe_last_sep_idx], suffix), + format!("{}{suffix}", &lit_snip[..maybe_last_sep_idx]), Applicability::MachineApplicable, ); } else { @@ -28,9 +28,9 @@ pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, lit_snip: &str, suffix: &s cx, UNSEPARATED_LITERAL_SUFFIX, lit.span, - &format!("{} type suffix should be separated by an underscore", sugg_type), + &format!("{sugg_type} type suffix should be separated by an underscore"), "add an underscore", - format!("{}_{}", &lit_snip[..=maybe_last_sep_idx], suffix), + format!("{}_{suffix}", &lit_snip[..=maybe_last_sep_idx]), Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/misc_early/mod.rs b/clippy_lints/src/misc_early/mod.rs index 704918c0b979b..c8227ca445057 100644 --- a/clippy_lints/src/misc_early/mod.rs +++ b/clippy_lints/src/misc_early/mod.rs @@ -357,9 +357,8 @@ impl EarlyLintPass for MiscEarlyLints { DUPLICATE_UNDERSCORE_ARGUMENT, *correspondence, &format!( - "`{}` already exists, having another argument having almost the same \ - name makes code comprehension and documentation more difficult", - arg_name + "`{arg_name}` already exists, having another argument having almost the same \ + name makes code comprehension and documentation more difficult" ), ); } diff --git a/clippy_lints/src/misc_early/unneeded_field_pattern.rs b/clippy_lints/src/misc_early/unneeded_field_pattern.rs index fff533167ede2..676e5d40bb776 100644 --- a/clippy_lints/src/misc_early/unneeded_field_pattern.rs +++ b/clippy_lints/src/misc_early/unneeded_field_pattern.rs @@ -27,7 +27,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) { pat.span, "all the struct fields are matched to a wildcard pattern, consider using `..`", None, - &format!("try with `{} {{ .. }}` instead", type_name), + &format!("try with `{type_name} {{ .. }}` instead"), ); return; } @@ -63,7 +63,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) { "you matched a field with a wildcard pattern, consider using `..` \ instead", None, - &format!("try with `{} {{ {}, .. }}`", type_name, normal[..].join(", ")), + &format!("try with `{type_name} {{ {}, .. }}`", normal[..].join(", ")), ); } } diff --git a/clippy_lints/src/mismatching_type_param_order.rs b/clippy_lints/src/mismatching_type_param_order.rs index 020efeaebf029..6dd76a6531e49 100644 --- a/clippy_lints/src/mismatching_type_param_order.rs +++ b/clippy_lints/src/mismatching_type_param_order.rs @@ -91,10 +91,9 @@ impl<'tcx> LateLintPass<'tcx> for TypeParamMismatch { let type_name = segment.ident; for (i, (impl_param_name, impl_param_span)) in impl_params.iter().enumerate() { if mismatch_param_name(i, impl_param_name, &type_param_names_hashmap) { - let msg = format!("`{}` has a similarly named generic type parameter `{}` in its declaration, but in a different order", - type_name, impl_param_name); - let help = format!("try `{}`, or a name that does not conflict with `{}`'s generic params", - type_param_names[i], type_name); + let msg = format!("`{type_name}` has a similarly named generic type parameter `{impl_param_name}` in its declaration, but in a different order"); + let help = format!("try `{}`, or a name that does not conflict with `{type_name}`'s generic params", + type_param_names[i]); span_lint_and_help( cx, MISMATCHING_TYPE_PARAM_ORDER, diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index ee81f72a0e708..97c8fb17638ca 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -104,7 +104,7 @@ impl MissingDoc { cx, MISSING_DOCS_IN_PRIVATE_ITEMS, sp, - &format!("missing documentation for {} {}", article, desc), + &format!("missing documentation for {article} {desc}"), ); } } diff --git a/clippy_lints/src/missing_enforced_import_rename.rs b/clippy_lints/src/missing_enforced_import_rename.rs index 3d0a23822838e..697e6fd24dd11 100644 --- a/clippy_lints/src/missing_enforced_import_rename.rs +++ b/clippy_lints/src/missing_enforced_import_rename.rs @@ -90,9 +90,7 @@ impl LateLintPass<'_> for ImportRename { "this import should be renamed", "try", format!( - "{} as {}", - import, - name, + "{import} as {name}", ), Applicability::MachineApplicable, ); diff --git a/clippy_lints/src/missing_inline.rs b/clippy_lints/src/missing_inline.rs index 07bc2ca5d3cd2..18c4512009104 100644 --- a/clippy_lints/src/missing_inline.rs +++ b/clippy_lints/src/missing_inline.rs @@ -65,7 +65,7 @@ fn check_missing_inline_attrs(cx: &LateContext<'_>, attrs: &[ast::Attribute], sp cx, MISSING_INLINE_IN_PUBLIC_ITEMS, sp, - &format!("missing `#[inline]` for {}", desc), + &format!("missing `#[inline]` for {desc}"), ); } } diff --git a/clippy_lints/src/mut_reference.rs b/clippy_lints/src/mut_reference.rs index 82dc03ef5c5bc..463da11774a04 100644 --- a/clippy_lints/src/mut_reference.rs +++ b/clippy_lints/src/mut_reference.rs @@ -88,7 +88,7 @@ fn check_arguments<'tcx>( cx, UNNECESSARY_MUT_PASSED, argument.span, - &format!("the {} `{}` doesn't need a mutable reference", fn_kind, name), + &format!("the {fn_kind} `{name}` doesn't need a mutable reference"), ); } }, diff --git a/clippy_lints/src/mutable_debug_assertion.rs b/clippy_lints/src/mutable_debug_assertion.rs index 321db08dfe89a..3ef0c66345984 100644 --- a/clippy_lints/src/mutable_debug_assertion.rs +++ b/clippy_lints/src/mutable_debug_assertion.rs @@ -56,10 +56,7 @@ impl<'tcx> LateLintPass<'tcx> for DebugAssertWithMutCall { cx, DEBUG_ASSERT_WITH_MUT_CALL, span, - &format!( - "do not call a function with mutable arguments inside of `{}!`", - macro_name - ), + &format!("do not call a function with mutable arguments inside of `{macro_name}!`"), ); } } diff --git a/clippy_lints/src/mutex_atomic.rs b/clippy_lints/src/mutex_atomic.rs index a98577093ed5e..09cb53331763d 100644 --- a/clippy_lints/src/mutex_atomic.rs +++ b/clippy_lints/src/mutex_atomic.rs @@ -84,9 +84,8 @@ impl<'tcx> LateLintPass<'tcx> for Mutex { let mutex_param = subst.type_at(0); if let Some(atomic_name) = get_atomic_name(mutex_param) { let msg = format!( - "consider using an `{}` instead of a `Mutex` here; if you just want the locking \ - behavior and not the internal type, consider using `Mutex<()>`", - atomic_name + "consider using an `{atomic_name}` instead of a `Mutex` here; if you just want the locking \ + behavior and not the internal type, consider using `Mutex<()>`" ); match *mutex_param.kind() { ty::Uint(t) if t != ty::UintTy::Usize => span_lint(cx, MUTEX_INTEGER, expr.span, &msg), diff --git a/clippy_lints/src/needless_continue.rs b/clippy_lints/src/needless_continue.rs index 98a3bce1ff38a..6f0e755466e5a 100644 --- a/clippy_lints/src/needless_continue.rs +++ b/clippy_lints/src/needless_continue.rs @@ -309,7 +309,7 @@ fn emit_warning<'a>(cx: &EarlyContext<'_>, data: &'a LintData<'_>, header: &str, expr.span, message, None, - &format!("{}\n{}", header, snip), + &format!("{header}\n{snip}"), ); } @@ -322,10 +322,7 @@ fn suggestion_snippet_for_continue_inside_if<'a>(cx: &EarlyContext<'_>, data: &' let indent_if = indent_of(cx, data.if_expr.span).unwrap_or(0); format!( - "{indent}if {} {}\n{indent}{}", - cond_code, - continue_code, - else_code, + "{indent}if {cond_code} {continue_code}\n{indent}{else_code}", indent = " ".repeat(indent_if), ) } @@ -349,7 +346,7 @@ fn suggestion_snippet_for_continue_inside_else<'a>(cx: &EarlyContext<'_>, data: let span = cx.sess().source_map().stmt_span(stmt.span, data.loop_block.span); let snip = snippet_block(cx, span, "..", None).into_owned(); snip.lines() - .map(|line| format!("{}{}", " ".repeat(indent), line)) + .map(|line| format!("{}{line}", " ".repeat(indent))) .collect::>() .join("\n") }) @@ -358,10 +355,7 @@ fn suggestion_snippet_for_continue_inside_else<'a>(cx: &EarlyContext<'_>, data: let indent_if = indent_of(cx, data.if_expr.span).unwrap_or(0); format!( - "{indent_if}if {} {}\n{indent}// merged code follows:\n{}\n{indent_if}}}", - cond_code, - block_code, - to_annex, + "{indent_if}if {cond_code} {block_code}\n{indent}// merged code follows:\n{to_annex}\n{indent_if}}}", indent = " ".repeat(indent), indent_if = " ".repeat(indent_if), ) diff --git a/clippy_lints/src/needless_late_init.rs b/clippy_lints/src/needless_late_init.rs index de99f1d7078e9..cbad53f4450b2 100644 --- a/clippy_lints/src/needless_late_init.rs +++ b/clippy_lints/src/needless_late_init.rs @@ -287,7 +287,7 @@ fn check<'tcx>( diag.span_suggestion( assign.lhs_span, - &format!("declare `{}` here", binding_name), + &format!("declare `{binding_name}` here"), let_snippet, Applicability::MachineApplicable, ); @@ -307,8 +307,8 @@ fn check<'tcx>( diag.span_suggestion_verbose( usage.stmt.span.shrink_to_lo(), - &format!("declare `{}` here", binding_name), - format!("{} = ", let_snippet), + &format!("declare `{binding_name}` here"), + format!("{let_snippet} = "), applicability, ); @@ -338,8 +338,8 @@ fn check<'tcx>( diag.span_suggestion_verbose( usage.stmt.span.shrink_to_lo(), - &format!("declare `{}` here", binding_name), - format!("{} = ", let_snippet), + &format!("declare `{binding_name}` here"), + format!("{let_snippet} = "), applicability, ); diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 6d17c7a7346f3..d7e6e7de2cc10 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -236,7 +236,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { snippet_opt(cx, span) .map_or( "change the call to".into(), - |x| Cow::from(format!("change `{}` to", x)), + |x| Cow::from(format!("change `{x}` to")), ) .as_ref(), suggestion, @@ -266,7 +266,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { snippet_opt(cx, span) .map_or( "change the call to".into(), - |x| Cow::from(format!("change `{}` to", x)) + |x| Cow::from(format!("change `{x}` to")) ) .as_ref(), suggestion, diff --git a/clippy_lints/src/needless_question_mark.rs b/clippy_lints/src/needless_question_mark.rs index 8f85b00596c01..59b6492e112c0 100644 --- a/clippy_lints/src/needless_question_mark.rs +++ b/clippy_lints/src/needless_question_mark.rs @@ -134,7 +134,7 @@ fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { NEEDLESS_QUESTION_MARK, expr.span, "question mark operator is useless here", - &format!("try removing question mark and `{}`", sugg_remove), + &format!("try removing question mark and `{sugg_remove}`"), format!("{}", snippet(cx, inner_expr.span, r#""...""#)), Applicability::MachineApplicable, ); diff --git a/clippy_lints/src/neg_multiply.rs b/clippy_lints/src/neg_multiply.rs index b087cfb36b116..fb9a4abd0b4b0 100644 --- a/clippy_lints/src/neg_multiply.rs +++ b/clippy_lints/src/neg_multiply.rs @@ -62,9 +62,9 @@ fn check_mul(cx: &LateContext<'_>, span: Span, lit: &Expr<'_>, exp: &Expr<'_>) { let mut applicability = Applicability::MachineApplicable; let snip = snippet_with_applicability(cx, exp.span, "..", &mut applicability); let suggestion = if exp.precedence().order() < PREC_PREFIX && !has_enclosing_paren(&snip) { - format!("-({})", snip) + format!("-({snip})") } else { - format!("-{}", snip) + format!("-{snip}") }; span_lint_and_sugg( cx, diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index 5c45ee6d94ad3..cfd24e9b2d385 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -136,8 +136,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { id, impl_item.span, &format!( - "you should consider adding a `Default` implementation for `{}`", - self_type_snip + "you should consider adding a `Default` implementation for `{self_type_snip}`" ), |diag| { diag.suggest_prepend_item( @@ -161,9 +160,9 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { fn create_new_without_default_suggest_msg(self_type_snip: &str, generics_sugg: &str) -> String { #[rustfmt::skip] format!( -"impl{} Default for {} {{ +"impl{generics_sugg} Default for {self_type_snip} {{ fn default() -> Self {{ Self::new() }} -}}", generics_sugg, self_type_snip) +}}") } diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index b96af06b8d7c6..03fddd207ecb9 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -108,10 +108,7 @@ impl<'a, 'tcx> SimilarNamesLocalVisitor<'a, 'tcx> { self.cx, MANY_SINGLE_CHAR_NAMES, span, - &format!( - "{} bindings with single-character names in scope", - num_single_char_names - ), + &format!("{num_single_char_names} bindings with single-character names in scope"), ); } } diff --git a/clippy_lints/src/nonstandard_macro_braces.rs b/clippy_lints/src/nonstandard_macro_braces.rs index 5e38a95c40b3d..0ca0befc13515 100644 --- a/clippy_lints/src/nonstandard_macro_braces.rs +++ b/clippy_lints/src/nonstandard_macro_braces.rs @@ -107,11 +107,11 @@ fn is_offending_macro<'a>(cx: &EarlyContext<'_>, span: Span, mac_braces: &'a Mac if let Some(snip) = snippet_opt(cx, span_call_site); // we must check only invocation sites // https://github.com/rust-lang/rust-clippy/issues/7422 - if snip.starts_with(&format!("{}!", name)); + if snip.starts_with(&format!("{name}!")); if unnested_or_local(); // make formatting consistent let c = snip.replace(' ', ""); - if !c.starts_with(&format!("{}!{}", name, braces.0)); + if !c.starts_with(&format!("{name}!{}", braces.0)); if !mac_braces.done.contains(&span_call_site); then { Some((span_call_site, braces, snip)) @@ -131,9 +131,9 @@ fn emit_help(cx: &EarlyContext<'_>, snip: &str, braces: &(String, String), span: cx, NONSTANDARD_MACRO_BRACES, span, - &format!("use of irregular braces for `{}!` macro", macro_name), + &format!("use of irregular braces for `{macro_name}!` macro"), "consider writing", - format!("{}!{}{}{}", macro_name, braces.0, macro_args, braces.1), + format!("{macro_name}!{}{macro_args}{}", braces.0, braces.1), Applicability::MachineApplicable, ); } @@ -266,9 +266,7 @@ impl<'de> Deserialize<'de> for MacroMatcher { .iter() .find(|b| b.0 == brace) .map(|(o, c)| ((*o).to_owned(), (*c).to_owned())) - .ok_or_else(|| { - de::Error::custom(&format!("expected one of `(`, `{{`, `[` found `{}`", brace)) - })?, + .ok_or_else(|| de::Error::custom(&format!("expected one of `(`, `{{`, `[` found `{brace}`")))?, }) } } diff --git a/clippy_lints/src/octal_escapes.rs b/clippy_lints/src/octal_escapes.rs index bffbf20b4d289..f380a5065827d 100644 --- a/clippy_lints/src/octal_escapes.rs +++ b/clippy_lints/src/octal_escapes.rs @@ -102,7 +102,7 @@ fn check_lit(cx: &EarlyContext<'_>, lit: &Lit, span: Span, is_string: bool) { // construct a replacement escape // the maximum value is \077, or \x3f, so u8 is sufficient here if let Ok(n) = u8::from_str_radix(&contents[from + 1..to], 8) { - write!(suggest_1, "\\x{:02x}", n).unwrap(); + write!(suggest_1, "\\x{n:02x}").unwrap(); } // append the null byte as \x00 and the following digits literally diff --git a/clippy_lints/src/operators/absurd_extreme_comparisons.rs b/clippy_lints/src/operators/absurd_extreme_comparisons.rs index 1ec4240afefe5..d29ca37eaeb80 100644 --- a/clippy_lints/src/operators/absurd_extreme_comparisons.rs +++ b/clippy_lints/src/operators/absurd_extreme_comparisons.rs @@ -34,13 +34,12 @@ pub(super) fn check<'tcx>( }; let help = format!( - "because `{}` is the {} value for this type, {}", + "because `{}` is the {} value for this type, {conclusion}", snippet(cx, culprit.expr.span, "x"), match culprit.which { ExtremeType::Minimum => "minimum", ExtremeType::Maximum => "maximum", - }, - conclusion + } ); span_lint_and_help(cx, ABSURD_EXTREME_COMPARISONS, expr.span, msg, None, &help); diff --git a/clippy_lints/src/operators/assign_op_pattern.rs b/clippy_lints/src/operators/assign_op_pattern.rs index 945a09a647c41..cb5abfb809e23 100644 --- a/clippy_lints/src/operators/assign_op_pattern.rs +++ b/clippy_lints/src/operators/assign_op_pattern.rs @@ -55,7 +55,7 @@ pub(super) fn check<'tcx>( diag.span_suggestion( expr.span, "replace it with", - format!("{} {}= {}", snip_a, op.node.as_str(), snip_r), + format!("{snip_a} {}= {snip_r}", op.node.as_str()), Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/operators/bit_mask.rs b/clippy_lints/src/operators/bit_mask.rs index 74387fbc87be0..1369b3e74625c 100644 --- a/clippy_lints/src/operators/bit_mask.rs +++ b/clippy_lints/src/operators/bit_mask.rs @@ -64,10 +64,7 @@ fn check_bit_mask( cx, BAD_BIT_MASK, span, - &format!( - "incompatible bit mask: `_ & {}` can never be equal to `{}`", - mask_value, cmp_value - ), + &format!("incompatible bit mask: `_ & {mask_value}` can never be equal to `{cmp_value}`"), ); } } else if mask_value == 0 { @@ -80,10 +77,7 @@ fn check_bit_mask( cx, BAD_BIT_MASK, span, - &format!( - "incompatible bit mask: `_ | {}` can never be equal to `{}`", - mask_value, cmp_value - ), + &format!("incompatible bit mask: `_ | {mask_value}` can never be equal to `{cmp_value}`"), ); } }, @@ -96,10 +90,7 @@ fn check_bit_mask( cx, BAD_BIT_MASK, span, - &format!( - "incompatible bit mask: `_ & {}` will always be lower than `{}`", - mask_value, cmp_value - ), + &format!("incompatible bit mask: `_ & {mask_value}` will always be lower than `{cmp_value}`"), ); } else if mask_value == 0 { span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero"); @@ -111,10 +102,7 @@ fn check_bit_mask( cx, BAD_BIT_MASK, span, - &format!( - "incompatible bit mask: `_ | {}` will never be lower than `{}`", - mask_value, cmp_value - ), + &format!("incompatible bit mask: `_ | {mask_value}` will never be lower than `{cmp_value}`"), ); } else { check_ineffective_lt(cx, span, mask_value, cmp_value, "|"); @@ -130,10 +118,7 @@ fn check_bit_mask( cx, BAD_BIT_MASK, span, - &format!( - "incompatible bit mask: `_ & {}` will never be higher than `{}`", - mask_value, cmp_value - ), + &format!("incompatible bit mask: `_ & {mask_value}` will never be higher than `{cmp_value}`"), ); } else if mask_value == 0 { span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero"); @@ -145,10 +130,7 @@ fn check_bit_mask( cx, BAD_BIT_MASK, span, - &format!( - "incompatible bit mask: `_ | {}` will always be higher than `{}`", - mask_value, cmp_value - ), + &format!("incompatible bit mask: `_ | {mask_value}` will always be higher than `{cmp_value}`"), ); } else { check_ineffective_gt(cx, span, mask_value, cmp_value, "|"); @@ -167,10 +149,7 @@ fn check_ineffective_lt(cx: &LateContext<'_>, span: Span, m: u128, c: u128, op: cx, INEFFECTIVE_BIT_MASK, span, - &format!( - "ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly", - op, m, c - ), + &format!("ineffective bit mask: `x {op} {m}` compared to `{c}`, is the same as x compared directly"), ); } } @@ -181,10 +160,7 @@ fn check_ineffective_gt(cx: &LateContext<'_>, span: Span, m: u128, c: u128, op: cx, INEFFECTIVE_BIT_MASK, span, - &format!( - "ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly", - op, m, c - ), + &format!("ineffective bit mask: `x {op} {m}` compared to `{c}`, is the same as x compared directly"), ); } } diff --git a/clippy_lints/src/operators/cmp_owned.rs b/clippy_lints/src/operators/cmp_owned.rs index 638a514ff9b36..c9c777f1bd8d8 100644 --- a/clippy_lints/src/operators/cmp_owned.rs +++ b/clippy_lints/src/operators/cmp_owned.rs @@ -99,7 +99,7 @@ fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) let expr_snip; let eq_impl; if with_deref.is_implemented() { - expr_snip = format!("*{}", arg_snip); + expr_snip = format!("*{arg_snip}"); eq_impl = with_deref; } else { expr_snip = arg_snip.to_string(); @@ -121,17 +121,15 @@ fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) }; if eq_impl.ty_eq_other { hint = format!( - "{}{}{}", - expr_snip, + "{expr_snip}{}{}", snippet(cx, cmp_span, ".."), snippet(cx, other.span, "..") ); } else { hint = format!( - "{}{}{}", + "{}{}{expr_snip}", snippet(cx, other.span, ".."), - snippet(cx, cmp_span, ".."), - expr_snip + snippet(cx, cmp_span, "..") ); } } diff --git a/clippy_lints/src/operators/duration_subsec.rs b/clippy_lints/src/operators/duration_subsec.rs index 827a2b2670935..49e662cacb0c3 100644 --- a/clippy_lints/src/operators/duration_subsec.rs +++ b/clippy_lints/src/operators/duration_subsec.rs @@ -31,12 +31,11 @@ pub(crate) fn check<'tcx>( cx, DURATION_SUBSEC, expr.span, - &format!("calling `{}()` is more concise than this calculation", suggested_fn), + &format!("calling `{suggested_fn}()` is more concise than this calculation"), "try", format!( - "{}.{}()", - snippet_with_applicability(cx, self_arg.span, "_", &mut applicability), - suggested_fn + "{}.{suggested_fn}()", + snippet_with_applicability(cx, self_arg.span, "_", &mut applicability) ), applicability, ); diff --git a/clippy_lints/src/operators/eq_op.rs b/clippy_lints/src/operators/eq_op.rs index 44cf0bb06120a..67913f7392c04 100644 --- a/clippy_lints/src/operators/eq_op.rs +++ b/clippy_lints/src/operators/eq_op.rs @@ -22,7 +22,7 @@ pub(crate) fn check_assert<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { cx, EQ_OP, lhs.span.to(rhs.span), - &format!("identical args used in this `{}!` macro call", macro_name), + &format!("identical args used in this `{macro_name}!` macro call"), ); } } diff --git a/clippy_lints/src/operators/misrefactored_assign_op.rs b/clippy_lints/src/operators/misrefactored_assign_op.rs index 0024384d9278d..ae805147f07a2 100644 --- a/clippy_lints/src/operators/misrefactored_assign_op.rs +++ b/clippy_lints/src/operators/misrefactored_assign_op.rs @@ -47,18 +47,14 @@ fn lint_misrefactored_assign_op( if let (Some(snip_a), Some(snip_r)) = (snippet_opt(cx, assignee.span), snippet_opt(cx, rhs_other.span)) { let a = &sugg::Sugg::hir(cx, assignee, ".."); let r = &sugg::Sugg::hir(cx, rhs, ".."); - let long = format!("{} = {}", snip_a, sugg::make_binop(op.into(), a, r)); + let long = format!("{snip_a} = {}", sugg::make_binop(op.into(), a, r)); diag.span_suggestion( expr.span, &format!( - "did you mean `{} = {} {} {}` or `{}`? Consider replacing it with", - snip_a, - snip_a, - op.as_str(), - snip_r, - long + "did you mean `{snip_a} = {snip_a} {} {snip_r}` or `{long}`? Consider replacing it with", + op.as_str() ), - format!("{} {}= {}", snip_a, op.as_str(), snip_r), + format!("{snip_a} {}= {snip_r}", op.as_str()), Applicability::MaybeIncorrect, ); diag.span_suggestion( diff --git a/clippy_lints/src/operators/needless_bitwise_bool.rs b/clippy_lints/src/operators/needless_bitwise_bool.rs index e902235a014e8..ab5fb1787004e 100644 --- a/clippy_lints/src/operators/needless_bitwise_bool.rs +++ b/clippy_lints/src/operators/needless_bitwise_bool.rs @@ -27,7 +27,7 @@ pub(super) fn check(cx: &LateContext<'_>, e: &Expr<'_>, op: BinOpKind, lhs: &Exp if let Some(lhs_snip) = snippet_opt(cx, lhs.span) && let Some(rhs_snip) = snippet_opt(cx, rhs.span) { - let sugg = format!("{} {} {}", lhs_snip, op_str, rhs_snip); + let sugg = format!("{lhs_snip} {op_str} {rhs_snip}"); diag.span_suggestion(e.span, "try", sugg, Applicability::MachineApplicable); } }, diff --git a/clippy_lints/src/operators/ptr_eq.rs b/clippy_lints/src/operators/ptr_eq.rs index 1aefc2741c21c..1229c202f5a09 100644 --- a/clippy_lints/src/operators/ptr_eq.rs +++ b/clippy_lints/src/operators/ptr_eq.rs @@ -34,7 +34,7 @@ pub(super) fn check<'tcx>( expr.span, LINT_MSG, "try", - format!("std::ptr::eq({}, {})", left_snip, right_snip), + format!("std::ptr::eq({left_snip}, {right_snip})"), Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/operators/self_assignment.rs b/clippy_lints/src/operators/self_assignment.rs index 9d6bec05bf095..7c9d5320a3a8b 100644 --- a/clippy_lints/src/operators/self_assignment.rs +++ b/clippy_lints/src/operators/self_assignment.rs @@ -14,7 +14,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, lhs: &'tcx cx, SELF_ASSIGNMENT, e.span, - &format!("self-assignment of `{}` to `{}`", rhs, lhs), + &format!("self-assignment of `{rhs}` to `{lhs}`"), ); } } diff --git a/clippy_lints/src/operators/verbose_bit_mask.rs b/clippy_lints/src/operators/verbose_bit_mask.rs index ff85fd5542988..fbf65e92b322a 100644 --- a/clippy_lints/src/operators/verbose_bit_mask.rs +++ b/clippy_lints/src/operators/verbose_bit_mask.rs @@ -35,7 +35,7 @@ pub(super) fn check<'tcx>( diag.span_suggestion( e.span, "try", - format!("{}.trailing_zeros() >= {}", sugg, n.count_ones()), + format!("{sugg}.trailing_zeros() >= {}", n.count_ones()), Applicability::MaybeIncorrect, ); }, diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index 0315678bf97a9..256d24500011f 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -163,7 +163,7 @@ fn try_get_option_occurence<'tcx>( return Some(OptionOccurence { option: format_option_in_sugg(cx, cond_expr, as_ref, as_mut), method_sugg: method_sugg.to_string(), - some_expr: format!("|{}{}| {}", capture_mut, capture_name, Sugg::hir_with_macro_callsite(cx, some_body, "..")), + some_expr: format!("|{capture_mut}{capture_name}| {}", Sugg::hir_with_macro_callsite(cx, some_body, "..")), none_expr: format!("{}{}", if method_sugg == "map_or" { "" } else { "|| " }, Sugg::hir_with_macro_callsite(cx, none_body, "..")), }); } diff --git a/clippy_lints/src/pass_by_ref_or_value.rs b/clippy_lints/src/pass_by_ref_or_value.rs index 0960b050c240e..152e0c5ec9aa4 100644 --- a/clippy_lints/src/pass_by_ref_or_value.rs +++ b/clippy_lints/src/pass_by_ref_or_value.rs @@ -209,7 +209,7 @@ impl<'tcx> PassByRefOrValue { cx, TRIVIALLY_COPY_PASS_BY_REF, input.span, - &format!("this argument ({} byte) is passed by reference, but would be more efficient if passed by value (limit: {} byte)", size, self.ref_min_size), + &format!("this argument ({size} byte) is passed by reference, but would be more efficient if passed by value (limit: {} byte)", self.ref_min_size), "consider passing by value instead", value_type, Applicability::Unspecified, @@ -237,7 +237,7 @@ impl<'tcx> PassByRefOrValue { cx, LARGE_TYPES_PASSED_BY_VALUE, input.span, - &format!("this argument ({} byte) is passed by value, but might be more efficient if passed by reference (limit: {} byte)", size, self.value_max_size), + &format!("this argument ({size} byte) is passed by value, but might be more efficient if passed by reference (limit: {} byte)", self.value_max_size), "consider passing by reference instead", format!("&{}", snippet(cx, input.span, "_")), Applicability::MaybeIncorrect, diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 41d1baba64f85..85e0710eb50d8 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -463,7 +463,7 @@ fn check_fn_args<'cx, 'tcx: 'cx>( diag.span_suggestion( hir_ty.span, "change this to", - format!("&{}{}", mutability.prefix_str(), ty_name), + format!("&{}{ty_name}", mutability.prefix_str()), Applicability::Unspecified, ); } diff --git a/clippy_lints/src/ptr_offset_with_cast.rs b/clippy_lints/src/ptr_offset_with_cast.rs index 4dc65da3ea1fd..b0a5d1a675828 100644 --- a/clippy_lints/src/ptr_offset_with_cast.rs +++ b/clippy_lints/src/ptr_offset_with_cast.rs @@ -60,7 +60,7 @@ impl<'tcx> LateLintPass<'tcx> for PtrOffsetWithCast { None => return, }; - let msg = format!("use of `{}` with a `usize` casted to an `isize`", method); + let msg = format!("use of `{method}` with a `usize` casted to an `isize`"); if let Some(sugg) = build_suggestion(cx, method, receiver_expr, cast_lhs_expr) { span_lint_and_sugg( cx, @@ -124,7 +124,7 @@ fn build_suggestion<'tcx>( ) -> Option { let receiver = snippet_opt(cx, receiver_expr.span)?; let cast_lhs = snippet_opt(cx, cast_lhs_expr.span)?; - Some(format!("{}.{}({})", receiver, method.suggestion(), cast_lhs)) + Some(format!("{receiver}.{}({cast_lhs})", method.suggestion())) } #[derive(Copy, Clone)] diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index f4f1fd336df7c..d53614722aa1b 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -97,12 +97,12 @@ fn check_is_none_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: &Ex !matches!(caller.kind, ExprKind::Call(..) | ExprKind::MethodCall(..)); let sugg = if let Some(else_inner) = r#else { if eq_expr_value(cx, caller, peel_blocks(else_inner)) { - format!("Some({}?)", receiver_str) + format!("Some({receiver_str}?)") } else { return; } } else { - format!("{}{}?;", receiver_str, if by_ref { ".as_ref()" } else { "" }) + format!("{receiver_str}{}?;", if by_ref { ".as_ref()" } else { "" }) }; span_lint_and_sugg( @@ -134,8 +134,7 @@ fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: let receiver_str = snippet_with_applicability(cx, let_expr.span, "..", &mut applicability); let requires_semi = matches!(get_parent_node(cx.tcx, expr.hir_id), Some(Node::Stmt(_))); let sugg = format!( - "{}{}?{}", - receiver_str, + "{receiver_str}{}?{}", if by_ref == ByRef::Yes { ".as_ref()" } else { "" }, if requires_semi { ";" } else { "" } ); diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 918d624eec6fa..c6fbb5e805ab2 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -243,9 +243,9 @@ fn check_possible_range_contains( cx, MANUAL_RANGE_CONTAINS, span, - &format!("manual `{}::contains` implementation", range_type), + &format!("manual `{range_type}::contains` implementation"), "use", - format!("({}{}{}{}).contains(&{})", lo, space, range_op, hi, name), + format!("({lo}{space}{range_op}{hi}).contains(&{name})"), applicability, ); } else if !combine_and && ord == Some(l.ord) { @@ -273,9 +273,9 @@ fn check_possible_range_contains( cx, MANUAL_RANGE_CONTAINS, span, - &format!("manual `!{}::contains` implementation", range_type), + &format!("manual `!{range_type}::contains` implementation"), "use", - format!("!({}{}{}{}).contains(&{})", lo, space, range_op, hi, name), + format!("!({lo}{space}{range_op}{hi}).contains(&{name})"), applicability, ); } @@ -372,14 +372,14 @@ fn check_exclusive_range_plus_one(cx: &LateContext<'_>, expr: &Expr<'_>) { diag.span_suggestion( span, "use", - format!("({}..={})", start, end), + format!("({start}..={end})"), Applicability::MaybeIncorrect, ); } else { diag.span_suggestion( span, "use", - format!("{}..={}", start, end), + format!("{start}..={end}"), Applicability::MachineApplicable, // snippet ); } @@ -408,7 +408,7 @@ fn check_inclusive_range_minus_one(cx: &LateContext<'_>, expr: &Expr<'_>) { diag.span_suggestion( expr.span, "use", - format!("{}..{}", start, end), + format!("{start}..{end}"), Applicability::MachineApplicable, // snippet ); }, @@ -486,7 +486,7 @@ fn check_reversed_empty_range(cx: &LateContext<'_>, expr: &Expr<'_>) { expr.span, "consider using the following if you are attempting to iterate over this \ range in reverse", - format!("({}{}{}).rev()", end_snippet, dots, start_snippet), + format!("({end_snippet}{dots}{start_snippet}).rev()"), Applicability::MaybeIncorrect, ); } diff --git a/clippy_lints/src/read_zero_byte_vec.rs b/clippy_lints/src/read_zero_byte_vec.rs index 94dec191103c5..ae80b6f126916 100644 --- a/clippy_lints/src/read_zero_byte_vec.rs +++ b/clippy_lints/src/read_zero_byte_vec.rs @@ -101,9 +101,8 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec { next_stmt_span, "reading zero byte data to `Vec`", "try", - format!("{}.resize({}, 0); {}", + format!("{}.resize({len}, 0); {}", ident.as_str(), - len, snippet(cx, next_stmt_span, "..") ), applicability, diff --git a/clippy_lints/src/redundant_pub_crate.rs b/clippy_lints/src/redundant_pub_crate.rs index 323326381d407..9c71a3daeeee8 100644 --- a/clippy_lints/src/redundant_pub_crate.rs +++ b/clippy_lints/src/redundant_pub_crate.rs @@ -56,7 +56,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate { cx, REDUNDANT_PUB_CRATE, span, - &format!("pub(crate) {} inside private module", descr), + &format!("pub(crate) {descr} inside private module"), |diag| { diag.span_suggestion( item.vis_span, diff --git a/clippy_lints/src/redundant_slicing.rs b/clippy_lints/src/redundant_slicing.rs index 8693ca9af8300..245a02ea26e61 100644 --- a/clippy_lints/src/redundant_slicing.rs +++ b/clippy_lints/src/redundant_slicing.rs @@ -127,9 +127,9 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing { let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0; let sugg = if (deref_count != 0 || !reborrow_str.is_empty()) && needs_parens_for_prefix { - format!("({}{}{})", reborrow_str, "*".repeat(deref_count), snip) + format!("({reborrow_str}{}{snip})", "*".repeat(deref_count)) } else { - format!("{}{}{}", reborrow_str, "*".repeat(deref_count), snip) + format!("{reborrow_str}{}{snip}", "*".repeat(deref_count)) }; (lint, help_str, sugg) @@ -141,9 +141,9 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing { if deref_ty == expr_ty { let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0; let sugg = if needs_parens_for_prefix { - format!("(&{}{}*{})", mutability.prefix_str(), "*".repeat(indexed_ref_count), snip) + format!("(&{}{}*{snip})", mutability.prefix_str(), "*".repeat(indexed_ref_count)) } else { - format!("&{}{}*{}", mutability.prefix_str(), "*".repeat(indexed_ref_count), snip) + format!("&{}{}*{snip}", mutability.prefix_str(), "*".repeat(indexed_ref_count)) }; (DEREF_BY_SLICING_LINT, "dereference the original value instead", sugg) } else { diff --git a/clippy_lints/src/redundant_static_lifetimes.rs b/clippy_lints/src/redundant_static_lifetimes.rs index 2d751c274679f..60ba62c4a4332 100644 --- a/clippy_lints/src/redundant_static_lifetimes.rs +++ b/clippy_lints/src/redundant_static_lifetimes.rs @@ -67,7 +67,7 @@ impl RedundantStaticLifetimes { TyKind::Path(..) | TyKind::Slice(..) | TyKind::Array(..) | TyKind::Tup(..) => { if lifetime.ident.name == rustc_span::symbol::kw::StaticLifetime { let snip = snippet(cx, borrow_type.ty.span, ""); - let sugg = format!("&{}", snip); + let sugg = format!("&{snip}"); span_lint_and_then( cx, REDUNDANT_STATIC_LIFETIMES, diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index 6bcae0da8f48f..1fda58fa54de1 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -172,7 +172,7 @@ fn check_regex<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, utf8: bool) { ); }, Err(e) => { - span_lint(cx, INVALID_REGEX, expr.span, &format!("regex syntax error: {}", e)); + span_lint(cx, INVALID_REGEX, expr.span, &format!("regex syntax error: {e}")); }, } } @@ -200,7 +200,7 @@ fn check_regex<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, utf8: bool) { ); }, Err(e) => { - span_lint(cx, INVALID_REGEX, expr.span, &format!("regex syntax error: {}", e)); + span_lint(cx, INVALID_REGEX, expr.span, &format!("regex syntax error: {e}")); }, } } diff --git a/clippy_lints/src/same_name_method.rs b/clippy_lints/src/same_name_method.rs index 73f8e083b29a0..dead36e3bea8f 100644 --- a/clippy_lints/src/same_name_method.rs +++ b/clippy_lints/src/same_name_method.rs @@ -108,7 +108,7 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod { |diag| { diag.span_note( trait_method_span, - &format!("existing `{}` defined here", method_name), + &format!("existing `{method_name}` defined here"), ); }, ); @@ -151,7 +151,7 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod { // iterate on trait_spans? diag.span_note( trait_spans[0], - &format!("existing `{}` defined here", method_name), + &format!("existing `{method_name}` defined here"), ); }, ); diff --git a/clippy_lints/src/semicolon_if_nothing_returned.rs b/clippy_lints/src/semicolon_if_nothing_returned.rs index 729694da46d5c..66638eed99837 100644 --- a/clippy_lints/src/semicolon_if_nothing_returned.rs +++ b/clippy_lints/src/semicolon_if_nothing_returned.rs @@ -54,7 +54,7 @@ impl<'tcx> LateLintPass<'tcx> for SemicolonIfNothingReturned { } let sugg = sugg::Sugg::hir_with_macro_callsite(cx, expr, ".."); - let suggestion = format!("{0};", sugg); + let suggestion = format!("{sugg};"); span_lint_and_sugg( cx, SEMICOLON_IF_NOTHING_RETURNED, diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index c07aa00a12789..e57ab8cd7a3ac 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -174,7 +174,7 @@ impl SlowVectorInit { diag.span_suggestion( vec_alloc.allocation_expr.span, "consider replace allocation with", - format!("vec![0; {}]", len_expr), + format!("vec![0; {len_expr}]"), Applicability::Unspecified, ); }); diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 662d399ca538a..d356c99c8fc47 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -284,7 +284,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { e.span, "calling a slice of `as_bytes()` with `from_utf8` should be not necessary", "try", - format!("Some(&{}[{}])", snippet_app, snippet(cx, right.span, "..")), + format!("Some(&{snippet_app}[{}])", snippet(cx, right.span, "..")), applicability ) } @@ -500,8 +500,8 @@ impl<'tcx> LateLintPass<'tcx> for TrimSplitWhitespace { cx, TRIM_SPLIT_WHITESPACE, trim_span.with_hi(split_ws_span.lo()), - &format!("found call to `str::{}` before `str::split_whitespace`", trim_fn_name), - &format!("remove `{}()`", trim_fn_name), + &format!("found call to `str::{trim_fn_name}` before `str::split_whitespace`"), + &format!("remove `{trim_fn_name}()`"), String::new(), Applicability::MachineApplicable, ); diff --git a/clippy_lints/src/strlen_on_c_strings.rs b/clippy_lints/src/strlen_on_c_strings.rs index 78403d9fdb7e6..03324c66e8efc 100644 --- a/clippy_lints/src/strlen_on_c_strings.rs +++ b/clippy_lints/src/strlen_on_c_strings.rs @@ -79,7 +79,7 @@ impl<'tcx> LateLintPass<'tcx> for StrlenOnCStrings { span, "using `libc::strlen` on a `CString` or `CStr` value", "try this", - format!("{}.{}().len()", val_name, method_name), + format!("{val_name}.{method_name}().len()"), app, ); } diff --git a/clippy_lints/src/suspicious_operation_groupings.rs b/clippy_lints/src/suspicious_operation_groupings.rs index 5d36f0f5ff8bc..eef9bdc784940 100644 --- a/clippy_lints/src/suspicious_operation_groupings.rs +++ b/clippy_lints/src/suspicious_operation_groupings.rs @@ -326,8 +326,7 @@ fn replace_left_sugg( applicability: &mut Applicability, ) -> String { format!( - "{} {} {}", - left_suggestion, + "{left_suggestion} {} {}", binop.op.to_string(), snippet_with_applicability(cx, binop.right.span, "..", applicability), ) @@ -340,10 +339,9 @@ fn replace_right_sugg( applicability: &mut Applicability, ) -> String { format!( - "{} {} {}", + "{} {} {right_suggestion}", snippet_with_applicability(cx, binop.left.span, "..", applicability), binop.op.to_string(), - right_suggestion, ) } @@ -676,9 +674,8 @@ fn suggestion_with_swapped_ident( } Some(format!( - "{}{}{}", + "{}{new_ident}{}", snippet_with_applicability(cx, expr.span.with_hi(current_ident.span.lo()), "..", applicability), - new_ident, snippet_with_applicability(cx, expr.span.with_lo(current_ident.span.hi()), "..", applicability), )) }) diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index 1885f3ca414df..f46c21e126552 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -96,7 +96,7 @@ fn generate_swap_warning(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>, spa cx, MANUAL_SWAP, span, - &format!("this looks like you are swapping elements of `{}` manually", slice), + &format!("this looks like you are swapping elements of `{slice}` manually"), "try", format!( "{}.swap({}, {})", @@ -121,16 +121,16 @@ fn generate_swap_warning(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>, spa cx, MANUAL_SWAP, span, - &format!("this looks like you are swapping `{}` and `{}` manually", first, second), + &format!("this looks like you are swapping `{first}` and `{second}` manually"), |diag| { diag.span_suggestion( span, "try", - format!("{}::mem::swap({}, {})", sugg, first.mut_addr(), second.mut_addr()), + format!("{sugg}::mem::swap({}, {})", first.mut_addr(), second.mut_addr()), applicability, ); if !is_xor_based { - diag.note(&format!("or maybe you should use `{}::mem::replace`?", sugg)); + diag.note(&format!("or maybe you should use `{sugg}::mem::replace`?")); } }, ); @@ -182,7 +182,7 @@ fn check_suspicious_swap(cx: &LateContext<'_>, block: &Block<'_>) { let rhs0 = Sugg::hir_opt(cx, rhs0); let (what, lhs, rhs) = if let (Some(first), Some(second)) = (lhs0, rhs0) { ( - format!(" `{}` and `{}`", first, second), + format!(" `{first}` and `{second}`"), first.mut_addr().to_string(), second.mut_addr().to_string(), ) @@ -196,22 +196,19 @@ fn check_suspicious_swap(cx: &LateContext<'_>, block: &Block<'_>) { span_lint_and_then(cx, ALMOST_SWAPPED, span, - &format!("this looks like you are trying to swap{}", what), + &format!("this looks like you are trying to swap{what}"), |diag| { if !what.is_empty() { diag.span_suggestion( span, "try", format!( - "{}::mem::swap({}, {})", - sugg, - lhs, - rhs, + "{sugg}::mem::swap({lhs}, {rhs})", ), Applicability::MaybeIncorrect, ); diag.note( - &format!("or maybe you should use `{}::mem::replace`?", sugg) + &format!("or maybe you should use `{sugg}::mem::replace`?") ); } }); diff --git a/clippy_lints/src/swap_ptr_to_ref.rs b/clippy_lints/src/swap_ptr_to_ref.rs index 3cbbda80f3a9f..d085dda3582be 100644 --- a/clippy_lints/src/swap_ptr_to_ref.rs +++ b/clippy_lints/src/swap_ptr_to_ref.rs @@ -58,7 +58,7 @@ impl LateLintPass<'_> for SwapPtrToRef { let mut app = Applicability::MachineApplicable; let snip1 = snippet_with_context(cx, arg1_span.unwrap_or(arg1.span), ctxt, "..", &mut app).0; let snip2 = snippet_with_context(cx, arg2_span.unwrap_or(arg2.span), ctxt, "..", &mut app).0; - diag.span_suggestion(e.span, "use ptr::swap", format!("core::ptr::swap({}, {})", snip1, snip2), app); + diag.span_suggestion(e.span, "use ptr::swap", format!("core::ptr::swap({snip1}, {snip2})"), app); } } ); diff --git a/clippy_lints/src/to_digit_is_some.rs b/clippy_lints/src/to_digit_is_some.rs index 651201f34ed28..2512500a6be73 100644 --- a/clippy_lints/src/to_digit_is_some.rs +++ b/clippy_lints/src/to_digit_is_some.rs @@ -84,9 +84,9 @@ impl<'tcx> LateLintPass<'tcx> for ToDigitIsSome { "use of `.to_digit(..).is_some()`", "try this", if is_method_call { - format!("{}.is_digit({})", char_arg_snip, radix_snip) + format!("{char_arg_snip}.is_digit({radix_snip})") } else { - format!("char::is_digit({}, {})", char_arg_snip, radix_snip) + format!("char::is_digit({char_arg_snip}, {radix_snip})") }, applicability, ); diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index a25be93b8d616..bb146441f87f9 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -215,9 +215,8 @@ impl TraitBounds { .map(|(_, _, span)| snippet_with_applicability(cx, span, "..", &mut applicability)) .join(" + "); let hint_string = format!( - "consider combining the bounds: `{}: {}`", + "consider combining the bounds: `{}: {trait_bounds}`", snippet(cx, p.bounded_ty.span, "_"), - trait_bounds, ); span_lint_and_help( cx, diff --git a/clippy_lints/src/transmute/crosspointer_transmute.rs b/clippy_lints/src/transmute/crosspointer_transmute.rs index 25d0543c8611c..c4b9d82fc735b 100644 --- a/clippy_lints/src/transmute/crosspointer_transmute.rs +++ b/clippy_lints/src/transmute/crosspointer_transmute.rs @@ -13,10 +13,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty cx, CROSSPOINTER_TRANSMUTE, e.span, - &format!( - "transmute from a type (`{}`) to the type that it points to (`{}`)", - from_ty, to_ty - ), + &format!("transmute from a type (`{from_ty}`) to the type that it points to (`{to_ty}`)"), ); true }, @@ -25,10 +22,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty cx, CROSSPOINTER_TRANSMUTE, e.span, - &format!( - "transmute from a type (`{}`) to a pointer to that type (`{}`)", - from_ty, to_ty - ), + &format!("transmute from a type (`{from_ty}`) to a pointer to that type (`{to_ty}`)"), ); true }, diff --git a/clippy_lints/src/transmute/transmute_float_to_int.rs b/clippy_lints/src/transmute/transmute_float_to_int.rs index 1bde977cfa273..5ecba512b0fd6 100644 --- a/clippy_lints/src/transmute/transmute_float_to_int.rs +++ b/clippy_lints/src/transmute/transmute_float_to_int.rs @@ -24,7 +24,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_FLOAT_TO_INT, e.span, - &format!("transmute from a `{}` to a `{}`", from_ty, to_ty), + &format!("transmute from a `{from_ty}` to a `{to_ty}`"), |diag| { let mut sugg = sugg::Sugg::hir(cx, arg, ".."); @@ -38,7 +38,7 @@ pub(super) fn check<'tcx>( if let ExprKind::Lit(lit) = &arg.kind; if let ast::LitKind::Float(_, ast::LitFloatType::Unsuffixed) = lit.node; then { - let op = format!("{}{}", sugg, float_ty.name_str()).into(); + let op = format!("{sugg}{}", float_ty.name_str()).into(); match sugg { sugg::Sugg::MaybeParen(_) => sugg = sugg::Sugg::MaybeParen(op), _ => sugg = sugg::Sugg::NonParen(op) diff --git a/clippy_lints/src/transmute/transmute_int_to_bool.rs b/clippy_lints/src/transmute/transmute_int_to_bool.rs index 8c50b58ca4b86..58227c53de2f1 100644 --- a/clippy_lints/src/transmute/transmute_int_to_bool.rs +++ b/clippy_lints/src/transmute/transmute_int_to_bool.rs @@ -23,7 +23,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_INT_TO_BOOL, e.span, - &format!("transmute from a `{}` to a `bool`", from_ty), + &format!("transmute from a `{from_ty}` to a `bool`"), |diag| { let arg = sugg::Sugg::hir(cx, arg, ".."); let zero = sugg::Sugg::NonParen(Cow::from("0")); diff --git a/clippy_lints/src/transmute/transmute_int_to_char.rs b/clippy_lints/src/transmute/transmute_int_to_char.rs index 9e1823c373bfd..7d31c375f8cf2 100644 --- a/clippy_lints/src/transmute/transmute_int_to_char.rs +++ b/clippy_lints/src/transmute/transmute_int_to_char.rs @@ -23,7 +23,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_INT_TO_CHAR, e.span, - &format!("transmute from a `{}` to a `char`", from_ty), + &format!("transmute from a `{from_ty}` to a `char`"), |diag| { let arg = sugg::Sugg::hir(cx, arg, ".."); let arg = if let ty::Int(_) = from_ty.kind() { @@ -34,7 +34,7 @@ pub(super) fn check<'tcx>( diag.span_suggestion( e.span, "consider using", - format!("std::char::from_u32({}).unwrap()", arg), + format!("std::char::from_u32({arg}).unwrap()"), Applicability::Unspecified, ); }, diff --git a/clippy_lints/src/transmute/transmute_int_to_float.rs b/clippy_lints/src/transmute/transmute_int_to_float.rs index b8703052e6c86..cc3422edbbf13 100644 --- a/clippy_lints/src/transmute/transmute_int_to_float.rs +++ b/clippy_lints/src/transmute/transmute_int_to_float.rs @@ -22,7 +22,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_INT_TO_FLOAT, e.span, - &format!("transmute from a `{}` to a `{}`", from_ty, to_ty), + &format!("transmute from a `{from_ty}` to a `{to_ty}`"), |diag| { let arg = sugg::Sugg::hir(cx, arg, ".."); let arg = if let ty::Int(int_ty) = from_ty.kind() { @@ -36,7 +36,7 @@ pub(super) fn check<'tcx>( diag.span_suggestion( e.span, "consider using", - format!("{}::from_bits({})", to_ty, arg), + format!("{to_ty}::from_bits({arg})"), Applicability::Unspecified, ); }, diff --git a/clippy_lints/src/transmute/transmute_num_to_bytes.rs b/clippy_lints/src/transmute/transmute_num_to_bytes.rs index 52d193d11e1a0..009d5a7c8ae18 100644 --- a/clippy_lints/src/transmute/transmute_num_to_bytes.rs +++ b/clippy_lints/src/transmute/transmute_num_to_bytes.rs @@ -31,13 +31,13 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_NUM_TO_BYTES, e.span, - &format!("transmute from a `{}` to a `{}`", from_ty, to_ty), + &format!("transmute from a `{from_ty}` to a `{to_ty}`"), |diag| { let arg = sugg::Sugg::hir(cx, arg, ".."); diag.span_suggestion( e.span, "consider using `to_ne_bytes()`", - format!("{}.to_ne_bytes()", arg), + format!("{arg}.to_ne_bytes()"), Applicability::Unspecified, ); }, diff --git a/clippy_lints/src/transmute/transmute_ptr_to_ref.rs b/clippy_lints/src/transmute/transmute_ptr_to_ref.rs index 5eb03275b8ec1..12d0b866e1c9b 100644 --- a/clippy_lints/src/transmute/transmute_ptr_to_ref.rs +++ b/clippy_lints/src/transmute/transmute_ptr_to_ref.rs @@ -25,10 +25,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_PTR_TO_REF, e.span, - &format!( - "transmute from a pointer type (`{}`) to a reference type (`{}`)", - from_ty, to_ty - ), + &format!("transmute from a pointer type (`{from_ty}`) to a reference type (`{to_ty}`)"), |diag| { let arg = sugg::Sugg::hir(cx, arg, ".."); let (deref, cast) = if *mutbl == Mutability::Mut { @@ -41,26 +38,25 @@ pub(super) fn check<'tcx>( let sugg = if let Some(ty) = get_explicit_type(path) { let ty_snip = snippet_with_applicability(cx, ty.span, "..", &mut app); if meets_msrv(msrv, msrvs::POINTER_CAST) { - format!("{}{}.cast::<{}>()", deref, arg.maybe_par(), ty_snip) + format!("{deref}{}.cast::<{ty_snip}>()", arg.maybe_par()) } else if from_ptr_ty.has_erased_regions() { - sugg::make_unop(deref, arg.as_ty(format!("{} () as {} {}", cast, cast, ty_snip))) - .to_string() + sugg::make_unop(deref, arg.as_ty(format!("{cast} () as {cast} {ty_snip}"))).to_string() } else { - sugg::make_unop(deref, arg.as_ty(format!("{} {}", cast, ty_snip))).to_string() + sugg::make_unop(deref, arg.as_ty(format!("{cast} {ty_snip}"))).to_string() } } else if from_ptr_ty.ty == *to_ref_ty { if from_ptr_ty.has_erased_regions() { if meets_msrv(msrv, msrvs::POINTER_CAST) { - format!("{}{}.cast::<{}>()", deref, arg.maybe_par(), to_ref_ty) + format!("{deref}{}.cast::<{to_ref_ty}>()", arg.maybe_par()) } else { - sugg::make_unop(deref, arg.as_ty(format!("{} () as {} {}", cast, cast, to_ref_ty))) + sugg::make_unop(deref, arg.as_ty(format!("{cast} () as {cast} {to_ref_ty}"))) .to_string() } } else { sugg::make_unop(deref, arg).to_string() } } else { - sugg::make_unop(deref, arg.as_ty(format!("{} {}", cast, to_ref_ty))).to_string() + sugg::make_unop(deref, arg.as_ty(format!("{cast} {to_ref_ty}"))).to_string() }; diag.span_suggestion(e.span, "try", sugg, app); diff --git a/clippy_lints/src/transmute/transmute_ref_to_ref.rs b/clippy_lints/src/transmute/transmute_ref_to_ref.rs index 707a11d361c06..afb7f2e132696 100644 --- a/clippy_lints/src/transmute/transmute_ref_to_ref.rs +++ b/clippy_lints/src/transmute/transmute_ref_to_ref.rs @@ -38,7 +38,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_BYTES_TO_STR, e.span, - &format!("transmute from a `{}` to a `{}`", from_ty, to_ty), + &format!("transmute from a `{from_ty}` to a `{to_ty}`"), "consider using", if const_context { format!("std::str::from_utf8_unchecked{postfix}({snippet})") diff --git a/clippy_lints/src/transmute/transmute_undefined_repr.rs b/clippy_lints/src/transmute/transmute_undefined_repr.rs index b6d7d9f5b42ec..cac620cf8e8cb 100644 --- a/clippy_lints/src/transmute/transmute_undefined_repr.rs +++ b/clippy_lints/src/transmute/transmute_undefined_repr.rs @@ -75,10 +75,10 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_UNDEFINED_REPR, e.span, - &format!("transmute from `{}` which has an undefined layout", from_ty_orig), + &format!("transmute from `{from_ty_orig}` which has an undefined layout"), |diag| { if from_ty_orig.peel_refs() != from_ty.peel_refs() { - diag.note(&format!("the contained type `{}` has an undefined layout", from_ty)); + diag.note(&format!("the contained type `{from_ty}` has an undefined layout")); } }, ); @@ -89,10 +89,10 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_UNDEFINED_REPR, e.span, - &format!("transmute to `{}` which has an undefined layout", to_ty_orig), + &format!("transmute to `{to_ty_orig}` which has an undefined layout"), |diag| { if to_ty_orig.peel_refs() != to_ty.peel_refs() { - diag.note(&format!("the contained type `{}` has an undefined layout", to_ty)); + diag.note(&format!("the contained type `{to_ty}` has an undefined layout")); } }, ); @@ -116,8 +116,7 @@ pub(super) fn check<'tcx>( TRANSMUTE_UNDEFINED_REPR, e.span, &format!( - "transmute from `{}` to `{}`, both of which have an undefined layout", - from_ty_orig, to_ty_orig + "transmute from `{from_ty_orig}` to `{to_ty_orig}`, both of which have an undefined layout" ), |diag| { if let Some(same_adt_did) = same_adt_did { @@ -127,10 +126,10 @@ pub(super) fn check<'tcx>( )); } else { if from_ty_orig.peel_refs() != from_ty { - diag.note(&format!("the contained type `{}` has an undefined layout", from_ty)); + diag.note(&format!("the contained type `{from_ty}` has an undefined layout")); } if to_ty_orig.peel_refs() != to_ty { - diag.note(&format!("the contained type `{}` has an undefined layout", to_ty)); + diag.note(&format!("the contained type `{to_ty}` has an undefined layout")); } } }, @@ -145,10 +144,10 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_UNDEFINED_REPR, e.span, - &format!("transmute from `{}` which has an undefined layout", from_ty_orig), + &format!("transmute from `{from_ty_orig}` which has an undefined layout"), |diag| { if from_ty_orig.peel_refs() != from_ty { - diag.note(&format!("the contained type `{}` has an undefined layout", from_ty)); + diag.note(&format!("the contained type `{from_ty}` has an undefined layout")); } }, ); @@ -162,10 +161,10 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_UNDEFINED_REPR, e.span, - &format!("transmute into `{}` which has an undefined layout", to_ty_orig), + &format!("transmute into `{to_ty_orig}` which has an undefined layout"), |diag| { if to_ty_orig.peel_refs() != to_ty { - diag.note(&format!("the contained type `{}` has an undefined layout", to_ty)); + diag.note(&format!("the contained type `{to_ty}` has an undefined layout")); } }, ); diff --git a/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs b/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs index 626d7cd46fc43..6b444922a7cc7 100644 --- a/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs +++ b/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs @@ -21,10 +21,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS, e.span, - &format!( - "transmute from `{}` to `{}` which could be expressed as a pointer cast instead", - from_ty, to_ty - ), + &format!("transmute from `{from_ty}` to `{to_ty}` which could be expressed as a pointer cast instead"), |diag| { if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) { let sugg = arg.as_ty(&to_ty.to_string()).to_string(); diff --git a/clippy_lints/src/transmute/unsound_collection_transmute.rs b/clippy_lints/src/transmute/unsound_collection_transmute.rs index 831b0d450d20a..b1445311b7112 100644 --- a/clippy_lints/src/transmute/unsound_collection_transmute.rs +++ b/clippy_lints/src/transmute/unsound_collection_transmute.rs @@ -37,10 +37,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty cx, UNSOUND_COLLECTION_TRANSMUTE, e.span, - &format!( - "transmute from `{}` to `{}` with mismatched layout is unsound", - from_ty, to_ty - ), + &format!("transmute from `{from_ty}` to `{to_ty}` with mismatched layout is unsound"), ); true } else { diff --git a/clippy_lints/src/transmute/useless_transmute.rs b/clippy_lints/src/transmute/useless_transmute.rs index 8122cd716e011..f919bbd5afca3 100644 --- a/clippy_lints/src/transmute/useless_transmute.rs +++ b/clippy_lints/src/transmute/useless_transmute.rs @@ -21,7 +21,7 @@ pub(super) fn check<'tcx>( cx, USELESS_TRANSMUTE, e.span, - &format!("transmute from a type (`{}`) to itself", from_ty), + &format!("transmute from a type (`{from_ty}`) to itself"), ); true }, diff --git a/clippy_lints/src/transmute/wrong_transmute.rs b/clippy_lints/src/transmute/wrong_transmute.rs index 2118f3d695004..d1965565b9261 100644 --- a/clippy_lints/src/transmute/wrong_transmute.rs +++ b/clippy_lints/src/transmute/wrong_transmute.rs @@ -13,7 +13,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty cx, WRONG_TRANSMUTE, e.span, - &format!("transmute from a `{}` to a pointer", from_ty), + &format!("transmute from a `{from_ty}` to a pointer"), ); true }, diff --git a/clippy_lints/src/types/borrowed_box.rs b/clippy_lints/src/types/borrowed_box.rs index 94945b2e1a9e2..0a779b3786035 100644 --- a/clippy_lints/src/types/borrowed_box.rs +++ b/clippy_lints/src/types/borrowed_box.rs @@ -49,15 +49,15 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, m let inner_snippet = snippet(cx, inner.span, ".."); let suggestion = match &inner.kind { TyKind::TraitObject(bounds, lt_bound, _) if bounds.len() > 1 || !lt_bound.is_elided() => { - format!("&{}({})", ltopt, &inner_snippet) + format!("&{ltopt}({})", &inner_snippet) }, TyKind::Path(qpath) if get_bounds_if_impl_trait(cx, qpath, inner.hir_id) .map_or(false, |bounds| bounds.len() > 1) => { - format!("&{}({})", ltopt, &inner_snippet) + format!("&{ltopt}({})", &inner_snippet) }, - _ => format!("&{}{}", ltopt, &inner_snippet), + _ => format!("&{ltopt}{}", &inner_snippet), }; span_lint_and_sugg( cx, diff --git a/clippy_lints/src/types/box_collection.rs b/clippy_lints/src/types/box_collection.rs index ba51404d21483..08020ce663817 100644 --- a/clippy_lints/src/types/box_collection.rs +++ b/clippy_lints/src/types/box_collection.rs @@ -16,7 +16,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_ _ => "<..>", }; - let box_content = format!("{outer}{generic}", outer = item_type); + let box_content = format!("{item_type}{generic}"); span_lint_and_help( cx, BOX_COLLECTION, diff --git a/clippy_lints/src/types/rc_buffer.rs b/clippy_lints/src/types/rc_buffer.rs index 4d72a29e8c747..6b9de64e24c93 100644 --- a/clippy_lints/src/types/rc_buffer.rs +++ b/clippy_lints/src/types/rc_buffer.rs @@ -17,7 +17,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_ hir_ty.span, "usage of `Rc` when T is a buffer type", "try", - format!("Rc<{}>", alternate), + format!("Rc<{alternate}>"), Applicability::MachineApplicable, ); } else { @@ -57,7 +57,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_ hir_ty.span, "usage of `Arc` when T is a buffer type", "try", - format!("Arc<{}>", alternate), + format!("Arc<{alternate}>"), Applicability::MachineApplicable, ); } else if let Some(ty) = qpath_generic_tys(qpath).next() { diff --git a/clippy_lints/src/types/redundant_allocation.rs b/clippy_lints/src/types/redundant_allocation.rs index a1312fcda0b71..b95f0213e0cdb 100644 --- a/clippy_lints/src/types/redundant_allocation.rs +++ b/clippy_lints/src/types/redundant_allocation.rs @@ -27,13 +27,11 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_ cx, REDUNDANT_ALLOCATION, hir_ty.span, - &format!("usage of `{}<{}>`", outer_sym, generic_snippet), + &format!("usage of `{outer_sym}<{generic_snippet}>`"), |diag| { - diag.span_suggestion(hir_ty.span, "try", format!("{}", generic_snippet), applicability); + diag.span_suggestion(hir_ty.span, "try", format!("{generic_snippet}"), applicability); diag.note(&format!( - "`{generic}` is already a pointer, `{outer}<{generic}>` allocates a pointer on the heap", - outer = outer_sym, - generic = generic_snippet + "`{generic_snippet}` is already a pointer, `{outer_sym}<{generic_snippet}>` allocates a pointer on the heap" )); }, ); @@ -72,19 +70,16 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_ cx, REDUNDANT_ALLOCATION, hir_ty.span, - &format!("usage of `{}<{}<{}>>`", outer_sym, inner_sym, generic_snippet), + &format!("usage of `{outer_sym}<{inner_sym}<{generic_snippet}>>`"), |diag| { diag.span_suggestion( hir_ty.span, "try", - format!("{}<{}>", outer_sym, generic_snippet), + format!("{outer_sym}<{generic_snippet}>"), applicability, ); diag.note(&format!( - "`{inner}<{generic}>` is already on the heap, `{outer}<{inner}<{generic}>>` makes an extra allocation", - outer = outer_sym, - inner = inner_sym, - generic = generic_snippet + "`{inner_sym}<{generic_snippet}>` is already on the heap, `{outer_sym}<{inner_sym}<{generic_snippet}>>` makes an extra allocation" )); }, ); @@ -94,19 +89,13 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_ cx, REDUNDANT_ALLOCATION, hir_ty.span, - &format!("usage of `{}<{}<{}>>`", outer_sym, inner_sym, generic_snippet), + &format!("usage of `{outer_sym}<{inner_sym}<{generic_snippet}>>`"), |diag| { diag.note(&format!( - "`{inner}<{generic}>` is already on the heap, `{outer}<{inner}<{generic}>>` makes an extra allocation", - outer = outer_sym, - inner = inner_sym, - generic = generic_snippet + "`{inner_sym}<{generic_snippet}>` is already on the heap, `{outer_sym}<{inner_sym}<{generic_snippet}>>` makes an extra allocation" )); diag.help(&format!( - "consider using just `{outer}<{generic}>` or `{inner}<{generic}>`", - outer = outer_sym, - inner = inner_sym, - generic = generic_snippet + "consider using just `{outer_sym}<{generic_snippet}>` or `{inner_sym}<{generic_snippet}>`" )); }, ); diff --git a/clippy_lints/src/unit_return_expecting_ord.rs b/clippy_lints/src/unit_return_expecting_ord.rs index c0a4f3fbacd64..57aff5367dd15 100644 --- a/clippy_lints/src/unit_return_expecting_ord.rs +++ b/clippy_lints/src/unit_return_expecting_ord.rs @@ -157,8 +157,7 @@ impl<'tcx> LateLintPass<'tcx> for UnitReturnExpectingOrd { span, &format!( "this closure returns \ - the unit type which also implements {}", - trait_name + the unit type which also implements {trait_name}" ), ); }, @@ -169,8 +168,7 @@ impl<'tcx> LateLintPass<'tcx> for UnitReturnExpectingOrd { span, &format!( "this closure returns \ - the unit type which also implements {}", - trait_name + the unit type which also implements {trait_name}" ), Some(last_semi), "probably caused by this trailing semicolon", diff --git a/clippy_lints/src/unit_types/unit_arg.rs b/clippy_lints/src/unit_types/unit_arg.rs index a6f777abc6e94..f6d3fb00f4ee5 100644 --- a/clippy_lints/src/unit_types/unit_arg.rs +++ b/clippy_lints/src/unit_types/unit_arg.rs @@ -74,7 +74,7 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp cx, UNIT_ARG, expr.span, - &format!("passing {}unit value{} to a function", singular, plural), + &format!("passing {singular}unit value{plural} to a function"), |db| { let mut or = ""; args_to_recover @@ -129,7 +129,7 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp if arg_snippets_without_empty_blocks.is_empty() { db.multipart_suggestion( - &format!("use {}unit literal{} instead", singular, plural), + &format!("use {singular}unit literal{plural} instead"), args_to_recover .iter() .map(|arg| (arg.span, "()".to_string())) @@ -143,8 +143,7 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp db.span_suggestion( expr.span, &format!( - "{}move the expression{} in front of the call and replace {} with the unit literal `()`", - or, empty_or_s, it_or_them + "{or}move the expression{empty_or_s} in front of the call and replace {it_or_them} with the unit literal `()`" ), sugg, applicability, diff --git a/clippy_lints/src/unit_types/unit_cmp.rs b/clippy_lints/src/unit_types/unit_cmp.rs index 1dd8895ebd076..226495dcbda34 100644 --- a/clippy_lints/src/unit_types/unit_cmp.rs +++ b/clippy_lints/src/unit_types/unit_cmp.rs @@ -22,7 +22,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { cx, UNIT_CMP, macro_call.span, - &format!("`{}` of unit values detected. This will always {}", macro_name, result), + &format!("`{macro_name}` of unit values detected. This will always {result}"), ); } return; @@ -40,9 +40,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { UNIT_CMP, expr.span, &format!( - "{}-comparison of unit values detected. This will always be {}", - op.as_str(), - result + "{}-comparison of unit values detected. This will always be {result}", + op.as_str() ), ); } diff --git a/clippy_lints/src/unnecessary_self_imports.rs b/clippy_lints/src/unnecessary_self_imports.rs index 839a4bdab09de..bc0dd263d88ab 100644 --- a/clippy_lints/src/unnecessary_self_imports.rs +++ b/clippy_lints/src/unnecessary_self_imports.rs @@ -57,7 +57,7 @@ impl EarlyLintPass for UnnecessarySelfImports { format!( "{}{};", last_segment.ident, - if let UseTreeKind::Simple(Some(alias), ..) = self_tree.kind { format!(" as {}", alias) } else { String::new() }, + if let UseTreeKind::Simple(Some(alias), ..) = self_tree.kind { format!(" as {alias}") } else { String::new() }, ), Applicability::MaybeIncorrect, ); diff --git a/clippy_lints/src/unnecessary_wraps.rs b/clippy_lints/src/unnecessary_wraps.rs index 2c40827db0e75..83ef3b0fac874 100644 --- a/clippy_lints/src/unnecessary_wraps.rs +++ b/clippy_lints/src/unnecessary_wraps.rs @@ -153,11 +153,8 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { ) } else { ( - format!( - "this function's return value is unnecessarily wrapped by `{}`", - return_type_label - ), - format!("remove `{}` from the return type...", return_type_label), + format!("this function's return value is unnecessarily wrapped by `{return_type_label}`"), + format!("remove `{return_type_label}` from the return type..."), inner_type.to_string(), "...and then change returning expressions", ) diff --git a/clippy_lints/src/unsafe_removed_from_name.rs b/clippy_lints/src/unsafe_removed_from_name.rs index 64f7a055cd9bd..32cd468120141 100644 --- a/clippy_lints/src/unsafe_removed_from_name.rs +++ b/clippy_lints/src/unsafe_removed_from_name.rs @@ -65,10 +65,7 @@ fn unsafe_to_safe_check(old_name: Ident, new_name: Ident, cx: &EarlyContext<'_>, cx, UNSAFE_REMOVED_FROM_NAME, span, - &format!( - "removed `unsafe` from the name of `{}` in use as `{}`", - old_str, new_str - ), + &format!("removed `unsafe` from the name of `{old_str}` in use as `{new_str}`"), ); } } diff --git a/clippy_lints/src/unused_rounding.rs b/clippy_lints/src/unused_rounding.rs index b8a5d4ea8c9fb..3164937293b68 100644 --- a/clippy_lints/src/unused_rounding.rs +++ b/clippy_lints/src/unused_rounding.rs @@ -58,8 +58,8 @@ impl EarlyLintPass for UnusedRounding { cx, UNUSED_ROUNDING, expr.span, - &format!("used the `{}` method with a whole number float", method_name), - &format!("remove the `{}` method call", method_name), + &format!("used the `{method_name}` method with a whole number float"), + &format!("remove the `{method_name}` method call"), float, Applicability::MachineApplicable, ); diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index 7e451b7b7a419..45e2f55023603 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -257,9 +257,8 @@ impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> { expr.hir_id, expr.span, &format!( - "called `{}` on `{}` after checking its variant with `{}`", + "called `{}` on `{unwrappable_variable_name}` after checking its variant with `{}`", method_name.ident.name, - unwrappable_variable_name, unwrappable.check_name.ident.as_str(), ), |diag| { @@ -268,9 +267,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> { unwrappable.check.span.with_lo(unwrappable.if_expr.span.lo()), "try", format!( - "if let {} = {}", - suggested_pattern, - unwrappable_variable_name, + "if let {suggested_pattern} = {unwrappable_variable_name}", ), // We don't track how the unwrapped value is used inside the // block or suggest deleting the unwrap, so we can't offer a diff --git a/clippy_lints/src/upper_case_acronyms.rs b/clippy_lints/src/upper_case_acronyms.rs index 02bf09ed5068c..378cc427f5a01 100644 --- a/clippy_lints/src/upper_case_acronyms.rs +++ b/clippy_lints/src/upper_case_acronyms.rs @@ -93,7 +93,7 @@ fn check_ident(cx: &LateContext<'_>, ident: &Ident, be_aggressive: bool) { cx, UPPER_CASE_ACRONYMS, span, - &format!("name `{}` contains a capitalized acronym", ident), + &format!("name `{ident}` contains a capitalized acronym"), "consider making the acronym lowercase, except the initial letter", corrected, Applicability::MaybeIncorrect, diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index f1b6463ad0f7c..50c5a832430af 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { cx, USELESS_CONVERSION, e.span, - &format!("useless conversion to the same type: `{}`", b), + &format!("useless conversion to the same type: `{b}`"), "consider removing `.into()`", sugg, Applicability::MachineApplicable, // snippet @@ -97,7 +97,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { cx, USELESS_CONVERSION, e.span, - &format!("useless conversion to the same type: `{}`", b), + &format!("useless conversion to the same type: `{b}`"), "consider removing `.into_iter()`", sugg, Applicability::MachineApplicable, // snippet @@ -118,7 +118,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { cx, USELESS_CONVERSION, e.span, - &format!("useless conversion to the same type: `{}`", b), + &format!("useless conversion to the same type: `{b}`"), None, "consider removing `.try_into()`", ); @@ -146,7 +146,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { cx, USELESS_CONVERSION, e.span, - &format!("useless conversion to the same type: `{}`", b), + &format!("useless conversion to the same type: `{b}`"), None, &hint, ); @@ -165,7 +165,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { cx, USELESS_CONVERSION, e.span, - &format!("useless conversion to the same type: `{}`", b), + &format!("useless conversion to the same type: `{b}`"), &sugg_msg, sugg.to_string(), Applicability::MachineApplicable, // snippet diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index 4003fff27c006..65576b7203fdc 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -739,7 +739,7 @@ fn path_to_string(path: &QPath<'_>) -> String { *s += ", "; write!(s, "{:?}", segment.ident.as_str()).unwrap(); }, - other => write!(s, "/* unimplemented: {:?}*/", other).unwrap(), + other => write!(s, "/* unimplemented: {other:?}*/").unwrap(), }, QPath::LangItem(..) => panic!("path_to_string: called for lang item qpath"), } diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 2be3fa99c811c..6f5a638be12b9 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -482,16 +482,13 @@ pub fn format_error(error: Box) -> String { let field = fields.get(index).copied().unwrap_or_default(); write!( msg, - "{:separator_width$}{:field_width$}", - " ", - field, - separator_width = SEPARATOR_WIDTH, - field_width = column_width + "{:SEPARATOR_WIDTH$}{field:column_width$}", + " " ) .unwrap(); } } - write!(msg, "\n{}", suffix).unwrap(); + write!(msg, "\n{suffix}").unwrap(); msg } else { s diff --git a/clippy_lints/src/wildcard_imports.rs b/clippy_lints/src/wildcard_imports.rs index 5418eca382da0..33138551011cc 100644 --- a/clippy_lints/src/wildcard_imports.rs +++ b/clippy_lints/src/wildcard_imports.rs @@ -173,7 +173,7 @@ impl LateLintPass<'_> for WildcardImports { let sugg = if braced_glob { imports_string } else { - format!("{}::{}", import_source_snippet, imports_string) + format!("{import_source_snippet}::{imports_string}") }; let (lint, message) = if let Res::Def(DefKind::Enum, _) = use_path.res { diff --git a/clippy_lints/src/zero_div_zero.rs b/clippy_lints/src/zero_div_zero.rs index 50d3c079fe675..9b3de35dbd3cd 100644 --- a/clippy_lints/src/zero_div_zero.rs +++ b/clippy_lints/src/zero_div_zero.rs @@ -57,8 +57,7 @@ impl<'tcx> LateLintPass<'tcx> for ZeroDiv { "constant division of `0.0` with `0.0` will always result in NaN", None, &format!( - "consider using `{}::NAN` if you would like a constant representing NaN", - float_type, + "consider using `{float_type}::NAN` if you would like a constant representing NaN", ), ); } From cb6d1267c45d0f3668b730c2bdb3e087def6118a Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Fri, 23 Sep 2022 13:55:30 -0400 Subject: [PATCH 043/114] a few more core lint fixes --- src/driver.rs | 6 +++--- src/main.rs | 6 +++--- tests/compile-test.rs | 23 +++++++++-------------- tests/lint_message_convention.rs | 2 +- tests/missing-test-files.rs | 2 +- tests/versioncheck.rs | 6 +++--- 6 files changed, 20 insertions(+), 25 deletions(-) diff --git a/src/driver.rs b/src/driver.rs index 235eae5af1ec3..b12208ac62a88 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -193,8 +193,8 @@ fn report_clippy_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) { let xs: Vec> = vec![ "the compiler unexpectedly panicked. this is a bug.".into(), - format!("we would appreciate a bug report: {}", bug_report_url).into(), - format!("Clippy version: {}", version_info).into(), + format!("we would appreciate a bug report: {bug_report_url}").into(), + format!("Clippy version: {version_info}").into(), ]; for note in &xs { @@ -290,7 +290,7 @@ pub fn main() { if orig_args.iter().any(|a| a == "--version" || a == "-V") { let version_info = rustc_tools_util::get_version_info!(); - println!("{}", version_info); + println!("{version_info}"); exit(0); } diff --git a/src/main.rs b/src/main.rs index 4a32e0e54a81b..fce3cdfc462e0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -37,12 +37,12 @@ You can use tool lints to allow or deny lints from your code, eg.: "#; fn show_help() { - println!("{}", CARGO_CLIPPY_HELP); + println!("{CARGO_CLIPPY_HELP}"); } fn show_version() { let version_info = rustc_tools_util::get_version_info!(); - println!("{}", version_info); + println!("{version_info}"); } pub fn main() { @@ -133,7 +133,7 @@ impl ClippyCmd { let clippy_args: String = self .clippy_args .iter() - .map(|arg| format!("{}__CLIPPY_HACKERY__", arg)) + .map(|arg| format!("{arg}__CLIPPY_HACKERY__")) .collect(); // Currently, `CLIPPY_TERMINAL_WIDTH` is used only to format "unknown field" error messages. diff --git a/tests/compile-test.rs b/tests/compile-test.rs index ba6186e599e96..fa769222d1af3 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -111,15 +111,14 @@ static EXTERN_FLAGS: LazyLock = LazyLock::new(|| { .collect(); assert!( not_found.is_empty(), - "dependencies not found in depinfo: {:?}\n\ + "dependencies not found in depinfo: {not_found:?}\n\ help: Make sure the `-Z binary-dep-depinfo` rust flag is enabled\n\ help: Try adding to dev-dependencies in Cargo.toml\n\ help: Be sure to also add `extern crate ...;` to tests/compile-test.rs", - not_found, ); crates .into_iter() - .map(|(name, path)| format!(" --extern {}={}", name, path)) + .map(|(name, path)| format!(" --extern {name}={path}")) .collect() }); @@ -150,9 +149,8 @@ fn base_config(test_dir: &str) -> compiletest::Config { .map(|p| format!(" -L dependency={}", Path::new(p).join("deps").display())) .unwrap_or_default(); config.target_rustcflags = Some(format!( - "--emit=metadata -Dwarnings -Zui-testing -L dependency={}{}{}", + "--emit=metadata -Dwarnings -Zui-testing -L dependency={}{host_libs}{}", deps_path.display(), - host_libs, &*EXTERN_FLAGS, )); @@ -239,7 +237,7 @@ fn run_ui_toml() { Ok(true) => {}, Ok(false) => panic!("Some tests failed"), Err(e) => { - panic!("I/O failure during tests: {:?}", e); + panic!("I/O failure during tests: {e:?}"); }, } } @@ -348,7 +346,7 @@ fn run_ui_cargo() { Ok(true) => {}, Ok(false) => panic!("Some tests failed"), Err(e) => { - panic!("I/O failure during tests: {:?}", e); + panic!("I/O failure during tests: {e:?}"); }, } } @@ -419,16 +417,15 @@ fn check_rustfix_coverage() { if rs_path.starts_with("tests/ui/crashes") { continue; } - assert!(rs_path.starts_with("tests/ui/"), "{:?}", rs_file); + assert!(rs_path.starts_with("tests/ui/"), "{rs_file:?}"); let filename = rs_path.strip_prefix("tests/ui/").unwrap(); assert!( RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS .binary_search_by_key(&filename, Path::new) .is_ok(), - "`{}` runs `MachineApplicable` diagnostics but is missing a `run-rustfix` annotation. \ + "`{rs_file}` runs `MachineApplicable` diagnostics but is missing a `run-rustfix` annotation. \ Please either add `// run-rustfix` at the top of the file or add the file to \ `RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS` in `tests/compile-test.rs`.", - rs_file, ); } } @@ -478,15 +475,13 @@ fn ui_cargo_toml_metadata() { .map(|component| component.as_os_str().to_string_lossy().replace('-', "_")) .any(|s| *s == name) || path.starts_with(&cargo_common_metadata_path), - "{:?} has incorrect package name", - path + "{path:?} has incorrect package name" ); let publish = package.get("publish").and_then(toml::Value::as_bool).unwrap_or(true); assert!( !publish || publish_exceptions.contains(&path.parent().unwrap().to_path_buf()), - "{:?} lacks `publish = false`", - path + "{path:?} lacks `publish = false`" ); } } diff --git a/tests/lint_message_convention.rs b/tests/lint_message_convention.rs index 2e0f4e76075b3..abd0d1bc5934f 100644 --- a/tests/lint_message_convention.rs +++ b/tests/lint_message_convention.rs @@ -102,7 +102,7 @@ fn lint_message_convention() { "error: the test '{}' contained the following nonconforming lines :", message.path.display() ); - message.bad_lines.iter().for_each(|line| eprintln!("{}", line)); + message.bad_lines.iter().for_each(|line| eprintln!("{line}")); eprintln!("\n\n"); } diff --git a/tests/missing-test-files.rs b/tests/missing-test-files.rs index 7d6edc2b1e095..caedd5d76cd6f 100644 --- a/tests/missing-test-files.rs +++ b/tests/missing-test-files.rs @@ -17,7 +17,7 @@ fn test_missing_tests() { "Didn't see a test file for the following files:\n\n{}\n", missing_files .iter() - .map(|s| format!("\t{}", s)) + .map(|s| format!("\t{s}")) .collect::>() .join("\n") ); diff --git a/tests/versioncheck.rs b/tests/versioncheck.rs index 38498ebdcf2c1..9e07769a8e4fd 100644 --- a/tests/versioncheck.rs +++ b/tests/versioncheck.rs @@ -8,12 +8,12 @@ use std::fs; #[test] fn check_that_clippy_lints_and_clippy_utils_have_the_same_version_as_clippy() { fn read_version(path: &str) -> String { - let contents = fs::read_to_string(path).unwrap_or_else(|e| panic!("error reading `{}`: {:?}", path, e)); + let contents = fs::read_to_string(path).unwrap_or_else(|e| panic!("error reading `{path}`: {e:?}")); contents .lines() .filter_map(|l| l.split_once('=')) .find_map(|(k, v)| (k.trim() == "version").then(|| v.trim())) - .unwrap_or_else(|| panic!("error finding version in `{}`", path)) + .unwrap_or_else(|| panic!("error finding version in `{path}`")) .to_string() } @@ -83,7 +83,7 @@ fn check_that_clippy_has_the_same_major_version_as_rustc() { // we don't want our tests failing suddenly }, _ => { - panic!("Failed to parse rustc version: {:?}", vsplit); + panic!("Failed to parse rustc version: {vsplit:?}"); }, }; } From 59d0e8cabaec24b564db8420ef630c6a5880688f Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Fri, 23 Sep 2022 14:25:03 -0400 Subject: [PATCH 044/114] and a few more from other dirs --- clippy_dev/src/main.rs | 2 +- clippy_utils/src/attrs.rs | 4 +- clippy_utils/src/diagnostics.rs | 5 +-- clippy_utils/src/lib.rs | 2 +- clippy_utils/src/macros.rs | 2 +- clippy_utils/src/qualify_min_const_fn.rs | 11 +++-- clippy_utils/src/source.rs | 8 ++-- clippy_utils/src/sugg.rs | 52 ++++++++++++------------ rustc_tools_util/src/lib.rs | 6 +-- tests/integration.rs | 4 +- 10 files changed, 46 insertions(+), 50 deletions(-) diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index a417d3dd8a4e7..d3e036692040f 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -41,7 +41,7 @@ fn main() { matches.contains_id("msrv"), ) { Ok(_) => update_lints::update(update_lints::UpdateMode::Change), - Err(e) => eprintln!("Unable to create lint: {}", e), + Err(e) => eprintln!("Unable to create lint: {e}"), } }, Some(("setup", sub_command)) => match sub_command.subcommand() { diff --git a/clippy_utils/src/attrs.rs b/clippy_utils/src/attrs.rs index 8ab77c8816636..d9b22664fd25b 100644 --- a/clippy_utils/src/attrs.rs +++ b/clippy_utils/src/attrs.rs @@ -131,12 +131,12 @@ pub fn get_unique_inner_attr(sess: &Session, attrs: &[ast::Attribute], name: &'s match attr.style { ast::AttrStyle::Inner if unique_attr.is_none() => unique_attr = Some(attr.clone()), ast::AttrStyle::Inner => { - sess.struct_span_err(attr.span, &format!("`{}` is defined multiple times", name)) + sess.struct_span_err(attr.span, &format!("`{name}` is defined multiple times")) .span_note(unique_attr.as_ref().unwrap().span, "first definition found here") .emit(); }, ast::AttrStyle::Outer => { - sess.span_err(attr.span, &format!("`{}` cannot be an outer attribute", name)); + sess.span_err(attr.span, &format!("`{name}` cannot be an outer attribute")); }, } } diff --git a/clippy_utils/src/diagnostics.rs b/clippy_utils/src/diagnostics.rs index ad95369b9ef70..12e53e07c97c9 100644 --- a/clippy_utils/src/diagnostics.rs +++ b/clippy_utils/src/diagnostics.rs @@ -18,12 +18,11 @@ fn docs_link(diag: &mut Diagnostic, lint: &'static Lint) { if env::var("CLIPPY_DISABLE_DOCS_LINKS").is_err() { if let Some(lint) = lint.name_lower().strip_prefix("clippy::") { diag.help(&format!( - "for further information visit https://rust-lang.github.io/rust-clippy/{}/index.html#{}", + "for further information visit https://rust-lang.github.io/rust-clippy/{}/index.html#{lint}", &option_env!("RUST_RELEASE_NUM").map_or("master".to_string(), |n| { // extract just major + minor version and ignore patch versions format!("rust-{}", n.rsplit_once('.').unwrap().1) - }), - lint + }) )); } } diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index a1a716ebeca29..f3c3fd73f3939 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -121,7 +121,7 @@ pub fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option) -> Opt return Some(version); } else if let Some(sess) = sess { if let Some(span) = span { - sess.span_err(span, &format!("`{}` is not a valid Rust version", msrv)); + sess.span_err(span, &format!("`{msrv}` is not a valid Rust version")); } } None diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs index a1808c0972009..b9e6462a55efc 100644 --- a/clippy_utils/src/macros.rs +++ b/clippy_utils/src/macros.rs @@ -392,7 +392,7 @@ impl FormatString { unescape_literal(inner, mode, &mut |_, ch| match ch { Ok(ch) => unescaped.push(ch), Err(e) if !e.is_fatal() => (), - Err(e) => panic!("{:?}", e), + Err(e) => panic!("{e:?}"), }); let mut parts = Vec::new(); diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index d5f64e5118f56..efa7aaa40ee2c 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -33,10 +33,10 @@ pub fn is_min_const_fn<'a, 'tcx>(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, msrv: | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Trait(..) | ty::PredicateKind::TypeWellFormedFromEnv(..) => continue, - ty::PredicateKind::ObjectSafe(_) => panic!("object safe predicate on function: {:#?}", predicate), - ty::PredicateKind::ClosureKind(..) => panic!("closure kind predicate on function: {:#?}", predicate), - ty::PredicateKind::Subtype(_) => panic!("subtype predicate on function: {:#?}", predicate), - ty::PredicateKind::Coerce(_) => panic!("coerce predicate on function: {:#?}", predicate), + ty::PredicateKind::ObjectSafe(_) => panic!("object safe predicate on function: {predicate:#?}"), + ty::PredicateKind::ClosureKind(..) => panic!("closure kind predicate on function: {predicate:#?}"), + ty::PredicateKind::Subtype(_) => panic!("subtype predicate on function: {predicate:#?}"), + ty::PredicateKind::Coerce(_) => panic!("coerce predicate on function: {predicate:#?}"), } } match predicates.parent { @@ -315,8 +315,7 @@ fn check_terminator<'a, 'tcx>( span, format!( "can only call other `const fn` within a `const fn`, \ - but `{:?}` is not stable as `const fn`", - func, + but `{func:?}` is not stable as `const fn`", ) .into(), )); diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs index d85f591fb9a42..64c3f70efa5d7 100644 --- a/clippy_utils/src/source.rs +++ b/clippy_utils/src/source.rs @@ -25,11 +25,11 @@ pub fn expr_block<'a, T: LintContext>( if expr.span.from_expansion() { Cow::Owned(format!("{{ {} }}", snippet_with_macro_callsite(cx, expr.span, default))) } else if let ExprKind::Block(_, _) = expr.kind { - Cow::Owned(format!("{}{}", code, string)) + Cow::Owned(format!("{code}{string}")) } else if string.is_empty() { - Cow::Owned(format!("{{ {} }}", code)) + Cow::Owned(format!("{{ {code} }}")) } else { - Cow::Owned(format!("{{\n{};\n{}\n}}", code, string)) + Cow::Owned(format!("{{\n{code};\n{string}\n}}")) } } @@ -466,7 +466,7 @@ mod test { #[test] fn test_without_block_comments_lines_without_block_comments() { let result = without_block_comments(vec!["/*", "", "*/"]); - println!("result: {:?}", result); + println!("result: {result:?}"); assert!(result.is_empty()); let result = without_block_comments(vec!["", "/*", "", "*/", "#[crate_type = \"lib\"]", "/*", "", "*/", ""]); diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index f08275a4ac76b..00a2409996adc 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -310,19 +310,19 @@ impl<'a> Sugg<'a> { /// Convenience method to transform suggestion into a return call pub fn make_return(self) -> Sugg<'static> { - Sugg::NonParen(Cow::Owned(format!("return {}", self))) + Sugg::NonParen(Cow::Owned(format!("return {self}"))) } /// Convenience method to transform suggestion into a block /// where the suggestion is a trailing expression pub fn blockify(self) -> Sugg<'static> { - Sugg::NonParen(Cow::Owned(format!("{{ {} }}", self))) + Sugg::NonParen(Cow::Owned(format!("{{ {self} }}"))) } /// Convenience method to prefix the expression with the `async` keyword. /// Can be used after `blockify` to create an async block. pub fn asyncify(self) -> Sugg<'static> { - Sugg::NonParen(Cow::Owned(format!("async {}", self))) + Sugg::NonParen(Cow::Owned(format!("async {self}"))) } /// Convenience method to create the `..` or `...` @@ -346,12 +346,12 @@ impl<'a> Sugg<'a> { if has_enclosing_paren(&sugg) { Sugg::MaybeParen(sugg) } else { - Sugg::NonParen(format!("({})", sugg).into()) + Sugg::NonParen(format!("({sugg})").into()) } }, Sugg::BinOp(op, lhs, rhs) => { let sugg = binop_to_string(op, &lhs, &rhs); - Sugg::NonParen(format!("({})", sugg).into()) + Sugg::NonParen(format!("({sugg})").into()) }, } } @@ -379,20 +379,18 @@ fn binop_to_string(op: AssocOp, lhs: &str, rhs: &str) -> String { | AssocOp::Greater | AssocOp::GreaterEqual => { format!( - "{} {} {}", - lhs, - op.to_ast_binop().expect("Those are AST ops").to_string(), - rhs + "{lhs} {} {rhs}", + op.to_ast_binop().expect("Those are AST ops").to_string() ) }, - AssocOp::Assign => format!("{} = {}", lhs, rhs), + AssocOp::Assign => format!("{lhs} = {rhs}"), AssocOp::AssignOp(op) => { - format!("{} {}= {}", lhs, token_kind_to_string(&token::BinOp(op)), rhs) + format!("{lhs} {}= {rhs}", token_kind_to_string(&token::BinOp(op))) }, - AssocOp::As => format!("{} as {}", lhs, rhs), - AssocOp::DotDot => format!("{}..{}", lhs, rhs), - AssocOp::DotDotEq => format!("{}..={}", lhs, rhs), - AssocOp::Colon => format!("{}: {}", lhs, rhs), + AssocOp::As => format!("{lhs} as {rhs}"), + AssocOp::DotDot => format!("{lhs}..{rhs}"), + AssocOp::DotDotEq => format!("{lhs}..={rhs}"), + AssocOp::Colon => format!("{lhs}: {rhs}"), } } @@ -523,7 +521,7 @@ impl Display for ParenHelper { /// operators have the same /// precedence. pub fn make_unop(op: &str, expr: Sugg<'_>) -> Sugg<'static> { - Sugg::MaybeParen(format!("{}{}", op, expr.maybe_par()).into()) + Sugg::MaybeParen(format!("{op}{}", expr.maybe_par()).into()) } /// Builds the string for ` ` adding parenthesis when necessary. @@ -744,7 +742,7 @@ impl DiagnosticExt for rustc_errors::Diagnostic { if let Some(indent) = indentation(cx, item) { let span = item.with_hi(item.lo()); - self.span_suggestion(span, msg, format!("{}\n{}", attr, indent), applicability); + self.span_suggestion(span, msg, format!("{attr}\n{indent}"), applicability); } } @@ -758,14 +756,14 @@ impl DiagnosticExt for rustc_errors::Diagnostic { .map(|l| { if first { first = false; - format!("{}\n", l) + format!("{l}\n") } else { - format!("{}{}\n", indent, l) + format!("{indent}{l}\n") } }) .collect::(); - self.span_suggestion(span, msg, format!("{}\n{}", new_item, indent), applicability); + self.span_suggestion(span, msg, format!("{new_item}\n{indent}"), applicability); } } @@ -863,7 +861,7 @@ impl<'tcx> DerefDelegate<'_, 'tcx> { pub fn finish(&mut self) -> String { let end_span = Span::new(self.next_pos, self.closure_span.hi(), self.closure_span.ctxt(), None); let end_snip = snippet_with_applicability(self.cx, end_span, "..", &mut self.applicability); - let sugg = format!("{}{}", self.suggestion_start, end_snip); + let sugg = format!("{}{end_snip}", self.suggestion_start); if self.closure_arg_is_type_annotated_double_ref { sugg.replacen('&', "", 1) } else { @@ -925,7 +923,7 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { if cmt.place.projections.is_empty() { // handle item without any projection, that needs an explicit borrowing // i.e.: suggest `&x` instead of `x` - let _ = write!(self.suggestion_start, "{}&{}", start_snip, ident_str); + let _ = write!(self.suggestion_start, "{start_snip}&{ident_str}"); } else { // cases where a parent `Call` or `MethodCall` is using the item // i.e.: suggest `.contains(&x)` for `.find(|x| [1, 2, 3].contains(x)).is_none()` @@ -940,7 +938,7 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { // given expression is the self argument and will be handled completely by the compiler // i.e.: `|x| x.is_something()` ExprKind::MethodCall(_, self_expr, ..) if self_expr.hir_id == cmt.hir_id => { - let _ = write!(self.suggestion_start, "{}{}", start_snip, ident_str_with_proj); + let _ = write!(self.suggestion_start, "{start_snip}{ident_str_with_proj}"); self.next_pos = span.hi(); return; }, @@ -973,9 +971,9 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { } else { ident_str }; - format!("{}{}", start_snip, ident) + format!("{start_snip}{ident}") } else { - format!("{}&{}", start_snip, ident_str) + format!("{start_snip}&{ident_str}") }; self.suggestion_start.push_str(&ident_sugg); self.next_pos = span.hi(); @@ -1042,13 +1040,13 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { for item in projections { if item.kind == ProjectionKind::Deref { - replacement_str = format!("*{}", replacement_str); + replacement_str = format!("*{replacement_str}"); } } } } - let _ = write!(self.suggestion_start, "{}{}", start_snip, replacement_str); + let _ = write!(self.suggestion_start, "{start_snip}{replacement_str}"); } self.next_pos = span.hi(); } diff --git a/rustc_tools_util/src/lib.rs b/rustc_tools_util/src/lib.rs index 429dddc42ea91..0f98860167010 100644 --- a/rustc_tools_util/src/lib.rs +++ b/rustc_tools_util/src/lib.rs @@ -48,8 +48,8 @@ impl std::fmt::Display for VersionInfo { if (hash_trimmed.len() + date_trimmed.len()) > 0 { write!( f, - "{} {}.{}.{} ({} {})", - self.crate_name, self.major, self.minor, self.patch, hash_trimmed, date_trimmed, + "{} {}.{}.{} ({hash_trimmed} {date_trimmed})", + self.crate_name, self.major, self.minor, self.patch, )?; } else { write!(f, "{} {}.{}.{}", self.crate_name, self.major, self.minor, self.patch)?; @@ -153,7 +153,7 @@ mod test { #[test] fn test_debug_local() { let vi = get_version_info!(); - let s = format!("{:?}", vi); + let s = format!("{vi:?}"); assert_eq!( s, "VersionInfo { crate_name: \"rustc_tools_util\", major: 0, minor: 2, patch: 0 }" diff --git a/tests/integration.rs b/tests/integration.rs index 23a9bef3cccea..330460ff8a5d9 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -9,7 +9,7 @@ use std::process::Command; #[cfg_attr(feature = "integration", test)] fn integration_test() { let repo_name = env::var("INTEGRATION").expect("`INTEGRATION` var not set"); - let repo_url = format!("https://github.com/{}", repo_name); + let repo_url = format!("https://github.com/{repo_name}"); let crate_name = repo_name .split('/') .nth(1) @@ -83,7 +83,7 @@ fn integration_test() { match output.status.code() { Some(0) => println!("Compilation successful"), - Some(code) => eprintln!("Compilation failed. Exit code: {}", code), + Some(code) => eprintln!("Compilation failed. Exit code: {code}"), None => panic!("Process terminated by signal"), } } From 334f4535bd51c550d014f408364390095d99cd30 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Fri, 23 Sep 2022 18:03:44 +0200 Subject: [PATCH 045/114] Stabilize const `BTree{Map,Set}::new` Since `len` and `is_empty` are not const stable yet, this also creates a new feature for them since they previously used the same `const_btree_new` feature. --- tests/ui/crashes/ice-7126.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/ui/crashes/ice-7126.rs b/tests/ui/crashes/ice-7126.rs index ca563ba097851..b2dc2248b5562 100644 --- a/tests/ui/crashes/ice-7126.rs +++ b/tests/ui/crashes/ice-7126.rs @@ -1,13 +1,13 @@ // This test requires a feature gated const fn and will stop working in the future. -#![feature(const_btree_new)] +#![feature(const_btree_len)] use std::collections::BTreeMap; -struct Foo(BTreeMap); +struct Foo(usize); impl Foo { fn new() -> Self { - Self(BTreeMap::new()) + Self(BTreeMap::len(&BTreeMap::::new())) } } From e30b37b84b75dca4622a210ad1ad116d05a1bae9 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Fri, 23 Sep 2022 21:04:54 +0200 Subject: [PATCH 046/114] Fix clippy's const fn stability check for CURRENT_RUSTC_VERSION Since clippy can use a projects MSRV for its lints, it might not want to consider functions as const stable if they have been added lately. Functions that have been stabilized this version use CURRENT_RUSTC_VERSION as their version, which gets then turned into the current version, which might be something like `1.66.0-dev`. The version parser cannot deal with this version, so it has to be stripped off. --- clippy_utils/src/qualify_min_const_fn.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index 405f022868395..f7ce719177268 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -367,10 +367,21 @@ fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: Option) -> bo // Checking MSRV is manually necessary because `rustc` has no such concept. This entire // function could be removed if `rustc` provided a MSRV-aware version of `is_const_fn`. // as a part of an unimplemented MSRV check https://github.com/rust-lang/rust/issues/65262. + + // HACK(nilstrieb): CURRENT_RUSTC_VERSION can return versions like 1.66.0-dev. `rustc-semver` doesn't accept + // the `-dev` version number so we have to strip it off. + let short_version = since + .as_str() + .split('-') + .next() + .expect("rustc_attr::StabilityLevel::Stable::since` is empty"); + + let since = rustc_span::Symbol::intern(short_version); + crate::meets_msrv( msrv, RustcVersion::parse(since.as_str()) - .expect("`rustc_attr::StabilityLevel::Stable::since` is ill-formatted"), + .unwrap_or_else(|err| panic!("`rustc_attr::StabilityLevel::Stable::since` is ill-formatted: `{since}`, {err:?}")), ) } else { // Unstable const fn with the feature enabled. From cc6b375cd3edcee65adc6a7aa3e45a7a50fe8112 Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Fri, 23 Sep 2022 22:20:42 -0400 Subject: [PATCH 047/114] fallout2: rework clippy_dev & _lints fmt inlining * Inline format args where possible * simplify a few complex macros into format str * use formatdoc!() instead format!(indoc!(...)) --- clippy_dev/src/fmt.rs | 6 +- clippy_dev/src/new_lint.rs | 167 ++++++++---------- clippy_dev/src/serve.rs | 4 +- clippy_dev/src/setup/git_hook.rs | 7 +- clippy_dev/src/setup/intellij.rs | 25 +-- clippy_dev/src/setup/vscode.rs | 19 +- clippy_dev/src/update_lints.rs | 98 +++++----- clippy_lints/src/utils/internal_lints.rs | 24 +-- .../internal_lints/metadata_collector.rs | 97 ++++------ 9 files changed, 181 insertions(+), 266 deletions(-) diff --git a/clippy_dev/src/fmt.rs b/clippy_dev/src/fmt.rs index 357cf6fc43aad..2562314418172 100644 --- a/clippy_dev/src/fmt.rs +++ b/clippy_dev/src/fmt.rs @@ -82,16 +82,16 @@ pub fn run(check: bool, verbose: bool) { fn output_err(err: CliError) { match err { CliError::CommandFailed(command, stderr) => { - eprintln!("error: A command failed! `{}`\nstderr: {}", command, stderr); + eprintln!("error: A command failed! `{command}`\nstderr: {stderr}"); }, CliError::IoError(err) => { - eprintln!("error: {}", err); + eprintln!("error: {err}"); }, CliError::RustfmtNotInstalled => { eprintln!("error: rustfmt nightly is not installed."); }, CliError::WalkDirError(err) => { - eprintln!("error: {}", err); + eprintln!("error: {err}"); }, CliError::IntellijSetupActive => { eprintln!( diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index 9a68c6e775d87..cbb2ec7c836cc 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -1,5 +1,5 @@ use crate::clippy_project_root; -use indoc::{indoc, writedoc}; +use indoc::{formatdoc, writedoc}; use std::fmt::Write as _; use std::fs::{self, OpenOptions}; use std::io::prelude::*; @@ -23,7 +23,7 @@ impl Context for io::Result { match self { Ok(t) => Ok(t), Err(e) => { - let message = format!("{}: {}", text.as_ref(), e); + let message = format!("{}: {e}", text.as_ref()); Err(io::Error::new(ErrorKind::Other, message)) }, } @@ -72,7 +72,7 @@ fn create_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> { let lint_contents = get_lint_file_contents(lint, enable_msrv); let lint_path = format!("clippy_lints/src/{}.rs", lint.name); write_file(lint.project_root.join(&lint_path), lint_contents.as_bytes())?; - println!("Generated lint file: `{}`", lint_path); + println!("Generated lint file: `{lint_path}`"); Ok(()) } @@ -86,7 +86,7 @@ fn create_test(lint: &LintData<'_>) -> io::Result<()> { path.push("src"); fs::create_dir(&path)?; - let header = format!("// compile-flags: --crate-name={}", lint_name); + let header = format!("// compile-flags: --crate-name={lint_name}"); write_file(path.join("main.rs"), get_test_file_contents(lint_name, Some(&header)))?; Ok(()) @@ -106,7 +106,7 @@ fn create_test(lint: &LintData<'_>) -> io::Result<()> { let test_contents = get_test_file_contents(lint.name, None); write_file(lint.project_root.join(&test_path), test_contents)?; - println!("Generated test file: `{}`", test_path); + println!("Generated test file: `{test_path}`"); } Ok(()) @@ -184,38 +184,36 @@ pub(crate) fn get_stabilization_version() -> String { } fn get_test_file_contents(lint_name: &str, header_commands: Option<&str>) -> String { - let mut contents = format!( - indoc! {" - #![allow(unused)] - #![warn(clippy::{})] - - fn main() {{ - // test code goes here - }} - "}, - lint_name + let mut contents = formatdoc!( + r#" + #![allow(unused)] + #![warn(clippy::{lint_name})] + + fn main() {{ + // test code goes here + }} + "# ); if let Some(header) = header_commands { - contents = format!("{}\n{}", header, contents); + contents = format!("{header}\n{contents}"); } contents } fn get_manifest_contents(lint_name: &str, hint: &str) -> String { - format!( - indoc! {r#" - # {} - - [package] - name = "{}" - version = "0.1.0" - publish = false - - [workspace] - "#}, - hint, lint_name + formatdoc!( + r#" + # {hint} + + [package] + name = "{lint_name}" + version = "0.1.0" + publish = false + + [workspace] + "# ) } @@ -236,76 +234,61 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { let name_upper = lint_name.to_uppercase(); result.push_str(&if enable_msrv { - format!( - indoc! {" - use clippy_utils::msrvs; - {pass_import} - use rustc_lint::{{{context_import}, {pass_type}, LintContext}}; - use rustc_semver::RustcVersion; - use rustc_session::{{declare_tool_lint, impl_lint_pass}}; + formatdoc!( + r#" + use clippy_utils::msrvs; + {pass_import} + use rustc_lint::{{{context_import}, {pass_type}, LintContext}}; + use rustc_semver::RustcVersion; + use rustc_session::{{declare_tool_lint, impl_lint_pass}}; - "}, - pass_type = pass_type, - pass_import = pass_import, - context_import = context_import, + "# ) } else { - format!( - indoc! {" - {pass_import} - use rustc_lint::{{{context_import}, {pass_type}}}; - use rustc_session::{{declare_lint_pass, declare_tool_lint}}; - - "}, - pass_import = pass_import, - pass_type = pass_type, - context_import = context_import + formatdoc!( + r#" + {pass_import} + use rustc_lint::{{{context_import}, {pass_type}}}; + use rustc_session::{{declare_lint_pass, declare_tool_lint}}; + + "# ) }); let _ = write!(result, "{}", get_lint_declaration(&name_upper, category)); result.push_str(&if enable_msrv { - format!( - indoc! {" - pub struct {name_camel} {{ - msrv: Option, - }} + formatdoc!( + r#" + pub struct {name_camel} {{ + msrv: Option, + }} - impl {name_camel} {{ - #[must_use] - pub fn new(msrv: Option) -> Self {{ - Self {{ msrv }} - }} + impl {name_camel} {{ + #[must_use] + pub fn new(msrv: Option) -> Self {{ + Self {{ msrv }} }} + }} - impl_lint_pass!({name_camel} => [{name_upper}]); + impl_lint_pass!({name_camel} => [{name_upper}]); - impl {pass_type}{pass_lifetimes} for {name_camel} {{ - extract_msrv_attr!({context_import}); - }} + impl {pass_type}{pass_lifetimes} for {name_camel} {{ + extract_msrv_attr!({context_import}); + }} - // TODO: Add MSRV level to `clippy_utils/src/msrvs.rs` if needed. - // TODO: Add MSRV test to `tests/ui/min_rust_version_attr.rs`. - // TODO: Update msrv config comment in `clippy_lints/src/utils/conf.rs` - "}, - pass_type = pass_type, - pass_lifetimes = pass_lifetimes, - name_upper = name_upper, - name_camel = name_camel, - context_import = context_import, + // TODO: Add MSRV level to `clippy_utils/src/msrvs.rs` if needed. + // TODO: Add MSRV test to `tests/ui/min_rust_version_attr.rs`. + // TODO: Update msrv config comment in `clippy_lints/src/utils/conf.rs` + "# ) } else { - format!( - indoc! {" - declare_lint_pass!({name_camel} => [{name_upper}]); + formatdoc!( + r#" + declare_lint_pass!({name_camel} => [{name_upper}]); - impl {pass_type}{pass_lifetimes} for {name_camel} {{}} - "}, - pass_type = pass_type, - pass_lifetimes = pass_lifetimes, - name_upper = name_upper, - name_camel = name_camel, + impl {pass_type}{pass_lifetimes} for {name_camel} {{}} + "# ) }); @@ -313,8 +296,8 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { } fn get_lint_declaration(name_upper: &str, category: &str) -> String { - format!( - indoc! {r#" + formatdoc!( + r#" declare_clippy_lint! {{ /// ### What it does /// @@ -328,15 +311,13 @@ fn get_lint_declaration(name_upper: &str, category: &str) -> String { /// ```rust /// // example code which does not raise clippy warning /// ``` - #[clippy::version = "{version}"] + #[clippy::version = "{}"] pub {name_upper}, {category}, "default lint description" }} - "#}, - version = get_stabilization_version(), - name_upper = name_upper, - category = category, + "#, + get_stabilization_version(), ) } @@ -350,7 +331,7 @@ fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::R _ => {}, } - let ty_dir = lint.project_root.join(format!("clippy_lints/src/{}", ty)); + let ty_dir = lint.project_root.join(format!("clippy_lints/src/{ty}")); assert!( ty_dir.exists() && ty_dir.is_dir(), "Directory `{}` does not exist!", @@ -410,10 +391,10 @@ fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::R } write_file(lint_file_path.as_path(), lint_file_contents)?; - println!("Generated lint file: `clippy_lints/src/{}/{}.rs`", ty, lint.name); + println!("Generated lint file: `clippy_lints/src/{ty}/{}.rs`", lint.name); println!( - "Be sure to add a call to `{}::check` in `clippy_lints/src/{}/mod.rs`!", - lint.name, ty + "Be sure to add a call to `{}::check` in `clippy_lints/src/{ty}/mod.rs`!", + lint.name ); Ok(()) @@ -540,7 +521,7 @@ fn setup_mod_file(path: &Path, lint: &LintData<'_>) -> io::Result<&'static str> .chain(std::iter::once(&*lint_name_upper)) .filter(|s| !s.is_empty()) { - let _ = write!(new_arr_content, "\n {},", ident); + let _ = write!(new_arr_content, "\n {ident},"); } new_arr_content.push('\n'); diff --git a/clippy_dev/src/serve.rs b/clippy_dev/src/serve.rs index f15f24da94671..2e0794f12fa19 100644 --- a/clippy_dev/src/serve.rs +++ b/clippy_dev/src/serve.rs @@ -10,8 +10,8 @@ use std::time::{Duration, SystemTime}; /// Panics if the python commands could not be spawned pub fn run(port: u16, lint: Option<&String>) -> ! { let mut url = Some(match lint { - None => format!("http://localhost:{}", port), - Some(lint) => format!("http://localhost:{}/#{}", port, lint), + None => format!("http://localhost:{port}"), + Some(lint) => format!("http://localhost:{port}/#{lint}"), }); loop { diff --git a/clippy_dev/src/setup/git_hook.rs b/clippy_dev/src/setup/git_hook.rs index 3fbb77d59235c..1de5b1940bae1 100644 --- a/clippy_dev/src/setup/git_hook.rs +++ b/clippy_dev/src/setup/git_hook.rs @@ -30,10 +30,7 @@ pub fn install_hook(force_override: bool) { println!("info: the hook can be removed with `cargo dev remove git-hook`"); println!("git hook successfully installed"); }, - Err(err) => eprintln!( - "error: unable to copy `{}` to `{}` ({})", - HOOK_SOURCE_FILE, HOOK_TARGET_FILE, err - ), + Err(err) => eprintln!("error: unable to copy `{HOOK_SOURCE_FILE}` to `{HOOK_TARGET_FILE}` ({err})"), } } @@ -77,7 +74,7 @@ pub fn remove_hook() { fn delete_git_hook_file(path: &Path) -> bool { if let Err(err) = fs::remove_file(path) { - eprintln!("error: unable to delete existing pre-commit git hook ({})", err); + eprintln!("error: unable to delete existing pre-commit git hook ({err})"); false } else { true diff --git a/clippy_dev/src/setup/intellij.rs b/clippy_dev/src/setup/intellij.rs index bf741e6d1217f..b64e79733eb24 100644 --- a/clippy_dev/src/setup/intellij.rs +++ b/clippy_dev/src/setup/intellij.rs @@ -60,7 +60,7 @@ fn check_and_get_rustc_dir(rustc_path: &str) -> Result { path = absolute_path; }, Err(err) => { - eprintln!("error: unable to get the absolute path of rustc ({})", err); + eprintln!("error: unable to get the absolute path of rustc ({err})"); return Err(()); }, }; @@ -103,14 +103,14 @@ fn inject_deps_into_project(rustc_source_dir: &Path, project: &ClippyProjectInfo fn read_project_file(file_path: &str) -> Result { let path = Path::new(file_path); if !path.exists() { - eprintln!("error: unable to find the file `{}`", file_path); + eprintln!("error: unable to find the file `{file_path}`"); return Err(()); } match fs::read_to_string(path) { Ok(content) => Ok(content), Err(err) => { - eprintln!("error: the file `{}` could not be read ({})", file_path, err); + eprintln!("error: the file `{file_path}` could not be read ({err})"); Err(()) }, } @@ -124,10 +124,7 @@ fn inject_deps_into_manifest( ) -> std::io::Result<()> { // do not inject deps if we have already done so if cargo_toml.contains(RUSTC_PATH_SECTION) { - eprintln!( - "warn: dependencies are already setup inside {}, skipping file", - manifest_path - ); + eprintln!("warn: dependencies are already setup inside {manifest_path}, skipping file"); return Ok(()); } @@ -142,11 +139,7 @@ fn inject_deps_into_manifest( let new_deps = extern_crates.map(|dep| { // format the dependencies that are going to be put inside the Cargo.toml - format!( - "{dep} = {{ path = \"{source_path}/{dep}\" }}\n", - dep = dep, - source_path = rustc_source_dir.display() - ) + format!("{dep} = {{ path = \"{}/{dep}\" }}\n", rustc_source_dir.display()) }); // format a new [dependencies]-block with the new deps we need to inject @@ -163,11 +156,11 @@ fn inject_deps_into_manifest( // etc let new_manifest = cargo_toml.replacen("[dependencies]\n", &all_deps, 1); - // println!("{}", new_manifest); + // println!("{new_manifest}"); let mut file = File::create(manifest_path)?; file.write_all(new_manifest.as_bytes())?; - println!("info: successfully setup dependencies inside {}", manifest_path); + println!("info: successfully setup dependencies inside {manifest_path}"); Ok(()) } @@ -214,8 +207,8 @@ fn remove_rustc_src_from_project(project: &ClippyProjectInfo) -> bool { }, Err(err) => { eprintln!( - "error: unable to open file `{}` to remove rustc dependencies for {} ({})", - project.cargo_file, project.name, err + "error: unable to open file `{}` to remove rustc dependencies for {} ({err})", + project.cargo_file, project.name ); false }, diff --git a/clippy_dev/src/setup/vscode.rs b/clippy_dev/src/setup/vscode.rs index d59001b2c66af..dbcdc9b59e529 100644 --- a/clippy_dev/src/setup/vscode.rs +++ b/clippy_dev/src/setup/vscode.rs @@ -17,10 +17,7 @@ pub fn install_tasks(force_override: bool) { println!("info: the task file can be removed with `cargo dev remove vscode-tasks`"); println!("vscode tasks successfully installed"); }, - Err(err) => eprintln!( - "error: unable to copy `{}` to `{}` ({})", - TASK_SOURCE_FILE, TASK_TARGET_FILE, err - ), + Err(err) => eprintln!("error: unable to copy `{TASK_SOURCE_FILE}` to `{TASK_TARGET_FILE}` ({err})"), } } @@ -44,23 +41,17 @@ fn check_install_precondition(force_override: bool) -> bool { return delete_vs_task_file(path); } - eprintln!( - "error: there is already a `task.json` file inside the `{}` directory", - VSCODE_DIR - ); + eprintln!("error: there is already a `task.json` file inside the `{VSCODE_DIR}` directory"); println!("info: use the `--force-override` flag to override the existing `task.json` file"); return false; } } else { match fs::create_dir(vs_dir_path) { Ok(_) => { - println!("info: created `{}` directory for clippy", VSCODE_DIR); + println!("info: created `{VSCODE_DIR}` directory for clippy"); }, Err(err) => { - eprintln!( - "error: the task target directory `{}` could not be created ({})", - VSCODE_DIR, err - ); + eprintln!("error: the task target directory `{VSCODE_DIR}` could not be created ({err})"); }, } } @@ -82,7 +73,7 @@ pub fn remove_tasks() { fn delete_vs_task_file(path: &Path) -> bool { if let Err(err) = fs::remove_file(path) { - eprintln!("error: unable to delete the existing `tasks.json` file ({})", err); + eprintln!("error: unable to delete the existing `tasks.json` file ({err})"); return false; } diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs index b95061bf81a25..93955bee3f4dd 100644 --- a/clippy_dev/src/update_lints.rs +++ b/clippy_dev/src/update_lints.rs @@ -86,7 +86,7 @@ fn generate_lint_files( ) .sorted() { - writeln!(res, "[`{}`]: {}#{}", lint, DOCS_LINK, lint).unwrap(); + writeln!(res, "[`{lint}`]: {DOCS_LINK}#{lint}").unwrap(); } }, ); @@ -99,7 +99,7 @@ fn generate_lint_files( "// end lints modules, do not remove this comment, it’s used in `update_lints`", |res| { for lint_mod in usable_lints.iter().map(|l| &l.module).unique().sorted() { - writeln!(res, "mod {};", lint_mod).unwrap(); + writeln!(res, "mod {lint_mod};").unwrap(); } }, ); @@ -129,7 +129,7 @@ fn generate_lint_files( for (lint_group, lints) in Lint::by_lint_group(usable_lints.into_iter().chain(internal_lints)) { let content = gen_lint_group_list(&lint_group, lints.iter()); process_file( - &format!("clippy_lints/src/lib.register_{}.rs", lint_group), + &format!("clippy_lints/src/lib.register_{lint_group}.rs"), update_mode, &content, ); @@ -190,9 +190,9 @@ fn print_lint_names(header: &str, lints: &BTreeSet) -> bool { if lints.is_empty() { return false; } - println!("{}", header); + println!("{header}"); for lint in lints.iter().sorted() { - println!(" {}", lint); + println!(" {lint}"); } println!(); true @@ -205,16 +205,16 @@ pub fn print_lints() { let grouped_by_lint_group = Lint::by_lint_group(usable_lints.into_iter()); for (lint_group, mut lints) in grouped_by_lint_group { - println!("\n## {}", lint_group); + println!("\n## {lint_group}"); lints.sort_by_key(|l| l.name.clone()); for lint in lints { - println!("* [{}]({}#{}) ({})", lint.name, DOCS_LINK, lint.name, lint.desc); + println!("* [{}]({DOCS_LINK}#{}) ({})", lint.name, lint.name, lint.desc); } } - println!("there are {} lints", usable_lint_count); + println!("there are {usable_lint_count} lints"); } /// Runs the `rename_lint` command. @@ -235,10 +235,10 @@ pub fn print_lints() { #[allow(clippy::too_many_lines)] pub fn rename(old_name: &str, new_name: &str, uplift: bool) { if let Some((prefix, _)) = old_name.split_once("::") { - panic!("`{}` should not contain the `{}` prefix", old_name, prefix); + panic!("`{old_name}` should not contain the `{prefix}` prefix"); } if let Some((prefix, _)) = new_name.split_once("::") { - panic!("`{}` should not contain the `{}` prefix", new_name, prefix); + panic!("`{new_name}` should not contain the `{prefix}` prefix"); } let (mut lints, deprecated_lints, mut renamed_lints) = gather_all(); @@ -251,14 +251,14 @@ pub fn rename(old_name: &str, new_name: &str, uplift: bool) { found_new_name = true; } } - let old_lint_index = old_lint_index.unwrap_or_else(|| panic!("could not find lint `{}`", old_name)); + let old_lint_index = old_lint_index.unwrap_or_else(|| panic!("could not find lint `{old_name}`")); let lint = RenamedLint { - old_name: format!("clippy::{}", old_name), + old_name: format!("clippy::{old_name}"), new_name: if uplift { new_name.into() } else { - format!("clippy::{}", new_name) + format!("clippy::{new_name}") }, }; @@ -266,13 +266,11 @@ pub fn rename(old_name: &str, new_name: &str, uplift: bool) { // case. assert!( !renamed_lints.iter().any(|l| lint.old_name == l.old_name), - "`{}` has already been renamed", - old_name + "`{old_name}` has already been renamed" ); assert!( !deprecated_lints.iter().any(|l| lint.old_name == l.name), - "`{}` has already been deprecated", - old_name + "`{old_name}` has already been deprecated" ); // Update all lint level attributes. (`clippy::lint_name`) @@ -309,14 +307,12 @@ pub fn rename(old_name: &str, new_name: &str, uplift: bool) { if uplift { write_file(Path::new("tests/ui/rename.rs"), &gen_renamed_lints_test(&renamed_lints)); println!( - "`{}` has be uplifted. All the code inside `clippy_lints` related to it needs to be removed manually.", - old_name + "`{old_name}` has be uplifted. All the code inside `clippy_lints` related to it needs to be removed manually." ); } else if found_new_name { write_file(Path::new("tests/ui/rename.rs"), &gen_renamed_lints_test(&renamed_lints)); println!( - "`{}` is already defined. The old linting code inside `clippy_lints` needs to be updated/removed manually.", - new_name + "`{new_name}` is already defined. The old linting code inside `clippy_lints` needs to be updated/removed manually." ); } else { // Rename the lint struct and source files sharing a name with the lint. @@ -327,16 +323,16 @@ pub fn rename(old_name: &str, new_name: &str, uplift: bool) { // Rename test files. only rename `.stderr` and `.fixed` files if the new test name doesn't exist. if try_rename_file( - Path::new(&format!("tests/ui/{}.rs", old_name)), - Path::new(&format!("tests/ui/{}.rs", new_name)), + Path::new(&format!("tests/ui/{old_name}.rs")), + Path::new(&format!("tests/ui/{new_name}.rs")), ) { try_rename_file( - Path::new(&format!("tests/ui/{}.stderr", old_name)), - Path::new(&format!("tests/ui/{}.stderr", new_name)), + Path::new(&format!("tests/ui/{old_name}.stderr")), + Path::new(&format!("tests/ui/{new_name}.stderr")), ); try_rename_file( - Path::new(&format!("tests/ui/{}.fixed", old_name)), - Path::new(&format!("tests/ui/{}.fixed", new_name)), + Path::new(&format!("tests/ui/{old_name}.fixed")), + Path::new(&format!("tests/ui/{new_name}.fixed")), ); } @@ -344,8 +340,8 @@ pub fn rename(old_name: &str, new_name: &str, uplift: bool) { let replacements; let replacements = if lint.module == old_name && try_rename_file( - Path::new(&format!("clippy_lints/src/{}.rs", old_name)), - Path::new(&format!("clippy_lints/src/{}.rs", new_name)), + Path::new(&format!("clippy_lints/src/{old_name}.rs")), + Path::new(&format!("clippy_lints/src/{new_name}.rs")), ) { // Edit the module name in the lint list. Note there could be multiple lints. for lint in lints.iter_mut().filter(|l| l.module == old_name) { @@ -356,14 +352,14 @@ pub fn rename(old_name: &str, new_name: &str, uplift: bool) { } else if !lint.module.contains("::") // Catch cases like `methods/lint_name.rs` where the lint is stored in `methods/mod.rs` && try_rename_file( - Path::new(&format!("clippy_lints/src/{}/{}.rs", lint.module, old_name)), - Path::new(&format!("clippy_lints/src/{}/{}.rs", lint.module, new_name)), + Path::new(&format!("clippy_lints/src/{}/{old_name}.rs", lint.module)), + Path::new(&format!("clippy_lints/src/{}/{new_name}.rs", lint.module)), ) { // Edit the module name in the lint list. Note there could be multiple lints, or none. - let renamed_mod = format!("{}::{}", lint.module, old_name); + let renamed_mod = format!("{}::{old_name}", lint.module); for lint in lints.iter_mut().filter(|l| l.module == renamed_mod) { - lint.module = format!("{}::{}", lint.module, new_name); + lint.module = format!("{}::{new_name}", lint.module); } replacements = [(&*old_name_upper, &*new_name_upper), (old_name, new_name)]; replacements.as_slice() @@ -379,7 +375,7 @@ pub fn rename(old_name: &str, new_name: &str, uplift: bool) { } generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints); - println!("{} has been successfully renamed", old_name); + println!("{old_name} has been successfully renamed"); } println!("note: `cargo uitest` still needs to be run to update the test results"); @@ -408,7 +404,7 @@ pub fn deprecate(name: &str, reason: Option<&String>) { }); generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints); - println!("info: `{}` has successfully been deprecated", name); + println!("info: `{name}` has successfully been deprecated"); if reason == DEFAULT_DEPRECATION_REASON { println!("note: the deprecation reason must be updated in `clippy_lints/src/deprecated_lints.rs`"); @@ -421,7 +417,7 @@ pub fn deprecate(name: &str, reason: Option<&String>) { let name_upper = name.to_uppercase(); let (mut lints, deprecated_lints, renamed_lints) = gather_all(); - let Some(lint) = lints.iter().find(|l| l.name == name_lower) else { eprintln!("error: failed to find lint `{}`", name); return; }; + let Some(lint) = lints.iter().find(|l| l.name == name_lower) else { eprintln!("error: failed to find lint `{name}`"); return; }; let mod_path = { let mut mod_path = PathBuf::from(format!("clippy_lints/src/{}", lint.module)); @@ -450,7 +446,7 @@ fn remove_lint_declaration(name: &str, path: &Path, lints: &mut Vec) -> io } fn remove_test_assets(name: &str) { - let test_file_stem = format!("tests/ui/{}", name); + let test_file_stem = format!("tests/ui/{name}"); let path = Path::new(&test_file_stem); // Some lints have their own directories, delete them @@ -512,8 +508,7 @@ fn remove_lint_declaration(name: &str, path: &Path, lints: &mut Vec) -> io fs::read_to_string(path).unwrap_or_else(|_| panic!("failed to read `{}`", path.to_string_lossy())); eprintln!( - "warn: you will have to manually remove any code related to `{}` from `{}`", - name, + "warn: you will have to manually remove any code related to `{name}` from `{}`", path.display() ); @@ -528,7 +523,7 @@ fn remove_lint_declaration(name: &str, path: &Path, lints: &mut Vec) -> io content.replace_range(lint.declaration_range.clone(), ""); // Remove the module declaration (mod xyz;) - let mod_decl = format!("\nmod {};", name); + let mod_decl = format!("\nmod {name};"); content = content.replacen(&mod_decl, "", 1); remove_impl_lint_pass(&lint.name.to_uppercase(), &mut content); @@ -621,13 +616,13 @@ fn round_to_fifty(count: usize) -> usize { fn process_file(path: impl AsRef, update_mode: UpdateMode, content: &str) { if update_mode == UpdateMode::Check { let old_content = - fs::read_to_string(&path).unwrap_or_else(|e| panic!("Cannot read from {}: {}", path.as_ref().display(), e)); + fs::read_to_string(&path).unwrap_or_else(|e| panic!("Cannot read from {}: {e}", path.as_ref().display())); if content != old_content { exit_with_failure(); } } else { fs::write(&path, content.as_bytes()) - .unwrap_or_else(|e| panic!("Cannot write to {}: {}", path.as_ref().display(), e)); + .unwrap_or_else(|e| panic!("Cannot write to {}: {e}", path.as_ref().display())); } } @@ -731,11 +726,10 @@ fn gen_lint_group_list<'a>(group_name: &str, lints: impl Iterator( if !is_public { output.push_str(" #[cfg(feature = \"internal\")]\n"); } - let _ = writeln!(output, " {}::{},", module_name, lint_name); + let _ = writeln!(output, " {module_name}::{lint_name},"); } output.push_str("])\n"); @@ -841,7 +835,7 @@ fn gather_all() -> (Vec, Vec, Vec) { for (rel_path, file) in clippy_lints_src_files() { let path = file.path(); let contents = - fs::read_to_string(path).unwrap_or_else(|e| panic!("Cannot read from `{}`: {}", path.display(), e)); + fs::read_to_string(path).unwrap_or_else(|e| panic!("Cannot read from `{}`: {e}", path.display())); let module = rel_path .components() .map(|c| c.as_os_str().to_str().unwrap()) @@ -1050,7 +1044,7 @@ fn remove_line_splices(s: &str) -> String { .trim_matches('#') .strip_prefix('"') .and_then(|s| s.strip_suffix('"')) - .unwrap_or_else(|| panic!("expected quoted string, found `{}`", s)); + .unwrap_or_else(|| panic!("expected quoted string, found `{s}`")); let mut res = String::with_capacity(s.len()); unescape::unescape_literal(s, unescape::Mode::Str, &mut |range, ch| { if ch.is_ok() { @@ -1076,10 +1070,10 @@ fn replace_region_in_file( end: &str, write_replacement: impl FnMut(&mut String), ) { - let contents = fs::read_to_string(path).unwrap_or_else(|e| panic!("Cannot read from `{}`: {}", path.display(), e)); + let contents = fs::read_to_string(path).unwrap_or_else(|e| panic!("Cannot read from `{}`: {e}", path.display())); let new_contents = match replace_region_in_text(&contents, start, end, write_replacement) { Ok(x) => x, - Err(delim) => panic!("Couldn't find `{}` in file `{}`", delim, path.display()), + Err(delim) => panic!("Couldn't find `{delim}` in file `{}`", path.display()), }; match update_mode { @@ -1087,7 +1081,7 @@ fn replace_region_in_file( UpdateMode::Check => (), UpdateMode::Change => { if let Err(e) = fs::write(path, new_contents.as_bytes()) { - panic!("Cannot write to `{}`: {}", path.display(), e); + panic!("Cannot write to `{}`: {e}", path.display()); } }, } @@ -1135,7 +1129,7 @@ fn try_rename_file(old_name: &Path, new_name: &Path) -> bool { #[allow(clippy::needless_pass_by_value)] fn panic_file(error: io::Error, name: &Path, action: &str) -> ! { - panic!("failed to {} file `{}`: {}", action, name.display(), error) + panic!("failed to {action} file `{}`: {error}", name.display()) } fn rewrite_file(path: &Path, f: impl FnOnce(&str) -> Option) { diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index 17d9a04185767..5332779c1c051 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -530,7 +530,7 @@ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass { cx, LINT_WITHOUT_LINT_PASS, lint_span, - &format!("the lint `{}` is not added to any `LintPass`", lint_name), + &format!("the lint `{lint_name}` is not added to any `LintPass`"), ); } } @@ -666,7 +666,7 @@ impl<'tcx> LateLintPass<'tcx> for CompilerLintFunctions { path.ident.span, "usage of a compiler lint function", None, - &format!("please use the Clippy variant of this function: `{}`", sugg), + &format!("please use the Clippy variant of this function: `{sugg}`"), ); } } @@ -854,13 +854,8 @@ fn suggest_help( "this call is collapsible", "collapse into", format!( - "span_lint_and_help({}, {}, {}, {}, {}, {})", - and_then_snippets.cx, - and_then_snippets.lint, - and_then_snippets.span, - and_then_snippets.msg, - &option_span, - help + "span_lint_and_help({}, {}, {}, {}, {}, {help})", + and_then_snippets.cx, and_then_snippets.lint, and_then_snippets.span, and_then_snippets.msg, &option_span, ), Applicability::MachineApplicable, ); @@ -886,13 +881,8 @@ fn suggest_note( "this call is collapsible", "collapse into", format!( - "span_lint_and_note({}, {}, {}, {}, {}, {})", - and_then_snippets.cx, - and_then_snippets.lint, - and_then_snippets.span, - and_then_snippets.msg, - note_span, - note + "span_lint_and_note({}, {}, {}, {}, {note_span}, {note})", + and_then_snippets.cx, and_then_snippets.lint, and_then_snippets.span, and_then_snippets.msg, ), Applicability::MachineApplicable, ); @@ -927,7 +917,7 @@ impl<'tcx> LateLintPass<'tcx> for MatchTypeOnDiagItem { expr.span, "usage of `clippy_utils::ty::match_type()` on a type diagnostic item", "try", - format!("clippy_utils::ty::is_type_diagnostic_item({}, {}, sym::{})", cx_snippet, ty_snippet, item_name), + format!("clippy_utils::ty::is_type_diagnostic_item({cx_snippet}, {ty_snippet}, sym::{item_name})"), Applicability::MaybeIncorrect, ); } diff --git a/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/clippy_lints/src/utils/internal_lints/metadata_collector.rs index 342f627e38275..c84191bb01034 100644 --- a/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ b/clippy_lints/src/utils/internal_lints/metadata_collector.rs @@ -64,46 +64,6 @@ const DEFAULT_LINT_LEVELS: &[(&str, &str)] = &[ /// This prefix is in front of the lint groups in the lint store. The prefix will be trimmed /// to only keep the actual lint group in the output. const CLIPPY_LINT_GROUP_PREFIX: &str = "clippy::"; - -/// This template will be used to format the configuration section in the lint documentation. -/// The `configurations` parameter will be replaced with one or multiple formatted -/// `ClippyConfiguration` instances. See `CONFIGURATION_VALUE_TEMPLATE` for further customizations -macro_rules! CONFIGURATION_SECTION_TEMPLATE { - () => { - r#" -### Configuration -This lint has the following configuration variables: - -{configurations} -"# - }; -} -/// This template will be used to format an individual `ClippyConfiguration` instance in the -/// lint documentation. -/// -/// The format function will provide strings for the following parameters: `name`, `ty`, `doc` and -/// `default` -macro_rules! CONFIGURATION_VALUE_TEMPLATE { - () => { - "* `{name}`: `{ty}`: {doc} (defaults to `{default}`)\n" - }; -} - -macro_rules! RENAMES_SECTION_TEMPLATE { - () => { - r#" -### Past names - -{names} -"# - }; -} -macro_rules! RENAME_VALUE_TEMPLATE { - () => { - "* `{name}`\n" - }; -} - const LINT_EMISSION_FUNCTIONS: [&[&str]; 7] = [ &["clippy_utils", "diagnostics", "span_lint"], &["clippy_utils", "diagnostics", "span_lint_and_help"], @@ -205,7 +165,16 @@ impl MetadataCollector { .filter(|config| config.lints.iter().any(|lint| lint == lint_name)) .map(ToString::to_string) .reduce(|acc, x| acc + &x) - .map(|configurations| format!(CONFIGURATION_SECTION_TEMPLATE!(), configurations = configurations)) + .map(|configurations| { + format!( + r#" +### Configuration +This lint has the following configuration variables: + +{configurations} +"# + ) + }) } } @@ -291,16 +260,13 @@ fn replace_produces(lint_name: &str, docs: &mut String, clippy_project_root: &Pa continue; } - panic!("lint `{}` has an unterminated code block", lint_name) + panic!("lint `{lint_name}` has an unterminated code block") } break; }, Some(line) if line.trim_start() == "{{produces}}" => { - panic!( - "lint `{}` has marker {{{{produces}}}} with an ignored or missing code block", - lint_name - ) + panic!("lint `{lint_name}` has marker {{{{produces}}}} with an ignored or missing code block") }, Some(line) => { let line = line.trim(); @@ -319,7 +285,7 @@ fn replace_produces(lint_name: &str, docs: &mut String, clippy_project_root: &Pa match lines.next() { Some(line) if line.trim_start() == "```" => break, Some(line) => example.push(line), - None => panic!("lint `{}` has an unterminated code block", lint_name), + None => panic!("lint `{lint_name}` has an unterminated code block"), } } @@ -336,10 +302,9 @@ fn replace_produces(lint_name: &str, docs: &mut String, clippy_project_root: &Pa Produces\n\ \n\ ```text\n\ - {}\n\ + {output}\n\ ```\n\ - ", - output + " ), ); @@ -394,7 +359,7 @@ fn get_lint_output(lint_name: &str, example: &[&mut String], clippy_project_root panic!("failed to write to `{}`: {e}", file.as_path().to_string_lossy()); } - let prefixed_name = format!("{}{lint_name}", CLIPPY_LINT_GROUP_PREFIX); + let prefixed_name = format!("{CLIPPY_LINT_GROUP_PREFIX}{lint_name}"); let mut cmd = Command::new("cargo"); @@ -417,7 +382,7 @@ fn get_lint_output(lint_name: &str, example: &[&mut String], clippy_project_root let output = cmd .arg(file.as_path()) .output() - .unwrap_or_else(|e| panic!("failed to run `{:?}`: {e}", cmd)); + .unwrap_or_else(|e| panic!("failed to run `{cmd:?}`: {e}")); let tmp_file_path = file.to_string_lossy(); let stderr = std::str::from_utf8(&output.stderr).unwrap(); @@ -441,8 +406,7 @@ fn get_lint_output(lint_name: &str, example: &[&mut String], clippy_project_root let rendered: Vec<&str> = msgs.iter().filter_map(|msg| msg["rendered"].as_str()).collect(); let non_json: Vec<&str> = stderr.lines().filter(|line| !line.starts_with('{')).collect(); panic!( - "did not find lint `{}` in output of example, got:\n{}\n{}", - lint_name, + "did not find lint `{lint_name}` in output of example, got:\n{}\n{}", non_json.join("\n"), rendered.join("\n") ); @@ -588,13 +552,10 @@ fn to_kebab(config_name: &str) -> String { impl fmt::Display for ClippyConfiguration { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> fmt::Result { - write!( + writeln!( f, - CONFIGURATION_VALUE_TEMPLATE!(), - name = self.name, - ty = self.config_type, - doc = self.doc, - default = self.default + "* `{}`: `{}`: {} (defaults to `{}`)", + self.name, self.config_type, self.doc, self.default ) } } @@ -811,7 +772,7 @@ fn get_lint_group_and_level_or_lint( lint_collection_error_item( cx, item, - &format!("Unable to determine lint level for found group `{}`", group), + &format!("Unable to determine lint level for found group `{group}`"), ); None } @@ -869,7 +830,7 @@ fn collect_renames(lints: &mut Vec) { if name == lint_name; if let Some(past_name) = k.strip_prefix(CLIPPY_LINT_GROUP_PREFIX); then { - write!(collected, RENAME_VALUE_TEMPLATE!(), name = past_name).unwrap(); + writeln!(collected, "* `{past_name}`").unwrap(); names.push(past_name.to_string()); } } @@ -882,7 +843,15 @@ fn collect_renames(lints: &mut Vec) { } if !collected.is_empty() { - write!(&mut lint.docs, RENAMES_SECTION_TEMPLATE!(), names = collected).unwrap(); + write!( + &mut lint.docs, + r#" +### Past names + +{collected} +"# + ) + .unwrap(); } } } @@ -895,7 +864,7 @@ fn lint_collection_error_item(cx: &LateContext<'_>, item: &Item<'_>, message: &s cx, INTERNAL_METADATA_COLLECTOR, item.ident.span, - &format!("metadata collection error for `{}`: {}", item.ident.name, message), + &format!("metadata collection error for `{}`: {message}", item.ident.name), ); } From fc77d91469244bbba292d6746d7f206dbba812b5 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Wed, 21 Sep 2022 12:29:05 +0000 Subject: [PATCH 048/114] Add `cargo lintcheck --recursive` to check dependencies of crates --- lintcheck/Cargo.toml | 2 + lintcheck/README.md | 20 +++- lintcheck/lintcheck_crates.toml | 8 ++ lintcheck/src/config.rs | 10 +- lintcheck/src/driver.rs | 67 +++++++++++++ lintcheck/src/main.rs | 164 +++++++++++++++++++++----------- lintcheck/src/recursive.rs | 123 ++++++++++++++++++++++++ 7 files changed, 339 insertions(+), 55 deletions(-) create mode 100644 lintcheck/src/driver.rs create mode 100644 lintcheck/src/recursive.rs diff --git a/lintcheck/Cargo.toml b/lintcheck/Cargo.toml index 737c845c04515..de31c16b819ef 100644 --- a/lintcheck/Cargo.toml +++ b/lintcheck/Cargo.toml @@ -12,9 +12,11 @@ publish = false [dependencies] cargo_metadata = "0.14" clap = "3.2" +crossbeam-channel = "0.5.6" flate2 = "1.0" rayon = "1.5.1" serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0.85" tar = "0.4" toml = "0.5" ureq = "2.2" diff --git a/lintcheck/README.md b/lintcheck/README.md index 6f3d23382ce15..6142de5e3130e 100644 --- a/lintcheck/README.md +++ b/lintcheck/README.md @@ -69,9 +69,27 @@ is checked. is explicitly specified in the options. ### Fix mode -You can run `./lintcheck/target/debug/lintcheck --fix` which will run Clippy with `--fix` and +You can run `cargo lintcheck --fix` which will run Clippy with `--fix` and print a warning if Clippy's suggestions fail to apply (if the resulting code does not build). This lets us spot bad suggestions or false positives automatically in some cases. Please note that the target dir should be cleaned afterwards since clippy will modify the downloaded sources which can lead to unexpected results when running lintcheck again afterwards. + +### Recursive mode +You can run `cargo lintcheck --recursive` to also run Clippy on the dependencies +of the crates listed in the crates source `.toml`. e.g. adding `rand 0.8.5` +would also lint `rand_core`, `rand_chacha`, etc. + +Particularly slow crates in the dependency graph can be ignored using +`recursive.ignore`: + +```toml +[crates] +cargo = {name = "cargo", versions = ['0.64.0']} + +[recursive] +ignore = [ + "unicode-normalization", +] +``` diff --git a/lintcheck/lintcheck_crates.toml b/lintcheck/lintcheck_crates.toml index ebbe9c9ae675f..52f7fee47b616 100644 --- a/lintcheck/lintcheck_crates.toml +++ b/lintcheck/lintcheck_crates.toml @@ -33,3 +33,11 @@ cfg-expr = {name = "cfg-expr", versions = ['0.7.1']} puffin = {name = "puffin", git_url = "https://github.com/EmbarkStudios/puffin", git_hash = "02dd4a3"} rpmalloc = {name = "rpmalloc", versions = ['0.2.0']} tame-oidc = {name = "tame-oidc", versions = ['0.1.0']} + +[recursive] +ignore = [ + # Takes ~30s to lint + "combine", + # Has 1.2 million `clippy::match_same_arms`s + "unicode-normalization", +] diff --git a/lintcheck/src/config.rs b/lintcheck/src/config.rs index 1742cf677c0f9..b344db634f612 100644 --- a/lintcheck/src/config.rs +++ b/lintcheck/src/config.rs @@ -34,11 +34,16 @@ fn get_clap_config() -> ArgMatches { Arg::new("markdown") .long("markdown") .help("Change the reports table to use markdown links"), + Arg::new("recursive") + .long("--recursive") + .help("Run clippy on the dependencies of crates specified in crates-toml") + .conflicts_with("threads") + .conflicts_with("fix"), ]) .get_matches() } -#[derive(Debug)] +#[derive(Debug, Clone)] pub(crate) struct LintcheckConfig { /// max number of jobs to spawn (default 1) pub max_jobs: usize, @@ -54,6 +59,8 @@ pub(crate) struct LintcheckConfig { pub lint_filter: Vec, /// Indicate if the output should support markdown syntax pub markdown: bool, + /// Run clippy on the dependencies of crates + pub recursive: bool, } impl LintcheckConfig { @@ -119,6 +126,7 @@ impl LintcheckConfig { fix: clap_config.contains_id("fix"), lint_filter, markdown, + recursive: clap_config.contains_id("recursive"), } } } diff --git a/lintcheck/src/driver.rs b/lintcheck/src/driver.rs new file mode 100644 index 0000000000000..63221bab32d31 --- /dev/null +++ b/lintcheck/src/driver.rs @@ -0,0 +1,67 @@ +use crate::recursive::{deserialize_line, serialize_line, DriverInfo}; + +use std::io::{self, BufReader, Write}; +use std::net::TcpStream; +use std::process::{self, Command, Stdio}; +use std::{env, mem}; + +/// 1. Sends [DriverInfo] to the [crate::recursive::LintcheckServer] running on `addr` +/// 2. Receives [bool] from the server, if `false` returns `None` +/// 3. Otherwise sends the stderr of running `clippy-driver` to the server +fn run_clippy(addr: &str) -> Option { + let driver_info = DriverInfo { + package_name: env::var("CARGO_PKG_NAME").ok()?, + crate_name: env::var("CARGO_CRATE_NAME").ok()?, + version: env::var("CARGO_PKG_VERSION").ok()?, + }; + + let mut stream = BufReader::new(TcpStream::connect(addr).unwrap()); + + serialize_line(&driver_info, stream.get_mut()); + + let should_run = deserialize_line::(&mut stream); + if !should_run { + return None; + } + + // Remove --cap-lints allow so that clippy runs and lints are emitted + let mut include_next = true; + let args = env::args().skip(1).filter(|arg| match arg.as_str() { + "--cap-lints=allow" => false, + "--cap-lints" => { + include_next = false; + false + }, + _ => mem::replace(&mut include_next, true), + }); + + let output = Command::new(env::var("CLIPPY_DRIVER").expect("missing env CLIPPY_DRIVER")) + .args(args) + .stdout(Stdio::inherit()) + .output() + .expect("failed to run clippy-driver"); + + stream + .get_mut() + .write_all(&output.stderr) + .unwrap_or_else(|e| panic!("{e:?} in {driver_info:?}")); + + match output.status.code() { + Some(0) => Some(0), + code => { + io::stderr().write_all(&output.stderr).unwrap(); + Some(code.expect("killed by signal")) + }, + } +} + +pub fn drive(addr: &str) { + process::exit(run_clippy(addr).unwrap_or_else(|| { + Command::new("rustc") + .args(env::args_os().skip(2)) + .status() + .unwrap() + .code() + .unwrap() + })) +} diff --git a/lintcheck/src/main.rs b/lintcheck/src/main.rs index 9ee25280f046f..cc2b3e1acec71 100644 --- a/lintcheck/src/main.rs +++ b/lintcheck/src/main.rs @@ -8,13 +8,17 @@ #![allow(clippy::collapsible_else_if)] mod config; +mod driver; +mod recursive; -use config::LintcheckConfig; +use crate::config::LintcheckConfig; +use crate::recursive::LintcheckServer; -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::env; +use std::env::consts::EXE_SUFFIX; use std::fmt::Write as _; -use std::fs::write; +use std::fs; use std::io::ErrorKind; use std::path::{Path, PathBuf}; use std::process::Command; @@ -22,22 +26,12 @@ use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread; use std::time::Duration; -use cargo_metadata::diagnostic::DiagnosticLevel; +use cargo_metadata::diagnostic::{Diagnostic, DiagnosticLevel}; use cargo_metadata::Message; use rayon::prelude::*; use serde::{Deserialize, Serialize}; use walkdir::{DirEntry, WalkDir}; -#[cfg(not(windows))] -const CLIPPY_DRIVER_PATH: &str = "target/debug/clippy-driver"; -#[cfg(not(windows))] -const CARGO_CLIPPY_PATH: &str = "target/debug/cargo-clippy"; - -#[cfg(windows)] -const CLIPPY_DRIVER_PATH: &str = "target/debug/clippy-driver.exe"; -#[cfg(windows)] -const CARGO_CLIPPY_PATH: &str = "target/debug/cargo-clippy.exe"; - const LINTCHECK_DOWNLOADS: &str = "target/lintcheck/downloads"; const LINTCHECK_SOURCES: &str = "target/lintcheck/sources"; @@ -45,6 +39,13 @@ const LINTCHECK_SOURCES: &str = "target/lintcheck/sources"; #[derive(Debug, Serialize, Deserialize)] struct SourceList { crates: HashMap, + #[serde(default)] + recursive: RecursiveOptions, +} + +#[derive(Debug, Serialize, Deserialize, Default)] +struct RecursiveOptions { + ignore: HashSet, } /// A crate source stored inside the .toml @@ -105,12 +106,7 @@ struct ClippyWarning { #[allow(unused)] impl ClippyWarning { - fn new(cargo_message: Message, krate: &Crate) -> Option { - let diag = match cargo_message { - Message::CompilerMessage(message) => message.message, - _ => return None, - }; - + fn new(diag: Diagnostic, crate_name: &str, crate_version: &str) -> Option { let lint_type = diag.code?.code; if !(lint_type.contains("clippy") || diag.message.contains("clippy")) || diag.message.contains("could not read cargo metadata") @@ -124,12 +120,12 @@ impl ClippyWarning { Ok(stripped) => format!("$CARGO_HOME/{}", stripped.display()), Err(_) => format!( "target/lintcheck/sources/{}-{}/{}", - krate.name, krate.version, span.file_name + crate_name, crate_version, span.file_name ), }; Some(Self { - crate_name: krate.name.clone(), + crate_name: crate_name.to_owned(), file, line: span.line_start, column: span.column_start, @@ -142,8 +138,6 @@ impl ClippyWarning { fn to_output(&self, markdown: bool) -> String { let file_with_pos = format!("{}:{}:{}", &self.file, &self.line, &self.column); if markdown { - let lint = format!("`{}`", self.lint_type); - let mut file = self.file.clone(); if !file.starts_with('$') { file.insert_str(0, "../"); @@ -151,7 +145,7 @@ impl ClippyWarning { let mut output = String::from("| "); let _ = write!(output, "[`{}`]({}#L{})", file_with_pos, file, self.line); - let _ = write!(output, r#" | {:<50} | "{}" |"#, lint, self.message); + let _ = write!(output, r#" | `{:<50}` | "{}" |"#, self.lint_type, self.message); output.push('\n'); output } else { @@ -243,6 +237,7 @@ impl CrateSource { } // check out the commit/branch/whatever if !Command::new("git") + .args(["-c", "advice.detachedHead=false"]) .arg("checkout") .arg(commit) .current_dir(&repo_path) @@ -309,10 +304,12 @@ impl Crate { fn run_clippy_lints( &self, cargo_clippy_path: &Path, + clippy_driver_path: &Path, target_dir_index: &AtomicUsize, total_crates_to_lint: usize, config: &LintcheckConfig, lint_filter: &Vec, + server: &Option, ) -> Vec { // advance the atomic index by one let index = target_dir_index.fetch_add(1, Ordering::SeqCst); @@ -336,36 +333,67 @@ impl Crate { let shared_target_dir = clippy_project_root().join("target/lintcheck/shared_target_dir"); - let mut args = if config.fix { + let mut cargo_clippy_args = if config.fix { vec!["--fix", "--"] } else { vec!["--", "--message-format=json", "--"] }; + let mut clippy_args = Vec::<&str>::new(); if let Some(options) = &self.options { for opt in options { - args.push(opt); + clippy_args.push(opt); } } else { - args.extend(&["-Wclippy::pedantic", "-Wclippy::cargo"]) + clippy_args.extend(&["-Wclippy::pedantic", "-Wclippy::cargo"]) } if lint_filter.is_empty() { - args.push("--cap-lints=warn"); + clippy_args.push("--cap-lints=warn"); } else { - args.push("--cap-lints=allow"); - args.extend(lint_filter.iter().map(|filter| filter.as_str())) + clippy_args.push("--cap-lints=allow"); + clippy_args.extend(lint_filter.iter().map(|filter| filter.as_str())) + } + + if let Some(server) = server { + let target = shared_target_dir.join("recursive"); + + // `cargo clippy` is a wrapper around `cargo check` that mainly sets `RUSTC_WORKSPACE_WRAPPER` to + // `clippy-driver`. We do the same thing here with a couple changes: + // + // `RUSTC_WRAPPER` is used instead of `RUSTC_WORKSPACE_WRAPPER` so that we can lint all crate + // dependencies rather than only workspace members + // + // The wrapper is set to the `lintcheck` so we can force enable linting and ignore certain crates + // (see `crate::driver`) + let status = Command::new("cargo") + .arg("check") + .arg("--quiet") + .current_dir(&self.path) + .env("CLIPPY_ARGS", clippy_args.join("__CLIPPY_HACKERY__")) + .env("CARGO_TARGET_DIR", target) + .env("RUSTC_WRAPPER", env::current_exe().unwrap()) + // Pass the absolute path so `crate::driver` can find `clippy-driver`, as it's executed in various + // different working directories + .env("CLIPPY_DRIVER", clippy_driver_path) + .env("LINTCHECK_SERVER", server.local_addr.to_string()) + .status() + .expect("failed to run cargo"); + + assert_eq!(status.code(), Some(0)); + + return Vec::new(); } - let all_output = std::process::Command::new(&cargo_clippy_path) + cargo_clippy_args.extend(clippy_args); + + let all_output = Command::new(&cargo_clippy_path) // use the looping index to create individual target dirs .env( "CARGO_TARGET_DIR", shared_target_dir.join(format!("_{:?}", thread_index)), ) - // lint warnings will look like this: - // src/cargo/ops/cargo_compile.rs:127:35: warning: usage of `FromIterator::from_iter` - .args(&args) + .args(&cargo_clippy_args) .current_dir(&self.path) .output() .unwrap_or_else(|error| { @@ -404,7 +432,10 @@ impl Crate { // get all clippy warnings and ICEs let warnings: Vec = Message::parse_stream(stdout.as_bytes()) - .filter_map(|msg| ClippyWarning::new(msg.unwrap(), &self)) + .filter_map(|msg| match msg { + Ok(Message::CompilerMessage(message)) => ClippyWarning::new(message.message, &self.name, &self.version), + _ => None, + }) .collect(); warnings @@ -423,8 +454,8 @@ fn build_clippy() { } } -/// Read a `toml` file and return a list of `CrateSources` that we want to check with clippy -fn read_crates(toml_path: &Path) -> Vec { +/// Read a `lintcheck_crates.toml` file +fn read_crates(toml_path: &Path) -> (Vec, RecursiveOptions) { let toml_content: String = std::fs::read_to_string(&toml_path).unwrap_or_else(|_| panic!("Failed to read {}", toml_path.display())); let crate_list: SourceList = @@ -484,7 +515,7 @@ fn read_crates(toml_path: &Path) -> Vec { // sort the crates crate_sources.sort(); - crate_sources + (crate_sources, crate_list.recursive) } /// Generate a short list of occurring lints-types and their count @@ -516,20 +547,20 @@ fn gather_stats(clippy_warnings: &[ClippyWarning]) -> (String, HashMap<&String, /// check if the latest modification of the logfile is older than the modification date of the /// clippy binary, if this is true, we should clean the lintchec shared target directory and recheck -fn lintcheck_needs_rerun(lintcheck_logs_path: &Path) -> bool { +fn lintcheck_needs_rerun(lintcheck_logs_path: &Path, paths: [&Path; 2]) -> bool { if !lintcheck_logs_path.exists() { return true; } let clippy_modified: std::time::SystemTime = { - let mut times = [CLIPPY_DRIVER_PATH, CARGO_CLIPPY_PATH].iter().map(|p| { + let [cargo, driver] = paths.map(|p| { std::fs::metadata(p) .expect("failed to get metadata of file") .modified() .expect("failed to get modification date") }); // the oldest modification of either of the binaries - std::cmp::max(times.next().unwrap(), times.next().unwrap()) + std::cmp::max(cargo, driver) }; let logs_modified: std::time::SystemTime = std::fs::metadata(lintcheck_logs_path) @@ -543,6 +574,11 @@ fn lintcheck_needs_rerun(lintcheck_logs_path: &Path) -> bool { } fn main() { + // We're being executed as a `RUSTC_WRAPPER` as part of `--recursive` + if let Ok(addr) = env::var("LINTCHECK_SERVER") { + driver::drive(&addr); + } + // assert that we launch lintcheck from the repo root (via cargo lintcheck) if std::fs::metadata("lintcheck/Cargo.toml").is_err() { eprintln!("lintcheck needs to be run from clippy's repo root!\nUse `cargo lintcheck` alternatively."); @@ -555,9 +591,15 @@ fn main() { build_clippy(); println!("Done compiling"); + let cargo_clippy_path = fs::canonicalize(format!("target/debug/cargo-clippy{EXE_SUFFIX}")).unwrap(); + let clippy_driver_path = fs::canonicalize(format!("target/debug/clippy-driver{EXE_SUFFIX}")).unwrap(); + // if the clippy bin is newer than our logs, throw away target dirs to force clippy to // refresh the logs - if lintcheck_needs_rerun(&config.lintcheck_results_path) { + if lintcheck_needs_rerun( + &config.lintcheck_results_path, + [&cargo_clippy_path, &clippy_driver_path], + ) { let shared_target_dir = "target/lintcheck/shared_target_dir"; // if we get an Err here, the shared target dir probably does simply not exist if let Ok(metadata) = std::fs::metadata(&shared_target_dir) { @@ -569,10 +611,6 @@ fn main() { } } - let cargo_clippy_path: PathBuf = PathBuf::from(CARGO_CLIPPY_PATH) - .canonicalize() - .expect("failed to canonicalize path to clippy binary"); - // assert that clippy is found assert!( cargo_clippy_path.is_file(), @@ -580,7 +618,7 @@ fn main() { cargo_clippy_path.display() ); - let clippy_ver = std::process::Command::new(CARGO_CLIPPY_PATH) + let clippy_ver = std::process::Command::new(&cargo_clippy_path) .arg("--version") .output() .map(|o| String::from_utf8_lossy(&o.stdout).into_owned()) @@ -589,7 +627,7 @@ fn main() { // download and extract the crates, then run clippy on them and collect clippy's warnings // flatten into one big list of warnings - let crates = read_crates(&config.sources_toml_path); + let (crates, recursive_options) = read_crates(&config.sources_toml_path); let old_stats = read_stats_from_file(&config.lintcheck_results_path); let counter = AtomicUsize::new(1); @@ -639,11 +677,31 @@ fn main() { .build_global() .unwrap(); - let clippy_warnings: Vec = crates + let server = config.recursive.then(|| { + let _ = fs::remove_dir_all("target/lintcheck/shared_target_dir/recursive"); + + LintcheckServer::spawn(recursive_options) + }); + + let mut clippy_warnings: Vec = crates .par_iter() - .flat_map(|krate| krate.run_clippy_lints(&cargo_clippy_path, &counter, crates.len(), &config, &lint_filter)) + .flat_map(|krate| { + krate.run_clippy_lints( + &cargo_clippy_path, + &clippy_driver_path, + &counter, + crates.len(), + &config, + &lint_filter, + &server, + ) + }) .collect(); + if let Some(server) = server { + clippy_warnings.extend(server.warnings()); + } + // if we are in --fix mode, don't change the log files, terminate here if config.fix { return; @@ -681,8 +739,8 @@ fn main() { } println!("Writing logs to {}", config.lintcheck_results_path.display()); - std::fs::create_dir_all(config.lintcheck_results_path.parent().unwrap()).unwrap(); - write(&config.lintcheck_results_path, text).unwrap(); + fs::create_dir_all(config.lintcheck_results_path.parent().unwrap()).unwrap(); + fs::write(&config.lintcheck_results_path, text).unwrap(); print_stats(old_stats, new_stats, &config.lint_filter); } diff --git a/lintcheck/src/recursive.rs b/lintcheck/src/recursive.rs new file mode 100644 index 0000000000000..67dcfc2b199c4 --- /dev/null +++ b/lintcheck/src/recursive.rs @@ -0,0 +1,123 @@ +//! In `--recursive` mode we set the `lintcheck` binary as the `RUSTC_WRAPPER` of `cargo check`, +//! this allows [crate::driver] to be run for every dependency. The driver connects to +//! [LintcheckServer] to ask if it should be skipped, and if not sends the stderr of running clippy +//! on the crate to the server + +use crate::ClippyWarning; +use crate::RecursiveOptions; + +use std::collections::HashSet; +use std::io::{BufRead, BufReader, Read, Write}; +use std::net::{SocketAddr, TcpListener, TcpStream}; +use std::sync::{Arc, Mutex}; +use std::thread; + +use cargo_metadata::diagnostic::Diagnostic; +use crossbeam_channel::{Receiver, Sender}; +use serde::de::DeserializeOwned; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Eq, Hash, PartialEq, Clone, Serialize, Deserialize)] +pub(crate) struct DriverInfo { + pub package_name: String, + pub crate_name: String, + pub version: String, +} + +pub(crate) fn serialize_line(value: &T, writer: &mut W) +where + T: Serialize, + W: Write, +{ + let mut buf = serde_json::to_vec(&value).expect("failed to serialize"); + buf.push(b'\n'); + writer.write_all(&buf).expect("write_all failed"); +} + +pub(crate) fn deserialize_line(reader: &mut R) -> T +where + T: DeserializeOwned, + R: BufRead, +{ + let mut string = String::new(); + reader.read_line(&mut string).expect("read_line failed"); + serde_json::from_str(&string).expect("failed to deserialize") +} + +fn process_stream( + stream: TcpStream, + sender: &Sender, + options: &RecursiveOptions, + seen: &Mutex>, +) { + let mut stream = BufReader::new(stream); + + let driver_info: DriverInfo = deserialize_line(&mut stream); + + let unseen = seen.lock().unwrap().insert(driver_info.clone()); + let ignored = options.ignore.contains(&driver_info.package_name); + let should_run = unseen && !ignored; + + serialize_line(&should_run, stream.get_mut()); + + let mut stderr = String::new(); + stream.read_to_string(&mut stderr).unwrap(); + + let messages = stderr + .lines() + .filter_map(|json_msg| serde_json::from_str::(json_msg).ok()) + .filter_map(|diag| ClippyWarning::new(diag, &driver_info.package_name, &driver_info.version)); + + for message in messages { + sender.send(message).unwrap(); + } +} + +pub(crate) struct LintcheckServer { + pub local_addr: SocketAddr, + receiver: Receiver, + sender: Arc>, +} + +impl LintcheckServer { + pub fn spawn(options: RecursiveOptions) -> Self { + let listener = TcpListener::bind("localhost:0").unwrap(); + let local_addr = listener.local_addr().unwrap(); + + let (sender, receiver) = crossbeam_channel::unbounded::(); + let sender = Arc::new(sender); + // The spawned threads hold a `Weak` so that they don't keep the channel connected + // indefinitely + let sender_weak = Arc::downgrade(&sender); + + // Ignore dependencies multiple times, e.g. for when it's both checked and compiled for a + // build dependency + let seen = Mutex::default(); + + thread::spawn(move || { + thread::scope(|s| { + s.spawn(|| { + while let Ok((stream, _)) = listener.accept() { + let sender = sender_weak.upgrade().expect("received connection after server closed"); + let options = &options; + let seen = &seen; + s.spawn(move || process_stream(stream, &sender, options, seen)); + } + }); + }); + }); + + Self { + local_addr, + sender, + receiver, + } + } + + pub fn warnings(self) -> impl Iterator { + // causes the channel to become disconnected so that the receiver iterator ends + drop(self.sender); + + self.receiver.into_iter() + } +} From ea75178219ab4fd12d035acfc3a0aedb04e91db7 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Tue, 20 Sep 2022 14:11:23 +0900 Subject: [PATCH 049/114] separate definitions and `HIR` owners fix a ui test use `into` fix clippy ui test fix a run-make-fulldeps test implement `IntoQueryParam` for `OwnerId` use `OwnerId` for more queries change the type of `ParentOwnerIterator::Item` to `(OwnerId, OwnerNode)` --- clippy_lints/src/dereference.rs | 2 +- clippy_lints/src/doc.rs | 10 +++++----- clippy_lints/src/enum_variants.rs | 2 +- clippy_lints/src/escape.rs | 2 +- clippy_lints/src/exhaustive_items.rs | 2 +- clippy_lints/src/exit.rs | 2 +- clippy_lints/src/fallible_impl_from.rs | 2 +- clippy_lints/src/functions/must_use.rs | 20 +++++++++---------- .../src/functions/not_unsafe_ptr_arg_deref.rs | 2 +- clippy_lints/src/functions/result.rs | 14 ++++++------- clippy_lints/src/implicit_hasher.rs | 2 +- clippy_lints/src/inherent_to_string.rs | 2 +- .../src/iter_not_returning_iterator.rs | 4 ++-- clippy_lints/src/len_zero.rs | 4 ++-- clippy_lints/src/lifetimes.rs | 4 ++-- clippy_lints/src/loops/mut_range_bound.rs | 2 +- clippy_lints/src/manual_non_exhaustive.rs | 2 +- clippy_lints/src/methods/mod.rs | 8 ++++---- clippy_lints/src/missing_const_for_fn.rs | 2 +- clippy_lints/src/missing_doc.rs | 2 +- clippy_lints/src/missing_inline.rs | 6 +++--- clippy_lints/src/mut_key.rs | 2 +- clippy_lints/src/new_without_default.rs | 4 ++-- clippy_lints/src/non_copy_const.rs | 2 +- clippy_lints/src/only_used_in_recursion.rs | 2 +- .../src/operators/assign_op_pattern.rs | 2 +- clippy_lints/src/pass_by_ref_or_value.rs | 2 +- clippy_lints/src/redundant_pub_crate.rs | 6 +++--- clippy_lints/src/return_self_not_must_use.rs | 2 +- clippy_lints/src/self_named_constructors.rs | 2 +- clippy_lints/src/suspicious_trait_impl.rs | 4 ++-- clippy_lints/src/transmute/utils.rs | 2 +- clippy_lints/src/types/borrowed_box.rs | 2 +- clippy_lints/src/types/mod.rs | 8 ++++---- clippy_lints/src/unused_self.rs | 4 ++-- clippy_lints/src/unwrap_in_result.rs | 2 +- clippy_lints/src/upper_case_acronyms.rs | 2 +- clippy_lints/src/use_self.rs | 2 +- clippy_lints/src/utils/author.rs | 2 +- clippy_lints/src/wildcard_imports.rs | 6 +++--- clippy_lints/src/zero_sized_map_values.rs | 2 +- clippy_utils/src/lib.rs | 12 +++++------ clippy_utils/src/usage.rs | 2 +- 43 files changed, 85 insertions(+), 85 deletions(-) diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 501f9ef78aebe..e54d71fc8e417 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -704,7 +704,7 @@ fn walk_parents<'tcx>( span, .. }) if span.ctxt() == ctxt => { - let ty = cx.tcx.type_of(def_id); + let ty = cx.tcx.type_of(def_id.def_id); Some(ty_auto_deref_stability(cx, ty, precedence).position_for_result(cx)) }, diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index eb158d850fa72..f48ba526d51e1 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -233,11 +233,11 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown { let body = cx.tcx.hir().body(body_id); let mut fpu = FindPanicUnwrap { cx, - typeck_results: cx.tcx.typeck(item.def_id), + typeck_results: cx.tcx.typeck(item.def_id.def_id), panic_span: None, }; fpu.visit_expr(body.value); - lint_for_missing_headers(cx, item.def_id, item.span, sig, headers, Some(body_id), fpu.panic_span); + lint_for_missing_headers(cx, item.def_id.def_id, item.span, sig, headers, Some(body_id), fpu.panic_span); } }, hir::ItemKind::Impl(impl_) => { @@ -268,7 +268,7 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown { let headers = check_attrs(cx, &self.valid_idents, attrs); if let hir::TraitItemKind::Fn(ref sig, ..) = item.kind { if !in_external_macro(cx.tcx.sess, item.span) { - lint_for_missing_headers(cx, item.def_id, item.span, sig, headers, None, None); + lint_for_missing_headers(cx, item.def_id.def_id, item.span, sig, headers, None, None); } } } @@ -283,11 +283,11 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown { let body = cx.tcx.hir().body(body_id); let mut fpu = FindPanicUnwrap { cx, - typeck_results: cx.tcx.typeck(item.def_id), + typeck_results: cx.tcx.typeck(item.def_id.def_id), panic_span: None, }; fpu.visit_expr(body.value); - lint_for_missing_headers(cx, item.def_id, item.span, sig, headers, Some(body_id), fpu.panic_span); + lint_for_missing_headers(cx, item.def_id.def_id, item.span, sig, headers, Some(body_id), fpu.panic_span); } } } diff --git a/clippy_lints/src/enum_variants.rs b/clippy_lints/src/enum_variants.rs index cd36f9fcd729e..c39a909b3ccb9 100644 --- a/clippy_lints/src/enum_variants.rs +++ b/clippy_lints/src/enum_variants.rs @@ -297,7 +297,7 @@ impl LateLintPass<'_> for EnumVariantNames { } } if let ItemKind::Enum(ref def, _) = item.kind { - if !(self.avoid_breaking_exported_api && cx.access_levels.is_exported(item.def_id)) { + if !(self.avoid_breaking_exported_api && cx.access_levels.is_exported(item.def_id.def_id)) { check_variant(cx, self.threshold, def, item_name, item.span); } } diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs index 327865e4c858a..a6ddb26e2dee3 100644 --- a/clippy_lints/src/escape.rs +++ b/clippy_lints/src/escape.rs @@ -71,7 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal { } } - let parent_id = cx.tcx.hir().get_parent_item(hir_id); + let parent_id = cx.tcx.hir().get_parent_item(hir_id).def_id; let parent_node = cx.tcx.hir().find_by_def_id(parent_id); let mut trait_self_ty = None; diff --git a/clippy_lints/src/exhaustive_items.rs b/clippy_lints/src/exhaustive_items.rs index 173d41b4b0506..f3d9ebc5f12de 100644 --- a/clippy_lints/src/exhaustive_items.rs +++ b/clippy_lints/src/exhaustive_items.rs @@ -73,7 +73,7 @@ impl LateLintPass<'_> for ExhaustiveItems { fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { if_chain! { if let ItemKind::Enum(..) | ItemKind::Struct(..) = item.kind; - if cx.access_levels.is_exported(item.def_id); + if cx.access_levels.is_exported(item.def_id.def_id); let attrs = cx.tcx.hir().attrs(item.hir_id()); if !attrs.iter().any(|a| a.has_name(sym::non_exhaustive)); then { diff --git a/clippy_lints/src/exit.rs b/clippy_lints/src/exit.rs index cbf52d19334c0..407dd1b39575f 100644 --- a/clippy_lints/src/exit.rs +++ b/clippy_lints/src/exit.rs @@ -33,7 +33,7 @@ impl<'tcx> LateLintPass<'tcx> for Exit { if let ExprKind::Path(ref path) = path_expr.kind; if let Some(def_id) = cx.qpath_res(path, path_expr.hir_id).opt_def_id(); if match_def_path(cx, def_id, &paths::EXIT); - let parent = cx.tcx.hir().get_parent_item(e.hir_id); + let parent = cx.tcx.hir().get_parent_item(e.hir_id).def_id; if let Some(Node::Item(Item{kind: ItemKind::Fn(..), ..})) = cx.tcx.hir().find_by_def_id(parent); // If the next item up is a function we check if it is an entry point // and only then emit a linter warning diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs index 1f69f34a229df..ef24a5d06ad0b 100644 --- a/clippy_lints/src/fallible_impl_from.rs +++ b/clippy_lints/src/fallible_impl_from.rs @@ -107,7 +107,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_items: &[h let body = cx.tcx.hir().body(body_id); let mut fpu = FindPanicUnwrap { lcx: cx, - typeck_results: cx.tcx.typeck(impl_item.id.def_id), + typeck_results: cx.tcx.typeck(impl_item.id.def_id.def_id), result: Vec::new(), }; fpu.visit_expr(body.value); diff --git a/clippy_lints/src/functions/must_use.rs b/clippy_lints/src/functions/must_use.rs index 00a4937763eb5..d6d33bda17381 100644 --- a/clippy_lints/src/functions/must_use.rs +++ b/clippy_lints/src/functions/must_use.rs @@ -21,7 +21,7 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_> let attrs = cx.tcx.hir().attrs(item.hir_id()); let attr = cx.tcx.get_attr(item.def_id.to_def_id(), sym::must_use); if let hir::ItemKind::Fn(ref sig, _generics, ref body_id) = item.kind { - let is_public = cx.access_levels.is_exported(item.def_id); + let is_public = cx.access_levels.is_exported(item.def_id.def_id); let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); if let Some(attr) = attr { check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr); @@ -31,7 +31,7 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_> sig.decl, cx.tcx.hir().body(*body_id), item.span, - item.def_id, + item.def_id.def_id, item.span.with_hi(sig.decl.output.span().hi()), "this function could have a `#[must_use]` attribute", ); @@ -41,19 +41,19 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_> pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) { if let hir::ImplItemKind::Fn(ref sig, ref body_id) = item.kind { - let is_public = cx.access_levels.is_exported(item.def_id); + let is_public = cx.access_levels.is_exported(item.def_id.def_id); let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); let attrs = cx.tcx.hir().attrs(item.hir_id()); let attr = cx.tcx.get_attr(item.def_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.def_id).is_none() { + } else if is_public && !is_proc_macro(cx.sess(), attrs) && trait_ref_of_method(cx, item.def_id.def_id).is_none() { check_must_use_candidate( cx, sig.decl, cx.tcx.hir().body(*body_id), item.span, - item.def_id, + item.def_id.def_id, item.span.with_hi(sig.decl.output.span().hi()), "this method could have a `#[must_use]` attribute", ); @@ -63,7 +63,7 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) { if let hir::TraitItemKind::Fn(ref sig, ref eid) = item.kind { - let is_public = cx.access_levels.is_exported(item.def_id); + let is_public = cx.access_levels.is_exported(item.def_id.def_id); let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); let attrs = cx.tcx.hir().attrs(item.hir_id()); @@ -78,7 +78,7 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr sig.decl, body, item.span, - item.def_id, + item.def_id.def_id, item.span.with_hi(sig.decl.output.span().hi()), "this method could have a `#[must_use]` attribute", ); @@ -171,7 +171,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).pat_ty(pat), pat.span, tys) + is_mutable_ty(cx, cx.tcx.typeck(pat.hir_id.owner.def_id).pat_ty(pat), pat.span, tys) } else { false } @@ -218,7 +218,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for StaticMutVisitor<'a, 'tcx> { if self.cx.tcx.has_typeck_results(arg.hir_id.owner.to_def_id()) && is_mutable_ty( self.cx, - self.cx.tcx.typeck(arg.hir_id.owner).expr_ty(arg), + self.cx.tcx.typeck(arg.hir_id.owner.def_id).expr_ty(arg), arg.span, &mut tys, ) @@ -236,7 +236,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for StaticMutVisitor<'a, 'tcx> { if self.cx.tcx.has_typeck_results(arg.hir_id.owner.to_def_id()) && is_mutable_ty( self.cx, - self.cx.tcx.typeck(arg.hir_id.owner).expr_ty(arg), + self.cx.tcx.typeck(arg.hir_id.owner.def_id).expr_ty(arg), arg.span, &mut tys, ) diff --git a/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs b/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs index 3bbfa52e81039..0b50431fbaaba 100644 --- a/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs +++ b/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs @@ -28,7 +28,7 @@ pub(super) fn check_fn<'tcx>( pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) { if let hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(eid)) = item.kind { let body = cx.tcx.hir().body(eid); - check_raw_ptr(cx, sig.header.unsafety, sig.decl, body, item.def_id); + check_raw_ptr(cx, sig.header.unsafety, sig.decl, body, item.def_id.def_id); } } diff --git a/clippy_lints/src/functions/result.rs b/clippy_lints/src/functions/result.rs index 9591405cb06f7..113c4e9f50910 100644 --- a/clippy_lints/src/functions/result.rs +++ b/clippy_lints/src/functions/result.rs @@ -34,9 +34,9 @@ fn result_err_ty<'tcx>( pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::Item<'tcx>, large_err_threshold: u64) { if let hir::ItemKind::Fn(ref sig, _generics, _) = item.kind - && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.def_id, item.span) + && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.def_id.def_id, item.span) { - if cx.access_levels.is_exported(item.def_id) { + if cx.access_levels.is_exported(item.def_id.def_id) { let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); check_result_unit_err(cx, err_ty, fn_header_span); } @@ -47,10 +47,10 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::Item<'tcx>, l pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::ImplItem<'tcx>, large_err_threshold: u64) { // Don't lint if method is a trait's implementation, we can't do anything about those if let hir::ImplItemKind::Fn(ref sig, _) = item.kind - && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.def_id, item.span) - && trait_ref_of_method(cx, item.def_id).is_none() + && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.def_id.def_id, item.span) + && trait_ref_of_method(cx, item.def_id.def_id).is_none() { - if cx.access_levels.is_exported(item.def_id) { + if cx.access_levels.is_exported(item.def_id.def_id) { let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); check_result_unit_err(cx, err_ty, fn_header_span); } @@ -61,8 +61,8 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::ImplItem pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::TraitItem<'tcx>, large_err_threshold: u64) { if let hir::TraitItemKind::Fn(ref sig, _) = item.kind { let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); - if let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.def_id, item.span) { - if cx.access_levels.is_exported(item.def_id) { + if let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.def_id.def_id, item.span) { + if cx.access_levels.is_exported(item.def_id.def_id) { check_result_unit_err(cx, err_ty, fn_header_span); } check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold); diff --git a/clippy_lints/src/implicit_hasher.rs b/clippy_lints/src/implicit_hasher.rs index 4f9680f60fe8b..804fdc2da0889 100644 --- a/clippy_lints/src/implicit_hasher.rs +++ b/clippy_lints/src/implicit_hasher.rs @@ -112,7 +112,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher { } } - if !cx.access_levels.is_exported(item.def_id) { + if !cx.access_levels.is_exported(item.def_id.def_id) { return; } diff --git a/clippy_lints/src/inherent_to_string.rs b/clippy_lints/src/inherent_to_string.rs index 17d867aacb533..cb6c2ec0fb985 100644 --- a/clippy_lints/src/inherent_to_string.rs +++ b/clippy_lints/src/inherent_to_string.rs @@ -108,7 +108,7 @@ impl<'tcx> LateLintPass<'tcx> for InherentToString { if is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id()), sym::String); // Filters instances of to_string which are required by a trait - if trait_ref_of_method(cx, impl_item.def_id).is_none(); + if trait_ref_of_method(cx, impl_item.def_id.def_id).is_none(); then { show_lint(cx, impl_item); diff --git a/clippy_lints/src/iter_not_returning_iterator.rs b/clippy_lints/src/iter_not_returning_iterator.rs index b56d87c5348c2..2027c23d328c9 100644 --- a/clippy_lints/src/iter_not_returning_iterator.rs +++ b/clippy_lints/src/iter_not_returning_iterator.rs @@ -44,7 +44,7 @@ impl<'tcx> LateLintPass<'tcx> for IterNotReturningIterator { let name = item.ident.name.as_str(); if matches!(name, "iter" | "iter_mut") { if let TraitItemKind::Fn(fn_sig, _) = &item.kind { - check_sig(cx, name, fn_sig, item.def_id); + check_sig(cx, name, fn_sig, item.def_id.def_id); } } } @@ -58,7 +58,7 @@ impl<'tcx> LateLintPass<'tcx> for IterNotReturningIterator { ) { if let ImplItemKind::Fn(fn_sig, _) = &item.kind { - check_sig(cx, name, fn_sig, item.def_id); + check_sig(cx, name, fn_sig, item.def_id.def_id); } } } diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 7ae8ef830faea..7d15dd4cb2164 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -134,7 +134,7 @@ impl<'tcx> LateLintPass<'tcx> for LenZero { if item.ident.name == sym::len; if let ImplItemKind::Fn(sig, _) = &item.kind; if sig.decl.implicit_self.has_implicit_self(); - if cx.access_levels.is_exported(item.def_id); + if cx.access_levels.is_exported(item.def_id.def_id); if matches!(sig.decl.output, FnRetTy::Return(_)); if let Some(imp) = get_parent_as_impl(cx.tcx, item.hir_id()); if imp.of_trait.is_none(); @@ -210,7 +210,7 @@ fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, trait_items } } - if cx.access_levels.is_exported(visited_trait.def_id) && trait_items.iter().any(|i| is_named_self(cx, i, sym::len)) + if cx.access_levels.is_exported(visited_trait.def_id.def_id) && trait_items.iter().any(|i| is_named_self(cx, i, sym::len)) { let mut current_and_super_traits = DefIdSet::default(); fill_trait_set(visited_trait.def_id.to_def_id(), &mut current_and_super_traits, cx); diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 643a7cfd577b7..399a03187d993 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -102,7 +102,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes { fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) { if let ImplItemKind::Fn(ref sig, id) = item.kind { - let report_extra_lifetimes = trait_ref_of_method(cx, item.def_id).is_none(); + let report_extra_lifetimes = trait_ref_of_method(cx, item.def_id.def_id).is_none(); check_fn_inner( cx, sig.decl, @@ -276,7 +276,7 @@ fn could_use_elision<'tcx>( let mut checker = BodyLifetimeChecker { lifetimes_used_in_body: false, }; - checker.visit_expr(body.value); + checker.visit_expr(&body.value); if checker.lifetimes_used_in_body { return false; } diff --git a/clippy_lints/src/loops/mut_range_bound.rs b/clippy_lints/src/loops/mut_range_bound.rs index fce2d54639cbf..be7f96e9bb077 100644 --- a/clippy_lints/src/loops/mut_range_bound.rs +++ b/clippy_lints/src/loops/mut_range_bound.rs @@ -69,7 +69,7 @@ fn check_for_mutation<'tcx>( ExprUseVisitor::new( &mut delegate, &infcx, - body.hir_id.owner, + body.hir_id.owner.def_id, cx.param_env, cx.typeck_results(), ) diff --git a/clippy_lints/src/manual_non_exhaustive.rs b/clippy_lints/src/manual_non_exhaustive.rs index 2b04475c7a9de..53e7565bd33f3 100644 --- a/clippy_lints/src/manual_non_exhaustive.rs +++ b/clippy_lints/src/manual_non_exhaustive.rs @@ -166,7 +166,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum { if let Some((id, span)) = iter.next() && iter.next().is_none() { - self.potential_enums.push((item.def_id, id, item.span, span)); + self.potential_enums.push((item.def_id.def_id, id, item.span, span)); } } } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index cdde4c54d6378..ddb6d1ca26c91 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3250,7 +3250,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { return; } let name = impl_item.ident.name.as_str(); - let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id()); + let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id()).def_id; let item = cx.tcx.hir().expect_item(parent); let self_ty = cx.tcx.type_of(item.def_id); @@ -3259,7 +3259,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { if let hir::ImplItemKind::Fn(ref sig, id) = impl_item.kind; if let Some(first_arg) = iter_input_pats(sig.decl, cx.tcx.hir().body(id)).next(); - let method_sig = cx.tcx.fn_sig(impl_item.def_id); + let method_sig = cx.tcx.fn_sig(impl_item.def_id.def_id); let method_sig = cx.tcx.erase_late_bound_regions(method_sig); let first_arg_ty = method_sig.inputs().iter().next(); @@ -3269,7 +3269,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { then { // if this impl block implements a trait, lint in trait definition instead - if !implements_trait && cx.access_levels.is_exported(impl_item.def_id) { + if !implements_trait && cx.access_levels.is_exported(impl_item.def_id.def_id) { // check missing trait implementations for method_config in &TRAIT_METHODS { if name == method_config.method_name && @@ -3301,7 +3301,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { if sig.decl.implicit_self.has_implicit_self() && !(self.avoid_breaking_exported_api - && cx.access_levels.is_exported(impl_item.def_id)) + && cx.access_levels.is_exported(impl_item.def_id.def_id)) { wrong_self_convention::check( cx, diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index bc304c081b906..f24b41411c816 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -136,7 +136,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { // Const fns are not allowed as methods in a trait. { - let parent = cx.tcx.hir().get_parent_item(hir_id); + let parent = cx.tcx.hir().get_parent_item(hir_id).def_id; if parent != CRATE_DEF_ID { if let hir::Node::Item(item) = cx.tcx.hir().get_by_def_id(parent) { if let hir::ItemKind::Trait(..) = &item.kind { diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index 3701fdb4adbff..4721955667688 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -131,7 +131,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { hir::ItemKind::Fn(..) => { // ignore main() if it.ident.name == sym::main { - let at_root = cx.tcx.local_parent(it.def_id) == CRATE_DEF_ID; + let at_root = cx.tcx.local_parent(it.def_id.def_id) == CRATE_DEF_ID; if at_root { return; } diff --git a/clippy_lints/src/missing_inline.rs b/clippy_lints/src/missing_inline.rs index 07bc2ca5d3cd2..9d5764ac09260 100644 --- a/clippy_lints/src/missing_inline.rs +++ b/clippy_lints/src/missing_inline.rs @@ -88,7 +88,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline { return; } - if !cx.access_levels.is_exported(it.def_id) { + if !cx.access_levels.is_exported(it.def_id.def_id) { return; } match it.kind { @@ -142,7 +142,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline { } // If the item being implemented is not exported, then we don't need #[inline] - if !cx.access_levels.is_exported(impl_item.def_id) { + if !cx.access_levels.is_exported(impl_item.def_id.def_id) { return; } @@ -159,7 +159,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline { }; if let Some(trait_def_id) = trait_def_id { - if trait_def_id.is_local() && !cx.access_levels.is_exported(impl_item.def_id) { + if trait_def_id.is_local() && !cx.access_levels.is_exported(impl_item.def_id.def_id) { // If a trait is being implemented for an item, and the // trait is not exported, we don't need #[inline] return; diff --git a/clippy_lints/src/mut_key.rs b/clippy_lints/src/mut_key.rs index 4db103bbc1305..25d6ca83a94bc 100644 --- a/clippy_lints/src/mut_key.rs +++ b/clippy_lints/src/mut_key.rs @@ -89,7 +89,7 @@ impl<'tcx> LateLintPass<'tcx> for MutableKeyType { 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.def_id).is_none() { + if trait_ref_of_method(cx, item.def_id.def_id).is_none() { check_sig(cx, item.hir_id(), sig.decl); } } diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index 5c45ee6d94ad3..357a71693d2c3 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -84,7 +84,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { // can't be implemented for unsafe new return; } - if cx.tcx.is_doc_hidden(impl_item.def_id) { + if cx.tcx.is_doc_hidden(impl_item.def_id.def_id) { // shouldn't be implemented when it is hidden in docs return; } @@ -96,7 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { if_chain! { if sig.decl.inputs.is_empty(); if name == sym::new; - if cx.access_levels.is_reachable(impl_item.def_id); + if cx.access_levels.is_reachable(impl_item.def_id.def_id); let self_def_id = cx.tcx.hir().get_parent_item(id); let self_ty = cx.tcx.type_of(self_def_id); if self_ty == return_ty(cx, id); diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index b15884527321c..616ef9e2f867f 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -286,7 +286,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) { if let ImplItemKind::Const(hir_ty, body_id) = &impl_item.kind { - let item_def_id = cx.tcx.hir().get_parent_item(impl_item.hir_id()); + let item_def_id = cx.tcx.hir().get_parent_item(impl_item.hir_id()).def_id; let item = cx.tcx.hir().expect_item(item_def_id); match &item.kind { diff --git a/clippy_lints/src/only_used_in_recursion.rs b/clippy_lints/src/only_used_in_recursion.rs index 6217110a1f3ae..d64a9cf71e17a 100644 --- a/clippy_lints/src/only_used_in_recursion.rs +++ b/clippy_lints/src/only_used_in_recursion.rs @@ -243,7 +243,7 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion { .. })) => { #[allow(trivial_casts)] - if let Some(Node::Item(item)) = get_parent_node(cx.tcx, cx.tcx.hir().local_def_id_to_hir_id(def_id)) + if let Some(Node::Item(item)) = get_parent_node(cx.tcx, def_id.into()) && let Some(trait_ref) = cx.tcx.impl_trait_ref(item.def_id) && let Some(trait_item_id) = cx.tcx.associated_item(def_id).trait_item_def_id { diff --git a/clippy_lints/src/operators/assign_op_pattern.rs b/clippy_lints/src/operators/assign_op_pattern.rs index 945a09a647c41..2c22c8b3d0819 100644 --- a/clippy_lints/src/operators/assign_op_pattern.rs +++ b/clippy_lints/src/operators/assign_op_pattern.rs @@ -28,7 +28,7 @@ pub(super) fn check<'tcx>( if_chain! { if let Some((_, lang_item)) = binop_traits(op.node); if let Ok(trait_id) = cx.tcx.lang_items().require(lang_item); - let parent_fn = cx.tcx.hir().get_parent_item(e.hir_id); + let parent_fn = cx.tcx.hir().get_parent_item(e.hir_id).def_id; if trait_ref_of_method(cx, parent_fn) .map_or(true, |t| t.path.res.def_id() != trait_id); if implements_trait(cx, ty, trait_id, &[rty.into()]); diff --git a/clippy_lints/src/pass_by_ref_or_value.rs b/clippy_lints/src/pass_by_ref_or_value.rs index 0960b050c240e..6b2eea4893225 100644 --- a/clippy_lints/src/pass_by_ref_or_value.rs +++ b/clippy_lints/src/pass_by_ref_or_value.rs @@ -261,7 +261,7 @@ impl<'tcx> LateLintPass<'tcx> for PassByRefOrValue { } if let hir::TraitItemKind::Fn(method_sig, _) = &item.kind { - self.check_poly_fn(cx, item.def_id, method_sig.decl, None); + self.check_poly_fn(cx, item.def_id.def_id, method_sig.decl, None); } } diff --git a/clippy_lints/src/redundant_pub_crate.rs b/clippy_lints/src/redundant_pub_crate.rs index 323326381d407..3c6ca9d98975d 100644 --- a/clippy_lints/src/redundant_pub_crate.rs +++ b/clippy_lints/src/redundant_pub_crate.rs @@ -46,8 +46,8 @@ impl_lint_pass!(RedundantPubCrate => [REDUNDANT_PUB_CRATE]); impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { if_chain! { - if cx.tcx.visibility(item.def_id) == ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id()); - if !cx.access_levels.is_exported(item.def_id) && self.is_exported.last() == Some(&false); + if cx.tcx.visibility(item.def_id.def_id) == ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id()); + if !cx.access_levels.is_exported(item.def_id.def_id) && self.is_exported.last() == Some(&false); if is_not_macro_export(item); then { let span = item.span.with_hi(item.ident.span.hi()); @@ -70,7 +70,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate { } if let ItemKind::Mod { .. } = item.kind { - self.is_exported.push(cx.access_levels.is_exported(item.def_id)); + self.is_exported.push(cx.access_levels.is_exported(item.def_id.def_id)); } } diff --git a/clippy_lints/src/return_self_not_must_use.rs b/clippy_lints/src/return_self_not_must_use.rs index 60be6bd335f68..16d702a3868d1 100644 --- a/clippy_lints/src/return_self_not_must_use.rs +++ b/clippy_lints/src/return_self_not_must_use.rs @@ -128,7 +128,7 @@ impl<'tcx> LateLintPass<'tcx> for ReturnSelfNotMustUse { fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'tcx>) { if let TraitItemKind::Fn(ref sig, _) = item.kind { - check_method(cx, sig.decl, item.def_id, item.span, item.hir_id()); + check_method(cx, sig.decl, item.def_id.def_id, item.span, item.hir_id()); } } } diff --git a/clippy_lints/src/self_named_constructors.rs b/clippy_lints/src/self_named_constructors.rs index 9cea4d8806710..1ac538f4c7c07 100644 --- a/clippy_lints/src/self_named_constructors.rs +++ b/clippy_lints/src/self_named_constructors.rs @@ -51,7 +51,7 @@ impl<'tcx> LateLintPass<'tcx> for SelfNamedConstructors { _ => return, } - let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id()); + let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id()).def_id; let item = cx.tcx.hir().expect_item(parent); let self_ty = cx.tcx.type_of(item.def_id); let ret_ty = return_ty(cx, impl_item.hir_id()); diff --git a/clippy_lints/src/suspicious_trait_impl.rs b/clippy_lints/src/suspicious_trait_impl.rs index 6add20c1fb712..d47ed459387ef 100644 --- a/clippy_lints/src/suspicious_trait_impl.rs +++ b/clippy_lints/src/suspicious_trait_impl.rs @@ -64,11 +64,11 @@ impl<'tcx> LateLintPass<'tcx> for SuspiciousImpl { // Check for more than one binary operation in the implemented function // Linting when multiple operations are involved can result in false positives - let parent_fn = cx.tcx.hir().get_parent_item(expr.hir_id); + let parent_fn = cx.tcx.hir().get_parent_item(expr.hir_id).def_id; if let hir::Node::ImplItem(impl_item) = cx.tcx.hir().get_by_def_id(parent_fn); if let hir::ImplItemKind::Fn(_, body_id) = impl_item.kind; let body = cx.tcx.hir().body(body_id); - let parent_fn = cx.tcx.hir().get_parent_item(expr.hir_id); + let parent_fn = cx.tcx.hir().get_parent_item(expr.hir_id).def_id; if let Some(trait_ref) = trait_ref_of_method(cx, parent_fn); let trait_id = trait_ref.path.res.def_id(); if ![binop_trait_id, op_assign_trait_id].contains(&trait_id); diff --git a/clippy_lints/src/transmute/utils.rs b/clippy_lints/src/transmute/utils.rs index 8bdadf2440231..8e90d20265ce1 100644 --- a/clippy_lints/src/transmute/utils.rs +++ b/clippy_lints/src/transmute/utils.rs @@ -42,7 +42,7 @@ pub(super) fn can_be_expressed_as_pointer_cast<'tcx>( /// messages. This function will panic if that occurs. fn check_cast<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx>, to_ty: Ty<'tcx>) -> Option { let hir_id = e.hir_id; - let local_def_id = hir_id.owner; + let local_def_id = hir_id.owner.def_id; Inherited::build(cx.tcx, local_def_id).enter(|inherited| { let fn_ctxt = FnCtxt::new(&inherited, cx.param_env, hir_id); diff --git a/clippy_lints/src/types/borrowed_box.rs b/clippy_lints/src/types/borrowed_box.rs index 94945b2e1a9e2..1268c23206a6f 100644 --- a/clippy_lints/src/types/borrowed_box.rs +++ b/clippy_lints/src/types/borrowed_box.rs @@ -104,7 +104,7 @@ fn get_bounds_if_impl_trait<'tcx>(cx: &LateContext<'tcx>, qpath: &QPath<'_>, id: if let Some(Node::GenericParam(generic_param)) = cx.tcx.hir().get_if_local(did); if let GenericParamKind::Type { synthetic, .. } = generic_param.kind; if synthetic; - if let Some(generics) = cx.tcx.hir().get_generics(id.owner); + if let Some(generics) = cx.tcx.hir().get_generics(id.owner.def_id); if let Some(pred) = generics.bounds_for_param(did.expect_local()).next(); then { Some(pred.bounds) diff --git a/clippy_lints/src/types/mod.rs b/clippy_lints/src/types/mod.rs index 353a6f6b899ea..aca55817c5250 100644 --- a/clippy_lints/src/types/mod.rs +++ b/clippy_lints/src/types/mod.rs @@ -313,7 +313,7 @@ impl_lint_pass!(Types => [BOX_COLLECTION, VEC_BOX, OPTION_OPTION, LINKEDLIST, BO impl<'tcx> LateLintPass<'tcx> for Types { fn check_fn(&mut self, cx: &LateContext<'_>, _: FnKind<'_>, decl: &FnDecl<'_>, _: &Body<'_>, _: Span, id: HirId) { let is_in_trait_impl = - if let Some(hir::Node::Item(item)) = cx.tcx.hir().find_by_def_id(cx.tcx.hir().get_parent_item(id)) { + if let Some(hir::Node::Item(item)) = cx.tcx.hir().find_by_def_id(cx.tcx.hir().get_parent_item(id).def_id) { matches!(item.kind, ItemKind::Impl(hir::Impl { of_trait: Some(_), .. })) } else { false @@ -333,7 +333,7 @@ impl<'tcx> LateLintPass<'tcx> for Types { } fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { - let is_exported = cx.access_levels.is_exported(item.def_id); + let is_exported = cx.access_levels.is_exported(item.def_id.def_id); match item.kind { ItemKind::Static(ty, _, _) | ItemKind::Const(ty, _) => self.check_ty( @@ -353,7 +353,7 @@ impl<'tcx> LateLintPass<'tcx> for Types { match item.kind { ImplItemKind::Const(ty, _) => { let is_in_trait_impl = if let Some(hir::Node::Item(item)) = - cx.tcx.hir().find_by_def_id(cx.tcx.hir().get_parent_item(item.hir_id())) + cx.tcx.hir().find_by_def_id(cx.tcx.hir().get_parent_item(item.hir_id()).def_id) { matches!(item.kind, ItemKind::Impl(hir::Impl { of_trait: Some(_), .. })) } else { @@ -390,7 +390,7 @@ impl<'tcx> LateLintPass<'tcx> for Types { } fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &TraitItem<'_>) { - let is_exported = cx.access_levels.is_exported(item.def_id); + let is_exported = cx.access_levels.is_exported(item.def_id.def_id); let context = CheckTyContext { is_exported, diff --git a/clippy_lints/src/unused_self.rs b/clippy_lints/src/unused_self.rs index 51c65d898cf5f..713fe06bad436 100644 --- a/clippy_lints/src/unused_self.rs +++ b/clippy_lints/src/unused_self.rs @@ -54,14 +54,14 @@ impl<'tcx> LateLintPass<'tcx> for UnusedSelf { if impl_item.span.from_expansion() { return; } - let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id()); + let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id()).def_id; let parent_item = cx.tcx.hir().expect_item(parent); let assoc_item = cx.tcx.associated_item(impl_item.def_id); if_chain! { if let ItemKind::Impl(Impl { of_trait: None, .. }) = parent_item.kind; if assoc_item.fn_has_self_parameter; if let ImplItemKind::Fn(.., body_id) = &impl_item.kind; - if !cx.access_levels.is_exported(impl_item.def_id) || !self.avoid_breaking_exported_api; + if !cx.access_levels.is_exported(impl_item.def_id.def_id) || !self.avoid_breaking_exported_api; let body = cx.tcx.hir().body(*body_id); if let [self_param, ..] = body.params; if !is_local_used(cx, body, self_param.pat.hir_id); diff --git a/clippy_lints/src/unwrap_in_result.rs b/clippy_lints/src/unwrap_in_result.rs index 46020adcaa2ca..baa53ba664f69 100644 --- a/clippy_lints/src/unwrap_in_result.rs +++ b/clippy_lints/src/unwrap_in_result.rs @@ -111,7 +111,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_item: &'tc let body = cx.tcx.hir().body(body_id); let mut fpu = FindExpectUnwrap { lcx: cx, - typeck_results: cx.tcx.typeck(impl_item.def_id), + typeck_results: cx.tcx.typeck(impl_item.def_id.def_id), result: Vec::new(), }; fpu.visit_expr(body.value); diff --git a/clippy_lints/src/upper_case_acronyms.rs b/clippy_lints/src/upper_case_acronyms.rs index 02bf09ed5068c..2c71f35d490cb 100644 --- a/clippy_lints/src/upper_case_acronyms.rs +++ b/clippy_lints/src/upper_case_acronyms.rs @@ -105,7 +105,7 @@ impl LateLintPass<'_> for UpperCaseAcronyms { fn check_item(&mut self, cx: &LateContext<'_>, it: &Item<'_>) { // do not lint public items or in macros if in_external_macro(cx.sess(), it.span) - || (self.avoid_breaking_exported_api && cx.access_levels.is_exported(it.def_id)) + || (self.avoid_breaking_exported_api && cx.access_levels.is_exported(it.def_id.def_id)) { return; } diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index 44ab9bca79596..ce51cb693fc02 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -106,7 +106,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { if !is_from_proc_macro(cx, item); // expensive, should be last check then { StackItem::Check { - impl_id: item.def_id, + impl_id: item.def_id.def_id, in_body: 0, types_to_skip: std::iter::once(self_ty.hir_id).collect(), } diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index 4003fff27c006..1df3135c962d1 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -140,7 +140,7 @@ impl<'tcx> LateLintPass<'tcx> for Author { fn check_item(cx: &LateContext<'_>, hir_id: HirId) { let hir = cx.tcx.hir(); - if let Some(body_id) = hir.maybe_body_owned_by(hir_id.expect_owner()) { + if let Some(body_id) = hir.maybe_body_owned_by(hir_id.expect_owner().def_id) { check_node(cx, hir_id, |v| { v.expr(&v.bind("expr", hir.body(body_id).value)); }); diff --git a/clippy_lints/src/wildcard_imports.rs b/clippy_lints/src/wildcard_imports.rs index 5418eca382da0..2604b1ee7c56a 100644 --- a/clippy_lints/src/wildcard_imports.rs +++ b/clippy_lints/src/wildcard_imports.rs @@ -120,14 +120,14 @@ impl LateLintPass<'_> for WildcardImports { if is_test_module_or_function(cx.tcx, item) { self.test_modules_deep = self.test_modules_deep.saturating_add(1); } - let module = cx.tcx.parent_module_from_def_id(item.def_id); - if cx.tcx.visibility(item.def_id) != ty::Visibility::Restricted(module.to_def_id()) { + let module = cx.tcx.parent_module_from_def_id(item.def_id.def_id); + if cx.tcx.visibility(item.def_id.def_id) != ty::Visibility::Restricted(module.to_def_id()) { return; } if_chain! { if let ItemKind::Use(use_path, UseKind::Glob) = &item.kind; if self.warn_on_all || !self.check_exceptions(item, use_path.segments); - let used_imports = cx.tcx.names_imported_by_glob_use(item.def_id); + let used_imports = cx.tcx.names_imported_by_glob_use(item.def_id.def_id); if !used_imports.is_empty(); // Already handled by `unused_imports` then { let mut applicability = Applicability::MachineApplicable; diff --git a/clippy_lints/src/zero_sized_map_values.rs b/clippy_lints/src/zero_sized_map_values.rs index 8dc43c0e29436..386f3c527f174 100644 --- a/clippy_lints/src/zero_sized_map_values.rs +++ b/clippy_lints/src/zero_sized_map_values.rs @@ -72,7 +72,7 @@ fn in_trait_impl(cx: &LateContext<'_>, hir_id: HirId) -> bool { let second_parent_id = cx .tcx .hir() - .get_parent_item(cx.tcx.hir().local_def_id_to_hir_id(parent_id)); + .get_parent_item(parent_id.into()).def_id; if let Some(Node::Item(item)) = cx.tcx.hir().find_by_def_id(second_parent_id) { if let ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) = item.kind { return true; diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 62da850a15e70..9343cf457b341 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -78,7 +78,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::unhash::UnhashMap; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_ID}; +use rustc_hir::def_id::{CrateNum, DefId, LocalDefId}; use rustc_hir::hir_id::{HirIdMap, HirIdSet}; use rustc_hir::intravisit::{walk_expr, FnKind, Visitor}; use rustc_hir::LangItem::{OptionNone, ResultErr, ResultOk}; @@ -212,7 +212,7 @@ pub fn find_binding_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option< /// } /// ``` pub fn in_constant(cx: &LateContext<'_>, id: HirId) -> bool { - let parent_id = cx.tcx.hir().get_parent_item(id); + let parent_id = cx.tcx.hir().get_parent_item(id).def_id; match cx.tcx.hir().get_by_def_id(parent_id) { Node::Item(&Item { kind: ItemKind::Const(..) | ItemKind::Static(..), @@ -597,8 +597,8 @@ pub fn trait_ref_of_method<'tcx>(cx: &LateContext<'tcx>, def_id: LocalDefId) -> let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id); let parent_impl = cx.tcx.hir().get_parent_item(hir_id); if_chain! { - if parent_impl != CRATE_DEF_ID; - if let hir::Node::Item(item) = cx.tcx.hir().get_by_def_id(parent_impl); + if parent_impl != hir::CRATE_OWNER_ID; + if let hir::Node::Item(item) = cx.tcx.hir().get_by_def_id(parent_impl.def_id); if let hir::ItemKind::Impl(impl_) = &item.kind; then { return impl_.of_trait.as_ref(); @@ -1104,7 +1104,7 @@ pub fn is_in_panic_handler(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { /// Gets the name of the item the expression is in, if available. pub fn get_item_name(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { - let parent_id = cx.tcx.hir().get_parent_item(expr.hir_id); + let parent_id = cx.tcx.hir().get_parent_item(expr.hir_id).def_id; match cx.tcx.hir().find_by_def_id(parent_id) { Some( Node::Item(Item { ident, .. }) @@ -1648,7 +1648,7 @@ pub fn any_parent_has_attr(tcx: TyCtxt<'_>, node: HirId, symbol: Symbol) -> bool return true; } prev_enclosing_node = Some(enclosing_node); - enclosing_node = map.local_def_id_to_hir_id(map.get_parent_item(enclosing_node)); + enclosing_node = map.get_parent_item(enclosing_node).into(); } false diff --git a/clippy_utils/src/usage.rs b/clippy_utils/src/usage.rs index 3af5dfb62f97e..a7c08839f5241 100644 --- a/clippy_utils/src/usage.rs +++ b/clippy_utils/src/usage.rs @@ -21,7 +21,7 @@ pub fn mutated_variables<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) -> ExprUseVisitor::new( &mut delegate, &infcx, - expr.hir_id.owner, + expr.hir_id.owner.def_id, cx.param_env, cx.typeck_results(), ) From 1141c553d8b443bdebc95e2fc13b04bd02031733 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sat, 24 Sep 2022 17:07:35 -0400 Subject: [PATCH 050/114] Fix ICE in `needless_pass_by_value` with unsized `dyn Fn` --- clippy_lints/src/needless_pass_by_value.rs | 3 ++- tests/ui/crashes/ice-9459.rs | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 tests/ui/crashes/ice-9459.rs diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index d7e6e7de2cc10..924d4f91970e6 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -18,7 +18,7 @@ use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::{self, TypeVisitable}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::kw; -use rustc_span::{sym, Span}; +use rustc_span::{sym, Span, DUMMY_SP}; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits; use rustc_trait_selection::traits::misc::can_type_implement_copy; @@ -186,6 +186,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { if !is_self(arg); if !ty.is_mutable_ptr(); if !is_copy(cx, ty); + if ty.is_sized(cx.tcx.at(DUMMY_SP), cx.param_env); if !allowed_traits.iter().any(|&t| implements_trait(cx, ty, t, &[])); if !implements_borrow_trait; if !all_borrowable_trait; diff --git a/tests/ui/crashes/ice-9459.rs b/tests/ui/crashes/ice-9459.rs new file mode 100644 index 0000000000000..55615124fcf01 --- /dev/null +++ b/tests/ui/crashes/ice-9459.rs @@ -0,0 +1,5 @@ +#![feature(unsized_fn_params)] + +pub fn f0(_f: dyn FnOnce()) {} + +fn main() {} From 93945a54a1a98bb6d7e268aa09cbe8eac34f3c99 Mon Sep 17 00:00:00 2001 From: alex-semenyuk Date: Sun, 25 Sep 2022 13:00:25 +0300 Subject: [PATCH 051/114] Please move derive_partial_eq_without_eq to nursery --- clippy_lints/src/derive.rs | 2 +- clippy_lints/src/lib.register_all.rs | 1 - clippy_lints/src/lib.register_nursery.rs | 1 + clippy_lints/src/lib.register_style.rs | 1 - 4 files changed, 2 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index 9ca443b7dff6c..8d90774333929 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -191,7 +191,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.63.0"] pub DERIVE_PARTIAL_EQ_WITHOUT_EQ, - style, + nursery, "deriving `PartialEq` on a type that can implement `Eq`, without implementing `Eq`" } diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index ae57a9a24a76a..d22cfcd81259a 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -44,7 +44,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(derivable_impls::DERIVABLE_IMPLS), LintId::of(derive::DERIVE_HASH_XOR_EQ), LintId::of(derive::DERIVE_ORD_XOR_PARTIAL_ORD), - LintId::of(derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ), LintId::of(disallowed_methods::DISALLOWED_METHODS), LintId::of(disallowed_names::DISALLOWED_NAMES), LintId::of(disallowed_types::DISALLOWED_TYPES), diff --git a/clippy_lints/src/lib.register_nursery.rs b/clippy_lints/src/lib.register_nursery.rs index 7171c655ccc8d..34835e22896cf 100644 --- a/clippy_lints/src/lib.register_nursery.rs +++ b/clippy_lints/src/lib.register_nursery.rs @@ -6,6 +6,7 @@ store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![ LintId::of(attrs::EMPTY_LINE_AFTER_OUTER_ATTR), 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), diff --git a/clippy_lints/src/lib.register_style.rs b/clippy_lints/src/lib.register_style.rs index 05d2ec2e9e1e6..ab7c4034b0e6a 100644 --- a/clippy_lints/src/lib.register_style.rs +++ b/clippy_lints/src/lib.register_style.rs @@ -15,7 +15,6 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ 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(derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ), LintId::of(disallowed_methods::DISALLOWED_METHODS), LintId::of(disallowed_names::DISALLOWED_NAMES), LintId::of(disallowed_types::DISALLOWED_TYPES), From 84933761f0b20012c25ede433da945f8ac942b3d Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 25 Sep 2022 00:39:05 -0400 Subject: [PATCH 052/114] Fix panic when displaying the backtrace of failing integration tests --- tests/integration.rs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/tests/integration.rs b/tests/integration.rs index 330460ff8a5d9..818ff70b33f4d 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -6,6 +6,11 @@ use std::env; use std::ffi::OsStr; use std::process::Command; +#[cfg(not(windows))] +const CARGO_CLIPPY: &str = "cargo-clippy"; +#[cfg(windows)] +const CARGO_CLIPPY: &str = "cargo-clippy.exe"; + #[cfg_attr(feature = "integration", test)] fn integration_test() { let repo_name = env::var("INTEGRATION").expect("`INTEGRATION` var not set"); @@ -31,7 +36,7 @@ fn integration_test() { let root_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")); let target_dir = std::path::Path::new(&root_dir).join("target"); - let clippy_binary = target_dir.join(env!("PROFILE")).join("cargo-clippy"); + let clippy_binary = target_dir.join(env!("PROFILE")).join(CARGO_CLIPPY); let output = Command::new(clippy_binary) .current_dir(repo_dir) @@ -51,17 +56,15 @@ fn integration_test() { .expect("unable to run clippy"); let stderr = String::from_utf8_lossy(&output.stderr); - if stderr.contains("internal compiler error") { - let backtrace_start = stderr - .find("thread 'rustc' panicked at") - .expect("start of backtrace not found"); - let backtrace_end = stderr - .rfind("error: internal compiler error") + if let Some(backtrace_start) = stderr.find("error: internal compiler error") { + static BACKTRACE_END_MSG: &str = "end of query stack"; + let backtrace_end = stderr[backtrace_start..] + .find(BACKTRACE_END_MSG) .expect("end of backtrace not found"); panic!( "internal compiler error\nBacktrace:\n\n{}", - &stderr[backtrace_start..backtrace_end] + &stderr[backtrace_start..backtrace_start + backtrace_end + BACKTRACE_END_MSG.len()] ); } else if stderr.contains("query stack during panic") { panic!("query stack during panic in the output"); From b180d954d600a8c9b98ee31d0298ce1b13b6291f Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 25 Sep 2022 17:37:56 -0400 Subject: [PATCH 053/114] Don't lint `*_interior_mutable_const` on unions due to potential ICE. --- clippy_lints/src/non_copy_const.rs | 3 +++ tests/ui/crashes/ice-9445.rs | 3 +++ 2 files changed, 6 insertions(+) create mode 100644 tests/ui/crashes/ice-9445.rs diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 72c86f28bbc6c..ea76ce2c57357 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -149,6 +149,9 @@ fn is_value_unfrozen_raw<'tcx>( // the fact that we have to dig into every structs to search enums // leads us to the point checking `UnsafeCell` directly is the only option. ty::Adt(ty_def, ..) if ty_def.is_unsafe_cell() => true, + // As of 2022-09-08 miri doesn't track which union field is active so there's no safe way to check the + // contained value. + ty::Adt(def, ..) if def.is_union() => false, ty::Array(..) | ty::Adt(..) | ty::Tuple(..) => { let val = cx.tcx.destructure_mir_constant(cx.param_env, val); val.fields.iter().any(|field| inner(cx, *field)) diff --git a/tests/ui/crashes/ice-9445.rs b/tests/ui/crashes/ice-9445.rs new file mode 100644 index 0000000000000..c67b22f6f8c47 --- /dev/null +++ b/tests/ui/crashes/ice-9445.rs @@ -0,0 +1,3 @@ +const UNINIT: core::mem::MaybeUninit> = core::mem::MaybeUninit::uninit(); + +fn main() {} From 5a71bbdf3faeedfe5227aecc2a97e566cbbbaf70 Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Wed, 14 Sep 2022 12:25:48 -0400 Subject: [PATCH 054/114] new uninlined_format_args lint to inline explicit arguments Implement https://github.com/rust-lang/rust-clippy/issues/8368 - a new lint to inline format arguments such as `print!("{}", var)` into `print!("{var}")`. code | suggestion | comment ---|---|--- `print!("{}", var)` | `print!("{var}")` | simple variables `print!("{0}", var)` | `print!("{var}")` | positional variables `print!("{v}", v=var)` | `print!("{var}")` | named variables `print!("{0} {0}", var)` | `print!("{var} {var}")` | aliased variables `print!("{0:1$}", var, width)` | `print!("{var:width$}")` | width support `print!("{0:.1$}", var, prec)` | `print!("{var:.prec$}")` | precision support `print!("{:.*}", prec, var)` | `print!("{var:.prec$}")` | asterisk support code | suggestion | comment ---|---|--- `print!("{0}={1}", var, 1+2)` | `print!("{var}={0}", 1+2)` | Format string uses an indexed argument that cannot be inlined. Supporting this case requires re-indexing of the format string. changelog: [`uninlined_format_args`]: A new lint to inline format arguments, i.e. `print!("{}", var)` into `print!("{var}")` --- CHANGELOG.md | 1 + clippy_lints/src/format_args.rs | 140 +++- clippy_lints/src/lib.register_lints.rs | 1 + clippy_lints/src/lib.register_pedantic.rs | 1 + clippy_lints/src/lib.rs | 2 +- clippy_lints/src/utils/conf.rs | 2 +- clippy_lints/src/write.rs | 11 +- clippy_utils/src/macros.rs | 69 +- clippy_utils/src/msrvs.rs | 1 + clippy_utils/src/source.rs | 10 + src/docs.rs | 1 + src/docs/uninlined_format_args.txt | 36 + tests/ui/uninlined_format_args.fixed | 168 +++++ tests/ui/uninlined_format_args.rs | 171 +++++ tests/ui/uninlined_format_args.stderr | 866 ++++++++++++++++++++++ 15 files changed, 1451 insertions(+), 29 deletions(-) create mode 100644 src/docs/uninlined_format_args.txt create mode 100644 tests/ui/uninlined_format_args.fixed create mode 100644 tests/ui/uninlined_format_args.rs create mode 100644 tests/ui/uninlined_format_args.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index a56be486217e3..325b9bd846946 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4274,6 +4274,7 @@ Released 2018-09-13 [`unimplemented`]: https://rust-lang.github.io/rust-clippy/master/index.html#unimplemented [`uninit_assumed_init`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninit_assumed_init [`uninit_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninit_vec +[`uninlined_format_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args [`unit_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_arg [`unit_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_cmp [`unit_hash`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_hash diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index 192f6258aa59c..89d81bdd4850e 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -1,16 +1,18 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::is_diag_trait_item; -use clippy_utils::macros::{is_format_macro, FormatArgsExpn}; -use clippy_utils::source::snippet_opt; +use clippy_utils::macros::FormatParamKind::{Implicit, Named, Numbered, Starred}; +use clippy_utils::macros::{is_format_macro, FormatArgsExpn, FormatParam, FormatParamUsage}; +use clippy_utils::source::{expand_past_previous_comma, snippet_opt}; use clippy_utils::ty::implements_trait; +use clippy_utils::{is_diag_trait_item, meets_msrv, msrvs}; use if_chain::if_chain; use itertools::Itertools; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, HirId}; +use rustc_hir::{Expr, ExprKind, HirId, Path, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::adjustment::{Adjust, Adjustment}; use rustc_middle::ty::Ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_semver::RustcVersion; +use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{sym, ExpnData, ExpnKind, Span, Symbol}; declare_clippy_lint! { @@ -64,7 +66,67 @@ declare_clippy_lint! { "`to_string` applied to a type that implements `Display` in format args" } -declare_lint_pass!(FormatArgs => [FORMAT_IN_FORMAT_ARGS, TO_STRING_IN_FORMAT_ARGS]); +declare_clippy_lint! { + /// ### What it does + /// Detect when a variable is not inlined in a format string, + /// and suggests to inline it. + /// + /// ### Why is this bad? + /// Non-inlined code is slightly more difficult to read and understand, + /// as it requires arguments to be matched against the format string. + /// The inlined syntax, where allowed, is simpler. + /// + /// ### Example + /// ```rust + /// # let var = 42; + /// # let width = 1; + /// # let prec = 2; + /// format!("{}", var); + /// format!("{v:?}", v = var); + /// format!("{0} {0}", var); + /// format!("{0:1$}", var, width); + /// format!("{:.*}", prec, var); + /// ``` + /// Use instead: + /// ```rust + /// # let var = 42; + /// # let width = 1; + /// # let prec = 2; + /// format!("{var}"); + /// format!("{var:?}"); + /// format!("{var} {var}"); + /// format!("{var:width$}"); + /// format!("{var:.prec$}"); + /// ``` + /// + /// ### Known Problems + /// + /// There may be a false positive if the format string is expanded from certain proc macros: + /// + /// ```ignore + /// println!(indoc!("{}"), var); + /// ``` + /// + /// If a format string contains a numbered argument that cannot be inlined + /// nothing will be suggested, e.g. `println!("{0}={1}", var, 1+2)`. + #[clippy::version = "1.65.0"] + pub UNINLINED_FORMAT_ARGS, + pedantic, + "using non-inlined variables in `format!` calls" +} + +impl_lint_pass!(FormatArgs => [FORMAT_IN_FORMAT_ARGS, UNINLINED_FORMAT_ARGS, TO_STRING_IN_FORMAT_ARGS]); + +pub struct FormatArgs { + msrv: Option, +} + +impl FormatArgs { + #[must_use] + pub fn new(msrv: Option) -> Self { + Self { msrv } + } +} impl<'tcx> LateLintPass<'tcx> for FormatArgs { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { @@ -86,9 +148,73 @@ impl<'tcx> LateLintPass<'tcx> for FormatArgs { check_format_in_format_args(cx, outermost_expn_data.call_site, name, arg.param.value); check_to_string_in_format_args(cx, name, arg.param.value); } + if meets_msrv(self.msrv, msrvs::FORMAT_ARGS_CAPTURE) { + check_uninlined_args(cx, &format_args, outermost_expn_data.call_site); + } } } } + + extract_msrv_attr!(LateContext); +} + +fn check_uninlined_args(cx: &LateContext<'_>, args: &FormatArgsExpn<'_>, call_site: Span) { + if args.format_string.span.from_expansion() { + return; + } + + let mut fixes = Vec::new(); + // If any of the arguments are referenced by an index number, + // and that argument is not a simple variable and cannot be inlined, + // we cannot remove any other arguments in the format string, + // because the index numbers might be wrong after inlining. + // Example of an un-inlinable format: print!("{}{1}", foo, 2) + if !args.params().all(|p| check_one_arg(cx, &p, &mut fixes)) || fixes.is_empty() { + return; + } + + // FIXME: Properly ignore a rare case where the format string is wrapped in a macro. + // Example: `format!(indoc!("{}"), foo);` + // If inlined, they will cause a compilation error: + // > to avoid ambiguity, `format_args!` cannot capture variables + // > when the format string is expanded from a macro + // @Alexendoo explanation: + // > indoc! is a proc macro that is producing a string literal with its span + // > set to its input it's not marked as from expansion, and since it's compatible + // > tokenization wise clippy_utils::is_from_proc_macro wouldn't catch it either + // This might be a relatively expensive test, so do it only we are ready to replace. + // See more examples in tests/ui/uninlined_format_args.rs + + span_lint_and_then( + cx, + UNINLINED_FORMAT_ARGS, + call_site, + "variables can be used directly in the `format!` string", + |diag| { + diag.multipart_suggestion("change this to", fixes, Applicability::MachineApplicable); + }, + ); +} + +fn check_one_arg(cx: &LateContext<'_>, param: &FormatParam<'_>, fixes: &mut Vec<(Span, String)>) -> bool { + if matches!(param.kind, Implicit | Starred | Named(_) | Numbered) + && let ExprKind::Path(QPath::Resolved(None, path)) = param.value.kind + && let Path { span, segments, .. } = path + && let [segment] = segments + { + let replacement = match param.usage { + FormatParamUsage::Argument => segment.ident.name.to_string(), + FormatParamUsage::Width => format!("{}$", segment.ident.name), + FormatParamUsage::Precision => format!(".{}$", segment.ident.name), + }; + fixes.push((param.span, replacement)); + let arg_span = expand_past_previous_comma(cx, *span); + fixes.push((arg_span, String::new())); + true // successful inlining, continue checking + } else { + // if we can't inline a numbered argument, we can't continue + param.kind != Numbered + } } fn outermost_expn_data(expn_data: ExpnData) -> ExpnData { @@ -170,7 +296,7 @@ fn check_to_string_in_format_args(cx: &LateContext<'_>, name: Symbol, value: &Ex } } -// Returns true if `hir_id` is referred to by multiple format params +/// Returns true if `hir_id` is referred to by multiple format params fn is_aliased(args: &FormatArgsExpn<'_>, hir_id: HirId) -> bool { args.params() .filter(|param| param.value.hir_id == hir_id) diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 02fcc8de50727..c6ac0178fface 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -159,6 +159,7 @@ store.register_lints(&[ format::USELESS_FORMAT, format_args::FORMAT_IN_FORMAT_ARGS, format_args::TO_STRING_IN_FORMAT_ARGS, + format_args::UNINLINED_FORMAT_ARGS, format_impl::PRINT_IN_FORMAT_IMPL, format_impl::RECURSIVE_FORMAT_IMPL, format_push_string::FORMAT_PUSH_STRING, diff --git a/clippy_lints/src/lib.register_pedantic.rs b/clippy_lints/src/lib.register_pedantic.rs index 03c3c202e0a8f..4eaabfbcc5fab 100644 --- a/clippy_lints/src/lib.register_pedantic.rs +++ b/clippy_lints/src/lib.register_pedantic.rs @@ -29,6 +29,7 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ 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), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 8a2a1682eca26..73349ace88264 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -855,7 +855,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: )) }); store.register_late_pass(move || Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks)); - store.register_late_pass(move || Box::new(format_args::FormatArgs)); + store.register_late_pass(move || Box::new(format_args::FormatArgs::new(msrv))); store.register_late_pass(|| Box::new(trailing_empty_array::TrailingEmptyArray)); store.register_early_pass(|| Box::new(octal_escapes::OctalEscapes)); store.register_late_pass(|| Box::new(needless_late_init::NeedlessLateInit)); diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 6f5a638be12b9..a8265b50f273f 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -213,7 +213,7 @@ define_Conf! { /// /// Suppress lints whenever the suggested change would cause breakage for other crates. (avoid_breaking_exported_api: bool = true), - /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED. + /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS. /// /// The minimum rust version that the project supports (msrv: Option = None), diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index 06e7d70170171..3d3686604b72a 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -1,12 +1,12 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::macros::{root_macro_call_first_node, FormatArgsExpn, MacroCall}; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::{expand_past_previous_comma, snippet_opt}; use rustc_ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, HirIdMap, Impl, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::{sym, BytePos, Span}; +use rustc_span::{sym, BytePos}; declare_clippy_lint! { /// ### What it does @@ -542,10 +542,3 @@ fn conservative_unescape(literal: &str) -> Result { if err { Err(UnescapeErr::Lint) } else { Ok(unescaped) } } - -// Expand from `writeln!(o, "")` to `writeln!(o, "")` -// ^^ ^^^^ -fn expand_past_previous_comma(cx: &LateContext<'_>, span: Span) -> Span { - let extended = cx.sess().source_map().span_extend_to_prev_char(span, ',', true); - extended.with_lo(extended.lo() - BytePos(1)) -} diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs index b9e6462a55efc..079c8f50f12a2 100644 --- a/clippy_utils/src/macros.rs +++ b/clippy_utils/src/macros.rs @@ -545,19 +545,32 @@ fn span_from_inner(base: SpanData, inner: rpf::InnerSpan) -> Span { ) } +/// How a format parameter is used in the format string #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum FormatParamKind { /// An implicit parameter , such as `{}` or `{:?}`. Implicit, - /// A parameter with an explicit number, or an asterisk precision. e.g. `{1}`, `{0:?}`, - /// `{:.0$}` or `{:.*}`. + /// A parameter with an explicit number, e.g. `{1}`, `{0:?}`, or `{:.0$}` Numbered, + /// A parameter with an asterisk precision. e.g. `{:.*}`. + Starred, /// A named parameter with a named `value_arg`, such as the `x` in `format!("{x}", x = 1)`. Named(Symbol), /// An implicit named parameter, such as the `y` in `format!("{y}")`. NamedInline(Symbol), } +/// Where a format parameter is being used in the format string +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum FormatParamUsage { + /// Appears as an argument, e.g. `format!("{}", foo)` + Argument, + /// Appears as a width, e.g. `format!("{:width$}", foo, width = 1)` + Width, + /// Appears as a precision, e.g. `format!("{:.precision$}", foo, precision = 1)` + Precision, +} + /// A `FormatParam` is any place in a `FormatArgument` that refers to a supplied value, e.g. /// /// ``` @@ -573,6 +586,8 @@ pub struct FormatParam<'tcx> { pub value: &'tcx Expr<'tcx>, /// How this parameter refers to its `value`. pub kind: FormatParamKind, + /// Where this format param is being used - argument/width/precision + pub usage: FormatParamUsage, /// Span of the parameter, may be zero width. Includes the whitespace of implicit parameters. /// /// ```text @@ -585,6 +600,7 @@ pub struct FormatParam<'tcx> { impl<'tcx> FormatParam<'tcx> { fn new( mut kind: FormatParamKind, + usage: FormatParamUsage, position: usize, inner: rpf::InnerSpan, values: &FormatArgsValues<'tcx>, @@ -599,7 +615,12 @@ impl<'tcx> FormatParam<'tcx> { kind = FormatParamKind::NamedInline(name); } - Some(Self { value, kind, span }) + Some(Self { + value, + kind, + usage, + span, + }) } } @@ -618,6 +639,7 @@ pub enum Count<'tcx> { impl<'tcx> Count<'tcx> { fn new( + usage: FormatParamUsage, count: rpf::Count<'_>, position: Option, inner: Option, @@ -625,15 +647,27 @@ impl<'tcx> Count<'tcx> { ) -> Option { Some(match count { rpf::Count::CountIs(val) => Self::Is(val, span_from_inner(values.format_string_span, inner?)), - rpf::Count::CountIsName(name, span) => Self::Param(FormatParam::new( + rpf::Count::CountIsName(name, _) => Self::Param(FormatParam::new( FormatParamKind::Named(Symbol::intern(name)), + usage, position?, - span, + inner?, + values, + )?), + rpf::Count::CountIsParam(_) => Self::Param(FormatParam::new( + FormatParamKind::Numbered, + usage, + position?, + inner?, + values, + )?), + rpf::Count::CountIsStar(_) => Self::Param(FormatParam::new( + FormatParamKind::Starred, + usage, + position?, + inner?, values, )?), - rpf::Count::CountIsParam(_) | rpf::Count::CountIsStar(_) => { - Self::Param(FormatParam::new(FormatParamKind::Numbered, position?, inner?, values)?) - }, rpf::Count::CountImplied => Self::Implied, }) } @@ -676,8 +710,20 @@ impl<'tcx> FormatSpec<'tcx> { fill: spec.fill, align: spec.align, flags: spec.flags, - precision: Count::new(spec.precision, positions.precision, spec.precision_span, values)?, - width: Count::new(spec.width, positions.width, spec.width_span, values)?, + precision: Count::new( + FormatParamUsage::Precision, + spec.precision, + positions.precision, + spec.precision_span, + values, + )?, + width: Count::new( + FormatParamUsage::Width, + spec.width, + positions.width, + spec.width_span, + values, + )?, r#trait: match spec.ty { "" => sym::Display, "?" => sym::Debug, @@ -723,7 +769,7 @@ pub struct FormatArg<'tcx> { pub struct FormatArgsExpn<'tcx> { /// The format string literal. pub format_string: FormatString, - // The format arguments, such as `{:?}`. + /// The format arguments, such as `{:?}`. pub args: Vec>, /// Has an added newline due to `println!()`/`writeln!()`/etc. The last format string part will /// include this added newline. @@ -797,6 +843,7 @@ impl<'tcx> FormatArgsExpn<'tcx> { // NamedInline is handled by `FormatParam::new()` rpf::Position::ArgumentNamed(name) => FormatParamKind::Named(Symbol::intern(name)), }, + FormatParamUsage::Argument, position.value, parsed_arg.position_span, &values, diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index 62020e21c8155..904091c57e837 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -13,6 +13,7 @@ macro_rules! msrv_aliases { // names may refer to stabilized feature flags or library items msrv_aliases! { 1,62,0 { BOOL_THEN_SOME } + 1,58,0 { FORMAT_ARGS_CAPTURE } 1,53,0 { OR_PATTERNS, MANUAL_BITS, BTREE_MAP_RETAIN, BTREE_SET_RETAIN, ARRAY_INTO_ITERATOR } 1,52,0 { STR_SPLIT_ONCE, REM_EUCLID_CONST } 1,51,0 { BORROW_AS_PTR, UNSIGNED_ABS } diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs index 64c3f70efa5d7..d28bd92d708ba 100644 --- a/clippy_utils/src/source.rs +++ b/clippy_utils/src/source.rs @@ -392,6 +392,16 @@ pub fn trim_span(sm: &SourceMap, span: Span) -> Span { .span() } +/// Expand a span to include a preceding comma +/// ```rust,ignore +/// writeln!(o, "") -> writeln!(o, "") +/// ^^ ^^^^ +/// ``` +pub fn expand_past_previous_comma(cx: &LateContext<'_>, span: Span) -> Span { + let extended = cx.sess().source_map().span_extend_to_prev_char(span, ',', true); + extended.with_lo(extended.lo() - BytePos(1)) +} + #[cfg(test)] mod test { use super::{reindent_multiline, without_block_comments}; diff --git a/src/docs.rs b/src/docs.rs index 6c89b4dde372d..a501b56ffbeb0 100644 --- a/src/docs.rs +++ b/src/docs.rs @@ -521,6 +521,7 @@ docs! { "unimplemented", "uninit_assumed_init", "uninit_vec", + "uninlined_format_args", "unit_arg", "unit_cmp", "unit_hash", diff --git a/src/docs/uninlined_format_args.txt b/src/docs/uninlined_format_args.txt new file mode 100644 index 0000000000000..3d2966c84dbe3 --- /dev/null +++ b/src/docs/uninlined_format_args.txt @@ -0,0 +1,36 @@ +### What it does +Detect when a variable is not inlined in a format string, +and suggests to inline it. + +### Why is this bad? +Non-inlined code is slightly more difficult to read and understand, +as it requires arguments to be matched against the format string. +The inlined syntax, where allowed, is simpler. + +### Example +``` +format!("{}", var); +format!("{v:?}", v = var); +format!("{0} {0}", var); +format!("{0:1$}", var, width); +format!("{:.*}", prec, var); +``` +Use instead: +``` +format!("{var}"); +format!("{var:?}"); +format!("{var} {var}"); +format!("{var:width$}"); +format!("{var:.prec$}"); +``` + +### Known Problems + +There may be a false positive if the format string is expanded from certain proc macros: + +``` +println!(indoc!("{}"), var); +``` + +If a format string contains a numbered argument that cannot be inlined +nothing will be suggested, e.g. `println!("{0}={1}", var, 1+2)`. \ No newline at end of file diff --git a/tests/ui/uninlined_format_args.fixed b/tests/ui/uninlined_format_args.fixed new file mode 100644 index 0000000000000..bade0ed8ad641 --- /dev/null +++ b/tests/ui/uninlined_format_args.fixed @@ -0,0 +1,168 @@ +// run-rustfix + +#![allow(clippy::eq_op)] +#![allow(clippy::format_in_format_args)] +#![allow(clippy::print_literal)] +#![allow(named_arguments_used_positionally)] +#![allow(unused_variables, unused_imports, unused_macros)] +#![warn(clippy::uninlined_format_args)] +#![feature(custom_inner_attributes)] + +macro_rules! no_param_str { + () => { + "{}" + }; +} + +macro_rules! pass_through { + ($expr:expr) => { + $expr + }; +} + +macro_rules! my_println { + ($($args:tt),*) => {{ + println!($($args),*) + }}; +} + +macro_rules! my_println_args { + ($($args:tt),*) => {{ + println!("foo: {}", format_args!($($args),*)) + }}; +} + +fn tester(fn_arg: i32) { + let local_i32 = 1; + let local_f64 = 2.0; + let local_opt: Option = Some(3); + let width = 4; + let prec = 5; + let val = 6; + + // make sure this file hasn't been corrupted with tabs converted to spaces + // let _ = ' '; // <- this is a single tab character + let _: &[u8; 3] = b" "; // <- + + println!("val='{local_i32}'"); + println!("val='{local_i32}'"); // 3 spaces + println!("val='{local_i32}'"); // tab + println!("val='{local_i32}'"); // space+tab + println!("val='{local_i32}'"); // tab+space + println!( + "val='{local_i32}'" + ); + println!("{local_i32}"); + println!("{fn_arg}"); + println!("{local_i32:?}"); + println!("{local_i32:#?}"); + println!("{local_i32:4}"); + println!("{local_i32:04}"); + println!("{local_i32:<3}"); + println!("{local_i32:#010x}"); + println!("{local_f64:.1}"); + println!("Hello {} is {local_f64:.local_i32$}", "x"); + println!("Hello {local_i32} is {local_f64:.*}", 5); + println!("Hello {local_i32} is {local_f64:.*}", 5); + println!("{local_i32} {local_f64}"); + println!("{local_i32}, {}", local_opt.unwrap()); + println!("{val}"); + println!("{val}"); + println!("{} {1}", local_i32, 42); + println!("val='{local_i32}'"); + println!("val='{local_i32}'"); + println!("val='{local_i32}'"); + println!("val='{fn_arg}'"); + println!("{local_i32}"); + println!("{local_i32:?}"); + println!("{local_i32:#?}"); + println!("{local_i32:04}"); + println!("{local_i32:<3}"); + println!("{local_i32:#010x}"); + println!("{local_f64:.1}"); + println!("{local_i32} {local_i32}"); + println!("{local_f64} {local_i32} {local_i32} {local_f64}"); + println!("{local_i32} {local_f64}"); + println!("{local_f64} {local_i32}"); + println!("{local_f64} {local_i32} {local_f64} {local_i32}"); + println!("{1} {0}", "str", local_i32); + println!("{local_i32}"); + println!("{local_i32:width$}"); + println!("{local_i32:width$}"); + println!("{local_i32:.prec$}"); + println!("{local_i32:.prec$}"); + println!("{val:val$}"); + println!("{val:val$}"); + println!("{val:val$.val$}"); + println!("{val:val$.val$}"); + println!("{val:val$.val$}"); + println!("{val:val$.val$}"); + println!("{val:val$.val$}"); + println!("{val:val$.val$}"); + println!("{val:val$.val$}"); + println!("{val:val$.val$}"); + println!("{width:width$}"); + println!("{local_i32:width$}"); + println!("{width:width$}"); + println!("{local_i32:width$}"); + println!("{prec:.prec$}"); + println!("{local_i32:.prec$}"); + println!("{prec:.prec$}"); + println!("{local_i32:.prec$}"); + println!("{width:width$.prec$}"); + println!("{width:width$.prec$}"); + println!("{local_f64:width$.prec$}"); + println!("{local_f64:width$.prec$} {local_f64} {width} {prec}"); + println!( + "{local_i32:width$.prec$} {local_i32:prec$.width$} {width:local_i32$.prec$} {width:prec$.local_i32$} {prec:local_i32$.width$} {prec:width$.local_i32$}", + ); + println!( + "{0:1$.2$} {0:2$.1$} {1:0$.2$} {1:2$.0$} {2:0$.1$} {2:1$.0$} {3}", + local_i32, + width, + prec, + 1 + 2 + ); + println!("Width = {local_i32}, value with width = {local_f64:local_i32$}"); + println!("{local_i32:width$.prec$}"); + println!("{width:width$.prec$}"); + println!("{}", format!("{local_i32}")); + my_println!("{}", local_i32); + my_println_args!("{}", local_i32); + + // these should NOT be modified by the lint + println!(concat!("nope ", "{}"), local_i32); + println!("val='{local_i32}'"); + println!("val='{local_i32 }'"); + println!("val='{local_i32 }'"); // with tab + println!("val='{local_i32\n}'"); + println!("{}", usize::MAX); + println!("{}", local_opt.unwrap()); + println!( + "val='{local_i32 + }'" + ); + println!(no_param_str!(), local_i32); + + // FIXME: bugs! + // println!(pass_through!("foo={local_i32}"), local_i32 = local_i32); + // println!(pass_through!("foo={}"), local_i32); + // println!(indoc!("foo={}"), local_i32); + // printdoc!("foo={}", local_i32); +} + +fn main() { + tester(42); +} + +fn _under_msrv() { + #![clippy::msrv = "1.57"] + let local_i32 = 1; + println!("don't expand='{}'", local_i32); +} + +fn _meets_msrv() { + #![clippy::msrv = "1.58"] + let local_i32 = 1; + println!("expand='{local_i32}'"); +} diff --git a/tests/ui/uninlined_format_args.rs b/tests/ui/uninlined_format_args.rs new file mode 100644 index 0000000000000..ac958f9e5b607 --- /dev/null +++ b/tests/ui/uninlined_format_args.rs @@ -0,0 +1,171 @@ +// run-rustfix + +#![allow(clippy::eq_op)] +#![allow(clippy::format_in_format_args)] +#![allow(clippy::print_literal)] +#![allow(named_arguments_used_positionally)] +#![allow(unused_variables, unused_imports, unused_macros)] +#![warn(clippy::uninlined_format_args)] +#![feature(custom_inner_attributes)] + +macro_rules! no_param_str { + () => { + "{}" + }; +} + +macro_rules! pass_through { + ($expr:expr) => { + $expr + }; +} + +macro_rules! my_println { + ($($args:tt),*) => {{ + println!($($args),*) + }}; +} + +macro_rules! my_println_args { + ($($args:tt),*) => {{ + println!("foo: {}", format_args!($($args),*)) + }}; +} + +fn tester(fn_arg: i32) { + let local_i32 = 1; + let local_f64 = 2.0; + let local_opt: Option = Some(3); + let width = 4; + let prec = 5; + let val = 6; + + // make sure this file hasn't been corrupted with tabs converted to spaces + // let _ = ' '; // <- this is a single tab character + let _: &[u8; 3] = b" "; // <- + + println!("val='{}'", local_i32); + println!("val='{ }'", local_i32); // 3 spaces + println!("val='{ }'", local_i32); // tab + println!("val='{ }'", local_i32); // space+tab + println!("val='{ }'", local_i32); // tab+space + println!( + "val='{ + }'", + local_i32 + ); + println!("{}", local_i32); + println!("{}", fn_arg); + println!("{:?}", local_i32); + println!("{:#?}", local_i32); + println!("{:4}", local_i32); + println!("{:04}", local_i32); + println!("{:<3}", local_i32); + println!("{:#010x}", local_i32); + println!("{:.1}", local_f64); + println!("Hello {} is {:.*}", "x", local_i32, local_f64); + println!("Hello {} is {:.*}", local_i32, 5, local_f64); + println!("Hello {} is {2:.*}", local_i32, 5, local_f64); + println!("{} {}", local_i32, local_f64); + println!("{}, {}", local_i32, local_opt.unwrap()); + println!("{}", val); + println!("{}", v = val); + println!("{} {1}", local_i32, 42); + println!("val='{\t }'", local_i32); + println!("val='{\n }'", local_i32); + println!("val='{local_i32}'", local_i32 = local_i32); + println!("val='{local_i32}'", local_i32 = fn_arg); + println!("{0}", local_i32); + println!("{0:?}", local_i32); + println!("{0:#?}", local_i32); + println!("{0:04}", local_i32); + println!("{0:<3}", local_i32); + println!("{0:#010x}", local_i32); + println!("{0:.1}", local_f64); + println!("{0} {0}", local_i32); + println!("{1} {} {0} {}", local_i32, local_f64); + println!("{0} {1}", local_i32, local_f64); + println!("{1} {0}", local_i32, local_f64); + println!("{1} {0} {1} {0}", local_i32, local_f64); + println!("{1} {0}", "str", local_i32); + println!("{v}", v = local_i32); + println!("{local_i32:0$}", width); + println!("{local_i32:w$}", w = width); + println!("{local_i32:.0$}", prec); + println!("{local_i32:.p$}", p = prec); + println!("{:0$}", v = val); + println!("{0:0$}", v = val); + println!("{:0$.0$}", v = val); + println!("{0:0$.0$}", v = val); + println!("{0:0$.v$}", v = val); + println!("{0:v$.0$}", v = val); + println!("{v:0$.0$}", v = val); + println!("{v:v$.0$}", v = val); + println!("{v:0$.v$}", v = val); + println!("{v:v$.v$}", v = val); + println!("{:0$}", width); + println!("{:1$}", local_i32, width); + println!("{:w$}", w = width); + println!("{:w$}", local_i32, w = width); + println!("{:.0$}", prec); + println!("{:.1$}", local_i32, prec); + println!("{:.p$}", p = prec); + println!("{:.p$}", local_i32, p = prec); + println!("{:0$.1$}", width, prec); + println!("{:0$.w$}", width, w = prec); + println!("{:1$.2$}", local_f64, width, prec); + println!("{:1$.2$} {0} {1} {2}", local_f64, width, prec); + println!( + "{0:1$.2$} {0:2$.1$} {1:0$.2$} {1:2$.0$} {2:0$.1$} {2:1$.0$}", + local_i32, width, prec, + ); + println!( + "{0:1$.2$} {0:2$.1$} {1:0$.2$} {1:2$.0$} {2:0$.1$} {2:1$.0$} {3}", + local_i32, + width, + prec, + 1 + 2 + ); + println!("Width = {}, value with width = {:0$}", local_i32, local_f64); + println!("{:w$.p$}", local_i32, w = width, p = prec); + println!("{:w$.p$}", w = width, p = prec); + println!("{}", format!("{}", local_i32)); + my_println!("{}", local_i32); + my_println_args!("{}", local_i32); + + // these should NOT be modified by the lint + println!(concat!("nope ", "{}"), local_i32); + println!("val='{local_i32}'"); + println!("val='{local_i32 }'"); + println!("val='{local_i32 }'"); // with tab + println!("val='{local_i32\n}'"); + println!("{}", usize::MAX); + println!("{}", local_opt.unwrap()); + println!( + "val='{local_i32 + }'" + ); + println!(no_param_str!(), local_i32); + + // FIXME: bugs! + // println!(pass_through!("foo={local_i32}"), local_i32 = local_i32); + // println!(pass_through!("foo={}"), local_i32); + // println!(indoc!("foo={}"), local_i32); + // printdoc!("foo={}", local_i32); +} + +fn main() { + tester(42); +} + +fn _under_msrv() { + #![clippy::msrv = "1.57"] + let local_i32 = 1; + println!("don't expand='{}'", local_i32); +} + +fn _meets_msrv() { + #![clippy::msrv = "1.58"] + let local_i32 = 1; + println!("expand='{}'", local_i32); +} diff --git a/tests/ui/uninlined_format_args.stderr b/tests/ui/uninlined_format_args.stderr new file mode 100644 index 0000000000000..7e652d0354f24 --- /dev/null +++ b/tests/ui/uninlined_format_args.stderr @@ -0,0 +1,866 @@ +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:47:5 + | +LL | println!("val='{}'", local_i32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::uninlined-format-args` implied by `-D warnings` +help: change this to + | +LL - println!("val='{}'", local_i32); +LL + println!("val='{local_i32}'"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:48:5 + | +LL | println!("val='{ }'", local_i32); // 3 spaces + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("val='{ }'", local_i32); // 3 spaces +LL + println!("val='{local_i32}'"); // 3 spaces + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:49:5 + | +LL | println!("val='{ }'", local_i32); // tab + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("val='{ }'", local_i32); // tab +LL + println!("val='{local_i32}'"); // tab + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:50:5 + | +LL | println!("val='{ }'", local_i32); // space+tab + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("val='{ }'", local_i32); // space+tab +LL + println!("val='{local_i32}'"); // space+tab + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:51:5 + | +LL | println!("val='{ }'", local_i32); // tab+space + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("val='{ }'", local_i32); // tab+space +LL + println!("val='{local_i32}'"); // tab+space + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:52:5 + | +LL | / println!( +LL | | "val='{ +LL | | }'", +LL | | local_i32 +LL | | ); + | |_____^ + | +help: change this to + | +LL - "val='{ +LL + "val='{local_i32}'" + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:57:5 + | +LL | println!("{}", local_i32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{}", local_i32); +LL + println!("{local_i32}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:58:5 + | +LL | println!("{}", fn_arg); + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{}", fn_arg); +LL + println!("{fn_arg}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:59:5 + | +LL | println!("{:?}", local_i32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{:?}", local_i32); +LL + println!("{local_i32:?}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:60:5 + | +LL | println!("{:#?}", local_i32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{:#?}", local_i32); +LL + println!("{local_i32:#?}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:61:5 + | +LL | println!("{:4}", local_i32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{:4}", local_i32); +LL + println!("{local_i32:4}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:62:5 + | +LL | println!("{:04}", local_i32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{:04}", local_i32); +LL + println!("{local_i32:04}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:63:5 + | +LL | println!("{:<3}", local_i32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{:<3}", local_i32); +LL + println!("{local_i32:<3}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:64:5 + | +LL | println!("{:#010x}", local_i32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{:#010x}", local_i32); +LL + println!("{local_i32:#010x}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:65:5 + | +LL | println!("{:.1}", local_f64); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{:.1}", local_f64); +LL + println!("{local_f64:.1}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:66:5 + | +LL | println!("Hello {} is {:.*}", "x", local_i32, local_f64); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("Hello {} is {:.*}", "x", local_i32, local_f64); +LL + println!("Hello {} is {local_f64:.local_i32$}", "x"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:67:5 + | +LL | println!("Hello {} is {:.*}", local_i32, 5, local_f64); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("Hello {} is {:.*}", local_i32, 5, local_f64); +LL + println!("Hello {local_i32} is {local_f64:.*}", 5); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:68:5 + | +LL | println!("Hello {} is {2:.*}", local_i32, 5, local_f64); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("Hello {} is {2:.*}", local_i32, 5, local_f64); +LL + println!("Hello {local_i32} is {local_f64:.*}", 5); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:69:5 + | +LL | println!("{} {}", local_i32, local_f64); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{} {}", local_i32, local_f64); +LL + println!("{local_i32} {local_f64}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:70:5 + | +LL | println!("{}, {}", local_i32, local_opt.unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{}, {}", local_i32, local_opt.unwrap()); +LL + println!("{local_i32}, {}", local_opt.unwrap()); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:71:5 + | +LL | println!("{}", val); + | ^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{}", val); +LL + println!("{val}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:72:5 + | +LL | println!("{}", v = val); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{}", v = val); +LL + println!("{val}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:74:5 + | +LL | println!("val='{/t }'", local_i32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("val='{/t }'", local_i32); +LL + println!("val='{local_i32}'"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:75:5 + | +LL | println!("val='{/n }'", local_i32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("val='{/n }'", local_i32); +LL + println!("val='{local_i32}'"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:76:5 + | +LL | println!("val='{local_i32}'", local_i32 = local_i32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("val='{local_i32}'", local_i32 = local_i32); +LL + println!("val='{local_i32}'"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:77:5 + | +LL | println!("val='{local_i32}'", local_i32 = fn_arg); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("val='{local_i32}'", local_i32 = fn_arg); +LL + println!("val='{fn_arg}'"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:78:5 + | +LL | println!("{0}", local_i32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{0}", local_i32); +LL + println!("{local_i32}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:79:5 + | +LL | println!("{0:?}", local_i32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{0:?}", local_i32); +LL + println!("{local_i32:?}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:80:5 + | +LL | println!("{0:#?}", local_i32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{0:#?}", local_i32); +LL + println!("{local_i32:#?}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:81:5 + | +LL | println!("{0:04}", local_i32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{0:04}", local_i32); +LL + println!("{local_i32:04}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:82:5 + | +LL | println!("{0:<3}", local_i32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{0:<3}", local_i32); +LL + println!("{local_i32:<3}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:83:5 + | +LL | println!("{0:#010x}", local_i32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{0:#010x}", local_i32); +LL + println!("{local_i32:#010x}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:84:5 + | +LL | println!("{0:.1}", local_f64); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{0:.1}", local_f64); +LL + println!("{local_f64:.1}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:85:5 + | +LL | println!("{0} {0}", local_i32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{0} {0}", local_i32); +LL + println!("{local_i32} {local_i32}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:86:5 + | +LL | println!("{1} {} {0} {}", local_i32, local_f64); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{1} {} {0} {}", local_i32, local_f64); +LL + println!("{local_f64} {local_i32} {local_i32} {local_f64}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:87:5 + | +LL | println!("{0} {1}", local_i32, local_f64); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{0} {1}", local_i32, local_f64); +LL + println!("{local_i32} {local_f64}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:88:5 + | +LL | println!("{1} {0}", local_i32, local_f64); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{1} {0}", local_i32, local_f64); +LL + println!("{local_f64} {local_i32}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:89:5 + | +LL | println!("{1} {0} {1} {0}", local_i32, local_f64); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{1} {0} {1} {0}", local_i32, local_f64); +LL + println!("{local_f64} {local_i32} {local_f64} {local_i32}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:91:5 + | +LL | println!("{v}", v = local_i32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{v}", v = local_i32); +LL + println!("{local_i32}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:92:5 + | +LL | println!("{local_i32:0$}", width); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{local_i32:0$}", width); +LL + println!("{local_i32:width$}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:93:5 + | +LL | println!("{local_i32:w$}", w = width); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{local_i32:w$}", w = width); +LL + println!("{local_i32:width$}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:94:5 + | +LL | println!("{local_i32:.0$}", prec); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{local_i32:.0$}", prec); +LL + println!("{local_i32:.prec$}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:95:5 + | +LL | println!("{local_i32:.p$}", p = prec); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{local_i32:.p$}", p = prec); +LL + println!("{local_i32:.prec$}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:96:5 + | +LL | println!("{:0$}", v = val); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{:0$}", v = val); +LL + println!("{val:val$}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:97:5 + | +LL | println!("{0:0$}", v = val); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{0:0$}", v = val); +LL + println!("{val:val$}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:98:5 + | +LL | println!("{:0$.0$}", v = val); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{:0$.0$}", v = val); +LL + println!("{val:val$.val$}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:99:5 + | +LL | println!("{0:0$.0$}", v = val); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{0:0$.0$}", v = val); +LL + println!("{val:val$.val$}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:100:5 + | +LL | println!("{0:0$.v$}", v = val); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{0:0$.v$}", v = val); +LL + println!("{val:val$.val$}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:101:5 + | +LL | println!("{0:v$.0$}", v = val); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{0:v$.0$}", v = val); +LL + println!("{val:val$.val$}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:102:5 + | +LL | println!("{v:0$.0$}", v = val); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{v:0$.0$}", v = val); +LL + println!("{val:val$.val$}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:103:5 + | +LL | println!("{v:v$.0$}", v = val); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{v:v$.0$}", v = val); +LL + println!("{val:val$.val$}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:104:5 + | +LL | println!("{v:0$.v$}", v = val); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{v:0$.v$}", v = val); +LL + println!("{val:val$.val$}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:105:5 + | +LL | println!("{v:v$.v$}", v = val); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{v:v$.v$}", v = val); +LL + println!("{val:val$.val$}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:106:5 + | +LL | println!("{:0$}", width); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{:0$}", width); +LL + println!("{width:width$}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:107:5 + | +LL | println!("{:1$}", local_i32, width); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{:1$}", local_i32, width); +LL + println!("{local_i32:width$}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:108:5 + | +LL | println!("{:w$}", w = width); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{:w$}", w = width); +LL + println!("{width:width$}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:109:5 + | +LL | println!("{:w$}", local_i32, w = width); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{:w$}", local_i32, w = width); +LL + println!("{local_i32:width$}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:110:5 + | +LL | println!("{:.0$}", prec); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{:.0$}", prec); +LL + println!("{prec:.prec$}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:111:5 + | +LL | println!("{:.1$}", local_i32, prec); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{:.1$}", local_i32, prec); +LL + println!("{local_i32:.prec$}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:112:5 + | +LL | println!("{:.p$}", p = prec); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{:.p$}", p = prec); +LL + println!("{prec:.prec$}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:113:5 + | +LL | println!("{:.p$}", local_i32, p = prec); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{:.p$}", local_i32, p = prec); +LL + println!("{local_i32:.prec$}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:114:5 + | +LL | println!("{:0$.1$}", width, prec); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{:0$.1$}", width, prec); +LL + println!("{width:width$.prec$}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:115:5 + | +LL | println!("{:0$.w$}", width, w = prec); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{:0$.w$}", width, w = prec); +LL + println!("{width:width$.prec$}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:116:5 + | +LL | println!("{:1$.2$}", local_f64, width, prec); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{:1$.2$}", local_f64, width, prec); +LL + println!("{local_f64:width$.prec$}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:117:5 + | +LL | println!("{:1$.2$} {0} {1} {2}", local_f64, width, prec); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{:1$.2$} {0} {1} {2}", local_f64, width, prec); +LL + println!("{local_f64:width$.prec$} {local_f64} {width} {prec}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:118:5 + | +LL | / println!( +LL | | "{0:1$.2$} {0:2$.1$} {1:0$.2$} {1:2$.0$} {2:0$.1$} {2:1$.0$}", +LL | | local_i32, width, prec, +LL | | ); + | |_____^ + | +help: change this to + | +LL ~ "{local_i32:width$.prec$} {local_i32:prec$.width$} {width:local_i32$.prec$} {width:prec$.local_i32$} {prec:local_i32$.width$} {prec:width$.local_i32$}", width, prec, +LL ~ "{0:1$.2$} {0:2$.1$} {1:0$.2$} {1:2$.0$} {2:0$.1$} {2:1$.0$}", width, prec, +LL ~ "{0:1$.2$} {0:2$.1$} {1:0$.2$} {1:2$.0$} {2:0$.1$} {2:1$.0$}", width, prec, +LL ~ "{0:1$.2$} {0:2$.1$} {1:0$.2$} {1:2$.0$} {2:0$.1$} {2:1$.0$}", width, prec, +LL ~ "{0:1$.2$} {0:2$.1$} {1:0$.2$} {1:2$.0$} {2:0$.1$} {2:1$.0$}", width, prec, +LL ~ "{0:1$.2$} {0:2$.1$} {1:0$.2$} {1:2$.0$} {2:0$.1$} {2:1$.0$}", + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:129:5 + | +LL | println!("Width = {}, value with width = {:0$}", local_i32, local_f64); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("Width = {}, value with width = {:0$}", local_i32, local_f64); +LL + println!("Width = {local_i32}, value with width = {local_f64:local_i32$}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:130:5 + | +LL | println!("{:w$.p$}", local_i32, w = width, p = prec); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{:w$.p$}", local_i32, w = width, p = prec); +LL + println!("{local_i32:width$.prec$}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:131:5 + | +LL | println!("{:w$.p$}", w = width, p = prec); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{:w$.p$}", w = width, p = prec); +LL + println!("{width:width$.prec$}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:132:20 + | +LL | println!("{}", format!("{}", local_i32)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{}", format!("{}", local_i32)); +LL + println!("{}", format!("{local_i32}")); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:170:5 + | +LL | println!("expand='{}'", local_i32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("expand='{}'", local_i32); +LL + println!("expand='{local_i32}'"); + | + +error: aborting due to 71 previous errors + From 06568fd6c707b878ae69ede1532b82c7ba47e07e Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Tue, 20 Sep 2022 15:41:42 +0200 Subject: [PATCH 055/114] remove cfg(bootstrap) --- clippy_dev/src/lib.rs | 1 - clippy_lints/src/lib.rs | 1 - clippy_utils/src/lib.rs | 1 - 3 files changed, 3 deletions(-) diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs index 54c7456a2a3b0..80bb83af43b19 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -1,5 +1,4 @@ #![feature(let_chains)] -#![cfg_attr(bootstrap, feature(let_else))] #![feature(once_cell)] #![feature(rustc_private)] #![cfg_attr(feature = "deny-warnings", deny(warnings))] diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 298566cb5b625..00bf6445c12d2 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -5,7 +5,6 @@ #![feature(drain_filter)] #![feature(iter_intersperse)] #![feature(let_chains)] -#![cfg_attr(bootstrap, feature(let_else))] #![feature(lint_reasons)] #![feature(never_type)] #![feature(once_cell)] diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 9343cf457b341..b1abd3b04c929 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -3,7 +3,6 @@ #![feature(control_flow_enum)] #![feature(let_chains)] #![feature(lint_reasons)] -#![cfg_attr(bootstrap, feature(let_else))] #![feature(once_cell)] #![feature(rustc_private)] #![recursion_limit = "512"] From 14abb8395c4ae09475539dbc55ba89dd533981d9 Mon Sep 17 00:00:00 2001 From: Philip Craig <689193+philipcraig@users.noreply.github.com> Date: Tue, 27 Sep 2022 09:32:55 +0100 Subject: [PATCH 056/114] fix typo "Saturing" -> "Saturating" --- clippy_lints/src/operators/mod.rs | 2 +- src/docs/arithmetic_side_effects.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/operators/mod.rs b/clippy_lints/src/operators/mod.rs index c32b4df4f75c1..b8a20d5ebe9bd 100644 --- a/clippy_lints/src/operators/mod.rs +++ b/clippy_lints/src/operators/mod.rs @@ -67,7 +67,7 @@ declare_clippy_lint! { /// Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow), /// or can panic (`/`, `%`). /// - /// Known safe built-in types like `Wrapping` or `Saturing`, floats, operations in constant + /// Known safe built-in types like `Wrapping` or `Saturating`, floats, operations in constant /// environments, allowed types and non-constant operations that won't overflow are ignored. /// /// ### Why is this bad? diff --git a/src/docs/arithmetic_side_effects.txt b/src/docs/arithmetic_side_effects.txt index 6c7d51a4989e0..4ae8bce88ad5f 100644 --- a/src/docs/arithmetic_side_effects.txt +++ b/src/docs/arithmetic_side_effects.txt @@ -5,7 +5,7 @@ Operators like `+`, `-`, `*` or `<<` are usually capable of overflowing accordin Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow), or can panic (`/`, `%`). -Known safe built-in types like `Wrapping` or `Saturing`, floats, operations in constant +Known safe built-in types like `Wrapping` or `Saturating`, floats, operations in constant environments, allowed types and non-constant operations that won't overflow are ignored. ### Why is this bad? From e5ce6d18df883f593e72f7958bebdc3ebcdbe85e Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 26 Sep 2022 13:00:29 +0200 Subject: [PATCH 057/114] rustc_typeck to rustc_hir_analysis --- clippy_lints/src/default_union_representation.rs | 2 +- clippy_lints/src/escape.rs | 4 ++-- clippy_lints/src/implicit_hasher.rs | 2 +- clippy_lints/src/large_const_arrays.rs | 2 +- clippy_lints/src/lib.rs | 2 +- clippy_lints/src/loops/mut_range_bound.rs | 4 ++-- clippy_lints/src/loops/utils.rs | 2 +- clippy_lints/src/matches/needless_match.rs | 2 +- clippy_lints/src/methods/mod.rs | 2 +- clippy_lints/src/methods/unnecessary_to_owned.rs | 2 +- clippy_lints/src/missing_const_for_fn.rs | 2 +- clippy_lints/src/needless_pass_by_value.rs | 4 ++-- clippy_lints/src/non_copy_const.rs | 2 +- clippy_lints/src/operators/assign_op_pattern.rs | 2 +- clippy_lints/src/transmute/utils.rs | 2 +- clippy_lints/src/types/redundant_allocation.rs | 2 +- clippy_lints/src/types/vec_box.rs | 2 +- clippy_lints/src/use_self.rs | 2 +- clippy_lints/src/utils/internal_lints.rs | 2 +- clippy_lints/src/zero_sized_map_values.rs | 2 +- clippy_utils/src/lib.rs | 4 ++-- clippy_utils/src/sugg.rs | 4 ++-- clippy_utils/src/usage.rs | 4 ++-- tests/ui/transmutes_expressible_as_ptr_casts.fixed | 2 +- tests/ui/transmutes_expressible_as_ptr_casts.rs | 2 +- 25 files changed, 31 insertions(+), 31 deletions(-) diff --git a/clippy_lints/src/default_union_representation.rs b/clippy_lints/src/default_union_representation.rs index d559ad423df5f..3905a6c2e2119 100644 --- a/clippy_lints/src/default_union_representation.rs +++ b/clippy_lints/src/default_union_representation.rs @@ -4,7 +4,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; -use rustc_typeck::hir_ty_to_ty; +use rustc_hir_analysis::hir_ty_to_ty; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs index a6ddb26e2dee3..8ccc969646ec5 100644 --- a/clippy_lints/src/escape.rs +++ b/clippy_lints/src/escape.rs @@ -10,7 +10,7 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; use rustc_span::symbol::kw; use rustc_target::spec::abi::Abi; -use rustc_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; +use rustc_hir_analysis::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; #[derive(Copy, Clone)] pub struct BoxedLocal { @@ -177,7 +177,7 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { } } - fn fake_read(&mut self, _: &rustc_typeck::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {} + fn fake_read(&mut self, _: &rustc_hir_analysis::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {} } impl<'a, 'tcx> EscapeDelegate<'a, 'tcx> { diff --git a/clippy_lints/src/implicit_hasher.rs b/clippy_lints/src/implicit_hasher.rs index 804fdc2da0889..a920c3bba2aed 100644 --- a/clippy_lints/src/implicit_hasher.rs +++ b/clippy_lints/src/implicit_hasher.rs @@ -12,7 +12,7 @@ use rustc_middle::ty::{Ty, TypeckResults}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use rustc_span::symbol::sym; -use rustc_typeck::hir_ty_to_ty; +use rustc_hir_analysis::hir_ty_to_ty; use if_chain::if_chain; diff --git a/clippy_lints/src/large_const_arrays.rs b/clippy_lints/src/large_const_arrays.rs index 984c5cd4e37c2..d6eb53ae29b5a 100644 --- a/clippy_lints/src/large_const_arrays.rs +++ b/clippy_lints/src/large_const_arrays.rs @@ -7,7 +7,7 @@ use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, ConstKind}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{BytePos, Pos, Span}; -use rustc_typeck::hir_ty_to_ty; +use rustc_hir_analysis::hir_ty_to_ty; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 00bf6445c12d2..c3db194c4ad85 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -43,7 +43,7 @@ extern crate rustc_session; extern crate rustc_span; extern crate rustc_target; extern crate rustc_trait_selection; -extern crate rustc_typeck; +extern crate rustc_hir_analysis; #[macro_use] extern crate clippy_utils; diff --git a/clippy_lints/src/loops/mut_range_bound.rs b/clippy_lints/src/loops/mut_range_bound.rs index be7f96e9bb077..6d585c2e45de6 100644 --- a/clippy_lints/src/loops/mut_range_bound.rs +++ b/clippy_lints/src/loops/mut_range_bound.rs @@ -8,7 +8,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; use rustc_middle::{mir::FakeReadCause, ty}; use rustc_span::source_map::Span; -use rustc_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; +use rustc_hir_analysis::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; pub(super) fn check(cx: &LateContext<'_>, arg: &Expr<'_>, body: &Expr<'_>) { if_chain! { @@ -114,7 +114,7 @@ impl<'tcx> Delegate<'tcx> for MutatePairDelegate<'_, 'tcx> { } } - fn fake_read(&mut self, _: &rustc_typeck::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {} + fn fake_read(&mut self, _: &rustc_hir_analysis::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {} } impl MutatePairDelegate<'_, '_> { diff --git a/clippy_lints/src/loops/utils.rs b/clippy_lints/src/loops/utils.rs index 4801a84eb92ce..f1f58db80b306 100644 --- a/clippy_lints/src/loops/utils.rs +++ b/clippy_lints/src/loops/utils.rs @@ -10,7 +10,7 @@ use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, Ty}; use rustc_span::source_map::Spanned; use rustc_span::symbol::{sym, Symbol}; -use rustc_typeck::hir_ty_to_ty; +use rustc_hir_analysis::hir_ty_to_ty; use std::iter::Iterator; #[derive(Debug, PartialEq, Eq)] diff --git a/clippy_lints/src/matches/needless_match.rs b/clippy_lints/src/matches/needless_match.rs index 634eef82e532a..58ea43e69d9b1 100644 --- a/clippy_lints/src/matches/needless_match.rs +++ b/clippy_lints/src/matches/needless_match.rs @@ -11,7 +11,7 @@ use rustc_hir::LangItem::OptionNone; use rustc_hir::{Arm, BindingAnnotation, ByRef, Expr, ExprKind, FnRetTy, Guard, Node, Pat, PatKind, Path, QPath}; use rustc_lint::LateContext; use rustc_span::sym; -use rustc_typeck::hir_ty_to_ty; +use rustc_hir_analysis::hir_ty_to_ty; pub(crate) fn check_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) { if arms.len() > 1 && expr_ty_matches_p_ty(cx, ex, expr) && check_all_arms(cx, ex, arms) { diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index ddb6d1ca26c91..428a354ec6b1e 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -115,7 +115,7 @@ use rustc_middle::ty::{self, TraitRef, Ty}; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{sym, Span}; -use rustc_typeck::hir_ty_to_ty; +use rustc_hir_analysis::hir_ty_to_ty; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index 79d784c342cac..559f32a563ed9 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -18,7 +18,7 @@ use rustc_middle::ty::{self, ParamTy, PredicateKind, ProjectionPredicate, TraitP use rustc_semver::RustcVersion; use rustc_span::{sym, Symbol}; use rustc_trait_selection::traits::{query::evaluate_obligation::InferCtxtExt as _, Obligation, ObligationCause}; -use rustc_typeck::check::{FnCtxt, Inherited}; +use rustc_hir_analysis::check::{FnCtxt, Inherited}; use std::cmp::max; use super::UNNECESSARY_TO_OWNED; diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index f24b41411c816..00376f0d79022 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -13,7 +13,7 @@ use rustc_middle::lint::in_external_macro; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::Span; -use rustc_typeck::hir_ty_to_ty; +use rustc_hir_analysis::hir_ty_to_ty; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 060037ed49691..4f46872439c3c 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -22,7 +22,7 @@ use rustc_span::{sym, Span}; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits; use rustc_trait_selection::traits::misc::can_type_implement_copy; -use rustc_typeck::expr_use_visitor as euv; +use rustc_hir_analysis::expr_use_visitor as euv; use std::borrow::Cow; declare_clippy_lint! { @@ -341,5 +341,5 @@ impl<'tcx> euv::Delegate<'tcx> for MovedVariablesCtxt { fn mutate(&mut self, _: &euv::PlaceWithHirId<'tcx>, _: HirId) {} - fn fake_read(&mut self, _: &rustc_typeck::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {} + fn fake_read(&mut self, _: &rustc_hir_analysis::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {} } diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 616ef9e2f867f..48ff737dae7bc 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -20,7 +20,7 @@ use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{sym, InnerSpan, Span, DUMMY_SP}; -use rustc_typeck::hir_ty_to_ty; +use rustc_hir_analysis::hir_ty_to_ty; // FIXME: this is a correctness problem but there's no suitable // warn-by-default category. diff --git a/clippy_lints/src/operators/assign_op_pattern.rs b/clippy_lints/src/operators/assign_op_pattern.rs index 2c22c8b3d0819..f134c6c4cdba5 100644 --- a/clippy_lints/src/operators/assign_op_pattern.rs +++ b/clippy_lints/src/operators/assign_op_pattern.rs @@ -11,7 +11,7 @@ use rustc_lint::LateContext; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::BorrowKind; use rustc_trait_selection::infer::TyCtxtInferExt; -use rustc_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; +use rustc_hir_analysis::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; use super::ASSIGN_OP_PATTERN; diff --git a/clippy_lints/src/transmute/utils.rs b/clippy_lints/src/transmute/utils.rs index 8e90d20265ce1..fdf847bf44593 100644 --- a/clippy_lints/src/transmute/utils.rs +++ b/clippy_lints/src/transmute/utils.rs @@ -2,7 +2,7 @@ use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::{cast::CastKind, Ty}; use rustc_span::DUMMY_SP; -use rustc_typeck::check::{cast::{self, CastCheckResult}, FnCtxt, Inherited}; +use rustc_hir_analysis::check::{cast::{self, CastCheckResult}, FnCtxt, Inherited}; // check if the component types of the transmuted collection and the result have different ABI, // size or alignment diff --git a/clippy_lints/src/types/redundant_allocation.rs b/clippy_lints/src/types/redundant_allocation.rs index a1312fcda0b71..d81c5c83845d8 100644 --- a/clippy_lints/src/types/redundant_allocation.rs +++ b/clippy_lints/src/types/redundant_allocation.rs @@ -5,7 +5,7 @@ use rustc_errors::Applicability; use rustc_hir::{self as hir, def_id::DefId, QPath, TyKind}; use rustc_lint::LateContext; use rustc_span::symbol::sym; -use rustc_typeck::hir_ty_to_ty; +use rustc_hir_analysis::hir_ty_to_ty; use super::{utils, REDUNDANT_ALLOCATION}; diff --git a/clippy_lints/src/types/vec_box.rs b/clippy_lints/src/types/vec_box.rs index b2f536ca7815b..236f9955722d0 100644 --- a/clippy_lints/src/types/vec_box.rs +++ b/clippy_lints/src/types/vec_box.rs @@ -8,7 +8,7 @@ use rustc_lint::LateContext; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::TypeVisitable; use rustc_span::symbol::sym; -use rustc_typeck::hir_ty_to_ty; +use rustc_hir_analysis::hir_ty_to_ty; use super::VEC_BOX; diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index ce51cb693fc02..6a767967ef409 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -16,7 +16,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::Span; -use rustc_typeck::hir_ty_to_ty; +use rustc_hir_analysis::hir_ty_to_ty; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index 17d9a04185767..78c036186f506 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -32,7 +32,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Spanned; use rustc_span::symbol::Symbol; use rustc_span::{sym, BytePos, Span}; -use rustc_typeck::hir_ty_to_ty; +use rustc_hir_analysis::hir_ty_to_ty; use std::borrow::{Borrow, Cow}; diff --git a/clippy_lints/src/zero_sized_map_values.rs b/clippy_lints/src/zero_sized_map_values.rs index 386f3c527f174..703ba2ef4b054 100644 --- a/clippy_lints/src/zero_sized_map_values.rs +++ b/clippy_lints/src/zero_sized_map_values.rs @@ -7,7 +7,7 @@ use rustc_middle::ty::layout::LayoutOf as _; use rustc_middle::ty::{Adt, Ty, TypeVisitable}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; -use rustc_typeck::hir_ty_to_ty; +use rustc_hir_analysis::hir_ty_to_ty; declare_clippy_lint! { /// ### What it does diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index b1abd3b04c929..627d6b51944a6 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -32,7 +32,7 @@ extern crate rustc_session; extern crate rustc_span; extern crate rustc_target; extern crate rustc_trait_selection; -extern crate rustc_typeck; +extern crate rustc_hir_analysis; #[macro_use] pub mod sym_helper; @@ -1386,7 +1386,7 @@ pub fn is_integer_literal(expr: &Expr<'_>, value: u128) -> bool { /// Examples of coercions can be found in the Nomicon at /// . /// -/// See `rustc_middle::ty::adjustment::Adjustment` and `rustc_typeck::check::coercion` for more +/// See `rustc_middle::ty::adjustment::Adjustment` and `rustc_hir_analysis::check::coercion` for more /// information on adjustments and coercions. pub fn is_adjusted(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { cx.typeck_results().adjustments().get(e.hir_id).is_some() diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index f08275a4ac76b..e53c40e95760b 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -16,7 +16,7 @@ use rustc_middle::hir::place::ProjectionKind; use rustc_middle::mir::{FakeReadCause, Mutability}; use rustc_middle::ty; use rustc_span::source_map::{BytePos, CharPos, Pos, Span, SyntaxContext}; -use rustc_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; +use rustc_hir_analysis::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; use std::borrow::Cow; use std::fmt::{Display, Write as _}; use std::ops::{Add, Neg, Not, Sub}; @@ -1056,7 +1056,7 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { fn mutate(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} - fn fake_read(&mut self, _: &rustc_typeck::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {} + fn fake_read(&mut self, _: &rustc_hir_analysis::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {} } #[cfg(test)] diff --git a/clippy_utils/src/usage.rs b/clippy_utils/src/usage.rs index a7c08839f5241..76bfec75726df 100644 --- a/clippy_utils/src/usage.rs +++ b/clippy_utils/src/usage.rs @@ -9,7 +9,7 @@ use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty; -use rustc_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; +use rustc_hir_analysis::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; /// Returns a set of mutated local variable IDs, or `None` if mutations could not be determined. pub fn mutated_variables<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) -> Option { @@ -73,7 +73,7 @@ impl<'tcx> Delegate<'tcx> for MutVarsDelegate { self.update(cmt); } - fn fake_read(&mut self, _: &rustc_typeck::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {} + fn fake_read(&mut self, _: &rustc_hir_analysis::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {} } pub struct ParamBindingIdCollector { diff --git a/tests/ui/transmutes_expressible_as_ptr_casts.fixed b/tests/ui/transmutes_expressible_as_ptr_casts.fixed index 539239fc18f94..7263abac15dfb 100644 --- a/tests/ui/transmutes_expressible_as_ptr_casts.fixed +++ b/tests/ui/transmutes_expressible_as_ptr_casts.fixed @@ -8,7 +8,7 @@ use std::mem::{size_of, transmute}; -// rustc_typeck::check::cast contains documentation about when a cast `e as U` is +// rustc_hir_analysis::check::cast contains documentation about when a cast `e as U` is // valid, which we quote from below. fn main() { // We should see an error message for each transmute, and no error messages for diff --git a/tests/ui/transmutes_expressible_as_ptr_casts.rs b/tests/ui/transmutes_expressible_as_ptr_casts.rs index b9e446dc89a95..d8e4421d4c18e 100644 --- a/tests/ui/transmutes_expressible_as_ptr_casts.rs +++ b/tests/ui/transmutes_expressible_as_ptr_casts.rs @@ -8,7 +8,7 @@ use std::mem::{size_of, transmute}; -// rustc_typeck::check::cast contains documentation about when a cast `e as U` is +// rustc_hir_analysis::check::cast contains documentation about when a cast `e as U` is // valid, which we quote from below. fn main() { // We should see an error message for each transmute, and no error messages for From 63f441ec855f0de342ccc2b9ff90776c633ca9e6 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Wed, 21 Sep 2022 23:43:49 +0200 Subject: [PATCH 058/114] add `box-default` lint --- CHANGELOG.md | 1 + clippy_lints/src/box_default.rs | 61 ++++++++++++++++++++++++++ clippy_lints/src/lib.register_all.rs | 1 + clippy_lints/src/lib.register_lints.rs | 1 + clippy_lints/src/lib.register_perf.rs | 1 + clippy_lints/src/lib.rs | 30 +++++++------ src/docs.rs | 1 + src/docs/box_default.txt | 23 ++++++++++ tests/ui/box_collection.rs | 4 +- tests/ui/box_default.rs | 31 +++++++++++++ tests/ui/box_default.stderr | 59 +++++++++++++++++++++++++ 11 files changed, 197 insertions(+), 16 deletions(-) create mode 100644 clippy_lints/src/box_default.rs create mode 100644 src/docs/box_default.txt create mode 100644 tests/ui/box_default.rs create mode 100644 tests/ui/box_default.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 044cbff4b78e5..f1e2e6f462dd0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3609,6 +3609,7 @@ Released 2018-09-13 [`borrow_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrow_interior_mutable_const [`borrowed_box`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrowed_box [`box_collection`]: https://rust-lang.github.io/rust-clippy/master/index.html#box_collection +[`box_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#box_default [`box_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#box_vec [`boxed_local`]: https://rust-lang.github.io/rust-clippy/master/index.html#boxed_local [`branches_sharing_code`]: https://rust-lang.github.io/rust-clippy/master/index.html#branches_sharing_code diff --git a/clippy_lints/src/box_default.rs b/clippy_lints/src/box_default.rs new file mode 100644 index 0000000000000..792183ac40814 --- /dev/null +++ b/clippy_lints/src/box_default.rs @@ -0,0 +1,61 @@ +use clippy_utils::{diagnostics::span_lint_and_help, is_default_equivalent, path_def_id}; +use rustc_hir::{Expr, ExprKind, QPath}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; + +declare_clippy_lint! { + /// ### What it does + /// checks for `Box::new(T::default())`, which is better written as + /// `Box::::default()`. + /// + /// ### Why is this bad? + /// First, it's more complex, involving two calls instead of one. + /// Second, `Box::default()` can be faster + /// [in certain cases](https://nnethercote.github.io/perf-book/standard-library-types.html#box). + /// + /// ### Known problems + /// The lint may miss some cases (e.g. Box::new(String::from(""))). + /// On the other hand, it will trigger on cases where the `default` + /// code comes from a macro that does something different based on + /// e.g. target operating system. + /// + /// ### Example + /// ```rust + /// let x: Box = Box::new(Default::default()); + /// ``` + /// Use instead: + /// ```rust + /// let x: Box = Box::default(); + /// ``` + #[clippy::version = "1.65.0"] + pub BOX_DEFAULT, + perf, + "Using Box::new(T::default()) instead of Box::default()" +} + +declare_lint_pass!(BoxDefault => [BOX_DEFAULT]); + +impl LateLintPass<'_> for BoxDefault { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + if let ExprKind::Call(box_new, [arg]) = expr.kind + && let ExprKind::Path(QPath::TypeRelative(ty, seg)) = box_new.kind + && let ExprKind::Call(..) = arg.kind + && !in_external_macro(cx.sess(), expr.span) + && expr.span.eq_ctxt(arg.span) + && seg.ident.name == sym::new + && path_def_id(cx, ty) == cx.tcx.lang_items().owned_box() + && is_default_equivalent(cx, arg) + { + span_lint_and_help( + cx, + BOX_DEFAULT, + expr.span, + "`Box::new(_)` of default value", + None, + "use `Box::default()` instead", + ); + } + } +} diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index ae57a9a24a76a..33490d1ccc5c1 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -21,6 +21,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ 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), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 02fcc8de50727..93ea32fa06941 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -60,6 +60,7 @@ store.register_lints(&[ 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, diff --git a/clippy_lints/src/lib.register_perf.rs b/clippy_lints/src/lib.register_perf.rs index 195ce41e31e9f..8e927470e02ff 100644 --- a/clippy_lints/src/lib.register_perf.rs +++ b/clippy_lints/src/lib.register_perf.rs @@ -3,6 +3,7 @@ // 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), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 83fdc15c9f02c..7bd49b11090e8 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -181,6 +181,7 @@ mod bool_assert_comparison; mod bool_to_int_with_if; mod booleans; mod borrow_deref_ref; +mod box_default; mod cargo; mod casts; mod checked_conversions; @@ -536,8 +537,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(utils::internal_lints::CompilerLintFunctions::new())); store.register_late_pass(|| Box::new(utils::internal_lints::IfChainStyle)); store.register_late_pass(|| Box::new(utils::internal_lints::InvalidPaths)); - store.register_late_pass(|| Box::new(utils::internal_lints::InterningDefinedSymbol::default())); - store.register_late_pass(|| Box::new(utils::internal_lints::LintWithoutLintPass::default())); + store.register_late_pass(|| Box::::default()); + store.register_late_pass(|| Box::::default()); store.register_late_pass(|| Box::new(utils::internal_lints::MatchTypeOnDiagItem)); store.register_late_pass(|| Box::new(utils::internal_lints::OuterExpnDataPass)); store.register_late_pass(|| Box::new(utils::internal_lints::MsrvAttrImpl)); @@ -630,10 +631,10 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: msrv, )) }); - store.register_late_pass(|| Box::new(shadow::Shadow::default())); + store.register_late_pass(|| Box::::default()); store.register_late_pass(|| Box::new(unit_types::UnitTypes)); store.register_late_pass(|| Box::new(loops::Loops)); - store.register_late_pass(|| Box::new(main_recursion::MainRecursion::default())); + store.register_late_pass(|| Box::::default()); store.register_late_pass(|| Box::new(lifetimes::Lifetimes)); store.register_late_pass(|| Box::new(entry::HashMapPass)); store.register_late_pass(|| Box::new(minmax::MinMaxPass)); @@ -667,7 +668,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(format::UselessFormat)); store.register_late_pass(|| Box::new(swap::Swap)); store.register_late_pass(|| Box::new(overflow_check_conditional::OverflowCheckConditional)); - store.register_late_pass(|| Box::new(new_without_default::NewWithoutDefault::default())); + store.register_late_pass(|| Box::::default()); let disallowed_names = conf.disallowed_names.iter().cloned().collect::>(); store.register_late_pass(move || Box::new(disallowed_names::DisallowedNames::new(disallowed_names.clone()))); let too_many_arguments_threshold = conf.too_many_arguments_threshold; @@ -706,7 +707,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(ref_option_ref::RefOptionRef)); store.register_late_pass(|| Box::new(infinite_iter::InfiniteIter)); store.register_late_pass(|| Box::new(inline_fn_without_body::InlineFnWithoutBody)); - store.register_late_pass(|| Box::new(useless_conversion::UselessConversion::default())); + store.register_late_pass(|| Box::::default()); store.register_late_pass(|| Box::new(implicit_hasher::ImplicitHasher)); store.register_late_pass(|| Box::new(fallible_impl_from::FallibleImplFrom)); store.register_late_pass(|| Box::new(question_mark::QuestionMark)); @@ -776,7 +777,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: upper_case_acronyms_aggressive, )) }); - store.register_late_pass(|| Box::new(default::Default::default())); + store.register_late_pass(|| Box::::default()); store.register_late_pass(move || Box::new(unused_self::UnusedSelf::new(avoid_breaking_exported_api))); store.register_late_pass(|| Box::new(mutable_debug_assertion::DebugAssertWithMutCall)); store.register_late_pass(|| Box::new(exit::Exit)); @@ -799,7 +800,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(|| Box::new(option_env_unwrap::OptionEnvUnwrap)); let warn_on_all_wildcard_imports = conf.warn_on_all_wildcard_imports; store.register_late_pass(move || Box::new(wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports))); - store.register_late_pass(|| Box::new(redundant_pub_crate::RedundantPubCrate::default())); + store.register_late_pass(|| Box::::default()); store.register_late_pass(|| Box::new(unnamed_address::UnnamedAddress)); store.register_late_pass(move || Box::new(dereference::Dereferencing::new(msrv))); store.register_late_pass(|| Box::new(option_if_let_else::OptionIfLetElse)); @@ -817,7 +818,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: }); let macro_matcher = conf.standard_macro_braces.iter().cloned().collect::>(); store.register_early_pass(move || Box::new(nonstandard_macro_braces::MacroBraces::new(¯o_matcher))); - store.register_late_pass(|| Box::new(macro_use::MacroUseImports::default())); + store.register_late_pass(|| Box::::default()); store.register_late_pass(|| Box::new(pattern_type_mismatch::PatternTypeMismatch)); store.register_late_pass(|| Box::new(unwrap_in_result::UnwrapInResult)); store.register_late_pass(|| Box::new(semicolon_if_nothing_returned::SemicolonIfNothingReturned)); @@ -830,7 +831,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(strings::StrToString)); store.register_late_pass(|| Box::new(strings::StringToString)); store.register_late_pass(|| Box::new(zero_sized_map_values::ZeroSizedMapValues)); - store.register_late_pass(|| Box::new(vec_init_then_push::VecInitThenPush::default())); + store.register_late_pass(|| Box::::default()); store.register_late_pass(|| Box::new(redundant_slicing::RedundantSlicing)); store.register_late_pass(|| Box::new(from_str_radix_10::FromStrRadix10)); store.register_late_pass(move || Box::new(if_then_some_else_none::IfThenSomeElseNone::new(msrv))); @@ -868,7 +869,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move || Box::new(manual_bits::ManualBits::new(msrv))); store.register_late_pass(|| Box::new(default_union_representation::DefaultUnionRepresentation)); store.register_early_pass(|| Box::new(doc_link_with_quotes::DocLinkWithQuotes)); - store.register_late_pass(|| Box::new(only_used_in_recursion::OnlyUsedInRecursion::default())); + store.register_late_pass(|| Box::::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 cargo_ignore_publish = conf.cargo_ignore_publish; @@ -877,7 +878,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: ignore_publish: cargo_ignore_publish, }) }); - store.register_late_pass(|| Box::new(write::Write::default())); + store.register_late_pass(|| Box::::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)); @@ -887,7 +888,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move || Box::new(large_include_file::LargeIncludeFile::new(max_include_file_size))); store.register_late_pass(|| Box::new(strings::TrimSplitWhitespace)); store.register_late_pass(|| Box::new(rc_clone_in_vec_init::RcCloneInVecInit)); - store.register_early_pass(|| Box::new(duplicate_mod::DuplicateMod::default())); + store.register_early_pass(|| Box::::default()); store.register_early_pass(|| Box::new(unused_rounding::UnusedRounding)); store.register_early_pass(move || Box::new(almost_complete_letter_range::AlmostCompleteLetterRange::new(msrv))); store.register_late_pass(|| Box::new(swap_ptr_to_ref::SwapPtrToRef)); @@ -899,13 +900,14 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: let verbose_bit_mask_threshold = conf.verbose_bit_mask_threshold; 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::new(std_instead_of_core::StdReexports::default())); + store.register_late_pass(|| Box::::default()); store.register_late_pass(|| Box::new(manual_instant_elapsed::ManualInstantElapsed)); store.register_late_pass(|| Box::new(partialeq_to_none::PartialeqToNone)); store.register_late_pass(|| Box::new(manual_string_new::ManualStringNew)); store.register_late_pass(|| Box::new(unused_peekable::UnusedPeekable)); store.register_early_pass(|| Box::new(multi_assignments::MultiAssignments)); store.register_late_pass(|| Box::new(bool_to_int_with_if::BoolToIntWithIf)); + store.register_late_pass(|| Box::new(box_default::BoxDefault)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/src/docs.rs b/src/docs.rs index 6c89b4dde372d..8ffe1281f6560 100644 --- a/src/docs.rs +++ b/src/docs.rs @@ -48,6 +48,7 @@ docs! { "borrow_interior_mutable_const", "borrowed_box", "box_collection", + "box_default", "boxed_local", "branches_sharing_code", "builtin_type_shadow", diff --git a/src/docs/box_default.txt b/src/docs/box_default.txt new file mode 100644 index 0000000000000..ffac894d0c50a --- /dev/null +++ b/src/docs/box_default.txt @@ -0,0 +1,23 @@ +### What it does +checks for `Box::new(T::default())`, which is better written as +`Box::::default()`. + +### Why is this bad? +First, it's more complex, involving two calls instead of one. +Second, `Box::default()` can be faster +[in certain cases](https://nnethercote.github.io/perf-book/standard-library-types.html#box). + +### Known problems +The lint may miss some cases (e.g. Box::new(String::from(""))). +On the other hand, it will trigger on cases where the `default` +code comes from a macro that does something different based on +e.g. target operating system. + +### Example +``` +let x: Box = Box::new(Default::default()); +``` +Use instead: +``` +let x: Box = Box::default(); +``` \ No newline at end of file diff --git a/tests/ui/box_collection.rs b/tests/ui/box_collection.rs index 0780c8f0586e0..4c9947b9ae724 100644 --- a/tests/ui/box_collection.rs +++ b/tests/ui/box_collection.rs @@ -15,7 +15,7 @@ macro_rules! boxit { } fn test_macro() { - boxit!(Vec::new(), Vec); + boxit!(vec![1], Vec); } fn test1(foo: Box>) {} @@ -50,7 +50,7 @@ fn test_local_not_linted() { pub fn pub_test(foo: Box>) {} pub fn pub_test_ret() -> Box> { - Box::new(Vec::new()) + Box::default() } fn main() {} diff --git a/tests/ui/box_default.rs b/tests/ui/box_default.rs new file mode 100644 index 0000000000000..dc522705bc624 --- /dev/null +++ b/tests/ui/box_default.rs @@ -0,0 +1,31 @@ +#![warn(clippy::box_default)] + +#[derive(Default)] +struct ImplementsDefault; + +struct OwnDefault; + +impl OwnDefault { + fn default() -> Self { + Self + } +} + +macro_rules! outer { + ($e: expr) => { + $e + }; +} + +fn main() { + let _string: Box = Box::new(Default::default()); + let _byte = Box::new(u8::default()); + let _vec = Box::new(Vec::::new()); + let _impl = Box::new(ImplementsDefault::default()); + let _impl2 = Box::new(::default()); + let _impl3: Box = Box::new(Default::default()); + let _own = Box::new(OwnDefault::default()); // should not lint + let _in_macro = outer!(Box::new(String::new())); + // false negative: default is from different expansion + let _vec2: Box> = Box::new(vec![]); +} diff --git a/tests/ui/box_default.stderr b/tests/ui/box_default.stderr new file mode 100644 index 0000000000000..341766a502b1a --- /dev/null +++ b/tests/ui/box_default.stderr @@ -0,0 +1,59 @@ +error: `Box::new(_)` of default value + --> $DIR/box_default.rs:21:32 + | +LL | let _string: Box = Box::new(Default::default()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::box-default` implied by `-D warnings` + = help: use `Box::default()` instead + +error: `Box::new(_)` of default value + --> $DIR/box_default.rs:22:17 + | +LL | let _byte = Box::new(u8::default()); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use `Box::default()` instead + +error: `Box::new(_)` of default value + --> $DIR/box_default.rs:23:16 + | +LL | let _vec = Box::new(Vec::::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use `Box::default()` instead + +error: `Box::new(_)` of default value + --> $DIR/box_default.rs:24:17 + | +LL | let _impl = Box::new(ImplementsDefault::default()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use `Box::default()` instead + +error: `Box::new(_)` of default value + --> $DIR/box_default.rs:25:18 + | +LL | let _impl2 = Box::new(::default()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use `Box::default()` instead + +error: `Box::new(_)` of default value + --> $DIR/box_default.rs:26:42 + | +LL | let _impl3: Box = Box::new(Default::default()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use `Box::default()` instead + +error: `Box::new(_)` of default value + --> $DIR/box_default.rs:28:28 + | +LL | let _in_macro = outer!(Box::new(String::new())); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use `Box::default()` instead + +error: aborting due to 7 previous errors + From 5b0f46a9d90ed2c7d26b2760dddee7399b379612 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Tue, 27 Sep 2022 18:21:14 +0000 Subject: [PATCH 059/114] Don't lint unstable moves in `std_instead_of_core` Such as the currently unstable `core::error` --- clippy_lints/src/std_instead_of_core.rs | 22 ++++++++++++++++++++++ tests/ui/std_instead_of_core.rs | 6 ++++++ tests/ui/std_instead_of_core.stderr | 16 ++++++++++++---- 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/std_instead_of_core.rs b/clippy_lints/src/std_instead_of_core.rs index ffd63cc687a11..d6b336bef943e 100644 --- a/clippy_lints/src/std_instead_of_core.rs +++ b/clippy_lints/src/std_instead_of_core.rs @@ -1,6 +1,8 @@ use clippy_utils::diagnostics::span_lint_and_help; +use rustc_hir::def_id::DefId; use rustc_hir::{def::Res, HirId, Path, PathSegment}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::DefIdTree; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{sym, symbol::kw, Span}; @@ -94,6 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports { fn check_path(&mut self, cx: &LateContext<'tcx>, path: &Path<'tcx>, _: HirId) { if let Res::Def(_, def_id) = path.res && let Some(first_segment) = get_first_segment(path) + && is_stable(cx, def_id) { let (lint, msg, help) = match first_segment.ident.name { sym::std => match cx.tcx.crate_name(def_id.krate) { @@ -146,3 +149,22 @@ fn get_first_segment<'tcx>(path: &Path<'tcx>) -> Option<&'tcx PathSegment<'tcx>> _ => None, } } + +/// Checks if all ancestors of `def_id` are stable, to avoid linting +/// [unstable moves](https://github.com/rust-lang/rust/pull/95956) +fn is_stable(cx: &LateContext<'_>, mut def_id: DefId) -> bool { + loop { + if cx + .tcx + .lookup_stability(def_id) + .map_or(false, |stability| stability.is_unstable()) + { + return false; + } + + match cx.tcx.opt_parent(def_id) { + Some(parent) => def_id = parent, + None => return true, + } + } +} diff --git a/tests/ui/std_instead_of_core.rs b/tests/ui/std_instead_of_core.rs index 6b27475de4c87..75b114ba0aed9 100644 --- a/tests/ui/std_instead_of_core.rs +++ b/tests/ui/std_instead_of_core.rs @@ -24,6 +24,12 @@ fn std_instead_of_core() { let cell_absolute = ::std::cell::Cell::new(8u32); let _ = std::env!("PATH"); + + // do not lint until `error_in_core` is stable + use std::error::Error; + + // lint items re-exported from private modules, `core::iter::traits::iterator::Iterator` + use std::iter::Iterator; } #[warn(clippy::std_instead_of_alloc)] diff --git a/tests/ui/std_instead_of_core.stderr b/tests/ui/std_instead_of_core.stderr index bc49dabf5868a..e9ead4db5f9ea 100644 --- a/tests/ui/std_instead_of_core.stderr +++ b/tests/ui/std_instead_of_core.stderr @@ -63,9 +63,17 @@ LL | let cell_absolute = ::std::cell::Cell::new(8u32); | = help: consider importing the item from `core` -error: used import from `std` instead of `alloc` +error: used import from `std` instead of `core` --> $DIR/std_instead_of_core.rs:32:9 | +LL | use std::iter::Iterator; + | ^^^^^^^^^^^^^^^^^^^ + | + = help: consider importing the item from `core` + +error: used import from `std` instead of `alloc` + --> $DIR/std_instead_of_core.rs:38:9 + | LL | use std::vec; | ^^^^^^^^ | @@ -73,7 +81,7 @@ LL | use std::vec; = help: consider importing the item from `alloc` error: used import from `std` instead of `alloc` - --> $DIR/std_instead_of_core.rs:33:9 + --> $DIR/std_instead_of_core.rs:39:9 | LL | use std::vec::Vec; | ^^^^^^^^^^^^^ @@ -81,7 +89,7 @@ LL | use std::vec::Vec; = help: consider importing the item from `alloc` error: used import from `alloc` instead of `core` - --> $DIR/std_instead_of_core.rs:38:9 + --> $DIR/std_instead_of_core.rs:44:9 | LL | use alloc::slice::from_ref; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -89,5 +97,5 @@ LL | use alloc::slice::from_ref; = note: `-D clippy::alloc-instead-of-core` implied by `-D warnings` = help: consider importing the item from `core` -error: aborting due to 11 previous errors +error: aborting due to 12 previous errors From 187c27e6b0c756db340e4acdb18b9aae7fd1a1df Mon Sep 17 00:00:00 2001 From: kraktus Date: Tue, 27 Sep 2022 21:01:23 +0200 Subject: [PATCH 060/114] rename `and_only_expr_in_arm` -> `is_single_call_in_arm` --- clippy_lints/src/drop_forget_ref.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/drop_forget_ref.rs b/clippy_lints/src/drop_forget_ref.rs index de94b87cc409f..81d04935d8966 100644 --- a/clippy_lints/src/drop_forget_ref.rs +++ b/clippy_lints/src/drop_forget_ref.rs @@ -204,11 +204,11 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef { { let arg_ty = cx.typeck_results().expr_ty(arg); let is_copy = is_copy(cx, arg_ty); - let drop_is_only_expr_in_arm = and_only_expr_in_arm(cx, arg, expr); + let drop_is_single_call_in_arm = is_single_call_in_arm(cx, arg, expr); let (lint, msg) = match fn_name { sym::mem_drop if arg_ty.is_ref() => (DROP_REF, DROP_REF_SUMMARY), sym::mem_forget if arg_ty.is_ref() => (FORGET_REF, FORGET_REF_SUMMARY), - sym::mem_drop if is_copy && !drop_is_only_expr_in_arm => (DROP_COPY, DROP_COPY_SUMMARY), + sym::mem_drop if is_copy && !drop_is_single_call_in_arm => (DROP_COPY, DROP_COPY_SUMMARY), sym::mem_forget if is_copy => (FORGET_COPY, FORGET_COPY_SUMMARY), sym::mem_drop if is_type_lang_item(cx, arg_ty, LangItem::ManuallyDrop) => { span_lint_and_help( @@ -225,7 +225,7 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef { if !(arg_ty.needs_drop(cx.tcx, cx.param_env) || is_must_use_func_call(cx, arg) || is_must_use_ty(cx, arg_ty) - || drop_is_only_expr_in_arm + || drop_is_single_call_in_arm ) => { (DROP_NON_DROP, DROP_NON_DROP_SUMMARY) @@ -252,7 +252,7 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef { // => drop(fn_with_side_effect_and_returning_some_value()), // .. // } -fn and_only_expr_in_arm<'tcx>(cx: &LateContext<'tcx>, arg: &'tcx Expr<'_>, drop_expr: &'tcx Expr<'_>) -> bool { +fn is_single_call_in_arm<'tcx>(cx: &LateContext<'tcx>, arg: &'tcx Expr<'_>, drop_expr: &'tcx Expr<'_>) -> bool { if matches!(arg.kind, ExprKind::Call(..) | ExprKind::MethodCall(..)) { let parent_node = get_parent_node(cx.tcx, drop_expr.hir_id); if let Some(Node::Arm(Arm { body, .. })) = &parent_node { From 14ba4fba11e0e38d35c63559553380d8fde4517a Mon Sep 17 00:00:00 2001 From: kraktus Date: Sat, 17 Sep 2022 13:59:02 +0200 Subject: [PATCH 061/114] fix [`needless_borrow`] and [`explicit_auto_deref`] false positive on unions --- clippy_lints/src/dereference.rs | 37 ++++++++++++++++++++++++++------- tests/ui/needless_borrow.fixed | 29 ++++++++++++++++++++++++++ tests/ui/needless_borrow.rs | 29 ++++++++++++++++++++++++++ 3 files changed, 87 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index d1b25a0f1b535..99212b45ed529 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -184,6 +184,7 @@ impl Dereferencing { } } +#[derive(Debug)] struct StateData { /// Span of the top level expression span: Span, @@ -191,12 +192,14 @@ struct StateData { position: Position, } +#[derive(Debug)] struct DerefedBorrow { count: usize, msg: &'static str, snip_expr: Option, } +#[derive(Debug)] enum State { // Any number of deref method calls. DerefMethod { @@ -276,10 +279,12 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { (None, kind) => { let expr_ty = typeck.expr_ty(expr); let (position, adjustments) = walk_parents(cx, expr, self.msrv); - match kind { RefOp::Deref => { - if let Position::FieldAccess(name) = position + if let Position::FieldAccess { + name, + of_union: false, + } = position && !ty_contains_field(typeck.expr_ty(sub_expr), name) { self.state = Some(( @@ -451,7 +456,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { (Some((State::DerefedBorrow(state), data)), RefOp::Deref) => { let position = data.position; report(cx, expr, State::DerefedBorrow(state), data); - if let Position::FieldAccess(name) = position + if let Position::FieldAccess{name, ..} = position && !ty_contains_field(typeck.expr_ty(sub_expr), name) { self.state = Some(( @@ -616,14 +621,17 @@ fn deref_method_same_type<'tcx>(result_ty: Ty<'tcx>, arg_ty: Ty<'tcx>) -> bool { } /// The position of an expression relative to it's parent. -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] enum Position { MethodReceiver, /// The method is defined on a reference type. e.g. `impl Foo for &T` MethodReceiverRefImpl, Callee, ImplArg(HirId), - FieldAccess(Symbol), + FieldAccess { + name: Symbol, + of_union: bool, + }, // union fields cannot be auto borrowed Postfix, Deref, /// Any other location which will trigger auto-deref to a specific time. @@ -645,7 +653,10 @@ impl Position { } fn can_auto_borrow(self) -> bool { - matches!(self, Self::MethodReceiver | Self::FieldAccess(_) | Self::Callee) + matches!( + self, + Self::MethodReceiver | Self::FieldAccess { of_union: false, .. } | Self::Callee + ) } fn lint_explicit_deref(self) -> bool { @@ -657,7 +668,7 @@ impl Position { Self::MethodReceiver | Self::MethodReceiverRefImpl | Self::Callee - | Self::FieldAccess(_) + | Self::FieldAccess { .. } | Self::Postfix => PREC_POSTFIX, Self::ImplArg(_) | Self::Deref => PREC_PREFIX, Self::DerefStable(p, _) | Self::ReborrowStable(p) | Self::Other(p) => p, @@ -844,7 +855,10 @@ fn walk_parents<'tcx>( } }) }, - ExprKind::Field(child, name) if child.hir_id == e.hir_id => Some(Position::FieldAccess(name.name)), + ExprKind::Field(child, name) if child.hir_id == e.hir_id => Some(Position::FieldAccess { + name: name.name, + of_union: is_union(cx.typeck_results(), child), + }), ExprKind::Unary(UnOp::Deref, child) if child.hir_id == e.hir_id => Some(Position::Deref), ExprKind::Match(child, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar) | ExprKind::Index(child, _) @@ -865,6 +879,13 @@ fn walk_parents<'tcx>( (position, adjustments) } +fn is_union<'tcx>(typeck: &'tcx TypeckResults<'_>, path_expr: &'tcx Expr<'_>) -> bool { + typeck + .expr_ty_adjusted(path_expr) + .ty_adt_def() + .map_or(false, rustc_middle::ty::AdtDef::is_union) +} + fn closure_result_position<'tcx>( cx: &LateContext<'tcx>, closure: &'tcx Closure<'_>, diff --git a/tests/ui/needless_borrow.fixed b/tests/ui/needless_borrow.fixed index 8cf93bd248173..6914f9183c7cc 100644 --- a/tests/ui/needless_borrow.fixed +++ b/tests/ui/needless_borrow.fixed @@ -298,3 +298,32 @@ mod meets_msrv { let _ = std::process::Command::new("ls").args(["-a", "-l"]).status().unwrap(); } } + +#[allow(unused)] +fn issue9383() { + // Should not lint because unions need explicit deref when accessing field + use std::mem::ManuallyDrop; + + union Coral { + crab: ManuallyDrop>, + } + + union Ocean { + coral: ManuallyDrop, + } + + let mut ocean = Ocean { + coral: ManuallyDrop::new(Coral { + crab: ManuallyDrop::new(vec![1, 2, 3]), + }), + }; + + unsafe { + ManuallyDrop::drop(&mut (&mut ocean.coral).crab); + + (*ocean.coral).crab = ManuallyDrop::new(vec![4, 5, 6]); + ManuallyDrop::drop(&mut (*ocean.coral).crab); + + ManuallyDrop::drop(&mut ocean.coral); + } +} diff --git a/tests/ui/needless_borrow.rs b/tests/ui/needless_borrow.rs index fd9b2a11df96f..e2a609fa5d275 100644 --- a/tests/ui/needless_borrow.rs +++ b/tests/ui/needless_borrow.rs @@ -298,3 +298,32 @@ mod meets_msrv { let _ = std::process::Command::new("ls").args(&["-a", "-l"]).status().unwrap(); } } + +#[allow(unused)] +fn issue9383() { + // Should not lint because unions need explicit deref when accessing field + use std::mem::ManuallyDrop; + + union Coral { + crab: ManuallyDrop>, + } + + union Ocean { + coral: ManuallyDrop, + } + + let mut ocean = Ocean { + coral: ManuallyDrop::new(Coral { + crab: ManuallyDrop::new(vec![1, 2, 3]), + }), + }; + + unsafe { + ManuallyDrop::drop(&mut (&mut ocean.coral).crab); + + (*ocean.coral).crab = ManuallyDrop::new(vec![4, 5, 6]); + ManuallyDrop::drop(&mut (*ocean.coral).crab); + + ManuallyDrop::drop(&mut ocean.coral); + } +} From 72898355429c278ea994758805a92e611aecb430 Mon Sep 17 00:00:00 2001 From: kraktus Date: Tue, 27 Sep 2022 22:24:14 +0200 Subject: [PATCH 062/114] [`should_implement_trait`] Also lint `default` method --- clippy_lints/src/methods/mod.rs | 83 +++++++++---------- .../ui/should_impl_trait/method_list_1.stderr | 12 ++- 2 files changed, 49 insertions(+), 46 deletions(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index cdde4c54d6378..c43f822e3a386 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3255,65 +3255,59 @@ impl<'tcx> LateLintPass<'tcx> for Methods { let self_ty = cx.tcx.type_of(item.def_id); let implements_trait = matches!(item.kind, hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. })); - if_chain! { - if let hir::ImplItemKind::Fn(ref sig, id) = impl_item.kind; - if let Some(first_arg) = iter_input_pats(sig.decl, cx.tcx.hir().body(id)).next(); - + if let hir::ImplItemKind::Fn(ref sig, id) = impl_item.kind { let method_sig = cx.tcx.fn_sig(impl_item.def_id); let method_sig = cx.tcx.erase_late_bound_regions(method_sig); - - let first_arg_ty = method_sig.inputs().iter().next(); - - // check conventions w.r.t. conversion method names and predicates - if let Some(first_arg_ty) = first_arg_ty; - - then { - // if this impl block implements a trait, lint in trait definition instead - if !implements_trait && cx.access_levels.is_exported(impl_item.def_id) { - // check missing trait implementations - for method_config in &TRAIT_METHODS { - if name == method_config.method_name && - sig.decl.inputs.len() == method_config.param_count && - method_config.output_type.matches(&sig.decl.output) && - method_config.self_kind.matches(cx, self_ty, *first_arg_ty) && - fn_header_equals(method_config.fn_header, sig.header) && - method_config.lifetime_param_cond(impl_item) - { - span_lint_and_help( - cx, - SHOULD_IMPLEMENT_TRAIT, - impl_item.span, - &format!( - "method `{}` can be confused for the standard trait method `{}::{}`", - method_config.method_name, - method_config.trait_name, - method_config.method_name - ), - None, - &format!( - "consider implementing the trait `{}` or choosing a less ambiguous method name", - method_config.trait_name - ) - ); - } + let first_arg_ty_opt = method_sig.inputs().iter().next().copied(); + // if this impl block implements a trait, lint in trait definition instead + if !implements_trait && cx.access_levels.is_exported(impl_item.def_id) { + // check missing trait implementations + for method_config in &TRAIT_METHODS { + if name == method_config.method_name + && sig.decl.inputs.len() == method_config.param_count + && method_config.output_type.matches(&sig.decl.output) + // in case there is no first arg, since we already have checked the number of arguments + // it's should be always true + && first_arg_ty_opt.map_or(true, |first_arg_ty| method_config + .self_kind.matches(cx, self_ty, first_arg_ty) + ) + && fn_header_equals(method_config.fn_header, sig.header) + && method_config.lifetime_param_cond(impl_item) + { + span_lint_and_help( + cx, + SHOULD_IMPLEMENT_TRAIT, + impl_item.span, + &format!( + "method `{}` can be confused for the standard trait method `{}::{}`", + method_config.method_name, method_config.trait_name, method_config.method_name + ), + None, + &format!( + "consider implementing the trait `{}` or choosing a less ambiguous method name", + method_config.trait_name + ), + ); } } + } - if sig.decl.implicit_self.has_implicit_self() + if sig.decl.implicit_self.has_implicit_self() && !(self.avoid_breaking_exported_api - && cx.access_levels.is_exported(impl_item.def_id)) + && cx.access_levels.is_exported(impl_item.def_id)) + && let Some(first_arg) = iter_input_pats(sig.decl, cx.tcx.hir().body(id)).next() + && let Some(first_arg_ty) = first_arg_ty_opt { wrong_self_convention::check( cx, name, self_ty, - *first_arg_ty, + first_arg_ty, first_arg.pat.span, implements_trait, false ); } - } } // if this impl block implements a trait, lint in trait definition instead @@ -3799,7 +3793,6 @@ const TRAIT_METHODS: [ShouldImplTraitCase; 30] = [ ShouldImplTraitCase::new("std::borrow::BorrowMut", "borrow_mut", 1, FN_HEADER, SelfKind::RefMut, OutType::Ref, true), ShouldImplTraitCase::new("std::clone::Clone", "clone", 1, FN_HEADER, SelfKind::Ref, OutType::Any, true), ShouldImplTraitCase::new("std::cmp::Ord", "cmp", 2, FN_HEADER, SelfKind::Ref, OutType::Any, true), - // FIXME: default doesn't work ShouldImplTraitCase::new("std::default::Default", "default", 0, FN_HEADER, SelfKind::No, OutType::Any, true), ShouldImplTraitCase::new("std::ops::Deref", "deref", 1, FN_HEADER, SelfKind::Ref, OutType::Ref, true), ShouldImplTraitCase::new("std::ops::DerefMut", "deref_mut", 1, FN_HEADER, SelfKind::RefMut, OutType::Ref, true), @@ -3827,7 +3820,7 @@ enum SelfKind { Value, Ref, RefMut, - No, + No, // When we want the first argument type to be different than `Self` } impl SelfKind { diff --git a/tests/ui/should_impl_trait/method_list_1.stderr b/tests/ui/should_impl_trait/method_list_1.stderr index 2b7d4628c3fa0..e6daedc565467 100644 --- a/tests/ui/should_impl_trait/method_list_1.stderr +++ b/tests/ui/should_impl_trait/method_list_1.stderr @@ -99,6 +99,16 @@ LL | | } | = help: consider implementing the trait `std::cmp::Ord` or choosing a less ambiguous method name +error: method `default` can be confused for the standard trait method `std::default::Default::default` + --> $DIR/method_list_1.rs:65:5 + | +LL | / pub fn default() -> Self { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::default::Default` or choosing a less ambiguous method name + error: method `deref` can be confused for the standard trait method `std::ops::Deref::deref` --> $DIR/method_list_1.rs:69:5 | @@ -139,5 +149,5 @@ LL | | } | = help: consider implementing the trait `std::ops::Drop` or choosing a less ambiguous method name -error: aborting due to 14 previous errors +error: aborting due to 15 previous errors From 458e83291db2532fec8877c74aca872a35353328 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Wed, 28 Sep 2022 14:27:50 +0200 Subject: [PATCH 063/114] Bump Clippy version -> 0.1.66 --- Cargo.toml | 2 +- clippy_lints/Cargo.toml | 2 +- clippy_utils/Cargo.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5e960fdbcf118..b1bec0c46cad3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.1.65" +version = "0.1.66" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index badd391302b6f..1ff976f48f619 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_lints" -version = "0.1.65" +version = "0.1.66" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" diff --git a/clippy_utils/Cargo.toml b/clippy_utils/Cargo.toml index c36bca06507d6..83fee7bb39c22 100644 --- a/clippy_utils/Cargo.toml +++ b/clippy_utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_utils" -version = "0.1.65" +version = "0.1.66" edition = "2021" publish = false From 8ba081c59734c48a6f3dea6fdf35767da5652a3b Mon Sep 17 00:00:00 2001 From: alex-semenyuk Date: Wed, 28 Sep 2022 23:01:11 +0300 Subject: [PATCH 064/114] Fix typo --- clippy_lints/src/option_if_let_else.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index 256d24500011f..2c1e3b855d52c 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -88,7 +88,7 @@ declare_lint_pass!(OptionIfLetElse => [OPTION_IF_LET_ELSE]); /// None/_ => {..} /// } /// ``` -struct OptionOccurence { +struct OptionOccurrence { option: String, method_sugg: String, some_expr: String, @@ -109,13 +109,13 @@ fn format_option_in_sugg(cx: &LateContext<'_>, cond_expr: &Expr<'_>, as_ref: boo ) } -fn try_get_option_occurence<'tcx>( +fn try_get_option_occurrence<'tcx>( cx: &LateContext<'tcx>, pat: &Pat<'tcx>, expr: &Expr<'_>, if_then: &'tcx Expr<'_>, if_else: &'tcx Expr<'_>, -) -> Option { +) -> Option { let cond_expr = match expr.kind { ExprKind::Unary(UnOp::Deref, inner_expr) | ExprKind::AddrOf(_, _, inner_expr) => inner_expr, _ => expr, @@ -160,7 +160,7 @@ fn try_get_option_occurence<'tcx>( } } - return Some(OptionOccurence { + return Some(OptionOccurrence { option: format_option_in_sugg(cx, cond_expr, as_ref, as_mut), method_sugg: method_sugg.to_string(), some_expr: format!("|{capture_mut}{capture_name}| {}", Sugg::hir_with_macro_callsite(cx, some_body, "..")), @@ -182,9 +182,9 @@ fn try_get_inner_pat<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'tcx>) -> Option<&' } /// If this expression is the option if let/else construct we're detecting, then -/// this function returns an `OptionOccurence` struct with details if +/// this function returns an `OptionOccurrence` struct with details if /// this construct is found, or None if this construct is not found. -fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option { +fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option { if let Some(higher::IfLet { let_pat, let_expr, @@ -193,16 +193,16 @@ fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> }) = higher::IfLet::hir(cx, expr) { if !is_else_clause(cx.tcx, expr) { - return try_get_option_occurence(cx, let_pat, let_expr, if_then, if_else); + return try_get_option_occurrence(cx, let_pat, let_expr, if_then, if_else); } } None } -fn detect_option_match<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option { +fn detect_option_match<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option { if let ExprKind::Match(ex, arms, MatchSource::Normal) = expr.kind { if let Some((let_pat, if_then, if_else)) = try_convert_match(cx, arms) { - return try_get_option_occurence(cx, let_pat, ex, if_then, if_else); + return try_get_option_occurrence(cx, let_pat, ex, if_then, if_else); } } None From 314d57a7908d596a0fdfd58735bdc9e3727aed29 Mon Sep 17 00:00:00 2001 From: kraktus Date: Wed, 28 Sep 2022 22:21:52 +0200 Subject: [PATCH 065/114] [`unnecessary_lazy_evaluations`] Do not suggest switching to early evaluation when type has custom `Drop` --- clippy_utils/src/eager_or_lazy.rs | 12 ++++- tests/ui/unnecessary_lazy_eval.fixed | 11 +++++ tests/ui/unnecessary_lazy_eval.rs | 11 +++++ tests/ui/unnecessary_lazy_eval.stderr | 68 +++++++++++++-------------- 4 files changed, 67 insertions(+), 35 deletions(-) diff --git a/clippy_utils/src/eager_or_lazy.rs b/clippy_utils/src/eager_or_lazy.rs index 91c9c382c236b..8724a4cd651de 100644 --- a/clippy_utils/src/eager_or_lazy.rs +++ b/clippy_utils/src/eager_or_lazy.rs @@ -113,7 +113,17 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS }, args, ) => match self.cx.qpath_res(path, hir_id) { - Res::Def(DefKind::Ctor(..) | DefKind::Variant, _) | Res::SelfCtor(_) => (), + Res::Def(DefKind::Ctor(..) | DefKind::Variant, _) | Res::SelfCtor(_) => { + if self + .cx + .typeck_results() + .expr_ty(e) + .has_significant_drop(self.cx.tcx, self.cx.param_env) + { + self.eagerness = Lazy; + return; + } + }, Res::Def(_, id) if self.cx.tcx.is_promotable_const_fn(id) => (), // No need to walk the arguments here, `is_const_evaluatable` already did Res::Def(..) if is_const_evaluatable(self.cx, e) => { diff --git a/tests/ui/unnecessary_lazy_eval.fixed b/tests/ui/unnecessary_lazy_eval.fixed index eed8179688321..878537050d42c 100644 --- a/tests/ui/unnecessary_lazy_eval.fixed +++ b/tests/ui/unnecessary_lazy_eval.fixed @@ -21,6 +21,14 @@ fn some_call() -> T { T::default() } +struct Issue9427(i32); + +impl Drop for Issue9427 { + fn drop(&mut self) { + println!("{}", self.0); + } +} + fn main() { let astronomers_pi = 10; let ext_arr: [usize; 1] = [2]; @@ -73,6 +81,9 @@ fn main() { let _ = deep.0.or_else(|| some_call()); let _ = opt.ok_or_else(|| ext_arr[0]); + // Should not lint - bool + let _ = (0 == 1).then(|| Issue9427(0)); // Issue9427 has a significant drop + // should not lint, bind_instead_of_map takes priority let _ = Some(10).and_then(|idx| Some(ext_arr[idx])); let _ = Some(10).and_then(|idx| Some(idx)); diff --git a/tests/ui/unnecessary_lazy_eval.rs b/tests/ui/unnecessary_lazy_eval.rs index 1588db79b38a8..f70cf332460e1 100644 --- a/tests/ui/unnecessary_lazy_eval.rs +++ b/tests/ui/unnecessary_lazy_eval.rs @@ -21,6 +21,14 @@ fn some_call() -> T { T::default() } +struct Issue9427(i32); + +impl Drop for Issue9427 { + fn drop(&mut self) { + println!("{}", self.0); + } +} + fn main() { let astronomers_pi = 10; let ext_arr: [usize; 1] = [2]; @@ -73,6 +81,9 @@ fn main() { let _ = deep.0.or_else(|| some_call()); let _ = opt.ok_or_else(|| ext_arr[0]); + // Should not lint - bool + let _ = (0 == 1).then(|| Issue9427(0)); // Issue9427 has a significant drop + // should not lint, bind_instead_of_map takes priority let _ = Some(10).and_then(|idx| Some(ext_arr[idx])); let _ = Some(10).and_then(|idx| Some(idx)); diff --git a/tests/ui/unnecessary_lazy_eval.stderr b/tests/ui/unnecessary_lazy_eval.stderr index 83dc7fd832c38..b46fbf56c4bd1 100644 --- a/tests/ui/unnecessary_lazy_eval.stderr +++ b/tests/ui/unnecessary_lazy_eval.stderr @@ -1,5 +1,5 @@ error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:36:13 + --> $DIR/unnecessary_lazy_eval.rs:44:13 | LL | let _ = opt.unwrap_or_else(|| 2); | ^^^^-------------------- @@ -9,7 +9,7 @@ LL | let _ = opt.unwrap_or_else(|| 2); = note: `-D clippy::unnecessary-lazy-evaluations` implied by `-D warnings` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:37:13 + --> $DIR/unnecessary_lazy_eval.rs:45:13 | LL | let _ = opt.unwrap_or_else(|| astronomers_pi); | ^^^^--------------------------------- @@ -17,7 +17,7 @@ LL | let _ = opt.unwrap_or_else(|| astronomers_pi); | help: use `unwrap_or(..)` instead: `unwrap_or(astronomers_pi)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:38:13 + --> $DIR/unnecessary_lazy_eval.rs:46:13 | LL | let _ = opt.unwrap_or_else(|| ext_str.some_field); | ^^^^------------------------------------- @@ -25,7 +25,7 @@ LL | let _ = opt.unwrap_or_else(|| ext_str.some_field); | help: use `unwrap_or(..)` instead: `unwrap_or(ext_str.some_field)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:40:13 + --> $DIR/unnecessary_lazy_eval.rs:48:13 | LL | let _ = opt.and_then(|_| ext_opt); | ^^^^--------------------- @@ -33,7 +33,7 @@ LL | let _ = opt.and_then(|_| ext_opt); | help: use `and(..)` instead: `and(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:41:13 + --> $DIR/unnecessary_lazy_eval.rs:49:13 | LL | let _ = opt.or_else(|| ext_opt); | ^^^^------------------- @@ -41,7 +41,7 @@ LL | let _ = opt.or_else(|| ext_opt); | help: use `or(..)` instead: `or(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:42:13 + --> $DIR/unnecessary_lazy_eval.rs:50:13 | LL | let _ = opt.or_else(|| None); | ^^^^---------------- @@ -49,7 +49,7 @@ LL | let _ = opt.or_else(|| None); | help: use `or(..)` instead: `or(None)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:43:13 + --> $DIR/unnecessary_lazy_eval.rs:51:13 | LL | let _ = opt.get_or_insert_with(|| 2); | ^^^^------------------------ @@ -57,7 +57,7 @@ LL | let _ = opt.get_or_insert_with(|| 2); | help: use `get_or_insert(..)` instead: `get_or_insert(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:44:13 + --> $DIR/unnecessary_lazy_eval.rs:52:13 | LL | let _ = opt.ok_or_else(|| 2); | ^^^^---------------- @@ -65,7 +65,7 @@ LL | let _ = opt.ok_or_else(|| 2); | help: use `ok_or(..)` instead: `ok_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:45:13 + --> $DIR/unnecessary_lazy_eval.rs:53:13 | LL | let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2))); | ^^^^^^^^^^^^^^^^^------------------------------- @@ -73,7 +73,7 @@ LL | let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2))); | help: use `unwrap_or(..)` instead: `unwrap_or(Some((1, 2)))` error: unnecessary closure used with `bool::then` - --> $DIR/unnecessary_lazy_eval.rs:46:13 + --> $DIR/unnecessary_lazy_eval.rs:54:13 | LL | let _ = cond.then(|| astronomers_pi); | ^^^^^----------------------- @@ -81,7 +81,7 @@ LL | let _ = cond.then(|| astronomers_pi); | help: use `then_some(..)` instead: `then_some(astronomers_pi)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:49:13 + --> $DIR/unnecessary_lazy_eval.rs:57:13 | LL | let _ = Some(10).unwrap_or_else(|| 2); | ^^^^^^^^^-------------------- @@ -89,7 +89,7 @@ LL | let _ = Some(10).unwrap_or_else(|| 2); | help: use `unwrap_or(..)` instead: `unwrap_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:50:13 + --> $DIR/unnecessary_lazy_eval.rs:58:13 | LL | let _ = Some(10).and_then(|_| ext_opt); | ^^^^^^^^^--------------------- @@ -97,7 +97,7 @@ LL | let _ = Some(10).and_then(|_| ext_opt); | help: use `and(..)` instead: `and(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:51:28 + --> $DIR/unnecessary_lazy_eval.rs:59:28 | LL | let _: Option = None.or_else(|| ext_opt); | ^^^^^------------------- @@ -105,7 +105,7 @@ LL | let _: Option = None.or_else(|| ext_opt); | help: use `or(..)` instead: `or(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:52:13 + --> $DIR/unnecessary_lazy_eval.rs:60:13 | LL | let _ = None.get_or_insert_with(|| 2); | ^^^^^------------------------ @@ -113,7 +113,7 @@ LL | let _ = None.get_or_insert_with(|| 2); | help: use `get_or_insert(..)` instead: `get_or_insert(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:53:35 + --> $DIR/unnecessary_lazy_eval.rs:61:35 | LL | let _: Result = None.ok_or_else(|| 2); | ^^^^^---------------- @@ -121,7 +121,7 @@ LL | let _: Result = None.ok_or_else(|| 2); | help: use `ok_or(..)` instead: `ok_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:54:28 + --> $DIR/unnecessary_lazy_eval.rs:62:28 | LL | let _: Option = None.or_else(|| None); | ^^^^^---------------- @@ -129,7 +129,7 @@ LL | let _: Option = None.or_else(|| None); | help: use `or(..)` instead: `or(None)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:57:13 + --> $DIR/unnecessary_lazy_eval.rs:65:13 | LL | let _ = deep.0.unwrap_or_else(|| 2); | ^^^^^^^-------------------- @@ -137,7 +137,7 @@ LL | let _ = deep.0.unwrap_or_else(|| 2); | help: use `unwrap_or(..)` instead: `unwrap_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:58:13 + --> $DIR/unnecessary_lazy_eval.rs:66:13 | LL | let _ = deep.0.and_then(|_| ext_opt); | ^^^^^^^--------------------- @@ -145,7 +145,7 @@ LL | let _ = deep.0.and_then(|_| ext_opt); | help: use `and(..)` instead: `and(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:59:13 + --> $DIR/unnecessary_lazy_eval.rs:67:13 | LL | let _ = deep.0.or_else(|| None); | ^^^^^^^---------------- @@ -153,7 +153,7 @@ LL | let _ = deep.0.or_else(|| None); | help: use `or(..)` instead: `or(None)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:60:13 + --> $DIR/unnecessary_lazy_eval.rs:68:13 | LL | let _ = deep.0.get_or_insert_with(|| 2); | ^^^^^^^------------------------ @@ -161,7 +161,7 @@ LL | let _ = deep.0.get_or_insert_with(|| 2); | help: use `get_or_insert(..)` instead: `get_or_insert(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:61:13 + --> $DIR/unnecessary_lazy_eval.rs:69:13 | LL | let _ = deep.0.ok_or_else(|| 2); | ^^^^^^^---------------- @@ -169,7 +169,7 @@ LL | let _ = deep.0.ok_or_else(|| 2); | help: use `ok_or(..)` instead: `ok_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:81:28 + --> $DIR/unnecessary_lazy_eval.rs:92:28 | LL | let _: Option = None.or_else(|| Some(3)); | ^^^^^------------------- @@ -177,7 +177,7 @@ LL | let _: Option = None.or_else(|| Some(3)); | help: use `or(..)` instead: `or(Some(3))` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:82:13 + --> $DIR/unnecessary_lazy_eval.rs:93:13 | LL | let _ = deep.0.or_else(|| Some(3)); | ^^^^^^^------------------- @@ -185,7 +185,7 @@ LL | let _ = deep.0.or_else(|| Some(3)); | help: use `or(..)` instead: `or(Some(3))` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:83:13 + --> $DIR/unnecessary_lazy_eval.rs:94:13 | LL | let _ = opt.or_else(|| Some(3)); | ^^^^------------------- @@ -193,7 +193,7 @@ LL | let _ = opt.or_else(|| Some(3)); | help: use `or(..)` instead: `or(Some(3))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:89:13 + --> $DIR/unnecessary_lazy_eval.rs:100:13 | LL | let _ = res2.unwrap_or_else(|_| 2); | ^^^^^--------------------- @@ -201,7 +201,7 @@ LL | let _ = res2.unwrap_or_else(|_| 2); | help: use `unwrap_or(..)` instead: `unwrap_or(2)` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:90:13 + --> $DIR/unnecessary_lazy_eval.rs:101:13 | LL | let _ = res2.unwrap_or_else(|_| astronomers_pi); | ^^^^^---------------------------------- @@ -209,7 +209,7 @@ LL | let _ = res2.unwrap_or_else(|_| astronomers_pi); | help: use `unwrap_or(..)` instead: `unwrap_or(astronomers_pi)` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:91:13 + --> $DIR/unnecessary_lazy_eval.rs:102:13 | LL | let _ = res2.unwrap_or_else(|_| ext_str.some_field); | ^^^^^-------------------------------------- @@ -217,7 +217,7 @@ LL | let _ = res2.unwrap_or_else(|_| ext_str.some_field); | help: use `unwrap_or(..)` instead: `unwrap_or(ext_str.some_field)` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:113:35 + --> $DIR/unnecessary_lazy_eval.rs:124:35 | LL | let _: Result = res.and_then(|_| Err(2)); | ^^^^-------------------- @@ -225,7 +225,7 @@ LL | let _: Result = res.and_then(|_| Err(2)); | help: use `and(..)` instead: `and(Err(2))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:114:35 + --> $DIR/unnecessary_lazy_eval.rs:125:35 | LL | let _: Result = res.and_then(|_| Err(astronomers_pi)); | ^^^^--------------------------------- @@ -233,7 +233,7 @@ LL | let _: Result = res.and_then(|_| Err(astronomers_pi)); | help: use `and(..)` instead: `and(Err(astronomers_pi))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:115:35 + --> $DIR/unnecessary_lazy_eval.rs:126:35 | LL | let _: Result = res.and_then(|_| Err(ext_str.some_field)); | ^^^^------------------------------------- @@ -241,7 +241,7 @@ LL | let _: Result = res.and_then(|_| Err(ext_str.some_field)) | help: use `and(..)` instead: `and(Err(ext_str.some_field))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:117:35 + --> $DIR/unnecessary_lazy_eval.rs:128:35 | LL | let _: Result = res.or_else(|_| Ok(2)); | ^^^^------------------ @@ -249,7 +249,7 @@ LL | let _: Result = res.or_else(|_| Ok(2)); | help: use `or(..)` instead: `or(Ok(2))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:118:35 + --> $DIR/unnecessary_lazy_eval.rs:129:35 | LL | let _: Result = res.or_else(|_| Ok(astronomers_pi)); | ^^^^------------------------------- @@ -257,7 +257,7 @@ LL | let _: Result = res.or_else(|_| Ok(astronomers_pi)); | help: use `or(..)` instead: `or(Ok(astronomers_pi))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:119:35 + --> $DIR/unnecessary_lazy_eval.rs:130:35 | LL | let _: Result = res.or_else(|_| Ok(ext_str.some_field)); | ^^^^----------------------------------- @@ -265,7 +265,7 @@ LL | let _: Result = res.or_else(|_| Ok(ext_str.some_field)); | help: use `or(..)` instead: `or(Ok(ext_str.some_field))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:120:35 + --> $DIR/unnecessary_lazy_eval.rs:131:35 | LL | let _: Result = res. | ___________________________________^ From 8b59fe4981d5d21874413668ff1d8d0b9d8e4ef6 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 16 Sep 2022 11:45:33 +1000 Subject: [PATCH 066/114] Shrink `hir::def::Res`. `Res::SelfTy` currently has two `Option`s. When the second one is `Some` the first one is never consulted. So we can split it into two variants, `Res::SelfTyParam` and `Res::SelfTyAlias`, reducing the size of `Res` from 24 bytes to 12. This then shrinks `hir::Path` and `hir::PathSegment`, which are the HIR types that take up the most space. --- clippy_lints/src/trait_bounds.rs | 2 +- clippy_lints/src/use_self.rs | 9 +++++++-- clippy_utils/src/lib.rs | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index a25be93b8d616..2be22884027e2 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -128,7 +128,7 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds { if !bound_predicate.span.from_expansion(); if let TyKind::Path(QPath::Resolved(_, Path { segments, .. })) = bound_predicate.bounded_ty.kind; if let Some(PathSegment { - res: Res::SelfTy{ trait_: Some(def_id), alias_to: _ }, .. + res: Res::SelfTyParam { trait_: def_id }, .. }) = segments.first(); if let Some( Node::Item( diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index 6a767967ef409..2c4f5075e9807 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -206,7 +206,12 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { ref types_to_skip, }) = self.stack.last(); if let TyKind::Path(QPath::Resolved(_, path)) = hir_ty.kind; - if !matches!(path.res, Res::SelfTy { .. } | Res::Def(DefKind::TyParam, _)); + if !matches!( + path.res, + Res::SelfTyParam { .. } + | Res::SelfTyAlias { .. } + | Res::Def(DefKind::TyParam, _) + ); if !types_to_skip.contains(&hir_ty.hir_id); let ty = if in_body > 0 { cx.typeck_results().node_type(hir_ty.hir_id) @@ -230,7 +235,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { } match expr.kind { ExprKind::Struct(QPath::Resolved(_, path), ..) => match path.res { - Res::SelfTy { .. } => (), + Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } => (), Res::Def(DefKind::Variant, _) => lint_path_to_variant(cx, path), _ => span_lint(cx, path.span), }, diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 627d6b51944a6..8f79c07c97724 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1535,7 +1535,7 @@ pub fn is_self(slf: &Param<'_>) -> bool { pub fn is_self_ty(slf: &hir::Ty<'_>) -> bool { if let TyKind::Path(QPath::Resolved(None, path)) = slf.kind { - if let Res::SelfTy { .. } = path.res { + if let Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } = path.res { return true; } } From 579791178de9092be554d3751401fd58181a16c0 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Wed, 28 Sep 2022 14:28:03 +0200 Subject: [PATCH 067/114] Bump nightly version -> 2022-09-29 --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index b6976366dafc9..423d6425e1048 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2022-09-08" +channel = "nightly-2022-09-29" components = ["cargo", "llvm-tools-preview", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] From 67af127f243e5a3abcdf95f395b1029560a63ac1 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Wed, 28 Sep 2022 14:31:29 +0200 Subject: [PATCH 068/114] Fix dogfood --- clippy_lints/src/equatable_if_let.rs | 2 +- clippy_lints/src/lifetimes.rs | 2 +- clippy_lints/src/matches/redundant_pattern_match.rs | 12 ++++++------ clippy_lints/src/ptr.rs | 2 +- clippy_lints/src/types/mod.rs | 2 +- clippy_utils/src/hir_utils.rs | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/clippy_lints/src/equatable_if_let.rs b/clippy_lints/src/equatable_if_let.rs index f5aa0dcf9a463..b40cb7cddaf17 100644 --- a/clippy_lints/src/equatable_if_let.rs +++ b/clippy_lints/src/equatable_if_let.rs @@ -51,7 +51,7 @@ fn unary_pattern(pat: &Pat<'_>) -> bool { false }, PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)), - PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => !etc.as_opt_usize().is_some() && array_rec(a), + PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => etc.as_opt_usize().is_none() && array_rec(a), PatKind::Ref(x, _) | PatKind::Box(x) => unary_pattern(x), PatKind::Path(_) | PatKind::Lit(_) => true, } diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index aef253303a8f4..13878eda0f1cd 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -461,7 +461,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> { sub_visitor.visit_fn_decl(decl); self.nested_elision_site_lts.append(&mut sub_visitor.all_lts()); }, - TyKind::TraitObject(bounds, ref lt, _) => { + TyKind::TraitObject(bounds, lt, _) => { if !lt.is_elided() { self.unelided_trait_object_lifetime = true; } diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs index 11495cca97ddc..6d6aa43df2a7e 100644 --- a/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/clippy_lints/src/matches/redundant_pattern_match.rs @@ -308,15 +308,15 @@ fn find_good_method_for_match<'a>( should_be_left: &'a str, should_be_right: &'a str, ) -> Option<&'a str> { - let pat_left = arms[0].pat; - let pat_right = arms[1].pat; + let first_pat = arms[0].pat; + let second_pat = arms[1].pat; - let body_node_pair = if (is_pat_variant(cx, pat_left, path_left, expected_item_left)) - && (is_pat_variant(cx, pat_right, path_right, expected_item_right)) + let body_node_pair = if (is_pat_variant(cx, first_pat, path_left, expected_item_left)) + && (is_pat_variant(cx, second_pat, path_right, expected_item_right)) { (&arms[0].body.kind, &arms[1].body.kind) - } else if (is_pat_variant(cx, pat_left, path_left, expected_item_right)) - && (is_pat_variant(cx, pat_right, path_right, expected_item_left)) + } else if (is_pat_variant(cx, first_pat, path_left, expected_item_right)) + && (is_pat_variant(cx, second_pat, path_right, expected_item_left)) { (&arms[1].body.kind, &arms[0].body.kind) } else { diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 85e0710eb50d8..d296a150b46d0 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -669,7 +669,7 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args: } fn get_rptr_lm<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> Option<(&'tcx Lifetime, Mutability, Span)> { - if let TyKind::Rptr(ref lt, ref m) = ty.kind { + if let TyKind::Rptr(lt, ref m) = ty.kind { Some((lt, m.mutbl, ty.span)) } else { None diff --git a/clippy_lints/src/types/mod.rs b/clippy_lints/src/types/mod.rs index b81d2c1cbc484..79c31efb9fcdf 100644 --- a/clippy_lints/src/types/mod.rs +++ b/clippy_lints/src/types/mod.rs @@ -537,7 +537,7 @@ impl Types { QPath::LangItem(..) => {}, } }, - TyKind::Rptr(ref lt, ref mut_ty) => { + TyKind::Rptr(lt, ref mut_ty) => { context.is_nested_call = true; if !borrowed_box::check(cx, hir_ty, lt, mut_ty) { self.check_ty(cx, mut_ty.ty, context); diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index 7212d9cd74451..cf24ec8b67b90 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -962,7 +962,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { mut_ty.mutbl.hash(&mut self.s); }, TyKind::Rptr(lifetime, ref mut_ty) => { - self.hash_lifetime(*lifetime); + self.hash_lifetime(lifetime); self.hash_ty(mut_ty.ty); mut_ty.mutbl.hash(&mut self.s); }, @@ -992,7 +992,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { in_trait.hash(&mut self.s); }, TyKind::TraitObject(_, lifetime, _) => { - self.hash_lifetime(*lifetime); + self.hash_lifetime(lifetime); }, TyKind::Typeof(anon_const) => { self.hash_body(anon_const.body); From 924c1ce97d33f75d6e9e92df1c523abdc7d90f02 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Wed, 28 Sep 2022 14:36:56 +0200 Subject: [PATCH 069/114] Update lints after sync --- src/docs/arithmetic_side_effects.txt | 2 +- src/docs/similar_names.txt | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/docs/arithmetic_side_effects.txt b/src/docs/arithmetic_side_effects.txt index b8c0872522ee1..4ae8bce88ad5f 100644 --- a/src/docs/arithmetic_side_effects.txt +++ b/src/docs/arithmetic_side_effects.txt @@ -30,4 +30,4 @@ let _n = Decimal::MAX + Decimal::MAX; ``` ### Allowed types -Custom allowed types can be specified through the "arithmetic-side-effects-allowed" filter. +Custom allowed types can be specified through the "arithmetic-side-effects-allowed" filter. \ No newline at end of file diff --git a/src/docs/similar_names.txt b/src/docs/similar_names.txt index 13aca9c0bb75b..f9eff21b67935 100644 --- a/src/docs/similar_names.txt +++ b/src/docs/similar_names.txt @@ -1,6 +1,10 @@ ### What it does Checks for names that are very similar and thus confusing. +Note: this lint looks for similar names throughout each +scope. To allow it, you need to allow it on the scope +level, not on the name that is reported. + ### Why is this bad? It's hard to distinguish between names that differ only by a single character. From 6ec7759c3bff136c1d39bbe0bc8a68ac8b438a55 Mon Sep 17 00:00:00 2001 From: kraktus Date: Thu, 29 Sep 2022 13:45:40 +0200 Subject: [PATCH 070/114] [`unnecessary_lazy_eval`] Do not lint in external macros --- .../src/methods/unnecessary_lazy_eval.rs | 6 +- tests/ui/unnecessary_lazy_eval.fixed | 10 +++ tests/ui/unnecessary_lazy_eval.rs | 10 +++ tests/ui/unnecessary_lazy_eval.stderr | 68 +++++++++---------- 4 files changed, 59 insertions(+), 35 deletions(-) diff --git a/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/clippy_lints/src/methods/unnecessary_lazy_eval.rs index ec9859fa298b6..0e73459ad65f7 100644 --- a/clippy_lints/src/methods/unnecessary_lazy_eval.rs +++ b/clippy_lints/src/methods/unnecessary_lazy_eval.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{eager_or_lazy, usage}; +use clippy_utils::{eager_or_lazy, is_from_proc_macro, usage}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -18,6 +18,10 @@ pub(super) fn check<'tcx>( arg: &'tcx hir::Expr<'_>, simplify_using: &str, ) { + if is_from_proc_macro(cx, expr) { + return; + } + let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Option); let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result); let is_bool = cx.typeck_results().expr_ty(recv).is_bool(); diff --git a/tests/ui/unnecessary_lazy_eval.fixed b/tests/ui/unnecessary_lazy_eval.fixed index 878537050d42c..ce4a82e021745 100644 --- a/tests/ui/unnecessary_lazy_eval.fixed +++ b/tests/ui/unnecessary_lazy_eval.fixed @@ -1,9 +1,13 @@ // run-rustfix +// aux-build: proc_macro_with_span.rs #![warn(clippy::unnecessary_lazy_evaluations)] #![allow(clippy::redundant_closure)] #![allow(clippy::bind_instead_of_map)] #![allow(clippy::map_identity)] +extern crate proc_macro_with_span; +use proc_macro_with_span::with_span; + struct Deep(Option); #[derive(Copy, Clone)] @@ -141,3 +145,9 @@ fn main() { let _: Result = res.and_then(|x| Err(x)); let _: Result = res.or_else(|err| Ok(err)); } + +#[allow(unused)] +fn issue9485() { + // should not lint, is in proc macro + with_span!(span Some(42).unwrap_or_else(|| 2);); +} diff --git a/tests/ui/unnecessary_lazy_eval.rs b/tests/ui/unnecessary_lazy_eval.rs index f70cf332460e1..59cdf66285463 100644 --- a/tests/ui/unnecessary_lazy_eval.rs +++ b/tests/ui/unnecessary_lazy_eval.rs @@ -1,9 +1,13 @@ // run-rustfix +// aux-build: proc_macro_with_span.rs #![warn(clippy::unnecessary_lazy_evaluations)] #![allow(clippy::redundant_closure)] #![allow(clippy::bind_instead_of_map)] #![allow(clippy::map_identity)] +extern crate proc_macro_with_span; +use proc_macro_with_span::with_span; + struct Deep(Option); #[derive(Copy, Clone)] @@ -141,3 +145,9 @@ fn main() { let _: Result = res.and_then(|x| Err(x)); let _: Result = res.or_else(|err| Ok(err)); } + +#[allow(unused)] +fn issue9485() { + // should not lint, is in proc macro + with_span!(span Some(42).unwrap_or_else(|| 2);); +} diff --git a/tests/ui/unnecessary_lazy_eval.stderr b/tests/ui/unnecessary_lazy_eval.stderr index b46fbf56c4bd1..8a9ece4aa7e54 100644 --- a/tests/ui/unnecessary_lazy_eval.stderr +++ b/tests/ui/unnecessary_lazy_eval.stderr @@ -1,5 +1,5 @@ error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:44:13 + --> $DIR/unnecessary_lazy_eval.rs:48:13 | LL | let _ = opt.unwrap_or_else(|| 2); | ^^^^-------------------- @@ -9,7 +9,7 @@ LL | let _ = opt.unwrap_or_else(|| 2); = note: `-D clippy::unnecessary-lazy-evaluations` implied by `-D warnings` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:45:13 + --> $DIR/unnecessary_lazy_eval.rs:49:13 | LL | let _ = opt.unwrap_or_else(|| astronomers_pi); | ^^^^--------------------------------- @@ -17,7 +17,7 @@ LL | let _ = opt.unwrap_or_else(|| astronomers_pi); | help: use `unwrap_or(..)` instead: `unwrap_or(astronomers_pi)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:46:13 + --> $DIR/unnecessary_lazy_eval.rs:50:13 | LL | let _ = opt.unwrap_or_else(|| ext_str.some_field); | ^^^^------------------------------------- @@ -25,7 +25,7 @@ LL | let _ = opt.unwrap_or_else(|| ext_str.some_field); | help: use `unwrap_or(..)` instead: `unwrap_or(ext_str.some_field)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:48:13 + --> $DIR/unnecessary_lazy_eval.rs:52:13 | LL | let _ = opt.and_then(|_| ext_opt); | ^^^^--------------------- @@ -33,7 +33,7 @@ LL | let _ = opt.and_then(|_| ext_opt); | help: use `and(..)` instead: `and(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:49:13 + --> $DIR/unnecessary_lazy_eval.rs:53:13 | LL | let _ = opt.or_else(|| ext_opt); | ^^^^------------------- @@ -41,7 +41,7 @@ LL | let _ = opt.or_else(|| ext_opt); | help: use `or(..)` instead: `or(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:50:13 + --> $DIR/unnecessary_lazy_eval.rs:54:13 | LL | let _ = opt.or_else(|| None); | ^^^^---------------- @@ -49,7 +49,7 @@ LL | let _ = opt.or_else(|| None); | help: use `or(..)` instead: `or(None)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:51:13 + --> $DIR/unnecessary_lazy_eval.rs:55:13 | LL | let _ = opt.get_or_insert_with(|| 2); | ^^^^------------------------ @@ -57,7 +57,7 @@ LL | let _ = opt.get_or_insert_with(|| 2); | help: use `get_or_insert(..)` instead: `get_or_insert(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:52:13 + --> $DIR/unnecessary_lazy_eval.rs:56:13 | LL | let _ = opt.ok_or_else(|| 2); | ^^^^---------------- @@ -65,7 +65,7 @@ LL | let _ = opt.ok_or_else(|| 2); | help: use `ok_or(..)` instead: `ok_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:53:13 + --> $DIR/unnecessary_lazy_eval.rs:57:13 | LL | let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2))); | ^^^^^^^^^^^^^^^^^------------------------------- @@ -73,7 +73,7 @@ LL | let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2))); | help: use `unwrap_or(..)` instead: `unwrap_or(Some((1, 2)))` error: unnecessary closure used with `bool::then` - --> $DIR/unnecessary_lazy_eval.rs:54:13 + --> $DIR/unnecessary_lazy_eval.rs:58:13 | LL | let _ = cond.then(|| astronomers_pi); | ^^^^^----------------------- @@ -81,7 +81,7 @@ LL | let _ = cond.then(|| astronomers_pi); | help: use `then_some(..)` instead: `then_some(astronomers_pi)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:57:13 + --> $DIR/unnecessary_lazy_eval.rs:61:13 | LL | let _ = Some(10).unwrap_or_else(|| 2); | ^^^^^^^^^-------------------- @@ -89,7 +89,7 @@ LL | let _ = Some(10).unwrap_or_else(|| 2); | help: use `unwrap_or(..)` instead: `unwrap_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:58:13 + --> $DIR/unnecessary_lazy_eval.rs:62:13 | LL | let _ = Some(10).and_then(|_| ext_opt); | ^^^^^^^^^--------------------- @@ -97,7 +97,7 @@ LL | let _ = Some(10).and_then(|_| ext_opt); | help: use `and(..)` instead: `and(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:59:28 + --> $DIR/unnecessary_lazy_eval.rs:63:28 | LL | let _: Option = None.or_else(|| ext_opt); | ^^^^^------------------- @@ -105,7 +105,7 @@ LL | let _: Option = None.or_else(|| ext_opt); | help: use `or(..)` instead: `or(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:60:13 + --> $DIR/unnecessary_lazy_eval.rs:64:13 | LL | let _ = None.get_or_insert_with(|| 2); | ^^^^^------------------------ @@ -113,7 +113,7 @@ LL | let _ = None.get_or_insert_with(|| 2); | help: use `get_or_insert(..)` instead: `get_or_insert(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:61:35 + --> $DIR/unnecessary_lazy_eval.rs:65:35 | LL | let _: Result = None.ok_or_else(|| 2); | ^^^^^---------------- @@ -121,7 +121,7 @@ LL | let _: Result = None.ok_or_else(|| 2); | help: use `ok_or(..)` instead: `ok_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:62:28 + --> $DIR/unnecessary_lazy_eval.rs:66:28 | LL | let _: Option = None.or_else(|| None); | ^^^^^---------------- @@ -129,7 +129,7 @@ LL | let _: Option = None.or_else(|| None); | help: use `or(..)` instead: `or(None)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:65:13 + --> $DIR/unnecessary_lazy_eval.rs:69:13 | LL | let _ = deep.0.unwrap_or_else(|| 2); | ^^^^^^^-------------------- @@ -137,7 +137,7 @@ LL | let _ = deep.0.unwrap_or_else(|| 2); | help: use `unwrap_or(..)` instead: `unwrap_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:66:13 + --> $DIR/unnecessary_lazy_eval.rs:70:13 | LL | let _ = deep.0.and_then(|_| ext_opt); | ^^^^^^^--------------------- @@ -145,7 +145,7 @@ LL | let _ = deep.0.and_then(|_| ext_opt); | help: use `and(..)` instead: `and(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:67:13 + --> $DIR/unnecessary_lazy_eval.rs:71:13 | LL | let _ = deep.0.or_else(|| None); | ^^^^^^^---------------- @@ -153,7 +153,7 @@ LL | let _ = deep.0.or_else(|| None); | help: use `or(..)` instead: `or(None)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:68:13 + --> $DIR/unnecessary_lazy_eval.rs:72:13 | LL | let _ = deep.0.get_or_insert_with(|| 2); | ^^^^^^^------------------------ @@ -161,7 +161,7 @@ LL | let _ = deep.0.get_or_insert_with(|| 2); | help: use `get_or_insert(..)` instead: `get_or_insert(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:69:13 + --> $DIR/unnecessary_lazy_eval.rs:73:13 | LL | let _ = deep.0.ok_or_else(|| 2); | ^^^^^^^---------------- @@ -169,7 +169,7 @@ LL | let _ = deep.0.ok_or_else(|| 2); | help: use `ok_or(..)` instead: `ok_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:92:28 + --> $DIR/unnecessary_lazy_eval.rs:96:28 | LL | let _: Option = None.or_else(|| Some(3)); | ^^^^^------------------- @@ -177,7 +177,7 @@ LL | let _: Option = None.or_else(|| Some(3)); | help: use `or(..)` instead: `or(Some(3))` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:93:13 + --> $DIR/unnecessary_lazy_eval.rs:97:13 | LL | let _ = deep.0.or_else(|| Some(3)); | ^^^^^^^------------------- @@ -185,7 +185,7 @@ LL | let _ = deep.0.or_else(|| Some(3)); | help: use `or(..)` instead: `or(Some(3))` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:94:13 + --> $DIR/unnecessary_lazy_eval.rs:98:13 | LL | let _ = opt.or_else(|| Some(3)); | ^^^^------------------- @@ -193,7 +193,7 @@ LL | let _ = opt.or_else(|| Some(3)); | help: use `or(..)` instead: `or(Some(3))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:100:13 + --> $DIR/unnecessary_lazy_eval.rs:104:13 | LL | let _ = res2.unwrap_or_else(|_| 2); | ^^^^^--------------------- @@ -201,7 +201,7 @@ LL | let _ = res2.unwrap_or_else(|_| 2); | help: use `unwrap_or(..)` instead: `unwrap_or(2)` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:101:13 + --> $DIR/unnecessary_lazy_eval.rs:105:13 | LL | let _ = res2.unwrap_or_else(|_| astronomers_pi); | ^^^^^---------------------------------- @@ -209,7 +209,7 @@ LL | let _ = res2.unwrap_or_else(|_| astronomers_pi); | help: use `unwrap_or(..)` instead: `unwrap_or(astronomers_pi)` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:102:13 + --> $DIR/unnecessary_lazy_eval.rs:106:13 | LL | let _ = res2.unwrap_or_else(|_| ext_str.some_field); | ^^^^^-------------------------------------- @@ -217,7 +217,7 @@ LL | let _ = res2.unwrap_or_else(|_| ext_str.some_field); | help: use `unwrap_or(..)` instead: `unwrap_or(ext_str.some_field)` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:124:35 + --> $DIR/unnecessary_lazy_eval.rs:128:35 | LL | let _: Result = res.and_then(|_| Err(2)); | ^^^^-------------------- @@ -225,7 +225,7 @@ LL | let _: Result = res.and_then(|_| Err(2)); | help: use `and(..)` instead: `and(Err(2))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:125:35 + --> $DIR/unnecessary_lazy_eval.rs:129:35 | LL | let _: Result = res.and_then(|_| Err(astronomers_pi)); | ^^^^--------------------------------- @@ -233,7 +233,7 @@ LL | let _: Result = res.and_then(|_| Err(astronomers_pi)); | help: use `and(..)` instead: `and(Err(astronomers_pi))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:126:35 + --> $DIR/unnecessary_lazy_eval.rs:130:35 | LL | let _: Result = res.and_then(|_| Err(ext_str.some_field)); | ^^^^------------------------------------- @@ -241,7 +241,7 @@ LL | let _: Result = res.and_then(|_| Err(ext_str.some_field)) | help: use `and(..)` instead: `and(Err(ext_str.some_field))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:128:35 + --> $DIR/unnecessary_lazy_eval.rs:132:35 | LL | let _: Result = res.or_else(|_| Ok(2)); | ^^^^------------------ @@ -249,7 +249,7 @@ LL | let _: Result = res.or_else(|_| Ok(2)); | help: use `or(..)` instead: `or(Ok(2))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:129:35 + --> $DIR/unnecessary_lazy_eval.rs:133:35 | LL | let _: Result = res.or_else(|_| Ok(astronomers_pi)); | ^^^^------------------------------- @@ -257,7 +257,7 @@ LL | let _: Result = res.or_else(|_| Ok(astronomers_pi)); | help: use `or(..)` instead: `or(Ok(astronomers_pi))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:130:35 + --> $DIR/unnecessary_lazy_eval.rs:134:35 | LL | let _: Result = res.or_else(|_| Ok(ext_str.some_field)); | ^^^^----------------------------------- @@ -265,7 +265,7 @@ LL | let _: Result = res.or_else(|_| Ok(ext_str.some_field)); | help: use `or(..)` instead: `or(Ok(ext_str.some_field))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:131:35 + --> $DIR/unnecessary_lazy_eval.rs:135:35 | LL | let _: Result = res. | ___________________________________^ From 416da1264c48aa38c6ae8c6f6aefffa49ae3b21f Mon Sep 17 00:00:00 2001 From: Evan Typanski Date: Thu, 29 Sep 2022 19:31:32 -0400 Subject: [PATCH 071/114] [`redundant_closure`] Add `&mut` to more cases --- clippy_lints/src/eta_reduction.rs | 14 +++++--------- tests/ui/eta.fixed | 11 +++++++++++ tests/ui/eta.rs | 11 +++++++++++ tests/ui/eta.stderr | 14 +++++++++++++- 4 files changed, 40 insertions(+), 10 deletions(-) diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index 710fceceae57d..a5c6512a5e7d2 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::higher::VecArgs; use clippy_utils::source::snippet_opt; -use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use clippy_utils::usage::local_used_after_expr; use clippy_utils::{higher, is_adjusted, path_to_local, path_to_local_id}; use if_chain::if_chain; @@ -11,7 +11,7 @@ use rustc_hir::{Closure, Expr, ExprKind, Param, PatKind, Unsafety}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; use rustc_middle::ty::binding::BindingMode; -use rustc_middle::ty::{self, ClosureKind, Ty, TypeVisitable}; +use rustc_middle::ty::{self, Ty, TypeVisitable}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::sym; @@ -122,15 +122,11 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction { then { span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure", |diag| { if let Some(mut snippet) = snippet_opt(cx, callee.span) { - if_chain! { - if let ty::Closure(_, substs) = callee_ty.peel_refs().kind(); - if substs.as_closure().kind() == ClosureKind::FnMut; - if path_to_local(callee).map_or(false, |l| local_used_after_expr(cx, l, expr)); - - then { + if let Some(fn_mut_id) = cx.tcx.lang_items().fn_mut_trait() && + implements_trait(cx, callee_ty.peel_refs(), fn_mut_id, &[]) && + path_to_local(callee).map_or(false, |l| local_used_after_expr(cx, l, expr)) { // Mutable closure is used after current expr; we cannot consume it. snippet = format!("&mut {snippet}"); - } } diag.span_suggestion( expr.span, diff --git a/tests/ui/eta.fixed b/tests/ui/eta.fixed index f8d559bf226f1..112bb4b4817ae 100644 --- a/tests/ui/eta.fixed +++ b/tests/ui/eta.fixed @@ -303,3 +303,14 @@ fn not_general_enough() { fn f(_: impl FnMut(&Path) -> std::io::Result<()>) {} f(|path| std::fs::remove_file(path)); } + +// https://github.com/rust-lang/rust-clippy/issues/9369 +pub fn mutable_impl_fn_mut(mut f: impl FnMut()) { + fn takes_fn_mut(_: impl FnMut()) {} + takes_fn_mut(&mut f); + + fn takes_fn_once(_: impl FnOnce()) {} + takes_fn_once(&mut f); + + f(); +} diff --git a/tests/ui/eta.rs b/tests/ui/eta.rs index f0fb55a1e5f06..970144e06ddfa 100644 --- a/tests/ui/eta.rs +++ b/tests/ui/eta.rs @@ -303,3 +303,14 @@ fn not_general_enough() { fn f(_: impl FnMut(&Path) -> std::io::Result<()>) {} f(|path| std::fs::remove_file(path)); } + +// https://github.com/rust-lang/rust-clippy/issues/9369 +pub fn mutable_impl_fn_mut(mut f: impl FnMut()) { + fn takes_fn_mut(_: impl FnMut()) {} + takes_fn_mut(|| f()); + + fn takes_fn_once(_: impl FnOnce()) {} + takes_fn_once(|| f()); + + f(); +} diff --git a/tests/ui/eta.stderr b/tests/ui/eta.stderr index bf2e97e744ab3..f7ead7257f6a6 100644 --- a/tests/ui/eta.stderr +++ b/tests/ui/eta.stderr @@ -116,5 +116,17 @@ error: redundant closure LL | Some(1).map(|n| in_loop(n)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `in_loop` -error: aborting due to 19 previous errors +error: redundant closure + --> $DIR/eta.rs:310:18 + | +LL | takes_fn_mut(|| f()); + | ^^^^^^ help: replace the closure with the function itself: `&mut f` + +error: redundant closure + --> $DIR/eta.rs:313:19 + | +LL | takes_fn_once(|| f()); + | ^^^^^^ help: replace the closure with the function itself: `&mut f` + +error: aborting due to 21 previous errors From 47a7d68c0772840e4436290a3303af2eeb1b9c76 Mon Sep 17 00:00:00 2001 From: xxchan Date: Fri, 30 Sep 2022 13:34:21 +0200 Subject: [PATCH 072/114] doc: make the usage of clippy.toml more clear --- README.md | 46 +++++++++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 1193771ff736b..a8a6b86d2a15b 100644 --- a/README.md +++ b/README.md @@ -139,25 +139,6 @@ line. (You can swap `clippy::all` with the specific lint category you are target ## Configuration -Some lints can be configured in a TOML file named `clippy.toml` or `.clippy.toml`. It contains a basic `variable = -value` mapping e.g. - -```toml -avoid-breaking-exported-api = false -disallowed-names = ["toto", "tata", "titi"] -cognitive-complexity-threshold = 30 -``` - -See the [list of lints](https://rust-lang.github.io/rust-clippy/master/index.html) for more information about which -lints can be configured and the meaning of the variables. - -Note that configuration changes will not apply for code that has already been compiled and cached under `./target/`; -for example, adding a new string to `doc-valid-idents` may still result in Clippy flagging that string. To be sure that -any configuration changes are applied, you may want to run `cargo clean` and re-compile your crate from scratch. - -To deactivate the “for further information visit *lint-link*” message you can -define the `CLIPPY_DISABLE_DOCS_LINKS` environment variable. - ### Allowing/denying lints You can add options to your code to `allow`/`warn`/`deny` Clippy lints: @@ -205,6 +186,33 @@ the lint(s) you are interested in: cargo clippy -- -A clippy::all -W clippy::useless_format -W clippy::... ``` +### Configure the behavior of some lints + +Some lints can be configured in a TOML file named `clippy.toml` or `.clippy.toml`. It contains a basic `variable = +value` mapping e.g. + +```toml +avoid-breaking-exported-api = false +disallowed-names = ["toto", "tata", "titi"] +cognitive-complexity-threshold = 30 +``` + +See the [list of lints](https://rust-lang.github.io/rust-clippy/master/index.html) for more information about which +lints can be configured and the meaning of the variables. + +> **Note** +> +> `clippy.toml` or `.clippy.toml` cannot be used to allow/deny lints. + +> **Note** +> +> Configuration changes will not apply for code that has already been compiled and cached under `./target/`; +> for example, adding a new string to `doc-valid-idents` may still result in Clippy flagging that string. To be sure +> that any configuration changes are applied, you may want to run `cargo clean` and re-compile your crate from scratch. + +To deactivate the “for further information visit *lint-link*” message you can +define the `CLIPPY_DISABLE_DOCS_LINKS` environment variable. + ### Specifying the minimum supported Rust version Projects that intend to support old versions of Rust can disable lints pertaining to newer features by From 85b8ff7f38149caefd60fd79dc156dc3d18c3c7c Mon Sep 17 00:00:00 2001 From: Evan Typanski Date: Fri, 30 Sep 2022 11:36:55 -0400 Subject: [PATCH 073/114] Fix style in `if let` chain Co-authored-by: Alex Macleod --- clippy_lints/src/eta_reduction.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index a5c6512a5e7d2..3732410e71e57 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -122,9 +122,10 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction { then { span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure", |diag| { if let Some(mut snippet) = snippet_opt(cx, callee.span) { - if let Some(fn_mut_id) = cx.tcx.lang_items().fn_mut_trait() && - implements_trait(cx, callee_ty.peel_refs(), fn_mut_id, &[]) && - path_to_local(callee).map_or(false, |l| local_used_after_expr(cx, l, expr)) { + if let Some(fn_mut_id) = cx.tcx.lang_items().fn_mut_trait() + && implements_trait(cx, callee_ty.peel_refs(), fn_mut_id, &[]) + && path_to_local(callee).map_or(false, |l| local_used_after_expr(cx, l, expr)) + { // Mutable closure is used after current expr; we cannot consume it. snippet = format!("&mut {snippet}"); } From dbadf37336825faae9c14814eace50468da06b48 Mon Sep 17 00:00:00 2001 From: Evan Typanski Date: Fri, 30 Sep 2022 11:37:50 -0400 Subject: [PATCH 074/114] Add test case where `FnMut` used once needs `&mut` --- tests/ui/eta.fixed | 4 +++- tests/ui/eta.rs | 4 +++- tests/ui/eta.stderr | 8 +++++++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/tests/ui/eta.fixed b/tests/ui/eta.fixed index 112bb4b4817ae..e257b3b3afa6f 100644 --- a/tests/ui/eta.fixed +++ b/tests/ui/eta.fixed @@ -305,7 +305,7 @@ fn not_general_enough() { } // https://github.com/rust-lang/rust-clippy/issues/9369 -pub fn mutable_impl_fn_mut(mut f: impl FnMut()) { +pub fn mutable_impl_fn_mut(mut f: impl FnMut(), mut f_used_once: impl FnMut()) -> impl FnMut() { fn takes_fn_mut(_: impl FnMut()) {} takes_fn_mut(&mut f); @@ -313,4 +313,6 @@ pub fn mutable_impl_fn_mut(mut f: impl FnMut()) { takes_fn_once(&mut f); f(); + + move || takes_fn_mut(&mut f_used_once) } diff --git a/tests/ui/eta.rs b/tests/ui/eta.rs index 970144e06ddfa..486a251f30b0e 100644 --- a/tests/ui/eta.rs +++ b/tests/ui/eta.rs @@ -305,7 +305,7 @@ fn not_general_enough() { } // https://github.com/rust-lang/rust-clippy/issues/9369 -pub fn mutable_impl_fn_mut(mut f: impl FnMut()) { +pub fn mutable_impl_fn_mut(mut f: impl FnMut(), mut f_used_once: impl FnMut()) -> impl FnMut() { fn takes_fn_mut(_: impl FnMut()) {} takes_fn_mut(|| f()); @@ -313,4 +313,6 @@ pub fn mutable_impl_fn_mut(mut f: impl FnMut()) { takes_fn_once(|| f()); f(); + + move || takes_fn_mut(|| f_used_once()) } diff --git a/tests/ui/eta.stderr b/tests/ui/eta.stderr index f7ead7257f6a6..434706b7e258f 100644 --- a/tests/ui/eta.stderr +++ b/tests/ui/eta.stderr @@ -128,5 +128,11 @@ error: redundant closure LL | takes_fn_once(|| f()); | ^^^^^^ help: replace the closure with the function itself: `&mut f` -error: aborting due to 21 previous errors +error: redundant closure + --> $DIR/eta.rs:317:26 + | +LL | move || takes_fn_mut(|| f_used_once()) + | ^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut f_used_once` + +error: aborting due to 22 previous errors From 4876882b29a1535779593d321fcb886a0c26c594 Mon Sep 17 00:00:00 2001 From: Caio Date: Fri, 30 Sep 2022 15:30:40 -0300 Subject: [PATCH 075/114] Fix #9544 --- .../src/operators/arithmetic_side_effects.rs | 37 ++-- tests/ui/arithmetic_side_effects.rs | 53 ++++- tests/ui/arithmetic_side_effects.stderr | 202 +++++++++++++++--- 3 files changed, 243 insertions(+), 49 deletions(-) diff --git a/clippy_lints/src/operators/arithmetic_side_effects.rs b/clippy_lints/src/operators/arithmetic_side_effects.rs index c8a374d90b559..d871b72db8f42 100644 --- a/clippy_lints/src/operators/arithmetic_side_effects.rs +++ b/clippy_lints/src/operators/arithmetic_side_effects.rs @@ -16,8 +16,9 @@ const HARD_CODED_ALLOWED: &[&str] = &[ "f32", "f64", "std::num::Saturating", - "std::string::String", "std::num::Wrapping", + "std::string::String", + "&str", ]; #[derive(Debug)] @@ -77,6 +78,11 @@ impl ArithmeticSideEffects { ) } + // For example, 8i32 or &i64::MAX. + fn is_integral<'expr, 'tcx>(cx: &LateContext<'tcx>, expr: &'expr hir::Expr<'tcx>) -> bool { + cx.typeck_results().expr_ty(expr).peel_refs().is_integral() + } + // Common entry-point to avoid code duplication. fn issue_lint(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) { let msg = "arithmetic operation that can potentially result in unexpected side-effects"; @@ -88,24 +94,13 @@ impl ArithmeticSideEffects { /// * Is `expr` is a literal integer reference like `&199`, returns the literal integer without /// references. /// * If `expr` is anything else, returns `None`. - fn literal_integer<'expr, 'tcx>( - cx: &LateContext<'tcx>, - expr: &'expr hir::Expr<'tcx>, - ) -> Option<&'expr hir::Expr<'tcx>> { - let expr_refs = cx.typeck_results().expr_ty(expr).peel_refs(); - - if !expr_refs.is_integral() { - return None; - } - + fn literal_integer<'expr, 'tcx>(expr: &'expr hir::Expr<'tcx>) -> Option<&'expr hir::Expr<'tcx>> { if matches!(expr.kind, hir::ExprKind::Lit(_)) { return Some(expr); } - if let hir::ExprKind::AddrOf(.., inn) = expr.kind && let hir::ExprKind::Lit(_) = inn.kind { return Some(inn) } - None } @@ -134,14 +129,18 @@ impl ArithmeticSideEffects { ) { return; }; - if self.is_allowed_ty(cx, lhs) || self.is_allowed_ty(cx, rhs) { + if self.is_allowed_ty(cx, lhs) && self.is_allowed_ty(cx, rhs) { return; } - let has_valid_op = match (Self::literal_integer(cx, lhs), Self::literal_integer(cx, rhs)) { - (None, None) => false, - (None, Some(local_expr)) => Self::has_valid_op(op, local_expr), - (Some(local_expr), None) => Self::has_valid_op(op, local_expr), - (Some(_), Some(_)) => true, + let has_valid_op = if Self::is_integral(cx, lhs) && Self::is_integral(cx, rhs) { + match (Self::literal_integer(lhs), Self::literal_integer(rhs)) { + (None, None) => false, + (None, Some(local_expr)) => Self::has_valid_op(op, local_expr), + (Some(local_expr), None) => Self::has_valid_op(op, local_expr), + (Some(_), Some(_)) => true, + } + } else { + false }; if !has_valid_op { self.issue_lint(cx, expr); diff --git a/tests/ui/arithmetic_side_effects.rs b/tests/ui/arithmetic_side_effects.rs index 6741e1485472c..c9c0f8be65336 100644 --- a/tests/ui/arithmetic_side_effects.rs +++ b/tests/ui/arithmetic_side_effects.rs @@ -12,6 +12,31 @@ use core::num::{Saturating, Wrapping}; +pub struct Custom; + +macro_rules! impl_arith { + ( $( $_trait:ident, $ty:ty, $method:ident; )* ) => { + $( + impl core::ops::$_trait<$ty> for Custom { + type Output = Self; + fn $method(self, _: $ty) -> Self::Output { Self } + } + )* + } +} + +impl_arith!( + Add, i32, add; + Div, i32, div; + Mul, i32, mul; + Sub, i32, sub; + + Add, f64, add; + Div, f64, div; + Mul, f64, mul; + Sub, f64, sub; +); + pub fn association_with_structures_should_not_trigger_the_lint() { enum Foo { Bar = -2, @@ -130,7 +155,7 @@ pub fn non_overflowing_ops_or_ops_already_handled_by_the_compiler_should_not_tri _n = -(-1); } -pub fn overflowing_runtime_ops() { +pub fn runtime_ops() { let mut _n = i32::MAX; // Assign @@ -163,6 +188,32 @@ pub fn overflowing_runtime_ops() { _n = 2 * _n; _n = &2 * _n; + // Custom + let _ = Custom + 0; + let _ = Custom + 1; + let _ = Custom + 2; + let _ = Custom + 0.0; + let _ = Custom + 1.0; + let _ = Custom + 2.0; + let _ = Custom - 0; + let _ = Custom - 1; + let _ = Custom - 2; + let _ = Custom - 0.0; + let _ = Custom - 1.0; + let _ = Custom - 2.0; + let _ = Custom / 0; + let _ = Custom / 1; + let _ = Custom / 2; + let _ = Custom / 0.0; + let _ = Custom / 1.0; + let _ = Custom / 2.0; + let _ = Custom * 0; + let _ = Custom * 1; + let _ = Custom * 2; + let _ = Custom * 0.0; + let _ = Custom * 1.0; + let _ = Custom * 2.0; + // Unary _n = -_n; _n = -&_n; diff --git a/tests/ui/arithmetic_side_effects.stderr b/tests/ui/arithmetic_side_effects.stderr index 4dce13b624b4a..7870c942e7dfc 100644 --- a/tests/ui/arithmetic_side_effects.stderr +++ b/tests/ui/arithmetic_side_effects.stderr @@ -1,5 +1,5 @@ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:137:5 + --> $DIR/arithmetic_side_effects.rs:162:5 | LL | _n += 1; | ^^^^^^^ @@ -7,166 +7,310 @@ LL | _n += 1; = note: `-D clippy::arithmetic-side-effects` implied by `-D warnings` error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:138:5 + --> $DIR/arithmetic_side_effects.rs:163:5 | LL | _n += &1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:139:5 + --> $DIR/arithmetic_side_effects.rs:164:5 | LL | _n -= 1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:140:5 + --> $DIR/arithmetic_side_effects.rs:165:5 | LL | _n -= &1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:141:5 + --> $DIR/arithmetic_side_effects.rs:166:5 | LL | _n /= 0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:142:5 + --> $DIR/arithmetic_side_effects.rs:167:5 | LL | _n /= &0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:143:5 + --> $DIR/arithmetic_side_effects.rs:168:5 | LL | _n %= 0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:144:5 + --> $DIR/arithmetic_side_effects.rs:169:5 | LL | _n %= &0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:145:5 + --> $DIR/arithmetic_side_effects.rs:170:5 | LL | _n *= 2; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:146:5 + --> $DIR/arithmetic_side_effects.rs:171:5 | LL | _n *= &2; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:149:10 + --> $DIR/arithmetic_side_effects.rs:174:10 | LL | _n = _n + 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:150:10 + --> $DIR/arithmetic_side_effects.rs:175:10 | LL | _n = _n + &1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:151:10 + --> $DIR/arithmetic_side_effects.rs:176:10 | LL | _n = 1 + _n; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:152:10 + --> $DIR/arithmetic_side_effects.rs:177:10 | LL | _n = &1 + _n; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:153:10 + --> $DIR/arithmetic_side_effects.rs:178:10 | LL | _n = _n - 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:154:10 + --> $DIR/arithmetic_side_effects.rs:179:10 | LL | _n = _n - &1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:155:10 + --> $DIR/arithmetic_side_effects.rs:180:10 | LL | _n = 1 - _n; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:156:10 + --> $DIR/arithmetic_side_effects.rs:181:10 | LL | _n = &1 - _n; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:157:10 + --> $DIR/arithmetic_side_effects.rs:182:10 | LL | _n = _n / 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:158:10 + --> $DIR/arithmetic_side_effects.rs:183:10 | LL | _n = _n / &0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:159:10 + --> $DIR/arithmetic_side_effects.rs:184:10 | LL | _n = _n % 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:160:10 + --> $DIR/arithmetic_side_effects.rs:185:10 | LL | _n = _n % &0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:161:10 + --> $DIR/arithmetic_side_effects.rs:186:10 | LL | _n = _n * 2; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:162:10 + --> $DIR/arithmetic_side_effects.rs:187:10 | LL | _n = _n * &2; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:163:10 + --> $DIR/arithmetic_side_effects.rs:188:10 | LL | _n = 2 * _n; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:164:10 + --> $DIR/arithmetic_side_effects.rs:189:10 | LL | _n = &2 * _n; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:167:10 + --> $DIR/arithmetic_side_effects.rs:192:13 + | +LL | let _ = Custom + 0; + | ^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:193:13 + | +LL | let _ = Custom + 1; + | ^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:194:13 + | +LL | let _ = Custom + 2; + | ^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:195:13 + | +LL | let _ = Custom + 0.0; + | ^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:196:13 + | +LL | let _ = Custom + 1.0; + | ^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:197:13 + | +LL | let _ = Custom + 2.0; + | ^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:198:13 + | +LL | let _ = Custom - 0; + | ^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:199:13 + | +LL | let _ = Custom - 1; + | ^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:200:13 + | +LL | let _ = Custom - 2; + | ^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:201:13 + | +LL | let _ = Custom - 0.0; + | ^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:202:13 + | +LL | let _ = Custom - 1.0; + | ^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:203:13 + | +LL | let _ = Custom - 2.0; + | ^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:204:13 + | +LL | let _ = Custom / 0; + | ^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:205:13 + | +LL | let _ = Custom / 1; + | ^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:206:13 + | +LL | let _ = Custom / 2; + | ^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:207:13 + | +LL | let _ = Custom / 0.0; + | ^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:208:13 + | +LL | let _ = Custom / 1.0; + | ^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:209:13 + | +LL | let _ = Custom / 2.0; + | ^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:210:13 + | +LL | let _ = Custom * 0; + | ^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:211:13 + | +LL | let _ = Custom * 1; + | ^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:212:13 + | +LL | let _ = Custom * 2; + | ^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:213:13 + | +LL | let _ = Custom * 0.0; + | ^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:214:13 + | +LL | let _ = Custom * 1.0; + | ^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:215:13 + | +LL | let _ = Custom * 2.0; + | ^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:218:10 | LL | _n = -_n; | ^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:168:10 + --> $DIR/arithmetic_side_effects.rs:219:10 | LL | _n = -&_n; | ^^^^ -error: aborting due to 28 previous errors +error: aborting due to 52 previous errors From 0867c64a542822ed40c002ea4ba937dea92d2e1e Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Fri, 16 Sep 2022 19:07:01 +0400 Subject: [PATCH 076/114] clippy: adopt to the new lint API --- clippy_lints/src/module_style.rs | 19 +++++++------ clippy_utils/src/diagnostics.rs | 46 ++++++++++++++------------------ 2 files changed, 29 insertions(+), 36 deletions(-) diff --git a/clippy_lints/src/module_style.rs b/clippy_lints/src/module_style.rs index 22071ab3044f4..102b9fbae83c5 100644 --- a/clippy_lints/src/module_style.rs +++ b/clippy_lints/src/module_style.rs @@ -117,11 +117,13 @@ impl EarlyLintPass for ModStyle { cx.struct_span_lint( SELF_NAMED_MODULE_FILES, Span::new(file.start_pos, file.start_pos, SyntaxContext::root(), None), - |build| { - let mut lint = - build.build(&format!("`mod.rs` files are required, found `{}`", path.display())); - lint.help(&format!("move `{}` to `{}`", path.display(), correct.display(),)); - lint.emit(); + format!("`mod.rs` files are required, found `{}`", path.display()), + |lint| { + lint.help(format!( + "move `{}` to `{}`", + path.display(), + correct.display(), + )) }, ); } @@ -156,11 +158,8 @@ fn check_self_named_mod_exists(cx: &EarlyContext<'_>, path: &Path, file: &Source cx.struct_span_lint( MOD_MODULE_FILES, Span::new(file.start_pos, file.start_pos, SyntaxContext::root(), None), - |build| { - let mut lint = build.build(&format!("`mod.rs` files are not allowed, found `{}`", path.display())); - lint.help(&format!("move `{}` to `{}`", path.display(), mod_file.display(),)); - lint.emit(); - }, + format!("`mod.rs` files are not allowed, found `{}`", path.display()), + |lint| lint.help(format!("move `{}` to `{}`", path.display(), mod_file.display())), ); } } diff --git a/clippy_utils/src/diagnostics.rs b/clippy_utils/src/diagnostics.rs index ad95369b9ef70..78960d1ab1da5 100644 --- a/clippy_utils/src/diagnostics.rs +++ b/clippy_utils/src/diagnostics.rs @@ -47,10 +47,9 @@ fn docs_link(diag: &mut Diagnostic, lint: &'static Lint) { /// | ^^^^^^^^^^^^^^^^^^^^^^^ /// ``` pub fn span_lint(cx: &T, lint: &'static Lint, sp: impl Into, msg: &str) { - cx.struct_span_lint(lint, sp, |diag| { - let mut diag = diag.build(msg); - docs_link(&mut diag, lint); - diag.emit(); + cx.struct_span_lint(lint, sp, msg, |diag| { + docs_link(diag, lint); + diag }); } @@ -82,15 +81,14 @@ pub fn span_lint_and_help<'a, T: LintContext>( help_span: Option, help: &str, ) { - cx.struct_span_lint(lint, span, |diag| { - let mut diag = diag.build(msg); + cx.struct_span_lint(lint, span, msg, |diag| { if let Some(help_span) = help_span { diag.span_help(help_span, help); } else { diag.help(help); } - docs_link(&mut diag, lint); - diag.emit(); + docs_link(diag, lint); + diag }); } @@ -125,15 +123,14 @@ pub fn span_lint_and_note<'a, T: LintContext>( note_span: Option, note: &str, ) { - cx.struct_span_lint(lint, span, |diag| { - let mut diag = diag.build(msg); + cx.struct_span_lint(lint, span, msg, |diag| { if let Some(note_span) = note_span { diag.span_note(note_span, note); } else { diag.note(note); } - docs_link(&mut diag, lint); - diag.emit(); + docs_link(diag, lint); + diag }); } @@ -147,19 +144,17 @@ where S: Into, F: FnOnce(&mut Diagnostic), { - cx.struct_span_lint(lint, sp, |diag| { - let mut diag = diag.build(msg); - f(&mut diag); - docs_link(&mut diag, lint); - diag.emit(); + cx.struct_span_lint(lint, sp, msg, |diag| { + f(diag); + docs_link(diag, lint); + diag }); } pub fn span_lint_hir(cx: &LateContext<'_>, lint: &'static Lint, hir_id: HirId, sp: Span, msg: &str) { - cx.tcx.struct_span_lint_hir(lint, hir_id, sp, |diag| { - let mut diag = diag.build(msg); - docs_link(&mut diag, lint); - diag.emit(); + cx.tcx.struct_span_lint_hir(lint, hir_id, sp, msg, |diag| { + docs_link(diag, lint); + diag }); } @@ -171,11 +166,10 @@ pub fn span_lint_hir_and_then( msg: &str, f: impl FnOnce(&mut Diagnostic), ) { - cx.tcx.struct_span_lint_hir(lint, hir_id, sp, |diag| { - let mut diag = diag.build(msg); - f(&mut diag); - docs_link(&mut diag, lint); - diag.emit(); + cx.tcx.struct_span_lint_hir(lint, hir_id, sp, msg, |diag| { + f(diag); + docs_link(diag, lint); + diag }); } From 8dfbad9e498f6067ce82d9068ceb376005ea644c Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Thu, 22 Sep 2022 20:04:22 +0400 Subject: [PATCH 077/114] bless clippy --- .../await_holding_invalid_type.stderr | 2 +- .../conf_deprecated_key/conf_deprecated_key.stderr | 2 +- tests/ui-toml/expect_used/expect_used.stderr | 2 +- tests/ui-toml/fn_params_excessive_bools/test.stderr | 2 +- .../large_include_file/large_include_file.stderr | 2 +- .../conf_nonstandard_macro_braces.stderr | 2 +- .../strict_non_send_fields_in_send_ty/test.stderr | 2 +- tests/ui-toml/struct_excessive_bools/test.stderr | 2 +- tests/ui-toml/unwrap_used/unwrap_used.stderr | 2 +- tests/ui/absurd-extreme-comparisons.stderr | 2 +- tests/ui/allow_attributes_without_reason.stderr | 2 +- tests/ui/approx_const.stderr | 2 +- tests/ui/as_conversions.stderr | 2 +- tests/ui/asm_syntax.stderr | 4 ++-- tests/ui/assertions_on_constants.stderr | 2 +- tests/ui/await_holding_lock.stderr | 2 +- tests/ui/await_holding_refcell_ref.stderr | 2 +- tests/ui/blanket_clippy_restriction_lints.stderr | 2 +- tests/ui/bool_to_int_with_if.stderr | 2 +- tests/ui/borrow_interior_mutable_const/enums.stderr | 2 +- tests/ui/borrow_interior_mutable_const/others.stderr | 2 +- tests/ui/borrow_interior_mutable_const/traits.stderr | 2 +- tests/ui/box_collection.stderr | 2 +- tests/ui/branches_sharing_code/shared_at_bottom.stderr | 2 +- tests/ui/branches_sharing_code/shared_at_top.stderr | 10 +++++----- .../shared_at_top_and_bottom.stderr | 10 +++++----- tests/ui/branches_sharing_code/valid_if_blocks.stderr | 10 +++++----- .../case_sensitive_file_extension_comparisons.stderr | 2 +- tests/ui/char_lit_as_u8.stderr | 2 +- tests/ui/char_lit_as_u8_suggestions.stderr | 2 +- tests/ui/checked_unwrap/complex_conditionals.stderr | 2 +- tests/ui/cognitive_complexity.stderr | 2 +- tests/ui/cognitive_complexity_attr_used.stderr | 2 +- tests/ui/collapsible_match.stderr | 2 +- tests/ui/collapsible_match2.stderr | 2 +- tests/ui/comparison_chain.stderr | 2 +- tests/ui/copy_iterator.stderr | 2 +- tests/ui/crashes/ice-360.stderr | 2 +- tests/ui/crashes/ice-6254.stderr | 2 +- tests/ui/crashes/ice-7868.stderr | 2 +- tests/ui/crashes/ice-7869.stderr | 2 +- tests/ui/crashes/ice-9463.stderr | 2 +- .../ui/crate_level_checks/entrypoint_recursion.stderr | 2 +- tests/ui/crate_level_checks/no_std_swap.stderr | 2 +- tests/ui/crate_level_checks/std_main_recursion.stderr | 2 +- tests/ui/def_id_nocore.stderr | 2 +- tests/ui/default_union_representation.stderr | 2 +- tests/ui/derive.stderr | 2 +- tests/ui/derive_hash_xor_eq.stderr | 2 +- tests/ui/derive_ord_xor_partial_ord.stderr | 2 +- tests/ui/doc/unbalanced_ticks.stderr | 2 +- tests/ui/double_must_use.stderr | 2 +- tests/ui/drop_forget_copy.stderr | 4 ++-- tests/ui/drop_non_drop.stderr | 2 +- tests/ui/drop_ref.stderr | 2 +- tests/ui/else_if_without_else.stderr | 2 +- tests/ui/empty_enum.stderr | 2 +- tests/ui/empty_loop.stderr | 2 +- tests/ui/empty_loop_no_std.stderr | 2 +- tests/ui/expect.stderr | 2 +- tests/ui/fallible_impl_from.stderr | 10 +++++----- tests/ui/field_reassign_with_default.stderr | 2 +- tests/ui/filetype_is_file.stderr | 2 +- tests/ui/float_cmp.stderr | 2 +- tests/ui/float_cmp_const.stderr | 2 +- tests/ui/fn_params_excessive_bools.stderr | 2 +- tests/ui/for_loops_over_fallibles.stderr | 2 +- tests/ui/forget_non_drop.stderr | 2 +- tests/ui/forget_ref.stderr | 2 +- tests/ui/format_args_unfixable.stderr | 2 +- tests/ui/format_push_string.stderr | 2 +- tests/ui/formatting.stderr | 4 ++-- tests/ui/from_over_into.stderr | 2 +- tests/ui/future_not_send.stderr | 2 +- tests/ui/get_unwrap.stderr | 2 +- tests/ui/if_let_mutex.stderr | 2 +- tests/ui/if_not_else.stderr | 2 +- tests/ui/if_same_then_else.stderr | 2 +- tests/ui/if_same_then_else2.stderr | 2 +- tests/ui/if_then_some_else_none.stderr | 2 +- tests/ui/ifs_same_cond.stderr | 2 +- tests/ui/impl.stderr | 2 +- tests/ui/indexing_slicing_index.stderr | 2 +- tests/ui/indexing_slicing_slice.stderr | 2 +- tests/ui/inefficient_to_string.stderr | 2 +- tests/ui/infinite_loop.stderr | 2 +- tests/ui/inherent_to_string.stderr | 4 ++-- tests/ui/inspect_for_each.stderr | 2 +- tests/ui/integer_division.stderr | 2 +- tests/ui/issue_4266.stderr | 2 +- tests/ui/iter_nth.stderr | 2 +- tests/ui/iter_skip_next_unfixable.stderr | 2 +- tests/ui/large_stack_arrays.stderr | 2 +- tests/ui/len_without_is_empty.stderr | 2 +- tests/ui/let_if_seq.stderr | 2 +- tests/ui/let_underscore_drop.stderr | 2 +- tests/ui/let_underscore_lock.stderr | 2 +- tests/ui/let_underscore_must_use.stderr | 2 +- tests/ui/linkedlist.stderr | 2 +- tests/ui/manual_find.stderr | 2 +- tests/ui/manual_flatten.stderr | 2 +- tests/ui/manual_non_exhaustive_enum.stderr | 2 +- tests/ui/manual_non_exhaustive_struct.stderr | 2 +- tests/ui/manual_strip.stderr | 2 +- tests/ui/map_err.stderr | 2 +- tests/ui/match_overlapping_arm.stderr | 2 +- tests/ui/match_same_arms.stderr | 2 +- tests/ui/match_same_arms2.stderr | 2 +- tests/ui/match_wild_err_arm.edition2018.stderr | 2 +- tests/ui/match_wild_err_arm.edition2021.stderr | 2 +- tests/ui/min_rust_version_attr.stderr | 2 +- tests/ui/mismatched_target_os_unix.stderr | 2 +- tests/ui/mismatching_type_param_order.stderr | 2 +- tests/ui/missing_panics_doc.stderr | 2 +- tests/ui/mixed_read_write_in_expression.stderr | 2 +- tests/ui/modulo_arithmetic_float.stderr | 2 +- tests/ui/modulo_arithmetic_integral.stderr | 2 +- tests/ui/modulo_arithmetic_integral_const.stderr | 2 +- tests/ui/mut_from_ref.stderr | 2 +- tests/ui/mut_range_bound.stderr | 2 +- tests/ui/needless_continue.stderr | 2 +- tests/ui/non_send_fields_in_send_ty.stderr | 2 +- tests/ui/octal_escapes.stderr | 2 +- tests/ui/ok_expect.stderr | 2 +- tests/ui/only_used_in_recursion.stderr | 2 +- tests/ui/only_used_in_recursion2.stderr | 2 +- tests/ui/option_env_unwrap.stderr | 2 +- tests/ui/overly_complex_bool_expr.stderr | 2 +- tests/ui/panic_in_result_fn.stderr | 2 +- tests/ui/panic_in_result_fn_assertions.stderr | 2 +- tests/ui/pattern_type_mismatch/mutability.stderr | 2 +- .../pattern_type_mismatch/pattern_alternatives.stderr | 2 +- tests/ui/pattern_type_mismatch/pattern_structs.stderr | 2 +- tests/ui/pattern_type_mismatch/pattern_tuples.stderr | 2 +- tests/ui/pattern_type_mismatch/syntax.stderr | 2 +- tests/ui/proc_macro.stderr | 2 +- tests/ui/pub_use.stderr | 2 +- tests/ui/rc_clone_in_vec_init/arc.stderr | 2 +- tests/ui/rc_clone_in_vec_init/rc.stderr | 2 +- tests/ui/rc_clone_in_vec_init/weak.stderr | 2 +- tests/ui/rc_mutex.stderr | 2 +- tests/ui/redundant_allocation.stderr | 2 +- tests/ui/redundant_allocation_fixable.stderr | 2 +- tests/ui/redundant_clone.stderr | 2 +- tests/ui/redundant_else.stderr | 2 +- tests/ui/redundant_pattern_matching_drop_order.stderr | 2 +- tests/ui/regex.stderr | 2 +- tests/ui/rest_pat_in_fully_bound_structs.stderr | 2 +- tests/ui/result_large_err.stderr | 2 +- tests/ui/result_unit_error.stderr | 2 +- tests/ui/return_self_not_must_use.stderr | 2 +- tests/ui/same_functions_in_if_condition.stderr | 2 +- tests/ui/same_item_push.stderr | 2 +- tests/ui/same_name_method.stderr | 2 +- tests/ui/search_is_some.stderr | 2 +- tests/ui/shadow.stderr | 6 +++--- tests/ui/should_impl_trait/method_list_1.stderr | 2 +- tests/ui/should_impl_trait/method_list_2.stderr | 2 +- tests/ui/significant_drop_in_scrutinee.stderr | 2 +- tests/ui/similar_names.stderr | 2 +- tests/ui/single_char_lifetime_names.stderr | 2 +- .../single_component_path_imports_nested_first.stderr | 2 +- tests/ui/size_of_in_element_count/expressions.stderr | 2 +- tests/ui/size_of_in_element_count/functions.stderr | 2 +- tests/ui/skip_while_next.stderr | 2 +- tests/ui/stable_sort_primitive.stderr | 2 +- tests/ui/std_instead_of_core.stderr | 6 +++--- tests/ui/str_to_string.stderr | 2 +- tests/ui/string_to_string.stderr | 2 +- tests/ui/struct_excessive_bools.stderr | 2 +- tests/ui/suspicious_else_formatting.stderr | 2 +- tests/ui/suspicious_map.stderr | 2 +- tests/ui/suspicious_splitn.stderr | 2 +- tests/ui/suspicious_unary_op_formatting.stderr | 2 +- tests/ui/swap.stderr | 4 ++-- tests/ui/trailing_empty_array.stderr | 2 +- tests/ui/trait_duplication_in_bounds_unfixable.stderr | 2 +- tests/ui/type_repetition_in_bounds.stderr | 2 +- tests/ui/undocumented_unsafe_blocks.stderr | 2 +- tests/ui/undropped_manually_drops.stderr | 2 +- tests/ui/uninit_vec.stderr | 2 +- tests/ui/unit_hash.stderr | 2 +- tests/ui/unit_return_expecting_ord.stderr | 2 +- tests/ui/unnecessary_self_imports.stderr | 2 +- tests/ui/unnecessary_to_owned.stderr | 2 +- tests/ui/unneeded_field_pattern.stderr | 2 +- tests/ui/unsafe_derive_deserialize.stderr | 2 +- tests/ui/unused_async.stderr | 2 +- tests/ui/unused_io_amount.stderr | 2 +- tests/ui/unused_peekable.stderr | 2 +- tests/ui/unused_self.stderr | 2 +- tests/ui/unwrap.stderr | 2 +- tests/ui/unwrap_expect_used.stderr | 4 ++-- tests/ui/unwrap_in_result.stderr | 2 +- tests/ui/useless_conversion_try.stderr | 2 +- tests/ui/vec_resize_to_zero.stderr | 2 +- tests/ui/verbose_file_reads.stderr | 2 +- tests/ui/vtable_address_comparisons.stderr | 2 +- tests/ui/wild_in_or_pats.stderr | 2 +- tests/ui/wrong_self_convention.stderr | 2 +- tests/ui/wrong_self_convention2.stderr | 2 +- tests/ui/wrong_self_conventions_mut.stderr | 2 +- tests/ui/zero_div_zero.stderr | 2 +- tests/ui/zero_sized_btreemap_values.stderr | 2 +- tests/ui/zero_sized_hashmap_values.stderr | 2 +- 205 files changed, 231 insertions(+), 231 deletions(-) diff --git a/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr b/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr index 62c45b54634f4..4c75998437fd5 100644 --- a/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr +++ b/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr @@ -4,8 +4,8 @@ error: `std::string::String` may not be held across an `await` point per `clippy LL | let _x = String::from("hello"); | ^^ | - = note: `-D clippy::await-holding-invalid-type` implied by `-D warnings` = note: strings are bad + = note: `-D clippy::await-holding-invalid-type` implied by `-D warnings` error: `std::net::Ipv4Addr` may not be held across an `await` point per `clippy.toml` --> $DIR/await_holding_invalid_type.rs:10:9 diff --git a/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr b/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr index 4c560299ebdd1..b2b57bdde89c6 100644 --- a/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr +++ b/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr @@ -8,8 +8,8 @@ error: the function has a cognitive complexity of (3/2) LL | fn cognitive_complexity() { | ^^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::cognitive-complexity` implied by `-D warnings` = help: you could split it up into multiple smaller functions + = note: `-D clippy::cognitive-complexity` implied by `-D warnings` error: aborting due to previous error; 2 warnings emitted diff --git a/tests/ui-toml/expect_used/expect_used.stderr b/tests/ui-toml/expect_used/expect_used.stderr index c5d95cb8a147f..28a08599c67c6 100644 --- a/tests/ui-toml/expect_used/expect_used.stderr +++ b/tests/ui-toml/expect_used/expect_used.stderr @@ -4,8 +4,8 @@ error: used `expect()` on `an Option` value LL | let _ = opt.expect(""); | ^^^^^^^^^^^^^^ | - = note: `-D clippy::expect-used` implied by `-D warnings` = help: if this value is `None`, it will panic + = note: `-D clippy::expect-used` implied by `-D warnings` error: used `expect()` on `a Result` value --> $DIR/expect_used.rs:11:13 diff --git a/tests/ui-toml/fn_params_excessive_bools/test.stderr b/tests/ui-toml/fn_params_excessive_bools/test.stderr index d05adc3d36e33..87bdb61c6a5e7 100644 --- a/tests/ui-toml/fn_params_excessive_bools/test.stderr +++ b/tests/ui-toml/fn_params_excessive_bools/test.stderr @@ -4,8 +4,8 @@ error: more than 1 bools in function parameters LL | fn g(_: bool, _: bool) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::fn-params-excessive-bools` implied by `-D warnings` = help: consider refactoring bools into two-variant enums + = note: `-D clippy::fn-params-excessive-bools` implied by `-D warnings` error: aborting due to previous error diff --git a/tests/ui-toml/large_include_file/large_include_file.stderr b/tests/ui-toml/large_include_file/large_include_file.stderr index 6a685a58318b9..7b5fb9e876594 100644 --- a/tests/ui-toml/large_include_file/large_include_file.stderr +++ b/tests/ui-toml/large_include_file/large_include_file.stderr @@ -4,8 +4,8 @@ error: attempted to include a large file LL | const TOO_BIG_INCLUDE_BYTES: &[u8; 654] = include_bytes!("too_big.txt"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::large-include-file` implied by `-D warnings` = note: the configuration allows a maximum size of 600 bytes + = note: `-D clippy::large-include-file` implied by `-D warnings` = note: this error originates in the macro `include_bytes` (in Nightly builds, run with -Z macro-backtrace for more info) error: attempted to include a large file diff --git a/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.stderr b/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.stderr index d80ad49f3086d..15fa4f42f9ba5 100644 --- a/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.stderr +++ b/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.stderr @@ -4,12 +4,12 @@ error: use of irregular braces for `vec!` macro LL | let _ = vec! {1, 2, 3}; | ^^^^^^^^^^^^^^ | - = note: `-D clippy::nonstandard-macro-braces` implied by `-D warnings` help: consider writing `vec![1, 2, 3]` --> $DIR/conf_nonstandard_macro_braces.rs:43:13 | LL | let _ = vec! {1, 2, 3}; | ^^^^^^^^^^^^^^ + = note: `-D clippy::nonstandard-macro-braces` implied by `-D warnings` error: use of irregular braces for `format!` macro --> $DIR/conf_nonstandard_macro_braces.rs:44:13 diff --git a/tests/ui-toml/strict_non_send_fields_in_send_ty/test.stderr b/tests/ui-toml/strict_non_send_fields_in_send_ty/test.stderr index 49eecf18b4c4f..c72f8c6488dbd 100644 --- a/tests/ui-toml/strict_non_send_fields_in_send_ty/test.stderr +++ b/tests/ui-toml/strict_non_send_fields_in_send_ty/test.stderr @@ -4,13 +4,13 @@ error: some fields in `NoGeneric` are not safe to be sent to another thread LL | unsafe impl Send for NoGeneric {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::non-send-fields-in-send-ty` implied by `-D warnings` note: it is not safe to send field `rc_is_not_send` to another thread --> $DIR/test.rs:8:5 | LL | rc_is_not_send: Rc, | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: use a thread-safe type that implements `Send` + = note: `-D clippy::non-send-fields-in-send-ty` implied by `-D warnings` error: some fields in `MultiField` are not safe to be sent to another thread --> $DIR/test.rs:19:1 diff --git a/tests/ui-toml/struct_excessive_bools/test.stderr b/tests/ui-toml/struct_excessive_bools/test.stderr index 65861d10d0fdb..4e7c70d18385c 100644 --- a/tests/ui-toml/struct_excessive_bools/test.stderr +++ b/tests/ui-toml/struct_excessive_bools/test.stderr @@ -6,8 +6,8 @@ LL | | a: bool, LL | | } | |_^ | - = note: `-D clippy::struct-excessive-bools` implied by `-D warnings` = help: consider using a state machine or refactoring bools into two-variant enums + = note: `-D clippy::struct-excessive-bools` implied by `-D warnings` error: aborting due to previous error diff --git a/tests/ui-toml/unwrap_used/unwrap_used.stderr b/tests/ui-toml/unwrap_used/unwrap_used.stderr index 6bcfa0a8b5647..681b5eaf54dba 100644 --- a/tests/ui-toml/unwrap_used/unwrap_used.stderr +++ b/tests/ui-toml/unwrap_used/unwrap_used.stderr @@ -16,8 +16,8 @@ error: used `unwrap()` on `an Option` value LL | let _ = boxed_slice.get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::unwrap-used` implied by `-D warnings` = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message + = note: `-D clippy::unwrap-used` implied by `-D warnings` error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise --> $DIR/unwrap_used.rs:36:17 diff --git a/tests/ui/absurd-extreme-comparisons.stderr b/tests/ui/absurd-extreme-comparisons.stderr index 6de554378aaa9..21cb11fa1bb84 100644 --- a/tests/ui/absurd-extreme-comparisons.stderr +++ b/tests/ui/absurd-extreme-comparisons.stderr @@ -4,8 +4,8 @@ error: this comparison involving the minimum or maximum element for this type co LL | u <= 0; | ^^^^^^ | - = note: `-D clippy::absurd-extreme-comparisons` implied by `-D warnings` = help: because `0` is the minimum value for this type, the case where the two sides are not equal never occurs, consider using `u == 0` instead + = note: `-D clippy::absurd-extreme-comparisons` implied by `-D warnings` error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false --> $DIR/absurd-extreme-comparisons.rs:15:5 diff --git a/tests/ui/allow_attributes_without_reason.stderr b/tests/ui/allow_attributes_without_reason.stderr index cd040a144aaca..23f17e9a7afb4 100644 --- a/tests/ui/allow_attributes_without_reason.stderr +++ b/tests/ui/allow_attributes_without_reason.stderr @@ -4,12 +4,12 @@ error: `allow` attribute without specifying a reason LL | #[allow(dead_code)] | ^^^^^^^^^^^^^^^^^^^ | + = help: try adding a reason at the end with `, reason = ".."` note: the lint level is defined here --> $DIR/allow_attributes_without_reason.rs:2:9 | LL | #![deny(clippy::allow_attributes_without_reason)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: try adding a reason at the end with `, reason = ".."` error: `allow` attribute without specifying a reason --> $DIR/allow_attributes_without_reason.rs:6:1 diff --git a/tests/ui/approx_const.stderr b/tests/ui/approx_const.stderr index 4da1b8215ae04..0932a2eec520f 100644 --- a/tests/ui/approx_const.stderr +++ b/tests/ui/approx_const.stderr @@ -4,8 +4,8 @@ error: approximate value of `f{32, 64}::consts::E` found LL | let my_e = 2.7182; | ^^^^^^ | - = note: `-D clippy::approx-constant` implied by `-D warnings` = help: consider using the constant directly + = note: `-D clippy::approx-constant` implied by `-D warnings` error: approximate value of `f{32, 64}::consts::E` found --> $DIR/approx_const.rs:5:20 diff --git a/tests/ui/as_conversions.stderr b/tests/ui/as_conversions.stderr index d11b56171b072..f5d59e1e5d836 100644 --- a/tests/ui/as_conversions.stderr +++ b/tests/ui/as_conversions.stderr @@ -4,8 +4,8 @@ error: using a potentially dangerous silent `as` conversion LL | let i = 0u32 as u64; | ^^^^^^^^^^^ | - = note: `-D clippy::as-conversions` implied by `-D warnings` = help: consider using a safe wrapper for this conversion + = note: `-D clippy::as-conversions` implied by `-D warnings` error: using a potentially dangerous silent `as` conversion --> $DIR/as_conversions.rs:17:13 diff --git a/tests/ui/asm_syntax.stderr b/tests/ui/asm_syntax.stderr index e9b150121aa31..9c7c3ba7d87e6 100644 --- a/tests/ui/asm_syntax.stderr +++ b/tests/ui/asm_syntax.stderr @@ -4,8 +4,8 @@ error: Intel x86 assembly syntax used LL | asm!(""); | ^^^^^^^^ | - = note: `-D clippy::inline-asm-x86-intel-syntax` implied by `-D warnings` = help: use AT&T x86 assembly syntax + = note: `-D clippy::inline-asm-x86-intel-syntax` implied by `-D warnings` error: Intel x86 assembly syntax used --> $DIR/asm_syntax.rs:9:9 @@ -29,8 +29,8 @@ error: AT&T x86 assembly syntax used LL | asm!("", options(att_syntax)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::inline-asm-x86-att-syntax` implied by `-D warnings` = help: use Intel x86 assembly syntax + = note: `-D clippy::inline-asm-x86-att-syntax` implied by `-D warnings` error: AT&T x86 assembly syntax used --> $DIR/asm_syntax.rs:24:9 diff --git a/tests/ui/assertions_on_constants.stderr b/tests/ui/assertions_on_constants.stderr index e1f818814d500..29fe009035f16 100644 --- a/tests/ui/assertions_on_constants.stderr +++ b/tests/ui/assertions_on_constants.stderr @@ -4,8 +4,8 @@ error: `assert!(true)` will be optimized out by the compiler LL | assert!(true); | ^^^^^^^^^^^^^ | - = note: `-D clippy::assertions-on-constants` implied by `-D warnings` = help: remove it + = note: `-D clippy::assertions-on-constants` implied by `-D warnings` error: `assert!(false)` should probably be replaced --> $DIR/assertions_on_constants.rs:11:5 diff --git a/tests/ui/await_holding_lock.stderr b/tests/ui/await_holding_lock.stderr index 976da8d924247..81a2d05243839 100644 --- a/tests/ui/await_holding_lock.stderr +++ b/tests/ui/await_holding_lock.stderr @@ -4,7 +4,6 @@ error: this `MutexGuard` is held across an `await` point LL | let guard = x.lock().unwrap(); | ^^^^^ | - = note: `-D clippy::await-holding-lock` implied by `-D warnings` = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await note: these are all the `await` points this lock is held through --> $DIR/await_holding_lock.rs:9:9 @@ -13,6 +12,7 @@ LL | / let guard = x.lock().unwrap(); LL | | baz().await LL | | } | |_____^ + = note: `-D clippy::await-holding-lock` implied by `-D warnings` error: this `MutexGuard` is held across an `await` point --> $DIR/await_holding_lock.rs:24:13 diff --git a/tests/ui/await_holding_refcell_ref.stderr b/tests/ui/await_holding_refcell_ref.stderr index 4339fca735dd4..25c15ab80602e 100644 --- a/tests/ui/await_holding_refcell_ref.stderr +++ b/tests/ui/await_holding_refcell_ref.stderr @@ -4,7 +4,6 @@ error: this `RefCell` reference is held across an `await` point LL | let b = x.borrow(); | ^ | - = note: `-D clippy::await-holding-refcell-ref` implied by `-D warnings` = help: ensure the reference is dropped before calling `await` note: these are all the `await` points this reference is held through --> $DIR/await_holding_refcell_ref.rs:6:5 @@ -13,6 +12,7 @@ LL | / let b = x.borrow(); LL | | baz().await LL | | } | |_^ + = note: `-D clippy::await-holding-refcell-ref` implied by `-D warnings` error: this `RefCell` reference is held across an `await` point --> $DIR/await_holding_refcell_ref.rs:11:9 diff --git a/tests/ui/blanket_clippy_restriction_lints.stderr b/tests/ui/blanket_clippy_restriction_lints.stderr index 537557f8b0af0..e83eb4d605aa7 100644 --- a/tests/ui/blanket_clippy_restriction_lints.stderr +++ b/tests/ui/blanket_clippy_restriction_lints.stderr @@ -4,8 +4,8 @@ error: restriction lints are not meant to be all enabled LL | #![warn(clippy::restriction)] | ^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::blanket-clippy-restriction-lints` implied by `-D warnings` = help: try enabling only the lints you really need + = note: `-D clippy::blanket-clippy-restriction-lints` implied by `-D warnings` error: restriction lints are not meant to be all enabled --> $DIR/blanket_clippy_restriction_lints.rs:5:9 diff --git a/tests/ui/bool_to_int_with_if.stderr b/tests/ui/bool_to_int_with_if.stderr index e695440f6682f..4cb5531bef6a1 100644 --- a/tests/ui/bool_to_int_with_if.stderr +++ b/tests/ui/bool_to_int_with_if.stderr @@ -8,8 +8,8 @@ LL | | 0 LL | | }; | |_____^ help: replace with from: `i32::from(a)` | - = note: `-D clippy::bool-to-int-with-if` implied by `-D warnings` = note: `a as i32` or `a.into()` can also be valid options + = note: `-D clippy::bool-to-int-with-if` implied by `-D warnings` error: boolean to int conversion using if --> $DIR/bool_to_int_with_if.rs:20:5 diff --git a/tests/ui/borrow_interior_mutable_const/enums.stderr b/tests/ui/borrow_interior_mutable_const/enums.stderr index 654a1ee7df659..b0cab977a0384 100644 --- a/tests/ui/borrow_interior_mutable_const/enums.stderr +++ b/tests/ui/borrow_interior_mutable_const/enums.stderr @@ -4,8 +4,8 @@ error: a `const` item with interior mutability should not be borrowed LL | let _ = &UNFROZEN_VARIANT; //~ ERROR interior mutability | ^^^^^^^^^^^^^^^^ | - = note: `-D clippy::borrow-interior-mutable-const` implied by `-D warnings` = help: assign this const to a local or static variable, and use the variable here + = note: `-D clippy::borrow-interior-mutable-const` implied by `-D warnings` error: a `const` item with interior mutability should not be borrowed --> $DIR/enums.rs:37:18 diff --git a/tests/ui/borrow_interior_mutable_const/others.stderr b/tests/ui/borrow_interior_mutable_const/others.stderr index 9a908cf30e945..c87ad206c2ae2 100644 --- a/tests/ui/borrow_interior_mutable_const/others.stderr +++ b/tests/ui/borrow_interior_mutable_const/others.stderr @@ -4,8 +4,8 @@ error: a `const` item with interior mutability should not be borrowed LL | ATOMIC.store(1, Ordering::SeqCst); //~ ERROR interior mutability | ^^^^^^ | - = note: `-D clippy::borrow-interior-mutable-const` implied by `-D warnings` = help: assign this const to a local or static variable, and use the variable here + = note: `-D clippy::borrow-interior-mutable-const` implied by `-D warnings` error: a `const` item with interior mutability should not be borrowed --> $DIR/others.rs:55:16 diff --git a/tests/ui/borrow_interior_mutable_const/traits.stderr b/tests/ui/borrow_interior_mutable_const/traits.stderr index 8f26403abd3ee..f34ae8814c335 100644 --- a/tests/ui/borrow_interior_mutable_const/traits.stderr +++ b/tests/ui/borrow_interior_mutable_const/traits.stderr @@ -4,8 +4,8 @@ error: a `const` item with interior mutability should not be borrowed LL | let _ = &Self::ATOMIC; //~ ERROR interior mutable | ^^^^^^^^^^^^ | - = note: `-D clippy::borrow-interior-mutable-const` implied by `-D warnings` = help: assign this const to a local or static variable, and use the variable here + = note: `-D clippy::borrow-interior-mutable-const` implied by `-D warnings` error: a `const` item with interior mutability should not be borrowed --> $DIR/traits.rs:26:18 diff --git a/tests/ui/box_collection.stderr b/tests/ui/box_collection.stderr index 2b28598ded92f..40b6f9be61d59 100644 --- a/tests/ui/box_collection.stderr +++ b/tests/ui/box_collection.stderr @@ -4,8 +4,8 @@ error: you seem to be trying to use `Box>`. Consider using just `Vec<..> LL | fn test1(foo: Box>) {} | ^^^^^^^^^^^^^^ | - = note: `-D clippy::box-collection` implied by `-D warnings` = help: `Vec<..>` is already on the heap, `Box>` makes an extra allocation + = note: `-D clippy::box-collection` implied by `-D warnings` error: you seem to be trying to use `Box`. Consider using just `String` --> $DIR/box_collection.rs:28:15 diff --git a/tests/ui/branches_sharing_code/shared_at_bottom.stderr b/tests/ui/branches_sharing_code/shared_at_bottom.stderr index 5e1a68d216ea8..b919812e098a3 100644 --- a/tests/ui/branches_sharing_code/shared_at_bottom.stderr +++ b/tests/ui/branches_sharing_code/shared_at_bottom.stderr @@ -7,12 +7,12 @@ LL | | result LL | | }; | |_____^ | + = note: the end suggestion probably needs some adjustments to use the expression result correctly note: the lint level is defined here --> $DIR/shared_at_bottom.rs:2:36 | LL | #![deny(clippy::if_same_then_else, clippy::branches_sharing_code)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: the end suggestion probably needs some adjustments to use the expression result correctly help: consider moving these statements after the if | LL ~ } diff --git a/tests/ui/branches_sharing_code/shared_at_top.stderr b/tests/ui/branches_sharing_code/shared_at_top.stderr index d890b12ecbb4c..fb3da641fb5e4 100644 --- a/tests/ui/branches_sharing_code/shared_at_top.stderr +++ b/tests/ui/branches_sharing_code/shared_at_top.stderr @@ -103,11 +103,6 @@ LL | | println!("This should trigger `IS_SAME_THAN_ELSE` as usual"); LL | | } else { | |_____^ | -note: the lint level is defined here - --> $DIR/shared_at_top.rs:2:9 - | -LL | #![deny(clippy::if_same_then_else, clippy::branches_sharing_code)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: same as this --> $DIR/shared_at_top.rs:98:12 | @@ -116,6 +111,11 @@ LL | } else { LL | | println!("This should trigger `IS_SAME_THAN_ELSE` as usual"); LL | | } | |_____^ +note: the lint level is defined here + --> $DIR/shared_at_top.rs:2:9 + | +LL | #![deny(clippy::if_same_then_else, clippy::branches_sharing_code)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 7 previous errors diff --git a/tests/ui/branches_sharing_code/shared_at_top_and_bottom.stderr b/tests/ui/branches_sharing_code/shared_at_top_and_bottom.stderr index a270f637f2b91..3edb8e53a7d4b 100644 --- a/tests/ui/branches_sharing_code/shared_at_top_and_bottom.stderr +++ b/tests/ui/branches_sharing_code/shared_at_top_and_bottom.stderr @@ -7,17 +7,17 @@ LL | | let _overlap_start = t * 2; LL | | let _overlap_end = 2 * t; | |_________________________________^ | -note: the lint level is defined here - --> $DIR/shared_at_top_and_bottom.rs:2:36 - | -LL | #![deny(clippy::if_same_then_else, clippy::branches_sharing_code)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: this code is shared at the end --> $DIR/shared_at_top_and_bottom.rs:28:5 | LL | / let _u = 9; LL | | } | |_____^ +note: the lint level is defined here + --> $DIR/shared_at_top_and_bottom.rs:2:36 + | +LL | #![deny(clippy::if_same_then_else, clippy::branches_sharing_code)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider moving these statements before the if | LL ~ let t = 7; diff --git a/tests/ui/branches_sharing_code/valid_if_blocks.stderr b/tests/ui/branches_sharing_code/valid_if_blocks.stderr index a815995e71721..d2acd6d9735c5 100644 --- a/tests/ui/branches_sharing_code/valid_if_blocks.stderr +++ b/tests/ui/branches_sharing_code/valid_if_blocks.stderr @@ -6,11 +6,6 @@ LL | if false { LL | | } else { | |_____^ | -note: the lint level is defined here - --> $DIR/valid_if_blocks.rs:2:9 - | -LL | #![deny(clippy::if_same_then_else, clippy::branches_sharing_code)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: same as this --> $DIR/valid_if_blocks.rs:105:12 | @@ -18,6 +13,11 @@ LL | } else { | ____________^ LL | | } | |_____^ +note: the lint level is defined here + --> $DIR/valid_if_blocks.rs:2:9 + | +LL | #![deny(clippy::if_same_then_else, clippy::branches_sharing_code)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: this `if` has identical blocks --> $DIR/valid_if_blocks.rs:115:15 diff --git a/tests/ui/case_sensitive_file_extension_comparisons.stderr b/tests/ui/case_sensitive_file_extension_comparisons.stderr index 5d9a043edb9a5..a28dd8bd5ad3f 100644 --- a/tests/ui/case_sensitive_file_extension_comparisons.stderr +++ b/tests/ui/case_sensitive_file_extension_comparisons.stderr @@ -4,8 +4,8 @@ error: case-sensitive file extension comparison LL | filename.ends_with(".rs") | ^^^^^^^^^^^^^^^^ | - = note: `-D clippy::case-sensitive-file-extension-comparisons` implied by `-D warnings` = help: consider using a case-insensitive comparison instead + = note: `-D clippy::case-sensitive-file-extension-comparisons` implied by `-D warnings` error: case-sensitive file extension comparison --> $DIR/case_sensitive_file_extension_comparisons.rs:17:27 diff --git a/tests/ui/char_lit_as_u8.stderr b/tests/ui/char_lit_as_u8.stderr index b9836d2f25532..39fc9d6dda674 100644 --- a/tests/ui/char_lit_as_u8.stderr +++ b/tests/ui/char_lit_as_u8.stderr @@ -4,8 +4,8 @@ error: casting a character literal to `u8` truncates LL | let _ = '❤' as u8; // no suggestion, since a byte literal won't work. | ^^^^^^^^^ | - = note: `-D clippy::char-lit-as-u8` implied by `-D warnings` = note: `char` is four bytes wide, but `u8` is a single byte + = note: `-D clippy::char-lit-as-u8` implied by `-D warnings` error: aborting due to previous error diff --git a/tests/ui/char_lit_as_u8_suggestions.stderr b/tests/ui/char_lit_as_u8_suggestions.stderr index bf7cb1607b4e2..586174c508820 100644 --- a/tests/ui/char_lit_as_u8_suggestions.stderr +++ b/tests/ui/char_lit_as_u8_suggestions.stderr @@ -4,8 +4,8 @@ error: casting a character literal to `u8` truncates LL | let _ = 'a' as u8; | ^^^^^^^^^ help: use a byte literal instead: `b'a'` | - = note: `-D clippy::char-lit-as-u8` implied by `-D warnings` = note: `char` is four bytes wide, but `u8` is a single byte + = note: `-D clippy::char-lit-as-u8` implied by `-D warnings` error: casting a character literal to `u8` truncates --> $DIR/char_lit_as_u8_suggestions.rs:7:13 diff --git a/tests/ui/checked_unwrap/complex_conditionals.stderr b/tests/ui/checked_unwrap/complex_conditionals.stderr index 46c6f69708eb7..d44d5072e4850 100644 --- a/tests/ui/checked_unwrap/complex_conditionals.stderr +++ b/tests/ui/checked_unwrap/complex_conditionals.stderr @@ -6,12 +6,12 @@ LL | if x.is_ok() && y.is_err() { LL | x.unwrap(); // unnecessary | ^^^^^^^^^^ | + = help: try using `if let` or `match` note: the lint level is defined here --> $DIR/complex_conditionals.rs:1:35 | LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: try using `if let` or `match` error: this call to `unwrap_err()` will always panic --> $DIR/complex_conditionals.rs:9:9 diff --git a/tests/ui/cognitive_complexity.stderr b/tests/ui/cognitive_complexity.stderr index a0ddc673abcc1..d7f2f24e52f2b 100644 --- a/tests/ui/cognitive_complexity.stderr +++ b/tests/ui/cognitive_complexity.stderr @@ -4,8 +4,8 @@ error: the function has a cognitive complexity of (28/25) LL | fn main() { | ^^^^ | - = note: `-D clippy::cognitive-complexity` implied by `-D warnings` = help: you could split it up into multiple smaller functions + = note: `-D clippy::cognitive-complexity` implied by `-D warnings` error: the function has a cognitive complexity of (7/1) --> $DIR/cognitive_complexity.rs:91:4 diff --git a/tests/ui/cognitive_complexity_attr_used.stderr b/tests/ui/cognitive_complexity_attr_used.stderr index f5ff53dda603b..bb48f32974867 100644 --- a/tests/ui/cognitive_complexity_attr_used.stderr +++ b/tests/ui/cognitive_complexity_attr_used.stderr @@ -4,8 +4,8 @@ error: the function has a cognitive complexity of (3/0) LL | fn kaboom() { | ^^^^^^ | - = note: `-D clippy::cognitive-complexity` implied by `-D warnings` = help: you could split it up into multiple smaller functions + = note: `-D clippy::cognitive-complexity` implied by `-D warnings` error: aborting due to previous error diff --git a/tests/ui/collapsible_match.stderr b/tests/ui/collapsible_match.stderr index 5f18b69350295..33562e8401cad 100644 --- a/tests/ui/collapsible_match.stderr +++ b/tests/ui/collapsible_match.stderr @@ -8,7 +8,6 @@ LL | | _ => return, LL | | }, | |_________^ | - = note: `-D clippy::collapsible-match` implied by `-D warnings` help: the outer pattern can be modified to include the inner pattern --> $DIR/collapsible_match.rs:12:12 | @@ -16,6 +15,7 @@ LL | Ok(val) => match val { | ^^^ replace this binding LL | Some(n) => foo(n), | ^^^^^^^ with this pattern + = note: `-D clippy::collapsible-match` implied by `-D warnings` error: this `match` can be collapsed into the outer `match` --> $DIR/collapsible_match.rs:21:20 diff --git a/tests/ui/collapsible_match2.stderr b/tests/ui/collapsible_match2.stderr index fe64e4693792d..144dbe40a7ad6 100644 --- a/tests/ui/collapsible_match2.stderr +++ b/tests/ui/collapsible_match2.stderr @@ -8,7 +8,6 @@ LL | | _ => return, LL | | }, | |_____________^ | - = note: `-D clippy::collapsible-match` implied by `-D warnings` help: the outer pattern can be modified to include the inner pattern --> $DIR/collapsible_match2.rs:13:16 | @@ -16,6 +15,7 @@ LL | Ok(val) if make() => match val { | ^^^ replace this binding LL | Some(n) => foo(n), | ^^^^^^^ with this pattern + = note: `-D clippy::collapsible-match` implied by `-D warnings` error: this `match` can be collapsed into the outer `match` --> $DIR/collapsible_match2.rs:20:24 diff --git a/tests/ui/comparison_chain.stderr b/tests/ui/comparison_chain.stderr index be25a80dde0a1..2eeb50202cd43 100644 --- a/tests/ui/comparison_chain.stderr +++ b/tests/ui/comparison_chain.stderr @@ -8,8 +8,8 @@ LL | | b() LL | | } | |_____^ | - = note: `-D clippy::comparison-chain` implied by `-D warnings` = help: consider rewriting the `if` chain to use `cmp` and `match` + = note: `-D clippy::comparison-chain` implied by `-D warnings` error: `if` chain can be rewritten with `match` --> $DIR/comparison_chain.rs:27:5 diff --git a/tests/ui/copy_iterator.stderr b/tests/ui/copy_iterator.stderr index f8ce6af7961a6..6bc6fd6b6fa84 100644 --- a/tests/ui/copy_iterator.stderr +++ b/tests/ui/copy_iterator.stderr @@ -10,8 +10,8 @@ LL | | } LL | | } | |_^ | - = note: `-D clippy::copy-iterator` implied by `-D warnings` = note: consider implementing `IntoIterator` instead + = note: `-D clippy::copy-iterator` implied by `-D warnings` error: aborting due to previous error diff --git a/tests/ui/crashes/ice-360.stderr b/tests/ui/crashes/ice-360.stderr index 0eb7bb12b3546..a2e2ab8fd192f 100644 --- a/tests/ui/crashes/ice-360.stderr +++ b/tests/ui/crashes/ice-360.stderr @@ -18,8 +18,8 @@ error: empty `loop {}` wastes CPU cycles LL | loop {} | ^^^^^^^ | - = note: `-D clippy::empty-loop` implied by `-D warnings` = help: you should either use `panic!()` or add `std::thread::sleep(..);` to the loop body + = note: `-D clippy::empty-loop` implied by `-D warnings` error: aborting due to 2 previous errors diff --git a/tests/ui/crashes/ice-6254.stderr b/tests/ui/crashes/ice-6254.stderr index f37ab2e9b0c79..22d82a30c6aad 100644 --- a/tests/ui/crashes/ice-6254.stderr +++ b/tests/ui/crashes/ice-6254.stderr @@ -4,9 +4,9 @@ error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated wit LL | FOO_REF_REF => {}, | ^^^^^^^^^^^ | - = note: `-D indirect-structural-match` implied by `-D warnings` = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #62411 + = note: `-D indirect-structural-match` implied by `-D warnings` error: aborting due to previous error diff --git a/tests/ui/crashes/ice-7868.stderr b/tests/ui/crashes/ice-7868.stderr index 1a33e647588f1..1d8314e889fa1 100644 --- a/tests/ui/crashes/ice-7868.stderr +++ b/tests/ui/crashes/ice-7868.stderr @@ -4,8 +4,8 @@ error: unsafe block missing a safety comment LL | unsafe { 0 }; | ^^^^^^^^^^^^ | - = note: `-D clippy::undocumented-unsafe-blocks` implied by `-D warnings` = help: consider adding a safety comment on the preceding line + = note: `-D clippy::undocumented-unsafe-blocks` implied by `-D warnings` error: aborting due to previous error diff --git a/tests/ui/crashes/ice-7869.stderr b/tests/ui/crashes/ice-7869.stderr index 4fa9fb27e7659..35d1e8fd29573 100644 --- a/tests/ui/crashes/ice-7869.stderr +++ b/tests/ui/crashes/ice-7869.stderr @@ -8,8 +8,8 @@ LL | | TyöValmis, LL | | } | |_^ | - = note: `-D clippy::enum-variant-names` implied by `-D warnings` = help: remove the prefixes and use full paths to the variants instead of glob imports + = note: `-D clippy::enum-variant-names` implied by `-D warnings` error: aborting due to previous error diff --git a/tests/ui/crashes/ice-9463.stderr b/tests/ui/crashes/ice-9463.stderr index 7daa08aeb6c94..b0ce306d6838e 100644 --- a/tests/ui/crashes/ice-9463.stderr +++ b/tests/ui/crashes/ice-9463.stderr @@ -22,8 +22,8 @@ error: literal out of range for `u32` LL | let _y = 1u32 >> 10000000000000u32; | ^^^^^^^^^^^^^^^^^ | - = note: `#[deny(overflowing_literals)]` on by default = note: the literal `10000000000000u32` does not fit into the type `u32` whose range is `0..=4294967295` + = note: `#[deny(overflowing_literals)]` on by default error: aborting due to 3 previous errors diff --git a/tests/ui/crate_level_checks/entrypoint_recursion.stderr b/tests/ui/crate_level_checks/entrypoint_recursion.stderr index 459cf12a1c209..3d79a115cb301 100644 --- a/tests/ui/crate_level_checks/entrypoint_recursion.stderr +++ b/tests/ui/crate_level_checks/entrypoint_recursion.stderr @@ -4,8 +4,8 @@ error: recursing into entrypoint `a` LL | a(); | ^ | - = note: `-D clippy::main-recursion` implied by `-D warnings` = help: consider using another function for this recursion + = note: `-D clippy::main-recursion` implied by `-D warnings` error: aborting due to previous error diff --git a/tests/ui/crate_level_checks/no_std_swap.stderr b/tests/ui/crate_level_checks/no_std_swap.stderr index 48152d8ad7743..7d8ea3f76b0f6 100644 --- a/tests/ui/crate_level_checks/no_std_swap.stderr +++ b/tests/ui/crate_level_checks/no_std_swap.stderr @@ -5,8 +5,8 @@ LL | / a = b; LL | | b = a; | |_________^ help: try: `core::mem::swap(&mut a, &mut b)` | - = note: `-D clippy::almost-swapped` implied by `-D warnings` = note: or maybe you should use `core::mem::replace`? + = note: `-D clippy::almost-swapped` implied by `-D warnings` error: aborting due to previous error diff --git a/tests/ui/crate_level_checks/std_main_recursion.stderr b/tests/ui/crate_level_checks/std_main_recursion.stderr index 0a260f9d2309e..82c68bd1cfef9 100644 --- a/tests/ui/crate_level_checks/std_main_recursion.stderr +++ b/tests/ui/crate_level_checks/std_main_recursion.stderr @@ -4,8 +4,8 @@ error: recursing into entrypoint `main` LL | main(); | ^^^^ | - = note: `-D clippy::main-recursion` implied by `-D warnings` = help: consider using another function for this recursion + = note: `-D clippy::main-recursion` implied by `-D warnings` error: aborting due to previous error diff --git a/tests/ui/def_id_nocore.stderr b/tests/ui/def_id_nocore.stderr index 6210d7c6cfd80..f8fc17e872bd4 100644 --- a/tests/ui/def_id_nocore.stderr +++ b/tests/ui/def_id_nocore.stderr @@ -4,8 +4,8 @@ error: methods called `as_*` usually take `self` by reference or `self` by mutab LL | pub fn as_ref(self) -> &'static str { | ^^^^ | - = note: `-D clippy::wrong-self-convention` implied by `-D warnings` = help: consider choosing a less ambiguous name + = note: `-D clippy::wrong-self-convention` implied by `-D warnings` error: aborting due to previous error diff --git a/tests/ui/default_union_representation.stderr b/tests/ui/default_union_representation.stderr index 138884af868c7..8b7ed94cbc611 100644 --- a/tests/ui/default_union_representation.stderr +++ b/tests/ui/default_union_representation.stderr @@ -7,8 +7,8 @@ LL | | b: u32, LL | | } | |_^ | - = note: `-D clippy::default-union-representation` implied by `-D warnings` = help: consider annotating `NoAttribute` with `#[repr(C)]` to explicitly specify memory layout + = note: `-D clippy::default-union-representation` implied by `-D warnings` error: this union has the default representation --> $DIR/default_union_representation.rs:16:1 diff --git a/tests/ui/derive.stderr b/tests/ui/derive.stderr index 82a70ceecc368..e1fbb8dcd1ee9 100644 --- a/tests/ui/derive.stderr +++ b/tests/ui/derive.stderr @@ -8,7 +8,6 @@ LL | | } LL | | } | |_^ | - = note: `-D clippy::expl-impl-clone-on-copy` implied by `-D warnings` note: consider deriving `Clone` or removing `Copy` --> $DIR/derive.rs:8:1 | @@ -18,6 +17,7 @@ LL | | Qux LL | | } LL | | } | |_^ + = note: `-D clippy::expl-impl-clone-on-copy` implied by `-D warnings` error: you are implementing `Clone` explicitly on a `Copy` type --> $DIR/derive.rs:32:1 diff --git a/tests/ui/derive_hash_xor_eq.stderr b/tests/ui/derive_hash_xor_eq.stderr index 2a4abb0c5193a..16c92397804e5 100644 --- a/tests/ui/derive_hash_xor_eq.stderr +++ b/tests/ui/derive_hash_xor_eq.stderr @@ -4,12 +4,12 @@ error: you are deriving `Hash` but have implemented `PartialEq` explicitly LL | #[derive(Hash)] | ^^^^ | - = note: `#[deny(clippy::derive_hash_xor_eq)]` on by default note: `PartialEq` implemented here --> $DIR/derive_hash_xor_eq.rs:15:1 | LL | impl PartialEq for Bar { | ^^^^^^^^^^^^^^^^^^^^^^ + = note: `#[deny(clippy::derive_hash_xor_eq)]` on by default = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info) error: you are deriving `Hash` but have implemented `PartialEq` explicitly diff --git a/tests/ui/derive_ord_xor_partial_ord.stderr b/tests/ui/derive_ord_xor_partial_ord.stderr index baf8341aba908..58efbb8541f66 100644 --- a/tests/ui/derive_ord_xor_partial_ord.stderr +++ b/tests/ui/derive_ord_xor_partial_ord.stderr @@ -4,12 +4,12 @@ error: you are deriving `Ord` but have implemented `PartialOrd` explicitly LL | #[derive(Ord, PartialEq, Eq)] | ^^^ | - = note: `-D clippy::derive-ord-xor-partial-ord` implied by `-D warnings` note: `PartialOrd` implemented here --> $DIR/derive_ord_xor_partial_ord.rs:24:1 | LL | impl PartialOrd for DeriveOrd { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `-D clippy::derive-ord-xor-partial-ord` implied by `-D warnings` = note: this error originates in the derive macro `Ord` (in Nightly builds, run with -Z macro-backtrace for more info) error: you are deriving `Ord` but have implemented `PartialOrd` explicitly diff --git a/tests/ui/doc/unbalanced_ticks.stderr b/tests/ui/doc/unbalanced_ticks.stderr index a462b98871a88..f2ac6bc3269aa 100644 --- a/tests/ui/doc/unbalanced_ticks.stderr +++ b/tests/ui/doc/unbalanced_ticks.stderr @@ -7,8 +7,8 @@ LL | | /// Because of the initial `unbalanced_tick` pair, the error message is LL | | /// very `confusing_and_misleading`. | |____________________________________^ | - = note: `-D clippy::doc-markdown` implied by `-D warnings` = help: a backtick may be missing a pair + = note: `-D clippy::doc-markdown` implied by `-D warnings` error: backticks are unbalanced --> $DIR/unbalanced_ticks.rs:13:1 diff --git a/tests/ui/double_must_use.stderr b/tests/ui/double_must_use.stderr index 8290ece1cad18..3d34557a881bd 100644 --- a/tests/ui/double_must_use.stderr +++ b/tests/ui/double_must_use.stderr @@ -4,8 +4,8 @@ error: this function has an empty `#[must_use]` attribute, but returns a type al LL | pub fn must_use_result() -> Result<(), ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::double-must-use` implied by `-D warnings` = help: either add some descriptive text or remove the attribute + = note: `-D clippy::double-must-use` implied by `-D warnings` error: this function has an empty `#[must_use]` attribute, but returns a type already marked as `#[must_use]` --> $DIR/double_must_use.rs:10:1 diff --git a/tests/ui/drop_forget_copy.stderr b/tests/ui/drop_forget_copy.stderr index 88228afae89c0..21adb3b3a5043 100644 --- a/tests/ui/drop_forget_copy.stderr +++ b/tests/ui/drop_forget_copy.stderr @@ -4,12 +4,12 @@ error: calls to `std::mem::drop` with a value that implements `Copy`. Dropping a LL | drop(s1); | ^^^^^^^^ | - = note: `-D clippy::drop-copy` implied by `-D warnings` note: argument has type `SomeStruct` --> $DIR/drop_forget_copy.rs:33:10 | LL | drop(s1); | ^^ + = note: `-D clippy::drop-copy` implied by `-D warnings` error: calls to `std::mem::drop` with a value that implements `Copy`. Dropping a copy leaves the original intact --> $DIR/drop_forget_copy.rs:34:5 @@ -41,12 +41,12 @@ error: calls to `std::mem::forget` with a value that implements `Copy`. Forgetti LL | forget(s1); | ^^^^^^^^^^ | - = note: `-D clippy::forget-copy` implied by `-D warnings` note: argument has type `SomeStruct` --> $DIR/drop_forget_copy.rs:39:12 | LL | forget(s1); | ^^ + = note: `-D clippy::forget-copy` implied by `-D warnings` error: calls to `std::mem::forget` with a value that implements `Copy`. Forgetting a copy leaves the original intact --> $DIR/drop_forget_copy.rs:40:5 diff --git a/tests/ui/drop_non_drop.stderr b/tests/ui/drop_non_drop.stderr index 30121033de7ea..b86057c0c321f 100644 --- a/tests/ui/drop_non_drop.stderr +++ b/tests/ui/drop_non_drop.stderr @@ -4,12 +4,12 @@ error: call to `std::mem::drop` with a value that does not implement `Drop`. Dro LL | drop(Foo); | ^^^^^^^^^ | - = note: `-D clippy::drop-non-drop` implied by `-D warnings` note: argument has type `main::Foo` --> $DIR/drop_non_drop.rs:22:10 | LL | drop(Foo); | ^^^ + = note: `-D clippy::drop-non-drop` implied by `-D warnings` error: call to `std::mem::drop` with a value that does not implement `Drop`. Dropping such a type only extends its contained lifetimes --> $DIR/drop_non_drop.rs:37:5 diff --git a/tests/ui/drop_ref.stderr b/tests/ui/drop_ref.stderr index 531849f0680ae..4743cf79b5d3c 100644 --- a/tests/ui/drop_ref.stderr +++ b/tests/ui/drop_ref.stderr @@ -4,12 +4,12 @@ error: calls to `std::mem::drop` with a reference instead of an owned value. Dro LL | drop(&SomeStruct); | ^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::drop-ref` implied by `-D warnings` note: argument has type `&SomeStruct` --> $DIR/drop_ref.rs:11:10 | LL | drop(&SomeStruct); | ^^^^^^^^^^^ + = note: `-D clippy::drop-ref` implied by `-D warnings` error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing --> $DIR/drop_ref.rs:14:5 diff --git a/tests/ui/else_if_without_else.stderr b/tests/ui/else_if_without_else.stderr index 6f47658cfb184..90ccfb4fad641 100644 --- a/tests/ui/else_if_without_else.stderr +++ b/tests/ui/else_if_without_else.stderr @@ -8,8 +8,8 @@ LL | | println!("else if"); LL | | } | |_____^ | - = note: `-D clippy::else-if-without-else` implied by `-D warnings` = help: add an `else` block here + = note: `-D clippy::else-if-without-else` implied by `-D warnings` error: `if` expression with an `else if`, but without a final `else` --> $DIR/else_if_without_else.rs:54:12 diff --git a/tests/ui/empty_enum.stderr b/tests/ui/empty_enum.stderr index 7125e5f602b75..0d9aa5818e28d 100644 --- a/tests/ui/empty_enum.stderr +++ b/tests/ui/empty_enum.stderr @@ -4,8 +4,8 @@ error: enum with no variants LL | enum Empty {} | ^^^^^^^^^^^^^ | - = note: `-D clippy::empty-enum` implied by `-D warnings` = help: consider using the uninhabited type `!` (never type) or a wrapper around it to introduce a type which can't be instantiated + = note: `-D clippy::empty-enum` implied by `-D warnings` error: aborting due to previous error diff --git a/tests/ui/empty_loop.stderr b/tests/ui/empty_loop.stderr index 555f3d3d884a9..7602412334bbf 100644 --- a/tests/ui/empty_loop.stderr +++ b/tests/ui/empty_loop.stderr @@ -4,8 +4,8 @@ error: empty `loop {}` wastes CPU cycles LL | loop {} | ^^^^^^^ | - = note: `-D clippy::empty-loop` implied by `-D warnings` = help: you should either use `panic!()` or add `std::thread::sleep(..);` to the loop body + = note: `-D clippy::empty-loop` implied by `-D warnings` error: empty `loop {}` wastes CPU cycles --> $DIR/empty_loop.rs:11:9 diff --git a/tests/ui/empty_loop_no_std.stderr b/tests/ui/empty_loop_no_std.stderr index 5ded35a6f0d8d..71af64f49d522 100644 --- a/tests/ui/empty_loop_no_std.stderr +++ b/tests/ui/empty_loop_no_std.stderr @@ -4,8 +4,8 @@ error: empty `loop {}` wastes CPU cycles LL | loop {} | ^^^^^^^ | - = note: `-D clippy::empty-loop` implied by `-D warnings` = help: you should either use `panic!()` or add a call pausing or sleeping the thread to the loop body + = note: `-D clippy::empty-loop` implied by `-D warnings` error: empty `loop {}` wastes CPU cycles --> $DIR/empty_loop_no_std.rs:25:5 diff --git a/tests/ui/expect.stderr b/tests/ui/expect.stderr index 904c090464523..f6738865cac12 100644 --- a/tests/ui/expect.stderr +++ b/tests/ui/expect.stderr @@ -4,8 +4,8 @@ error: used `expect()` on `an Option` value LL | let _ = opt.expect(""); | ^^^^^^^^^^^^^^ | - = note: `-D clippy::expect-used` implied by `-D warnings` = help: if this value is `None`, it will panic + = note: `-D clippy::expect-used` implied by `-D warnings` error: used `expect()` on `a Result` value --> $DIR/expect.rs:10:13 diff --git a/tests/ui/fallible_impl_from.stderr b/tests/ui/fallible_impl_from.stderr index d637dbce5d792..28a061af664d7 100644 --- a/tests/ui/fallible_impl_from.stderr +++ b/tests/ui/fallible_impl_from.stderr @@ -8,17 +8,17 @@ LL | | } LL | | } | |_^ | -note: the lint level is defined here - --> $DIR/fallible_impl_from.rs:1:9 - | -LL | #![deny(clippy::fallible_impl_from)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail note: potential failure(s) --> $DIR/fallible_impl_from.rs:7:13 | LL | Foo(s.parse().unwrap()) | ^^^^^^^^^^^^^^^^^^ +note: the lint level is defined here + --> $DIR/fallible_impl_from.rs:1:9 + | +LL | #![deny(clippy::fallible_impl_from)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: consider implementing `TryFrom` instead --> $DIR/fallible_impl_from.rs:26:1 diff --git a/tests/ui/field_reassign_with_default.stderr b/tests/ui/field_reassign_with_default.stderr index 3ce4b91a54869..710bb66a48a40 100644 --- a/tests/ui/field_reassign_with_default.stderr +++ b/tests/ui/field_reassign_with_default.stderr @@ -4,12 +4,12 @@ error: field assignment outside of initializer for an instance created with Defa LL | a.i = 42; | ^^^^^^^^^ | - = note: `-D clippy::field-reassign-with-default` implied by `-D warnings` note: consider initializing the variable with `main::A { i: 42, ..Default::default() }` and removing relevant reassignments --> $DIR/field_reassign_with_default.rs:62:5 | LL | let mut a: A = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `-D clippy::field-reassign-with-default` implied by `-D warnings` error: field assignment outside of initializer for an instance created with Default::default() --> $DIR/field_reassign_with_default.rs:103:5 diff --git a/tests/ui/filetype_is_file.stderr b/tests/ui/filetype_is_file.stderr index cd1e3ac37fe86..e51a90d6cfd24 100644 --- a/tests/ui/filetype_is_file.stderr +++ b/tests/ui/filetype_is_file.stderr @@ -4,8 +4,8 @@ error: `FileType::is_file()` only covers regular files LL | if fs::metadata("foo.txt")?.file_type().is_file() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::filetype-is-file` implied by `-D warnings` = help: use `!FileType::is_dir()` instead + = note: `-D clippy::filetype-is-file` implied by `-D warnings` error: `!FileType::is_file()` only denies regular files --> $DIR/filetype_is_file.rs:13:8 diff --git a/tests/ui/float_cmp.stderr b/tests/ui/float_cmp.stderr index 9cc1f1b75ed44..e3e9f3949fdf8 100644 --- a/tests/ui/float_cmp.stderr +++ b/tests/ui/float_cmp.stderr @@ -4,8 +4,8 @@ error: strict comparison of `f32` or `f64` LL | ONE as f64 != 2.0; | ^^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(ONE as f64 - 2.0).abs() > error_margin` | - = note: `-D clippy::float-cmp` implied by `-D warnings` = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` + = note: `-D clippy::float-cmp` implied by `-D warnings` error: strict comparison of `f32` or `f64` --> $DIR/float_cmp.rs:62:5 diff --git a/tests/ui/float_cmp_const.stderr b/tests/ui/float_cmp_const.stderr index d8182cf855b08..65c45648ab380 100644 --- a/tests/ui/float_cmp_const.stderr +++ b/tests/ui/float_cmp_const.stderr @@ -4,8 +4,8 @@ error: strict comparison of `f32` or `f64` constant LL | 1f32 == ONE; | ^^^^^^^^^^^ help: consider comparing them within some margin of error: `(1f32 - ONE).abs() < error_margin` | - = note: `-D clippy::float-cmp-const` implied by `-D warnings` = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` + = note: `-D clippy::float-cmp-const` implied by `-D warnings` error: strict comparison of `f32` or `f64` constant --> $DIR/float_cmp_const.rs:17:5 diff --git a/tests/ui/fn_params_excessive_bools.stderr b/tests/ui/fn_params_excessive_bools.stderr index cd9d07fa115d6..11627105691b7 100644 --- a/tests/ui/fn_params_excessive_bools.stderr +++ b/tests/ui/fn_params_excessive_bools.stderr @@ -4,8 +4,8 @@ error: more than 3 bools in function parameters LL | fn g(_: bool, _: bool, _: bool, _: bool) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::fn-params-excessive-bools` implied by `-D warnings` = help: consider refactoring bools into two-variant enums + = note: `-D clippy::fn-params-excessive-bools` implied by `-D warnings` error: more than 3 bools in function parameters --> $DIR/fn_params_excessive_bools.rs:21:1 diff --git a/tests/ui/for_loops_over_fallibles.stderr b/tests/ui/for_loops_over_fallibles.stderr index 8c8c022243aeb..68d2735b040e0 100644 --- a/tests/ui/for_loops_over_fallibles.stderr +++ b/tests/ui/for_loops_over_fallibles.stderr @@ -4,8 +4,8 @@ error: for loop over `option`, which is an `Option`. This is more readably writt LL | for x in option { | ^^^^^^ | - = note: `-D clippy::for-loops-over-fallibles` implied by `-D warnings` = help: consider replacing `for x in option` with `if let Some(x) = option` + = note: `-D clippy::for-loops-over-fallibles` implied by `-D warnings` error: for loop over `option`, which is an `Option`. This is more readably written as an `if let` statement --> $DIR/for_loops_over_fallibles.rs:14:14 diff --git a/tests/ui/forget_non_drop.stderr b/tests/ui/forget_non_drop.stderr index 03fb00960a447..194e37c8b4247 100644 --- a/tests/ui/forget_non_drop.stderr +++ b/tests/ui/forget_non_drop.stderr @@ -4,12 +4,12 @@ error: call to `std::mem::forget` with a value that does not implement `Drop`. F LL | forget(Foo); | ^^^^^^^^^^^ | - = note: `-D clippy::forget-non-drop` implied by `-D warnings` note: argument has type `main::Foo` --> $DIR/forget_non_drop.rs:13:12 | LL | forget(Foo); | ^^^ + = note: `-D clippy::forget-non-drop` implied by `-D warnings` error: call to `std::mem::forget` with a value that does not implement `Drop`. Forgetting such a type is the same as dropping it --> $DIR/forget_non_drop.rs:24:5 diff --git a/tests/ui/forget_ref.stderr b/tests/ui/forget_ref.stderr index df5cd8cacdb8d..011cdefc665f8 100644 --- a/tests/ui/forget_ref.stderr +++ b/tests/ui/forget_ref.stderr @@ -4,12 +4,12 @@ error: calls to `std::mem::forget` with a reference instead of an owned value. F LL | forget(&SomeStruct); | ^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::forget-ref` implied by `-D warnings` note: argument has type `&SomeStruct` --> $DIR/forget_ref.rs:11:12 | LL | forget(&SomeStruct); | ^^^^^^^^^^^ + = note: `-D clippy::forget-ref` implied by `-D warnings` error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing --> $DIR/forget_ref.rs:14:5 diff --git a/tests/ui/format_args_unfixable.stderr b/tests/ui/format_args_unfixable.stderr index 4476218ad58e9..37a6afb1ba7bf 100644 --- a/tests/ui/format_args_unfixable.stderr +++ b/tests/ui/format_args_unfixable.stderr @@ -4,9 +4,9 @@ error: `format!` in `println!` args LL | println!("error: {}", format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::format-in-format-args` implied by `-D warnings` = help: combine the `format!(..)` arguments with the outer `println!(..)` call = help: or consider changing `format!` to `format_args!` + = note: `-D clippy::format-in-format-args` implied by `-D warnings` error: `format!` in `println!` args --> $DIR/format_args_unfixable.rs:28:5 diff --git a/tests/ui/format_push_string.stderr b/tests/ui/format_push_string.stderr index 953784bcc0684..d7be9a5f206c1 100644 --- a/tests/ui/format_push_string.stderr +++ b/tests/ui/format_push_string.stderr @@ -4,8 +4,8 @@ error: `format!(..)` appended to existing `String` LL | string += &format!("{:?}", 1234); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::format-push-string` implied by `-D warnings` = help: consider using `write!` to avoid the extra allocation + = note: `-D clippy::format-push-string` implied by `-D warnings` error: `format!(..)` appended to existing `String` --> $DIR/format_push_string.rs:6:5 diff --git a/tests/ui/formatting.stderr b/tests/ui/formatting.stderr index 9272cd6048441..caccd5cba1784 100644 --- a/tests/ui/formatting.stderr +++ b/tests/ui/formatting.stderr @@ -4,8 +4,8 @@ error: this looks like you are trying to use `.. -= ..`, but you really are doin LL | a =- 35; | ^^^^ | - = note: `-D clippy::suspicious-assignment-formatting` implied by `-D warnings` = note: to remove this lint, use either `-=` or `= -` + = note: `-D clippy::suspicious-assignment-formatting` implied by `-D warnings` error: this looks like you are trying to use `.. *= ..`, but you really are doing `.. = (* ..)` --> $DIR/formatting.rs:17:6 @@ -29,8 +29,8 @@ error: possibly missing a comma here LL | -1, -2, -3 // <= no comma here | ^ | - = note: `-D clippy::possible-missing-comma` implied by `-D warnings` = note: to remove this lint, add a comma or write the expr in a single line + = note: `-D clippy::possible-missing-comma` implied by `-D warnings` error: possibly missing a comma here --> $DIR/formatting.rs:33:19 diff --git a/tests/ui/from_over_into.stderr b/tests/ui/from_over_into.stderr index 2951e6bdac430..469adadd2196d 100644 --- a/tests/ui/from_over_into.stderr +++ b/tests/ui/from_over_into.stderr @@ -4,8 +4,8 @@ error: an implementation of `From` is preferred since it gives you `Into<_>` for LL | impl Into for String { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::from-over-into` implied by `-D warnings` = help: consider to implement `From` instead + = note: `-D clippy::from-over-into` implied by `-D warnings` error: aborting due to previous error diff --git a/tests/ui/future_not_send.stderr b/tests/ui/future_not_send.stderr index a9f2ad36d0aba..5b6858e4568b5 100644 --- a/tests/ui/future_not_send.stderr +++ b/tests/ui/future_not_send.stderr @@ -4,7 +4,6 @@ error: future cannot be sent between threads safely LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell) -> bool { | ^^^^ future returned by `private_future` is not `Send` | - = note: `-D clippy::future-not-send` implied by `-D warnings` note: future is not `Send` as this value is used across an await --> $DIR/future_not_send.rs:8:19 | @@ -25,6 +24,7 @@ LL | async { true }.await LL | } | - `cell` is later dropped here = note: `std::cell::Cell` doesn't implement `std::marker::Sync` + = note: `-D clippy::future-not-send` implied by `-D warnings` error: future cannot be sent between threads safely --> $DIR/future_not_send.rs:11:42 diff --git a/tests/ui/get_unwrap.stderr b/tests/ui/get_unwrap.stderr index ea8fec5273511..937f859040831 100644 --- a/tests/ui/get_unwrap.stderr +++ b/tests/ui/get_unwrap.stderr @@ -16,8 +16,8 @@ error: used `unwrap()` on `an Option` value LL | let _ = boxed_slice.get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::unwrap-used` implied by `-D warnings` = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message + = note: `-D clippy::unwrap-used` implied by `-D warnings` error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise --> $DIR/get_unwrap.rs:36:17 diff --git a/tests/ui/if_let_mutex.stderr b/tests/ui/if_let_mutex.stderr index 8a4d5dbac592b..da0cc25f0ab52 100644 --- a/tests/ui/if_let_mutex.stderr +++ b/tests/ui/if_let_mutex.stderr @@ -13,8 +13,8 @@ LL | | do_stuff(lock); LL | | }; | |_____^ | - = note: `-D clippy::if-let-mutex` implied by `-D warnings` = help: move the lock call outside of the `if let ...` expression + = note: `-D clippy::if-let-mutex` implied by `-D warnings` error: calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock --> $DIR/if_let_mutex.rs:22:5 diff --git a/tests/ui/if_not_else.stderr b/tests/ui/if_not_else.stderr index 8c8cc44bb0358..46671c15274f7 100644 --- a/tests/ui/if_not_else.stderr +++ b/tests/ui/if_not_else.stderr @@ -8,8 +8,8 @@ LL | | println!("Bunny"); LL | | } | |_____^ | - = note: `-D clippy::if-not-else` implied by `-D warnings` = help: remove the `!` and swap the blocks of the `if`/`else` + = note: `-D clippy::if-not-else` implied by `-D warnings` error: unnecessary `!=` operation --> $DIR/if_not_else.rs:17:5 diff --git a/tests/ui/if_same_then_else.stderr b/tests/ui/if_same_then_else.stderr index 2cdf442486a30..fb23b81d36d72 100644 --- a/tests/ui/if_same_then_else.stderr +++ b/tests/ui/if_same_then_else.stderr @@ -11,7 +11,6 @@ LL | | foo(); LL | | } else { | |_____^ | - = note: `-D clippy::if-same-then-else` implied by `-D warnings` note: same as this --> $DIR/if_same_then_else.rs:31:12 | @@ -24,6 +23,7 @@ LL | | 0..10; LL | | foo(); LL | | } | |_____^ + = note: `-D clippy::if-same-then-else` implied by `-D warnings` error: this `if` has identical blocks --> $DIR/if_same_then_else.rs:67:21 diff --git a/tests/ui/if_same_then_else2.stderr b/tests/ui/if_same_then_else2.stderr index cac788f859d1e..704cfd9669ac8 100644 --- a/tests/ui/if_same_then_else2.stderr +++ b/tests/ui/if_same_then_else2.stderr @@ -11,7 +11,6 @@ LL | | } LL | | } else { | |_____^ | - = note: `-D clippy::if-same-then-else` implied by `-D warnings` note: same as this --> $DIR/if_same_then_else2.rs:23:12 | @@ -24,6 +23,7 @@ LL | | let bar: &Option<_> = &Some::(42); LL | | } LL | | } | |_____^ + = note: `-D clippy::if-same-then-else` implied by `-D warnings` error: this `if` has identical blocks --> $DIR/if_same_then_else2.rs:35:13 diff --git a/tests/ui/if_then_some_else_none.stderr b/tests/ui/if_then_some_else_none.stderr index c22ace30d2dc2..24e0b5947f19d 100644 --- a/tests/ui/if_then_some_else_none.stderr +++ b/tests/ui/if_then_some_else_none.stderr @@ -10,8 +10,8 @@ LL | | None LL | | }; | |_____^ | - = note: `-D clippy::if-then-some-else-none` implied by `-D warnings` = help: consider using `bool::then` like: `foo().then(|| { /* snippet */ "foo" })` + = note: `-D clippy::if-then-some-else-none` implied by `-D warnings` error: this could be simplified with `bool::then` --> $DIR/if_then_some_else_none.rs:14:13 diff --git a/tests/ui/ifs_same_cond.stderr b/tests/ui/ifs_same_cond.stderr index 0c8f49b8687f0..4113087327a28 100644 --- a/tests/ui/ifs_same_cond.stderr +++ b/tests/ui/ifs_same_cond.stderr @@ -4,12 +4,12 @@ error: this `if` has the same condition as a previous `if` LL | } else if b { | ^ | - = note: `-D clippy::ifs-same-cond` implied by `-D warnings` note: same as this --> $DIR/ifs_same_cond.rs:8:8 | LL | if b { | ^ + = note: `-D clippy::ifs-same-cond` implied by `-D warnings` error: this `if` has the same condition as a previous `if` --> $DIR/ifs_same_cond.rs:14:15 diff --git a/tests/ui/impl.stderr b/tests/ui/impl.stderr index 8703ecac93e89..e28b1bf0cdd94 100644 --- a/tests/ui/impl.stderr +++ b/tests/ui/impl.stderr @@ -6,7 +6,6 @@ LL | | fn second() {} LL | | } | |_^ | - = note: `-D clippy::multiple-inherent-impl` implied by `-D warnings` note: first implementation here --> $DIR/impl.rs:6:1 | @@ -14,6 +13,7 @@ LL | / impl MyStruct { LL | | fn first() {} LL | | } | |_^ + = note: `-D clippy::multiple-inherent-impl` implied by `-D warnings` error: multiple implementations of this structure --> $DIR/impl.rs:24:5 diff --git a/tests/ui/indexing_slicing_index.stderr b/tests/ui/indexing_slicing_index.stderr index 6ae700753f06d..a8d8b38163d0d 100644 --- a/tests/ui/indexing_slicing_index.stderr +++ b/tests/ui/indexing_slicing_index.stderr @@ -16,8 +16,8 @@ error: indexing may panic LL | x[index]; | ^^^^^^^^ | - = note: `-D clippy::indexing-slicing` implied by `-D warnings` = help: consider using `.get(n)` or `.get_mut(n)` instead + = note: `-D clippy::indexing-slicing` implied by `-D warnings` error: indexing may panic --> $DIR/indexing_slicing_index.rs:38:5 diff --git a/tests/ui/indexing_slicing_slice.stderr b/tests/ui/indexing_slicing_slice.stderr index f70722b92a5b8..dc54bd41365d3 100644 --- a/tests/ui/indexing_slicing_slice.stderr +++ b/tests/ui/indexing_slicing_slice.stderr @@ -4,8 +4,8 @@ error: slicing may panic LL | &x[index..]; | ^^^^^^^^^^ | - = note: `-D clippy::indexing-slicing` implied by `-D warnings` = help: consider using `.get(n..)` or .get_mut(n..)` instead + = note: `-D clippy::indexing-slicing` implied by `-D warnings` error: slicing may panic --> $DIR/indexing_slicing_slice.rs:13:6 diff --git a/tests/ui/inefficient_to_string.stderr b/tests/ui/inefficient_to_string.stderr index 1c0490ffa44cc..914dc92bfb65a 100644 --- a/tests/ui/inefficient_to_string.stderr +++ b/tests/ui/inefficient_to_string.stderr @@ -4,12 +4,12 @@ error: calling `to_string` on `&&str` LL | let _: String = rrstr.to_string(); | ^^^^^^^^^^^^^^^^^ help: try dereferencing the receiver: `(*rrstr).to_string()` | + = help: `&str` implements `ToString` through a slower blanket impl, but `str` has a fast specialization of `ToString` note: the lint level is defined here --> $DIR/inefficient_to_string.rs:2:9 | LL | #![deny(clippy::inefficient_to_string)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: `&str` implements `ToString` through a slower blanket impl, but `str` has a fast specialization of `ToString` error: calling `to_string` on `&&&str` --> $DIR/inefficient_to_string.rs:12:21 diff --git a/tests/ui/infinite_loop.stderr b/tests/ui/infinite_loop.stderr index 4ec7d900ade3d..85258b9d64f94 100644 --- a/tests/ui/infinite_loop.stderr +++ b/tests/ui/infinite_loop.stderr @@ -4,8 +4,8 @@ error: variables in the condition are not mutated in the loop body LL | while y < 10 { | ^^^^^^ | - = note: `#[deny(clippy::while_immutable_condition)]` on by default = note: this may lead to an infinite or to a never running loop + = note: `#[deny(clippy::while_immutable_condition)]` on by default error: variables in the condition are not mutated in the loop body --> $DIR/infinite_loop.rs:25:11 diff --git a/tests/ui/inherent_to_string.stderr b/tests/ui/inherent_to_string.stderr index 4f331f5bec9e6..443fecae1aadf 100644 --- a/tests/ui/inherent_to_string.stderr +++ b/tests/ui/inherent_to_string.stderr @@ -6,8 +6,8 @@ LL | | "A.to_string()".to_string() LL | | } | |_____^ | - = note: `-D clippy::inherent-to-string` implied by `-D warnings` = help: implement trait `Display` for type `A` instead + = note: `-D clippy::inherent-to-string` implied by `-D warnings` error: type `C` implements inherent method `to_string(&self) -> String` which shadows the implementation of `Display` --> $DIR/inherent_to_string.rs:44:5 @@ -17,12 +17,12 @@ LL | | "C.to_string()".to_string() LL | | } | |_____^ | + = help: remove the inherent method from type `C` note: the lint level is defined here --> $DIR/inherent_to_string.rs:2:9 | LL | #![deny(clippy::inherent_to_string_shadow_display)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: remove the inherent method from type `C` error: aborting due to 2 previous errors diff --git a/tests/ui/inspect_for_each.stderr b/tests/ui/inspect_for_each.stderr index 9f976bb74584e..67c2d5e53c78d 100644 --- a/tests/ui/inspect_for_each.stderr +++ b/tests/ui/inspect_for_each.stderr @@ -9,8 +9,8 @@ LL | | b.push(z); LL | | }); | |______^ | - = note: `-D clippy::inspect-for-each` implied by `-D warnings` = help: move the code from `inspect(..)` to `for_each(..)` and remove the `inspect(..)` + = note: `-D clippy::inspect-for-each` implied by `-D warnings` error: aborting due to previous error diff --git a/tests/ui/integer_division.stderr b/tests/ui/integer_division.stderr index cbb7f88142495..ca80012792075 100644 --- a/tests/ui/integer_division.stderr +++ b/tests/ui/integer_division.stderr @@ -4,8 +4,8 @@ error: integer division LL | let n = 1 / 2; | ^^^^^ | - = note: `-D clippy::integer-division` implied by `-D warnings` = help: division of integers may cause loss of precision. consider using floats + = note: `-D clippy::integer-division` implied by `-D warnings` error: integer division --> $DIR/integer_division.rs:6:13 diff --git a/tests/ui/issue_4266.stderr b/tests/ui/issue_4266.stderr index e5042aaa776b4..240f4bcc38fd5 100644 --- a/tests/ui/issue_4266.stderr +++ b/tests/ui/issue_4266.stderr @@ -18,8 +18,8 @@ error: methods called `new` usually take no `self` LL | pub async fn new(&mut self) -> Self { | ^^^^^^^^^ | - = note: `-D clippy::wrong-self-convention` implied by `-D warnings` = help: consider choosing a less ambiguous name + = note: `-D clippy::wrong-self-convention` implied by `-D warnings` error: aborting due to 3 previous errors diff --git a/tests/ui/iter_nth.stderr b/tests/ui/iter_nth.stderr index d00b2fb672bb6..a0fe353bcf75c 100644 --- a/tests/ui/iter_nth.stderr +++ b/tests/ui/iter_nth.stderr @@ -4,8 +4,8 @@ error: called `.iter().nth()` on a Vec LL | let bad_vec = some_vec.iter().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::iter-nth` implied by `-D warnings` = help: calling `.get()` is both faster and more readable + = note: `-D clippy::iter-nth` implied by `-D warnings` error: called `.iter().nth()` on a slice --> $DIR/iter_nth.rs:34:26 diff --git a/tests/ui/iter_skip_next_unfixable.stderr b/tests/ui/iter_skip_next_unfixable.stderr index 74c327c748361..4062706f94206 100644 --- a/tests/ui/iter_skip_next_unfixable.stderr +++ b/tests/ui/iter_skip_next_unfixable.stderr @@ -4,12 +4,12 @@ error: called `skip(..).next()` on an iterator LL | let _: Vec<&str> = sp.skip(1).next().unwrap().split(' ').collect(); | ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(1)` | - = note: `-D clippy::iter-skip-next` implied by `-D warnings` help: for this change `sp` has to be mutable --> $DIR/iter_skip_next_unfixable.rs:8:9 | LL | let sp = test_string.split('|').map(|s| s.trim()); | ^^ + = note: `-D clippy::iter-skip-next` implied by `-D warnings` error: called `skip(..).next()` on an iterator --> $DIR/iter_skip_next_unfixable.rs:11:29 diff --git a/tests/ui/large_stack_arrays.stderr b/tests/ui/large_stack_arrays.stderr index 0d91b65b42840..c7bf941ad0091 100644 --- a/tests/ui/large_stack_arrays.stderr +++ b/tests/ui/large_stack_arrays.stderr @@ -4,8 +4,8 @@ error: allocating a local array larger than 512000 bytes LL | [0u32; 20_000_000], | ^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::large-stack-arrays` implied by `-D warnings` = help: consider allocating on the heap with `vec![0u32; 20_000_000].into_boxed_slice()` + = note: `-D clippy::large-stack-arrays` implied by `-D warnings` error: allocating a local array larger than 512000 bytes --> $DIR/large_stack_arrays.rs:24:9 diff --git a/tests/ui/len_without_is_empty.stderr b/tests/ui/len_without_is_empty.stderr index a1f48f7610b44..8e890e2e2590e 100644 --- a/tests/ui/len_without_is_empty.stderr +++ b/tests/ui/len_without_is_empty.stderr @@ -92,8 +92,8 @@ error: this returns a `Result<_, ()>` LL | pub fn len(&self) -> Result { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::result-unit-err` implied by `-D warnings` = help: use a custom `Error` type instead + = note: `-D clippy::result-unit-err` implied by `-D warnings` error: this returns a `Result<_, ()>` --> $DIR/len_without_is_empty.rs:240:5 diff --git a/tests/ui/let_if_seq.stderr b/tests/ui/let_if_seq.stderr index 271ccce681c9f..f2e0edb6fbc30 100644 --- a/tests/ui/let_if_seq.stderr +++ b/tests/ui/let_if_seq.stderr @@ -7,8 +7,8 @@ LL | | foo = 42; LL | | } | |_____^ help: it is more idiomatic to write: `let foo = if f() { 42 } else { 0 };` | - = note: `-D clippy::useless-let-if-seq` implied by `-D warnings` = note: you might not need `mut` at all + = note: `-D clippy::useless-let-if-seq` implied by `-D warnings` error: `if _ { .. } else { .. }` is an expression --> $DIR/let_if_seq.rs:71:5 diff --git a/tests/ui/let_underscore_drop.stderr b/tests/ui/let_underscore_drop.stderr index ee7bbe995f168..324b7cd431d46 100644 --- a/tests/ui/let_underscore_drop.stderr +++ b/tests/ui/let_underscore_drop.stderr @@ -4,8 +4,8 @@ error: non-binding `let` on a type that implements `Drop` LL | let _ = Box::new(()); | ^^^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::let-underscore-drop` implied by `-D warnings` = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + = note: `-D clippy::let-underscore-drop` implied by `-D warnings` error: non-binding `let` on a type that implements `Drop` --> $DIR/let_underscore_drop.rs:18:5 diff --git a/tests/ui/let_underscore_lock.stderr b/tests/ui/let_underscore_lock.stderr index 4365b48fabb9c..d7779e7b6c48a 100644 --- a/tests/ui/let_underscore_lock.stderr +++ b/tests/ui/let_underscore_lock.stderr @@ -4,8 +4,8 @@ error: non-binding let on a synchronization lock LL | let _ = m.lock(); | ^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::let-underscore-lock` implied by `-D warnings` = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + = note: `-D clippy::let-underscore-lock` implied by `-D warnings` error: non-binding let on a synchronization lock --> $DIR/let_underscore_lock.rs:10:5 diff --git a/tests/ui/let_underscore_must_use.stderr b/tests/ui/let_underscore_must_use.stderr index 5b751ea56deff..bae60f2ff9b79 100644 --- a/tests/ui/let_underscore_must_use.stderr +++ b/tests/ui/let_underscore_must_use.stderr @@ -4,8 +4,8 @@ error: non-binding let on a result of a `#[must_use]` function LL | let _ = f(); | ^^^^^^^^^^^^ | - = note: `-D clippy::let-underscore-must-use` implied by `-D warnings` = help: consider explicitly using function result + = note: `-D clippy::let-underscore-must-use` implied by `-D warnings` error: non-binding let on an expression with `#[must_use]` type --> $DIR/let_underscore_must_use.rs:68:5 diff --git a/tests/ui/linkedlist.stderr b/tests/ui/linkedlist.stderr index 51327df132118..c76c949613129 100644 --- a/tests/ui/linkedlist.stderr +++ b/tests/ui/linkedlist.stderr @@ -4,8 +4,8 @@ error: you seem to be using a `LinkedList`! Perhaps you meant some other data st LL | const C: LinkedList = LinkedList::new(); | ^^^^^^^^^^^^^^^ | - = note: `-D clippy::linkedlist` implied by `-D warnings` = help: a `VecDeque` might work + = note: `-D clippy::linkedlist` implied by `-D warnings` error: you seem to be using a `LinkedList`! Perhaps you meant some other data structure? --> $DIR/linkedlist.rs:9:11 diff --git a/tests/ui/manual_find.stderr b/tests/ui/manual_find.stderr index da0fd4aaef7d6..ea04bb066e61d 100644 --- a/tests/ui/manual_find.stderr +++ b/tests/ui/manual_find.stderr @@ -9,8 +9,8 @@ LL | | } LL | | None | |________^ help: replace with an iterator: `strings.into_iter().find(|s| s == String::new())` | - = note: `-D clippy::manual-find` implied by `-D warnings` = note: you may need to dereference some variables + = note: `-D clippy::manual-find` implied by `-D warnings` error: manual implementation of `Iterator::find` --> $DIR/manual_find.rs:14:5 diff --git a/tests/ui/manual_flatten.stderr b/tests/ui/manual_flatten.stderr index da053c0566833..180a6ff4e9a73 100644 --- a/tests/ui/manual_flatten.stderr +++ b/tests/ui/manual_flatten.stderr @@ -11,7 +11,6 @@ LL | | } LL | | } | |_____^ | - = note: `-D clippy::manual-flatten` implied by `-D warnings` help: ...and remove the `if let` statement in the for loop --> $DIR/manual_flatten.rs:8:9 | @@ -19,6 +18,7 @@ LL | / if let Some(y) = n { LL | | println!("{}", y); LL | | } | |_________^ + = note: `-D clippy::manual-flatten` implied by `-D warnings` error: unnecessary `if let` since only the `Ok` variant of the iterator element is used --> $DIR/manual_flatten.rs:15:5 diff --git a/tests/ui/manual_non_exhaustive_enum.stderr b/tests/ui/manual_non_exhaustive_enum.stderr index 144fe86df554b..087f766be70d2 100644 --- a/tests/ui/manual_non_exhaustive_enum.stderr +++ b/tests/ui/manual_non_exhaustive_enum.stderr @@ -13,12 +13,12 @@ LL | | _C, LL | | } | |_^ | - = note: `-D clippy::manual-non-exhaustive` implied by `-D warnings` help: remove this variant --> $DIR/manual_non_exhaustive_enum.rs:9:5 | LL | _C, | ^^ + = note: `-D clippy::manual-non-exhaustive` implied by `-D warnings` error: this seems like a manual implementation of the non-exhaustive pattern --> $DIR/manual_non_exhaustive_enum.rs:14:1 diff --git a/tests/ui/manual_non_exhaustive_struct.stderr b/tests/ui/manual_non_exhaustive_struct.stderr index e0766c17b7580..d0bed8e11211a 100644 --- a/tests/ui/manual_non_exhaustive_struct.stderr +++ b/tests/ui/manual_non_exhaustive_struct.stderr @@ -12,12 +12,12 @@ LL | | _c: (), LL | | } | |_____^ | - = note: `-D clippy::manual-non-exhaustive` implied by `-D warnings` help: remove this field --> $DIR/manual_non_exhaustive_struct.rs:8:9 | LL | _c: (), | ^^^^^^ + = note: `-D clippy::manual-non-exhaustive` implied by `-D warnings` error: this seems like a manual implementation of the non-exhaustive pattern --> $DIR/manual_non_exhaustive_struct.rs:13:5 diff --git a/tests/ui/manual_strip.stderr b/tests/ui/manual_strip.stderr index 896edf2ae516d..2191ccb85dd5d 100644 --- a/tests/ui/manual_strip.stderr +++ b/tests/ui/manual_strip.stderr @@ -4,12 +4,12 @@ error: stripping a prefix manually LL | str::to_string(&s["ab".len()..]); | ^^^^^^^^^^^^^^^^ | - = note: `-D clippy::manual-strip` implied by `-D warnings` note: the prefix was tested here --> $DIR/manual_strip.rs:6:5 | LL | if s.starts_with("ab") { | ^^^^^^^^^^^^^^^^^^^^^^^ + = note: `-D clippy::manual-strip` implied by `-D warnings` help: try using the `strip_prefix` method | LL ~ if let Some() = s.strip_prefix("ab") { diff --git a/tests/ui/map_err.stderr b/tests/ui/map_err.stderr index c035840521e49..d44403a84a564 100644 --- a/tests/ui/map_err.stderr +++ b/tests/ui/map_err.stderr @@ -4,8 +4,8 @@ error: `map_err(|_|...` wildcard pattern discards the original error LL | println!("{:?}", x.map_err(|_| Errors::Ignored)); | ^^^ | - = note: `-D clippy::map-err-ignore` implied by `-D warnings` = help: consider storing the original error as a source in the new error, or silence this warning using an ignored identifier (`.map_err(|_foo| ...`) + = note: `-D clippy::map-err-ignore` implied by `-D warnings` error: aborting due to previous error diff --git a/tests/ui/match_overlapping_arm.stderr b/tests/ui/match_overlapping_arm.stderr index b81bb1ecfae02..a72becbeb669b 100644 --- a/tests/ui/match_overlapping_arm.stderr +++ b/tests/ui/match_overlapping_arm.stderr @@ -4,12 +4,12 @@ error: some ranges overlap LL | 0..=10 => println!("0..=10"), | ^^^^^^ | - = note: `-D clippy::match-overlapping-arm` implied by `-D warnings` note: overlaps with this --> $DIR/match_overlapping_arm.rs:14:9 | LL | 0..=11 => println!("0..=11"), | ^^^^^^ + = note: `-D clippy::match-overlapping-arm` implied by `-D warnings` error: some ranges overlap --> $DIR/match_overlapping_arm.rs:19:9 diff --git a/tests/ui/match_same_arms.stderr b/tests/ui/match_same_arms.stderr index b6d04263b37a3..db85b5964e842 100644 --- a/tests/ui/match_same_arms.stderr +++ b/tests/ui/match_same_arms.stderr @@ -4,13 +4,13 @@ error: this match arm has an identical body to the `_` wildcard arm LL | Abc::A => 0, | ^^^^^^^^^^^ help: try removing the arm | - = note: `-D clippy::match-same-arms` implied by `-D warnings` = help: or try changing either arm body note: `_` wildcard arm here --> $DIR/match_same_arms.rs:13:9 | LL | _ => 0, //~ ERROR match arms have same body | ^^^^^^ + = note: `-D clippy::match-same-arms` implied by `-D warnings` error: this match arm has an identical body to another arm --> $DIR/match_same_arms.rs:17:9 diff --git a/tests/ui/match_same_arms2.stderr b/tests/ui/match_same_arms2.stderr index 14a672ba2fec1..b260155d21890 100644 --- a/tests/ui/match_same_arms2.stderr +++ b/tests/ui/match_same_arms2.stderr @@ -10,7 +10,6 @@ LL | | a LL | | }, | |_________^ help: try removing the arm | - = note: `-D clippy::match-same-arms` implied by `-D warnings` = help: or try changing either arm body note: `_` wildcard arm here --> $DIR/match_same_arms2.rs:20:9 @@ -23,6 +22,7 @@ LL | | let mut a = 42 + [23].len() as i32; LL | | a LL | | }, | |_________^ + = note: `-D clippy::match-same-arms` implied by `-D warnings` error: this match arm has an identical body to another arm --> $DIR/match_same_arms2.rs:34:9 diff --git a/tests/ui/match_wild_err_arm.edition2018.stderr b/tests/ui/match_wild_err_arm.edition2018.stderr index 2d66daea8046e..525533bf07bb0 100644 --- a/tests/ui/match_wild_err_arm.edition2018.stderr +++ b/tests/ui/match_wild_err_arm.edition2018.stderr @@ -4,8 +4,8 @@ error: `Err(_)` matches all errors LL | Err(_) => panic!("err"), | ^^^^^^ | - = note: `-D clippy::match-wild-err-arm` implied by `-D warnings` = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable + = note: `-D clippy::match-wild-err-arm` implied by `-D warnings` error: `Err(_)` matches all errors --> $DIR/match_wild_err_arm.rs:20:9 diff --git a/tests/ui/match_wild_err_arm.edition2021.stderr b/tests/ui/match_wild_err_arm.edition2021.stderr index 2d66daea8046e..525533bf07bb0 100644 --- a/tests/ui/match_wild_err_arm.edition2021.stderr +++ b/tests/ui/match_wild_err_arm.edition2021.stderr @@ -4,8 +4,8 @@ error: `Err(_)` matches all errors LL | Err(_) => panic!("err"), | ^^^^^^ | - = note: `-D clippy::match-wild-err-arm` implied by `-D warnings` = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable + = note: `-D clippy::match-wild-err-arm` implied by `-D warnings` error: `Err(_)` matches all errors --> $DIR/match_wild_err_arm.rs:20:9 diff --git a/tests/ui/min_rust_version_attr.stderr b/tests/ui/min_rust_version_attr.stderr index b1c23b539ffde..6e749d2741c46 100644 --- a/tests/ui/min_rust_version_attr.stderr +++ b/tests/ui/min_rust_version_attr.stderr @@ -4,12 +4,12 @@ error: stripping a prefix manually LL | assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!"); | ^^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::manual-strip` implied by `-D warnings` note: the prefix was tested here --> $DIR/min_rust_version_attr.rs:203:9 | LL | if s.starts_with("hello, ") { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `-D clippy::manual-strip` implied by `-D warnings` help: try using the `strip_prefix` method | LL ~ if let Some() = s.strip_prefix("hello, ") { diff --git a/tests/ui/mismatched_target_os_unix.stderr b/tests/ui/mismatched_target_os_unix.stderr index 3534b53282f9b..9822c77c9dfea 100644 --- a/tests/ui/mismatched_target_os_unix.stderr +++ b/tests/ui/mismatched_target_os_unix.stderr @@ -6,8 +6,8 @@ LL | #[cfg(linux)] | | | help: try: `target_os = "linux"` | - = note: `-D clippy::mismatched-target-os` implied by `-D warnings` = help: did you mean `unix`? + = note: `-D clippy::mismatched-target-os` implied by `-D warnings` error: operating system used in target family position --> $DIR/mismatched_target_os_unix.rs:9:1 diff --git a/tests/ui/mismatching_type_param_order.stderr b/tests/ui/mismatching_type_param_order.stderr index cb720256c50e5..204d499055774 100644 --- a/tests/ui/mismatching_type_param_order.stderr +++ b/tests/ui/mismatching_type_param_order.stderr @@ -4,8 +4,8 @@ error: `Foo` has a similarly named generic type parameter `B` in its declaration LL | impl Foo {} | ^ | - = note: `-D clippy::mismatching-type-param-order` implied by `-D warnings` = help: try `A`, or a name that does not conflict with `Foo`'s generic params + = note: `-D clippy::mismatching-type-param-order` implied by `-D warnings` error: `Foo` has a similarly named generic type parameter `A` in its declaration, but in a different order --> $DIR/mismatching_type_param_order.rs:11:23 diff --git a/tests/ui/missing_panics_doc.stderr b/tests/ui/missing_panics_doc.stderr index 91ebd695238bb..c9ded7f1ad03e 100644 --- a/tests/ui/missing_panics_doc.stderr +++ b/tests/ui/missing_panics_doc.stderr @@ -7,12 +7,12 @@ LL | | result.unwrap() LL | | } | |_^ | - = note: `-D clippy::missing-panics-doc` implied by `-D warnings` note: first possible panic found here --> $DIR/missing_panics_doc.rs:8:5 | LL | result.unwrap() | ^^^^^^^^^^^^^^^ + = note: `-D clippy::missing-panics-doc` implied by `-D warnings` error: docs for function which may panic missing `# Panics` section --> $DIR/missing_panics_doc.rs:12:1 diff --git a/tests/ui/mixed_read_write_in_expression.stderr b/tests/ui/mixed_read_write_in_expression.stderr index 2e951cdbcbfd7..8cc68b0ac7b43 100644 --- a/tests/ui/mixed_read_write_in_expression.stderr +++ b/tests/ui/mixed_read_write_in_expression.stderr @@ -4,12 +4,12 @@ error: unsequenced read of `x` LL | } + x; | ^ | - = note: `-D clippy::mixed-read-write-in-expression` implied by `-D warnings` note: whether read occurs before this write depends on evaluation order --> $DIR/mixed_read_write_in_expression.rs:12:9 | LL | x = 1; | ^^^^^ + = note: `-D clippy::mixed-read-write-in-expression` implied by `-D warnings` error: unsequenced read of `x` --> $DIR/mixed_read_write_in_expression.rs:17:5 diff --git a/tests/ui/modulo_arithmetic_float.stderr b/tests/ui/modulo_arithmetic_float.stderr index 97844aaaa7598..36106de31f0bc 100644 --- a/tests/ui/modulo_arithmetic_float.stderr +++ b/tests/ui/modulo_arithmetic_float.stderr @@ -4,8 +4,8 @@ error: you are using modulo operator on constants with different signs: `-1.600 LL | -1.6 % 2.1; | ^^^^^^^^^^ | - = note: `-D clippy::modulo-arithmetic` implied by `-D warnings` = note: double check for expected result especially when interoperating with different languages + = note: `-D clippy::modulo-arithmetic` implied by `-D warnings` error: you are using modulo operator on constants with different signs: `1.600 % -2.100` --> $DIR/modulo_arithmetic_float.rs:7:5 diff --git a/tests/ui/modulo_arithmetic_integral.stderr b/tests/ui/modulo_arithmetic_integral.stderr index f71adf5b0d014..9ff676ff6bcb1 100644 --- a/tests/ui/modulo_arithmetic_integral.stderr +++ b/tests/ui/modulo_arithmetic_integral.stderr @@ -4,9 +4,9 @@ error: you are using modulo operator on types that might have different signs LL | a % b; | ^^^^^ | - = note: `-D clippy::modulo-arithmetic` implied by `-D warnings` = note: double check for expected result especially when interoperating with different languages = note: or consider using `rem_euclid` or similar function + = note: `-D clippy::modulo-arithmetic` implied by `-D warnings` error: you are using modulo operator on types that might have different signs --> $DIR/modulo_arithmetic_integral.rs:9:5 diff --git a/tests/ui/modulo_arithmetic_integral_const.stderr b/tests/ui/modulo_arithmetic_integral_const.stderr index 11b5f77461ba2..1453d44f488f3 100644 --- a/tests/ui/modulo_arithmetic_integral_const.stderr +++ b/tests/ui/modulo_arithmetic_integral_const.stderr @@ -4,9 +4,9 @@ error: you are using modulo operator on constants with different signs: `-1 % 2` LL | -1 % 2; | ^^^^^^ | - = note: `-D clippy::modulo-arithmetic` implied by `-D warnings` = note: double check for expected result especially when interoperating with different languages = note: or consider using `rem_euclid` or similar function + = note: `-D clippy::modulo-arithmetic` implied by `-D warnings` error: you are using modulo operator on constants with different signs: `1 % -2` --> $DIR/modulo_arithmetic_integral_const.rs:12:5 diff --git a/tests/ui/mut_from_ref.stderr b/tests/ui/mut_from_ref.stderr index b76d6a13ffb9c..c20ff54bf949b 100644 --- a/tests/ui/mut_from_ref.stderr +++ b/tests/ui/mut_from_ref.stderr @@ -4,12 +4,12 @@ error: mutable borrow from immutable input(s) LL | fn this_wont_hurt_a_bit(&self) -> &mut Foo { | ^^^^^^^^ | - = note: `-D clippy::mut-from-ref` implied by `-D warnings` note: immutable borrow here --> $DIR/mut_from_ref.rs:7:29 | LL | fn this_wont_hurt_a_bit(&self) -> &mut Foo { | ^^^^^ + = note: `-D clippy::mut-from-ref` implied by `-D warnings` error: mutable borrow from immutable input(s) --> $DIR/mut_from_ref.rs:13:25 diff --git a/tests/ui/mut_range_bound.stderr b/tests/ui/mut_range_bound.stderr index 4b5a3fc1e418c..e0c8dced382ef 100644 --- a/tests/ui/mut_range_bound.stderr +++ b/tests/ui/mut_range_bound.stderr @@ -4,8 +4,8 @@ error: attempt to mutate range bound within loop LL | m = 5; | ^ | - = note: `-D clippy::mut-range-bound` implied by `-D warnings` = note: the range of the loop is unchanged + = note: `-D clippy::mut-range-bound` implied by `-D warnings` error: attempt to mutate range bound within loop --> $DIR/mut_range_bound.rs:15:9 diff --git a/tests/ui/needless_continue.stderr b/tests/ui/needless_continue.stderr index b8657c74caa69..005ba010f34f7 100644 --- a/tests/ui/needless_continue.stderr +++ b/tests/ui/needless_continue.stderr @@ -7,7 +7,6 @@ LL | | continue; LL | | } | |_________^ | - = note: `-D clippy::needless-continue` implied by `-D warnings` = help: consider dropping the `else` clause and merging the code that follows (in the loop) with the `if` block if i % 2 == 0 && i % 3 == 0 { println!("{}", i); @@ -33,6 +32,7 @@ LL | | } } println!("bleh"); } + = note: `-D clippy::needless-continue` implied by `-D warnings` error: there is no need for an explicit `else` block for this `if` expression --> $DIR/needless_continue.rs:44:9 diff --git a/tests/ui/non_send_fields_in_send_ty.stderr b/tests/ui/non_send_fields_in_send_ty.stderr index b6c904a147a5f..e912b59a6e7b0 100644 --- a/tests/ui/non_send_fields_in_send_ty.stderr +++ b/tests/ui/non_send_fields_in_send_ty.stderr @@ -4,13 +4,13 @@ error: some fields in `RingBuffer` are not safe to be sent to another thread LL | unsafe impl Send for RingBuffer {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::non-send-fields-in-send-ty` implied by `-D warnings` note: it is not safe to send field `data` to another thread --> $DIR/non_send_fields_in_send_ty.rs:12:5 | LL | data: Vec>, | ^^^^^^^^^^^^^^^^^^^^^^^^ = help: add bounds on type parameter `T` that satisfy `Vec>: Send` + = note: `-D clippy::non-send-fields-in-send-ty` implied by `-D warnings` error: some fields in `MvccRwLock` are not safe to be sent to another thread --> $DIR/non_send_fields_in_send_ty.rs:25:1 diff --git a/tests/ui/octal_escapes.stderr b/tests/ui/octal_escapes.stderr index 54f5bbb0fc43a..295dc1798e36d 100644 --- a/tests/ui/octal_escapes.stderr +++ b/tests/ui/octal_escapes.stderr @@ -4,8 +4,8 @@ error: octal-looking escape in string literal LL | let _bad1 = "/033[0m"; | ^^^^^^^^^ | - = note: `-D clippy::octal-escapes` implied by `-D warnings` = help: octal escapes are not supported, `/0` is always a null character + = note: `-D clippy::octal-escapes` implied by `-D warnings` help: if an octal escape was intended, use the hexadecimal representation instead | LL | let _bad1 = "/x1b[0m"; diff --git a/tests/ui/ok_expect.stderr b/tests/ui/ok_expect.stderr index b02b28e7f68c8..6c40adbb53dc2 100644 --- a/tests/ui/ok_expect.stderr +++ b/tests/ui/ok_expect.stderr @@ -4,8 +4,8 @@ error: called `ok().expect()` on a `Result` value LL | res.ok().expect("disaster!"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::ok-expect` implied by `-D warnings` = help: you can call `expect()` directly on the `Result` + = note: `-D clippy::ok-expect` implied by `-D warnings` error: called `ok().expect()` on a `Result` value --> $DIR/ok_expect.rs:20:5 diff --git a/tests/ui/only_used_in_recursion.stderr b/tests/ui/only_used_in_recursion.stderr index 74057ddcfda4c..571e5c4b5faa9 100644 --- a/tests/ui/only_used_in_recursion.stderr +++ b/tests/ui/only_used_in_recursion.stderr @@ -4,12 +4,12 @@ error: parameter is only used in recursion LL | fn _one_unused(flag: u32, a: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_a` | - = note: `-D clippy::only-used-in-recursion` implied by `-D warnings` note: parameter used here --> $DIR/only_used_in_recursion.rs:12:53 | LL | if flag == 0 { 0 } else { _one_unused(flag - 1, a) } | ^ + = note: `-D clippy::only-used-in-recursion` implied by `-D warnings` error: parameter is only used in recursion --> $DIR/only_used_in_recursion.rs:15:27 diff --git a/tests/ui/only_used_in_recursion2.stderr b/tests/ui/only_used_in_recursion2.stderr index 23f6ffd30c976..8dcbfdd612ef2 100644 --- a/tests/ui/only_used_in_recursion2.stderr +++ b/tests/ui/only_used_in_recursion2.stderr @@ -4,12 +4,12 @@ error: parameter is only used in recursion LL | fn _with_inner(flag: u32, a: u32, b: u32) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_b` | - = note: `-D clippy::only-used-in-recursion` implied by `-D warnings` note: parameter used here --> $DIR/only_used_in_recursion2.rs:9:52 | LL | if flag == 0 { 0 } else { _with_inner(flag, a, b + x) } | ^ + = note: `-D clippy::only-used-in-recursion` implied by `-D warnings` error: parameter is only used in recursion --> $DIR/only_used_in_recursion2.rs:4:25 diff --git a/tests/ui/option_env_unwrap.stderr b/tests/ui/option_env_unwrap.stderr index 885ac096cc8f7..bc188a07e9e0a 100644 --- a/tests/ui/option_env_unwrap.stderr +++ b/tests/ui/option_env_unwrap.stderr @@ -4,8 +4,8 @@ error: this will panic at run-time if the environment variable doesn't exist at LL | let _ = option_env!("PATH").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::option-env-unwrap` implied by `-D warnings` = help: consider using the `env!` macro instead + = note: `-D clippy::option-env-unwrap` implied by `-D warnings` error: this will panic at run-time if the environment variable doesn't exist at compile-time --> $DIR/option_env_unwrap.rs:19:13 diff --git a/tests/ui/overly_complex_bool_expr.stderr b/tests/ui/overly_complex_bool_expr.stderr index 158cae8b8f373..e989f2ece3080 100644 --- a/tests/ui/overly_complex_bool_expr.stderr +++ b/tests/ui/overly_complex_bool_expr.stderr @@ -4,12 +4,12 @@ error: this boolean expression contains a logic bug LL | let _ = a && b || a; | ^^^^^^^^^^^ help: it would look like the following: `a` | - = note: `-D clippy::overly-complex-bool-expr` implied by `-D warnings` help: this expression can be optimized out by applying boolean operations to the outer expression --> $DIR/overly_complex_bool_expr.rs:11:18 | LL | let _ = a && b || a; | ^ + = note: `-D clippy::overly-complex-bool-expr` implied by `-D warnings` error: this boolean expression contains a logic bug --> $DIR/overly_complex_bool_expr.rs:13:13 diff --git a/tests/ui/panic_in_result_fn.stderr b/tests/ui/panic_in_result_fn.stderr index 561503ae54fa2..97787bc84e2c5 100644 --- a/tests/ui/panic_in_result_fn.stderr +++ b/tests/ui/panic_in_result_fn.stderr @@ -7,13 +7,13 @@ LL | | panic!("error"); LL | | } | |_____^ | - = note: `-D clippy::panic-in-result-fn` implied by `-D warnings` = help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing note: return Err() instead of panicking --> $DIR/panic_in_result_fn.rs:8:9 | LL | panic!("error"); | ^^^^^^^^^^^^^^^ + = note: `-D clippy::panic-in-result-fn` implied by `-D warnings` error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result` --> $DIR/panic_in_result_fn.rs:11:5 diff --git a/tests/ui/panic_in_result_fn_assertions.stderr b/tests/ui/panic_in_result_fn_assertions.stderr index b6aa005e7b521..eb0aacbb6a441 100644 --- a/tests/ui/panic_in_result_fn_assertions.stderr +++ b/tests/ui/panic_in_result_fn_assertions.stderr @@ -8,13 +8,13 @@ LL | | Ok(true) LL | | } | |_____^ | - = note: `-D clippy::panic-in-result-fn` implied by `-D warnings` = help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing note: return Err() instead of panicking --> $DIR/panic_in_result_fn_assertions.rs:9:9 | LL | assert!(x == 5, "wrong argument"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `-D clippy::panic-in-result-fn` implied by `-D warnings` error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result` --> $DIR/panic_in_result_fn_assertions.rs:13:5 diff --git a/tests/ui/pattern_type_mismatch/mutability.stderr b/tests/ui/pattern_type_mismatch/mutability.stderr index 3421d568365cc..87fb243b65efd 100644 --- a/tests/ui/pattern_type_mismatch/mutability.stderr +++ b/tests/ui/pattern_type_mismatch/mutability.stderr @@ -4,8 +4,8 @@ error: type of pattern does not match the expression type LL | Some(_) => (), | ^^^^^^^ | - = note: `-D clippy::pattern-type-mismatch` implied by `-D warnings` = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings + = note: `-D clippy::pattern-type-mismatch` implied by `-D warnings` error: type of pattern does not match the expression type --> $DIR/mutability.rs:15:9 diff --git a/tests/ui/pattern_type_mismatch/pattern_alternatives.stderr b/tests/ui/pattern_type_mismatch/pattern_alternatives.stderr index d285c93782c67..a91b5ac6cf742 100644 --- a/tests/ui/pattern_type_mismatch/pattern_alternatives.stderr +++ b/tests/ui/pattern_type_mismatch/pattern_alternatives.stderr @@ -4,8 +4,8 @@ error: type of pattern does not match the expression type LL | if let Value::B | Value::A(_) = ref_value {} | ^^^^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::pattern-type-mismatch` implied by `-D warnings` = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings + = note: `-D clippy::pattern-type-mismatch` implied by `-D warnings` error: type of pattern does not match the expression type --> $DIR/pattern_alternatives.rs:16:34 diff --git a/tests/ui/pattern_type_mismatch/pattern_structs.stderr b/tests/ui/pattern_type_mismatch/pattern_structs.stderr index d428e85b0c914..8bc5c63baab5b 100644 --- a/tests/ui/pattern_type_mismatch/pattern_structs.stderr +++ b/tests/ui/pattern_type_mismatch/pattern_structs.stderr @@ -4,8 +4,8 @@ error: type of pattern does not match the expression type LL | let Struct { .. } = ref_value; | ^^^^^^^^^^^^^ | - = note: `-D clippy::pattern-type-mismatch` implied by `-D warnings` = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings + = note: `-D clippy::pattern-type-mismatch` implied by `-D warnings` error: type of pattern does not match the expression type --> $DIR/pattern_structs.rs:14:33 diff --git a/tests/ui/pattern_type_mismatch/pattern_tuples.stderr b/tests/ui/pattern_type_mismatch/pattern_tuples.stderr index edd0074d00d3b..a1ef540d28313 100644 --- a/tests/ui/pattern_type_mismatch/pattern_tuples.stderr +++ b/tests/ui/pattern_type_mismatch/pattern_tuples.stderr @@ -4,8 +4,8 @@ error: type of pattern does not match the expression type LL | let TupleStruct(_) = ref_value; | ^^^^^^^^^^^^^^ | - = note: `-D clippy::pattern-type-mismatch` implied by `-D warnings` = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings + = note: `-D clippy::pattern-type-mismatch` implied by `-D warnings` error: type of pattern does not match the expression type --> $DIR/pattern_tuples.rs:12:25 diff --git a/tests/ui/pattern_type_mismatch/syntax.stderr b/tests/ui/pattern_type_mismatch/syntax.stderr index 12b3d3a8bd075..f56a3a893801b 100644 --- a/tests/ui/pattern_type_mismatch/syntax.stderr +++ b/tests/ui/pattern_type_mismatch/syntax.stderr @@ -4,8 +4,8 @@ error: type of pattern does not match the expression type LL | Some(_) => (), | ^^^^^^^ | - = note: `-D clippy::pattern-type-mismatch` implied by `-D warnings` = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings + = note: `-D clippy::pattern-type-mismatch` implied by `-D warnings` error: type of pattern does not match the expression type --> $DIR/syntax.rs:30:12 diff --git a/tests/ui/proc_macro.stderr b/tests/ui/proc_macro.stderr index 48fd58c9a4933..c795f6ad0d25f 100644 --- a/tests/ui/proc_macro.stderr +++ b/tests/ui/proc_macro.stderr @@ -4,8 +4,8 @@ error: approximate value of `f{32, 64}::consts::PI` found LL | let _x = 3.14; | ^^^^ | - = note: `#[deny(clippy::approx_constant)]` on by default = help: consider using the constant directly + = note: `#[deny(clippy::approx_constant)]` on by default error: aborting due to previous error diff --git a/tests/ui/pub_use.stderr b/tests/ui/pub_use.stderr index 9ab710df818ca..ba4ee732c05c4 100644 --- a/tests/ui/pub_use.stderr +++ b/tests/ui/pub_use.stderr @@ -4,8 +4,8 @@ error: using `pub use` LL | pub use inner::Test; | ^^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::pub-use` implied by `-D warnings` = help: move the exported item to a public module instead + = note: `-D clippy::pub-use` implied by `-D warnings` error: aborting due to previous error diff --git a/tests/ui/rc_clone_in_vec_init/arc.stderr b/tests/ui/rc_clone_in_vec_init/arc.stderr index cd7d91e120650..7814f5b54036b 100644 --- a/tests/ui/rc_clone_in_vec_init/arc.stderr +++ b/tests/ui/rc_clone_in_vec_init/arc.stderr @@ -4,8 +4,8 @@ error: initializing a reference-counted pointer in `vec![elem; len]` LL | let v = vec![Arc::new("x".to_string()); 2]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::rc-clone-in-vec-init` implied by `-D warnings` = note: each element will point to the same `Arc` instance + = note: `-D clippy::rc-clone-in-vec-init` implied by `-D warnings` help: consider initializing each `Arc` element individually | LL ~ let v = { diff --git a/tests/ui/rc_clone_in_vec_init/rc.stderr b/tests/ui/rc_clone_in_vec_init/rc.stderr index fe861afe05491..80deb7cb9f24d 100644 --- a/tests/ui/rc_clone_in_vec_init/rc.stderr +++ b/tests/ui/rc_clone_in_vec_init/rc.stderr @@ -4,8 +4,8 @@ error: initializing a reference-counted pointer in `vec![elem; len]` LL | let v = vec![Rc::new("x".to_string()); 2]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::rc-clone-in-vec-init` implied by `-D warnings` = note: each element will point to the same `Rc` instance + = note: `-D clippy::rc-clone-in-vec-init` implied by `-D warnings` help: consider initializing each `Rc` element individually | LL ~ let v = { diff --git a/tests/ui/rc_clone_in_vec_init/weak.stderr b/tests/ui/rc_clone_in_vec_init/weak.stderr index 4a21946ccdfa8..789e14a302f6f 100644 --- a/tests/ui/rc_clone_in_vec_init/weak.stderr +++ b/tests/ui/rc_clone_in_vec_init/weak.stderr @@ -4,8 +4,8 @@ error: initializing a reference-counted pointer in `vec![elem; len]` LL | let v = vec![SyncWeak::::new(); 2]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::rc-clone-in-vec-init` implied by `-D warnings` = note: each element will point to the same `Weak` instance + = note: `-D clippy::rc-clone-in-vec-init` implied by `-D warnings` help: consider initializing each `Weak` element individually | LL ~ let v = { diff --git a/tests/ui/rc_mutex.stderr b/tests/ui/rc_mutex.stderr index fe84361d78162..cee3bd8b224dc 100644 --- a/tests/ui/rc_mutex.stderr +++ b/tests/ui/rc_mutex.stderr @@ -4,8 +4,8 @@ error: usage of `Rc>` LL | foo: Rc>, | ^^^^^^^^^^^^^^ | - = note: `-D clippy::rc-mutex` implied by `-D warnings` = help: consider using `Rc>` or `Arc>` instead + = note: `-D clippy::rc-mutex` implied by `-D warnings` error: usage of `Rc>` --> $DIR/rc_mutex.rs:26:18 diff --git a/tests/ui/redundant_allocation.stderr b/tests/ui/redundant_allocation.stderr index 54d4d88dba819..e0826fefa6cfb 100644 --- a/tests/ui/redundant_allocation.stderr +++ b/tests/ui/redundant_allocation.stderr @@ -4,9 +4,9 @@ error: usage of `Box>` LL | pub fn box_test6(foo: Box>) {} | ^^^^^^^^^^ | - = note: `-D clippy::redundant-allocation` implied by `-D warnings` = note: `Rc` is already on the heap, `Box>` makes an extra allocation = help: consider using just `Box` or `Rc` + = note: `-D clippy::redundant-allocation` implied by `-D warnings` error: usage of `Box>` --> $DIR/redundant_allocation.rs:19:30 diff --git a/tests/ui/redundant_allocation_fixable.stderr b/tests/ui/redundant_allocation_fixable.stderr index fdd76ef17a55e..8dd4a6a268749 100644 --- a/tests/ui/redundant_allocation_fixable.stderr +++ b/tests/ui/redundant_allocation_fixable.stderr @@ -4,8 +4,8 @@ error: usage of `Box<&T>` LL | pub fn box_test1(foo: Box<&T>) {} | ^^^^^^^ help: try: `&T` | - = note: `-D clippy::redundant-allocation` implied by `-D warnings` = note: `&T` is already a pointer, `Box<&T>` allocates a pointer on the heap + = note: `-D clippy::redundant-allocation` implied by `-D warnings` error: usage of `Box<&MyStruct>` --> $DIR/redundant_allocation_fixable.rs:28:27 diff --git a/tests/ui/redundant_clone.stderr b/tests/ui/redundant_clone.stderr index aa1dd7cbb45cd..782590034d051 100644 --- a/tests/ui/redundant_clone.stderr +++ b/tests/ui/redundant_clone.stderr @@ -4,12 +4,12 @@ error: redundant clone LL | let _s = ["lorem", "ipsum"].join(" ").to_string(); | ^^^^^^^^^^^^ help: remove this | - = note: `-D clippy::redundant-clone` implied by `-D warnings` note: this value is dropped without further use --> $DIR/redundant_clone.rs:10:14 | LL | let _s = ["lorem", "ipsum"].join(" ").to_string(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `-D clippy::redundant-clone` implied by `-D warnings` error: redundant clone --> $DIR/redundant_clone.rs:13:15 diff --git a/tests/ui/redundant_else.stderr b/tests/ui/redundant_else.stderr index 9000cdc814b1f..de9d00a60246c 100644 --- a/tests/ui/redundant_else.stderr +++ b/tests/ui/redundant_else.stderr @@ -7,8 +7,8 @@ LL | | println!("yet don't pull down your hedge."); LL | | } | |_________^ | - = note: `-D clippy::redundant-else` implied by `-D warnings` = help: remove the `else` block and move the contents out + = note: `-D clippy::redundant-else` implied by `-D warnings` error: redundant else block --> $DIR/redundant_else.rs:17:16 diff --git a/tests/ui/redundant_pattern_matching_drop_order.stderr b/tests/ui/redundant_pattern_matching_drop_order.stderr index eb7aa70ee2738..23f08103f358f 100644 --- a/tests/ui/redundant_pattern_matching_drop_order.stderr +++ b/tests/ui/redundant_pattern_matching_drop_order.stderr @@ -4,9 +4,9 @@ error: redundant pattern matching, consider using `is_ok()` LL | if let Ok(_) = m.lock() {} | -------^^^^^----------- help: try this: `if m.lock().is_ok()` | - = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` = note: this will change drop order of the result, as well as all temporaries = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important + = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` error: redundant pattern matching, consider using `is_err()` --> $DIR/redundant_pattern_matching_drop_order.rs:13:12 diff --git a/tests/ui/regex.stderr b/tests/ui/regex.stderr index 1394a9b63bc61..2424644c6f6b1 100644 --- a/tests/ui/regex.stderr +++ b/tests/ui/regex.stderr @@ -4,8 +4,8 @@ error: trivial regex LL | let pipe_in_wrong_position = Regex::new("|"); | ^^^ | - = note: `-D clippy::trivial-regex` implied by `-D warnings` = help: the regex is unlikely to be useful as it is + = note: `-D clippy::trivial-regex` implied by `-D warnings` error: trivial regex --> $DIR/regex.rs:14:60 diff --git a/tests/ui/rest_pat_in_fully_bound_structs.stderr b/tests/ui/rest_pat_in_fully_bound_structs.stderr index 57ebd47f8c7ac..e15633fb1a136 100644 --- a/tests/ui/rest_pat_in_fully_bound_structs.stderr +++ b/tests/ui/rest_pat_in_fully_bound_structs.stderr @@ -4,8 +4,8 @@ error: unnecessary use of `..` pattern in struct binding. All fields were alread LL | A { a: 5, b: 42, c: "", .. } => {}, // Lint | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::rest-pat-in-fully-bound-structs` implied by `-D warnings` = help: consider removing `..` from this binding + = note: `-D clippy::rest-pat-in-fully-bound-structs` implied by `-D warnings` error: unnecessary use of `..` pattern in struct binding. All fields were already bound --> $DIR/rest_pat_in_fully_bound_structs.rs:23:9 diff --git a/tests/ui/result_large_err.stderr b/tests/ui/result_large_err.stderr index ef19f2854ab12..bea101fe20bf2 100644 --- a/tests/ui/result_large_err.stderr +++ b/tests/ui/result_large_err.stderr @@ -4,8 +4,8 @@ error: the `Err`-variant returned from this function is very large LL | pub fn large_err() -> Result<(), [u8; 512]> { | ^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 512 bytes | - = note: `-D clippy::result-large-err` implied by `-D warnings` = help: try reducing the size of `[u8; 512]`, for example by boxing large elements or replacing it with `Box<[u8; 512]>` + = note: `-D clippy::result-large-err` implied by `-D warnings` error: the `Err`-variant returned from this function is very large --> $DIR/result_large_err.rs:19:21 diff --git a/tests/ui/result_unit_error.stderr b/tests/ui/result_unit_error.stderr index 8c7573eabda94..8393a4bf03bc0 100644 --- a/tests/ui/result_unit_error.stderr +++ b/tests/ui/result_unit_error.stderr @@ -4,8 +4,8 @@ error: this returns a `Result<_, ()>` LL | pub fn returns_unit_error() -> Result { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::result-unit-err` implied by `-D warnings` = help: use a custom `Error` type instead + = note: `-D clippy::result-unit-err` implied by `-D warnings` error: this returns a `Result<_, ()>` --> $DIR/result_unit_error.rs:12:5 diff --git a/tests/ui/return_self_not_must_use.stderr b/tests/ui/return_self_not_must_use.stderr index 94be87dfa31c7..34932fe1c2c55 100644 --- a/tests/ui/return_self_not_must_use.stderr +++ b/tests/ui/return_self_not_must_use.stderr @@ -4,8 +4,8 @@ error: missing `#[must_use]` attribute on a method returning `Self` LL | fn what(&self) -> Self; | ^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::return-self-not-must-use` implied by `-D warnings` = help: consider adding the `#[must_use]` attribute to the method or directly to the `Self` type + = note: `-D clippy::return-self-not-must-use` implied by `-D warnings` error: missing `#[must_use]` attribute on a method returning `Self` --> $DIR/return_self_not_must_use.rs:18:5 diff --git a/tests/ui/same_functions_in_if_condition.stderr b/tests/ui/same_functions_in_if_condition.stderr index cd438b830401d..3901546cbd65c 100644 --- a/tests/ui/same_functions_in_if_condition.stderr +++ b/tests/ui/same_functions_in_if_condition.stderr @@ -4,12 +4,12 @@ error: this `if` has the same function call as a previous `if` LL | } else if function() { | ^^^^^^^^^^ | - = note: `-D clippy::same-functions-in-if-condition` implied by `-D warnings` note: same as this --> $DIR/same_functions_in_if_condition.rs:30:8 | LL | if function() { | ^^^^^^^^^^ + = note: `-D clippy::same-functions-in-if-condition` implied by `-D warnings` error: this `if` has the same function call as a previous `if` --> $DIR/same_functions_in_if_condition.rs:36:15 diff --git a/tests/ui/same_item_push.stderr b/tests/ui/same_item_push.stderr index d9ffa15780ad0..1d1254d9fcc61 100644 --- a/tests/ui/same_item_push.stderr +++ b/tests/ui/same_item_push.stderr @@ -4,8 +4,8 @@ error: it looks like the same item is being pushed into this Vec LL | vec.push(item); | ^^^ | - = note: `-D clippy::same-item-push` implied by `-D warnings` = help: try using vec![item;SIZE] or vec.resize(NEW_SIZE, item) + = note: `-D clippy::same-item-push` implied by `-D warnings` error: it looks like the same item is being pushed into this Vec --> $DIR/same_item_push.rs:29:9 diff --git a/tests/ui/same_name_method.stderr b/tests/ui/same_name_method.stderr index f55ec9f3cc66b..0c6908c09593f 100644 --- a/tests/ui/same_name_method.stderr +++ b/tests/ui/same_name_method.stderr @@ -4,12 +4,12 @@ error: method's name is the same as an existing method in a trait LL | fn foo() {} | ^^^^^^^^^^^ | - = note: `-D clippy::same-name-method` implied by `-D warnings` note: existing `foo` defined here --> $DIR/same_name_method.rs:25:13 | LL | fn foo() {} | ^^^^^^^^^^^ + = note: `-D clippy::same-name-method` implied by `-D warnings` error: method's name is the same as an existing method in a trait --> $DIR/same_name_method.rs:35:13 diff --git a/tests/ui/search_is_some.stderr b/tests/ui/search_is_some.stderr index 54760545bcedc..6bea8c6747797 100644 --- a/tests/ui/search_is_some.stderr +++ b/tests/ui/search_is_some.stderr @@ -8,8 +8,8 @@ LL | | } LL | | ).is_some(); | |______________________________^ | - = note: `-D clippy::search-is-some` implied by `-D warnings` = help: this is more succinctly expressed by calling `any()` + = note: `-D clippy::search-is-some` implied by `-D warnings` error: called `is_some()` after searching an `Iterator` with `position` --> $DIR/search_is_some.rs:20:13 diff --git a/tests/ui/shadow.stderr b/tests/ui/shadow.stderr index 43d76094d0e84..c3d7bc2a5360f 100644 --- a/tests/ui/shadow.stderr +++ b/tests/ui/shadow.stderr @@ -4,12 +4,12 @@ error: `x` is shadowed by itself in `x` LL | let x = x; | ^ | - = note: `-D clippy::shadow-same` implied by `-D warnings` note: previous binding is here --> $DIR/shadow.rs:5:9 | LL | let x = 1; | ^ + = note: `-D clippy::shadow-same` implied by `-D warnings` error: `mut x` is shadowed by itself in `&x` --> $DIR/shadow.rs:7:13 @@ -53,12 +53,12 @@ error: `x` is shadowed LL | let x = x.0; | ^ | - = note: `-D clippy::shadow-reuse` implied by `-D warnings` note: previous binding is here --> $DIR/shadow.rs:13:9 | LL | let x = ([[0]], ()); | ^ + = note: `-D clippy::shadow-reuse` implied by `-D warnings` error: `x` is shadowed --> $DIR/shadow.rs:15:9 @@ -150,12 +150,12 @@ error: `x` shadows a previous, unrelated binding LL | let x = 2; | ^ | - = note: `-D clippy::shadow-unrelated` implied by `-D warnings` note: previous binding is here --> $DIR/shadow.rs:30:9 | LL | let x = 1; | ^ + = note: `-D clippy::shadow-unrelated` implied by `-D warnings` error: `x` shadows a previous, unrelated binding --> $DIR/shadow.rs:36:13 diff --git a/tests/ui/should_impl_trait/method_list_1.stderr b/tests/ui/should_impl_trait/method_list_1.stderr index 2b7d4628c3fa0..d2f41e3f934a7 100644 --- a/tests/ui/should_impl_trait/method_list_1.stderr +++ b/tests/ui/should_impl_trait/method_list_1.stderr @@ -6,8 +6,8 @@ LL | | unimplemented!() LL | | } | |_____^ | - = note: `-D clippy::should-implement-trait` implied by `-D warnings` = help: consider implementing the trait `std::ops::Add` or choosing a less ambiguous method name + = note: `-D clippy::should-implement-trait` implied by `-D warnings` error: method `as_mut` can be confused for the standard trait method `std::convert::AsMut::as_mut` --> $DIR/method_list_1.rs:29:5 diff --git a/tests/ui/should_impl_trait/method_list_2.stderr b/tests/ui/should_impl_trait/method_list_2.stderr index b6fd435695698..10bfea68ff572 100644 --- a/tests/ui/should_impl_trait/method_list_2.stderr +++ b/tests/ui/should_impl_trait/method_list_2.stderr @@ -6,8 +6,8 @@ LL | | unimplemented!() LL | | } | |_____^ | - = note: `-D clippy::should-implement-trait` implied by `-D warnings` = help: consider implementing the trait `std::cmp::PartialEq` or choosing a less ambiguous method name + = note: `-D clippy::should-implement-trait` implied by `-D warnings` error: method `from_iter` can be confused for the standard trait method `std::iter::FromIterator::from_iter` --> $DIR/method_list_2.rs:30:5 diff --git a/tests/ui/significant_drop_in_scrutinee.stderr b/tests/ui/significant_drop_in_scrutinee.stderr index 88ea6bce25b6b..f1ed808ba0872 100644 --- a/tests/ui/significant_drop_in_scrutinee.stderr +++ b/tests/ui/significant_drop_in_scrutinee.stderr @@ -10,8 +10,8 @@ LL | mutex.lock().unwrap().bar(); LL | }; | - temporary lives until here | - = note: `-D clippy::significant-drop-in-scrutinee` implied by `-D warnings` = note: this might lead to deadlocks or other unexpected behavior + = note: `-D clippy::significant-drop-in-scrutinee` implied by `-D warnings` help: try moving the temporary above the match | LL ~ let value = mutex.lock().unwrap().foo(); diff --git a/tests/ui/similar_names.stderr b/tests/ui/similar_names.stderr index 6e77269389737..43c5cee4b4577 100644 --- a/tests/ui/similar_names.stderr +++ b/tests/ui/similar_names.stderr @@ -4,12 +4,12 @@ error: binding's name is too similar to existing binding LL | let bpple: i32; | ^^^^^ | - = note: `-D clippy::similar-names` implied by `-D warnings` note: existing binding defined here --> $DIR/similar_names.rs:19:9 | LL | let apple: i32; | ^^^^^ + = note: `-D clippy::similar-names` implied by `-D warnings` error: binding's name is too similar to existing binding --> $DIR/similar_names.rs:23:9 diff --git a/tests/ui/single_char_lifetime_names.stderr b/tests/ui/single_char_lifetime_names.stderr index 1438b3999dba8..bfe6d44b5898d 100644 --- a/tests/ui/single_char_lifetime_names.stderr +++ b/tests/ui/single_char_lifetime_names.stderr @@ -4,8 +4,8 @@ error: single-character lifetime names are likely uninformative LL | struct DiagnosticCtx<'a, 'b> | ^^ | - = note: `-D clippy::single-char-lifetime-names` implied by `-D warnings` = help: use a more informative name + = note: `-D clippy::single-char-lifetime-names` implied by `-D warnings` error: single-character lifetime names are likely uninformative --> $DIR/single_char_lifetime_names.rs:5:26 diff --git a/tests/ui/single_component_path_imports_nested_first.stderr b/tests/ui/single_component_path_imports_nested_first.stderr index cf990be1b9ff1..633546f6419a2 100644 --- a/tests/ui/single_component_path_imports_nested_first.stderr +++ b/tests/ui/single_component_path_imports_nested_first.stderr @@ -4,8 +4,8 @@ error: this import is redundant LL | use {regex, serde}; | ^^^^^ | - = note: `-D clippy::single-component-path-imports` implied by `-D warnings` = help: remove this import + = note: `-D clippy::single-component-path-imports` implied by `-D warnings` error: this import is redundant --> $DIR/single_component_path_imports_nested_first.rs:13:17 diff --git a/tests/ui/size_of_in_element_count/expressions.stderr b/tests/ui/size_of_in_element_count/expressions.stderr index 0f0dff57f51bd..037f695f3ee91 100644 --- a/tests/ui/size_of_in_element_count/expressions.stderr +++ b/tests/ui/size_of_in_element_count/expressions.stderr @@ -4,8 +4,8 @@ error: found a count of bytes instead of a count of elements of `T` LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; | ^^^^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::size-of-in-element-count` implied by `-D warnings` = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + = note: `-D clippy::size-of-in-element-count` implied by `-D warnings` error: found a count of bytes instead of a count of elements of `T` --> $DIR/expressions.rs:18:62 diff --git a/tests/ui/size_of_in_element_count/functions.stderr b/tests/ui/size_of_in_element_count/functions.stderr index c1e824167b7f3..4351e6a14fe58 100644 --- a/tests/ui/size_of_in_element_count/functions.stderr +++ b/tests/ui/size_of_in_element_count/functions.stderr @@ -4,8 +4,8 @@ error: found a count of bytes instead of a count of elements of `T` LL | unsafe { copy_nonoverlapping::(x.as_ptr(), y.as_mut_ptr(), size_of::()) }; | ^^^^^^^^^^^^^^^ | - = note: `-D clippy::size-of-in-element-count` implied by `-D warnings` = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + = note: `-D clippy::size-of-in-element-count` implied by `-D warnings` error: found a count of bytes instead of a count of elements of `T` --> $DIR/functions.rs:19:62 diff --git a/tests/ui/skip_while_next.stderr b/tests/ui/skip_while_next.stderr index 269cc13468bc8..7308ab4e55c9c 100644 --- a/tests/ui/skip_while_next.stderr +++ b/tests/ui/skip_while_next.stderr @@ -4,8 +4,8 @@ error: called `skip_while(

).next()` on an `Iterator` LL | let _ = v.iter().skip_while(|&x| *x < 0).next(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::skip-while-next` implied by `-D warnings` = help: this is more succinctly expressed by calling `.find(!

)` instead + = note: `-D clippy::skip-while-next` implied by `-D warnings` error: called `skip_while(

).next()` on an `Iterator` --> $DIR/skip_while_next.rs:17:13 diff --git a/tests/ui/stable_sort_primitive.stderr b/tests/ui/stable_sort_primitive.stderr index c35e0c22ae899..1432fdcff77ad 100644 --- a/tests/ui/stable_sort_primitive.stderr +++ b/tests/ui/stable_sort_primitive.stderr @@ -4,8 +4,8 @@ error: used `sort` on primitive type `i32` LL | vec.sort(); | ^^^^^^^^^^ help: try: `vec.sort_unstable()` | - = note: `-D clippy::stable-sort-primitive` implied by `-D warnings` = note: an unstable sort typically performs faster without any observable difference for this data type + = note: `-D clippy::stable-sort-primitive` implied by `-D warnings` error: used `sort` on primitive type `bool` --> $DIR/stable_sort_primitive.rs:9:5 diff --git a/tests/ui/std_instead_of_core.stderr b/tests/ui/std_instead_of_core.stderr index bc49dabf5868a..8138ccb82a000 100644 --- a/tests/ui/std_instead_of_core.stderr +++ b/tests/ui/std_instead_of_core.stderr @@ -4,8 +4,8 @@ error: used import from `std` instead of `core` LL | use std::hash::Hasher; | ^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::std-instead-of-core` implied by `-D warnings` = help: consider importing the item from `core` + = note: `-D clippy::std-instead-of-core` implied by `-D warnings` error: used import from `std` instead of `core` --> $DIR/std_instead_of_core.rs:11:9 @@ -69,8 +69,8 @@ error: used import from `std` instead of `alloc` LL | use std::vec; | ^^^^^^^^ | - = note: `-D clippy::std-instead-of-alloc` implied by `-D warnings` = help: consider importing the item from `alloc` + = note: `-D clippy::std-instead-of-alloc` implied by `-D warnings` error: used import from `std` instead of `alloc` --> $DIR/std_instead_of_core.rs:33:9 @@ -86,8 +86,8 @@ error: used import from `alloc` instead of `core` LL | use alloc::slice::from_ref; | ^^^^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::alloc-instead-of-core` implied by `-D warnings` = help: consider importing the item from `core` + = note: `-D clippy::alloc-instead-of-core` implied by `-D warnings` error: aborting due to 11 previous errors diff --git a/tests/ui/str_to_string.stderr b/tests/ui/str_to_string.stderr index b1f73eda5d26c..1d47da571fa1f 100644 --- a/tests/ui/str_to_string.stderr +++ b/tests/ui/str_to_string.stderr @@ -4,8 +4,8 @@ error: `to_string()` called on a `&str` LL | let hello = "hello world".to_string(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::str-to-string` implied by `-D warnings` = help: consider using `.to_owned()` + = note: `-D clippy::str-to-string` implied by `-D warnings` error: `to_string()` called on a `&str` --> $DIR/str_to_string.rs:6:5 diff --git a/tests/ui/string_to_string.stderr b/tests/ui/string_to_string.stderr index 1ebd17999bd8f..e304c3e346db1 100644 --- a/tests/ui/string_to_string.stderr +++ b/tests/ui/string_to_string.stderr @@ -4,8 +4,8 @@ error: `to_string()` called on a `String` LL | let mut v = message.to_string(); | ^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::string-to-string` implied by `-D warnings` = help: consider using `.clone()` + = note: `-D clippy::string-to-string` implied by `-D warnings` error: aborting due to previous error diff --git a/tests/ui/struct_excessive_bools.stderr b/tests/ui/struct_excessive_bools.stderr index 2941bf2983aa8..e4d50043acb0b 100644 --- a/tests/ui/struct_excessive_bools.stderr +++ b/tests/ui/struct_excessive_bools.stderr @@ -9,8 +9,8 @@ LL | | d: bool, LL | | } | |_^ | - = note: `-D clippy::struct-excessive-bools` implied by `-D warnings` = help: consider using a state machine or refactoring bools into two-variant enums + = note: `-D clippy::struct-excessive-bools` implied by `-D warnings` error: more than 3 bools in a struct --> $DIR/struct_excessive_bools.rs:38:5 diff --git a/tests/ui/suspicious_else_formatting.stderr b/tests/ui/suspicious_else_formatting.stderr index ee68eb5a791c4..2e512b47f1236 100644 --- a/tests/ui/suspicious_else_formatting.stderr +++ b/tests/ui/suspicious_else_formatting.stderr @@ -4,8 +4,8 @@ error: this looks like an `else {..}` but the `else` is missing LL | } { | ^ | - = note: `-D clippy::suspicious-else-formatting` implied by `-D warnings` = note: to remove this lint, add the missing `else` or add a new line before the next block + = note: `-D clippy::suspicious-else-formatting` implied by `-D warnings` error: this looks like an `else if` but the `else` is missing --> $DIR/suspicious_else_formatting.rs:21:6 diff --git a/tests/ui/suspicious_map.stderr b/tests/ui/suspicious_map.stderr index 3ffcd1a903174..e251674819e46 100644 --- a/tests/ui/suspicious_map.stderr +++ b/tests/ui/suspicious_map.stderr @@ -4,8 +4,8 @@ error: this call to `map()` won't have an effect on the call to `count()` LL | let _ = (0..3).map(|x| x + 2).count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::suspicious-map` implied by `-D warnings` = help: make sure you did not confuse `map` with `filter`, `for_each` or `inspect` + = note: `-D clippy::suspicious-map` implied by `-D warnings` error: this call to `map()` won't have an effect on the call to `count()` --> $DIR/suspicious_map.rs:7:13 diff --git a/tests/ui/suspicious_splitn.stderr b/tests/ui/suspicious_splitn.stderr index 3bcd681fa49d8..55ce63d4faa8c 100644 --- a/tests/ui/suspicious_splitn.stderr +++ b/tests/ui/suspicious_splitn.stderr @@ -4,8 +4,8 @@ error: `splitn` called with `0` splits LL | let _ = "a,b".splitn(0, ','); | ^^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::suspicious-splitn` implied by `-D warnings` = note: the resulting iterator will always return `None` + = note: `-D clippy::suspicious-splitn` implied by `-D warnings` error: `rsplitn` called with `0` splits --> $DIR/suspicious_splitn.rs:11:13 diff --git a/tests/ui/suspicious_unary_op_formatting.stderr b/tests/ui/suspicious_unary_op_formatting.stderr index 581527dcff8e4..9f1289ccba0c0 100644 --- a/tests/ui/suspicious_unary_op_formatting.stderr +++ b/tests/ui/suspicious_unary_op_formatting.stderr @@ -4,8 +4,8 @@ error: by not having a space between `>` and `-` it looks like `>-` is a single LL | if a >- 30 {} | ^^^^ | - = note: `-D clippy::suspicious-unary-op-formatting` implied by `-D warnings` = help: put a space between `>` and `-` and remove the space after `-` + = note: `-D clippy::suspicious-unary-op-formatting` implied by `-D warnings` error: by not having a space between `>=` and `-` it looks like `>=-` is a single operator --> $DIR/suspicious_unary_op_formatting.rs:9:9 diff --git a/tests/ui/swap.stderr b/tests/ui/swap.stderr index 2b556b475cee9..ee4b7a508a5e3 100644 --- a/tests/ui/swap.stderr +++ b/tests/ui/swap.stderr @@ -6,8 +6,8 @@ LL | | bar.a = bar.b; LL | | bar.b = temp; | |________________^ help: try: `std::mem::swap(&mut bar.a, &mut bar.b)` | - = note: `-D clippy::manual-swap` implied by `-D warnings` = note: or maybe you should use `std::mem::replace`? + = note: `-D clippy::manual-swap` implied by `-D warnings` error: this looks like you are swapping elements of `foo` manually --> $DIR/swap.rs:36:5 @@ -96,8 +96,8 @@ LL | / a = b; LL | | b = a; | |_________^ help: try: `std::mem::swap(&mut a, &mut b)` | - = note: `-D clippy::almost-swapped` implied by `-D warnings` = note: or maybe you should use `std::mem::replace`? + = note: `-D clippy::almost-swapped` implied by `-D warnings` error: this looks like you are trying to swap `c.0` and `a` --> $DIR/swap.rs:140:5 diff --git a/tests/ui/trailing_empty_array.stderr b/tests/ui/trailing_empty_array.stderr index 9e2bd31d9fa51..2e1484400352d 100644 --- a/tests/ui/trailing_empty_array.stderr +++ b/tests/ui/trailing_empty_array.stderr @@ -7,8 +7,8 @@ LL | | last: [usize; 0], LL | | } | |_^ | - = note: `-D clippy::trailing-empty-array` implied by `-D warnings` = help: consider annotating `RarelyUseful` with `#[repr(C)]` or another `repr` attribute + = note: `-D clippy::trailing-empty-array` implied by `-D warnings` error: trailing zero-sized array in a struct which is not marked with a `repr` attribute --> $DIR/trailing_empty_array.rs:10:1 diff --git a/tests/ui/trait_duplication_in_bounds_unfixable.stderr b/tests/ui/trait_duplication_in_bounds_unfixable.stderr index fbd9abb005f1f..4d56a94646cb6 100644 --- a/tests/ui/trait_duplication_in_bounds_unfixable.stderr +++ b/tests/ui/trait_duplication_in_bounds_unfixable.stderr @@ -4,12 +4,12 @@ error: this trait bound is already specified in the where clause LL | fn bad_foo(arg0: T, arg1: Z) | ^^^^^ | + = help: consider removing this trait bound note: the lint level is defined here --> $DIR/trait_duplication_in_bounds_unfixable.rs:1:9 | LL | #![deny(clippy::trait_duplication_in_bounds)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: consider removing this trait bound error: this trait bound is already specified in the where clause --> $DIR/trait_duplication_in_bounds_unfixable.rs:6:23 diff --git a/tests/ui/type_repetition_in_bounds.stderr b/tests/ui/type_repetition_in_bounds.stderr index 1d88714814d47..70d700c1cc460 100644 --- a/tests/ui/type_repetition_in_bounds.stderr +++ b/tests/ui/type_repetition_in_bounds.stderr @@ -4,12 +4,12 @@ error: this type has already been used as a bound predicate LL | T: Clone, | ^^^^^^^^ | + = help: consider combining the bounds: `T: Copy + Clone` note: the lint level is defined here --> $DIR/type_repetition_in_bounds.rs:1:9 | LL | #![deny(clippy::type_repetition_in_bounds)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: consider combining the bounds: `T: Copy + Clone` error: this type has already been used as a bound predicate --> $DIR/type_repetition_in_bounds.rs:25:5 diff --git a/tests/ui/undocumented_unsafe_blocks.stderr b/tests/ui/undocumented_unsafe_blocks.stderr index c6a2127443bef..2c466ff5c733b 100644 --- a/tests/ui/undocumented_unsafe_blocks.stderr +++ b/tests/ui/undocumented_unsafe_blocks.stderr @@ -4,8 +4,8 @@ error: unsafe block missing a safety comment LL | /* Safety: */ unsafe {} | ^^^^^^^^^ | - = note: `-D clippy::undocumented-unsafe-blocks` implied by `-D warnings` = help: consider adding a safety comment on the preceding line + = note: `-D clippy::undocumented-unsafe-blocks` implied by `-D warnings` error: unsafe block missing a safety comment --> $DIR/undocumented_unsafe_blocks.rs:266:5 diff --git a/tests/ui/undropped_manually_drops.stderr b/tests/ui/undropped_manually_drops.stderr index 2ac0fe98697ef..92611a9b7df4a 100644 --- a/tests/ui/undropped_manually_drops.stderr +++ b/tests/ui/undropped_manually_drops.stderr @@ -4,8 +4,8 @@ error: the inner value of this ManuallyDrop will not be dropped LL | drop(std::mem::ManuallyDrop::new(S)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::undropped-manually-drops` implied by `-D warnings` = help: to drop a `ManuallyDrop`, use std::mem::ManuallyDrop::drop + = note: `-D clippy::undropped-manually-drops` implied by `-D warnings` error: the inner value of this ManuallyDrop will not be dropped --> $DIR/undropped_manually_drops.rs:15:5 diff --git a/tests/ui/uninit_vec.stderr b/tests/ui/uninit_vec.stderr index 520bfb26b62e1..77fc689f07635 100644 --- a/tests/ui/uninit_vec.stderr +++ b/tests/ui/uninit_vec.stderr @@ -7,8 +7,8 @@ LL | unsafe { LL | vec.set_len(200); | ^^^^^^^^^^^^^^^^ | - = note: `-D clippy::uninit-vec` implied by `-D warnings` = help: initialize the buffer or wrap the content in `MaybeUninit` + = note: `-D clippy::uninit-vec` implied by `-D warnings` error: calling `set_len()` immediately after reserving a buffer creates uninitialized values --> $DIR/uninit_vec.rs:18:5 diff --git a/tests/ui/unit_hash.stderr b/tests/ui/unit_hash.stderr index 050fa55a12bea..089d1212dd17a 100644 --- a/tests/ui/unit_hash.stderr +++ b/tests/ui/unit_hash.stderr @@ -4,8 +4,8 @@ error: this call to `hash` on the unit type will do nothing LL | Foo::Empty => ().hash(&mut state), | ^^^^^^^^^^^^^^^^^^^ help: remove the call to `hash` or consider using: `0_u8.hash(&mut state)` | - = note: `-D clippy::unit-hash` implied by `-D warnings` = note: the implementation of `Hash` for `()` is a no-op + = note: `-D clippy::unit-hash` implied by `-D warnings` error: this call to `hash` on the unit type will do nothing --> $DIR/unit_hash.rs:24:5 diff --git a/tests/ui/unit_return_expecting_ord.stderr b/tests/ui/unit_return_expecting_ord.stderr index e63d58746090b..1d9564ce225e1 100644 --- a/tests/ui/unit_return_expecting_ord.stderr +++ b/tests/ui/unit_return_expecting_ord.stderr @@ -4,12 +4,12 @@ error: this closure returns the unit type which also implements Ord LL | structs.sort_by_key(|s| { | ^^^ | - = note: `-D clippy::unit-return-expecting-ord` implied by `-D warnings` help: probably caused by this trailing semicolon --> $DIR/unit_return_expecting_ord.rs:19:24 | LL | double(s.field); | ^ + = note: `-D clippy::unit-return-expecting-ord` implied by `-D warnings` error: this closure returns the unit type which also implements PartialOrd --> $DIR/unit_return_expecting_ord.rs:22:30 diff --git a/tests/ui/unnecessary_self_imports.stderr b/tests/ui/unnecessary_self_imports.stderr index 83a5618c983d3..db805eb3680be 100644 --- a/tests/ui/unnecessary_self_imports.stderr +++ b/tests/ui/unnecessary_self_imports.stderr @@ -6,8 +6,8 @@ LL | use std::fs::{self as alias}; | | | help: consider omitting `::{self}`: `fs as alias;` | - = note: `-D clippy::unnecessary-self-imports` implied by `-D warnings` = note: this will slightly change semantics; any non-module items at the same path will also be imported + = note: `-D clippy::unnecessary-self-imports` implied by `-D warnings` error: import ending with `::{self}` --> $DIR/unnecessary_self_imports.rs:8:1 diff --git a/tests/ui/unnecessary_to_owned.stderr b/tests/ui/unnecessary_to_owned.stderr index 7deb90b06f3b7..02bf45a33fbe1 100644 --- a/tests/ui/unnecessary_to_owned.stderr +++ b/tests/ui/unnecessary_to_owned.stderr @@ -4,12 +4,12 @@ error: redundant clone LL | require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap().to_owned()); | ^^^^^^^^^^^ help: remove this | - = note: `-D clippy::redundant-clone` implied by `-D warnings` note: this value is dropped without further use --> $DIR/unnecessary_to_owned.rs:151:20 | LL | require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap().to_owned()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `-D clippy::redundant-clone` implied by `-D warnings` error: redundant clone --> $DIR/unnecessary_to_owned.rs:152:40 diff --git a/tests/ui/unneeded_field_pattern.stderr b/tests/ui/unneeded_field_pattern.stderr index b8d3c2945322b..6f7c315456969 100644 --- a/tests/ui/unneeded_field_pattern.stderr +++ b/tests/ui/unneeded_field_pattern.stderr @@ -4,8 +4,8 @@ error: you matched a field with a wildcard pattern, consider using `..` instead LL | Foo { a: _, b: 0, .. } => {}, | ^^^^ | - = note: `-D clippy::unneeded-field-pattern` implied by `-D warnings` = help: try with `Foo { b: 0, .. }` + = note: `-D clippy::unneeded-field-pattern` implied by `-D warnings` error: all the struct fields are matched to a wildcard pattern, consider using `..` --> $DIR/unneeded_field_pattern.rs:16:9 diff --git a/tests/ui/unsafe_derive_deserialize.stderr b/tests/ui/unsafe_derive_deserialize.stderr index 18c4276c6ddfd..8aaae2d7fff48 100644 --- a/tests/ui/unsafe_derive_deserialize.stderr +++ b/tests/ui/unsafe_derive_deserialize.stderr @@ -4,8 +4,8 @@ error: you are deriving `serde::Deserialize` on a type that has methods using `u LL | #[derive(Deserialize)] | ^^^^^^^^^^^ | - = note: `-D clippy::unsafe-derive-deserialize` implied by `-D warnings` = help: consider implementing `serde::Deserialize` manually. See https://serde.rs/impl-deserialize.html + = note: `-D clippy::unsafe-derive-deserialize` implied by `-D warnings` = note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info) error: you are deriving `serde::Deserialize` on a type that has methods using `unsafe` diff --git a/tests/ui/unused_async.stderr b/tests/ui/unused_async.stderr index 8b8ad065a4caa..cff3eccbd32bb 100644 --- a/tests/ui/unused_async.stderr +++ b/tests/ui/unused_async.stderr @@ -6,8 +6,8 @@ LL | | 4 LL | | } | |_^ | - = note: `-D clippy::unused-async` implied by `-D warnings` = help: consider removing the `async` from this function + = note: `-D clippy::unused-async` implied by `-D warnings` error: unused `async` for function with no await statements --> $DIR/unused_async.rs:17:5 diff --git a/tests/ui/unused_io_amount.stderr b/tests/ui/unused_io_amount.stderr index e5bdd993aa1ad..7ba7e09c0f0df 100644 --- a/tests/ui/unused_io_amount.stderr +++ b/tests/ui/unused_io_amount.stderr @@ -4,8 +4,8 @@ error: written amount is not handled LL | s.write(b"test")?; | ^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::unused-io-amount` implied by `-D warnings` = help: use `Write::write_all` instead, or handle partial writes + = note: `-D clippy::unused-io-amount` implied by `-D warnings` error: read amount is not handled --> $DIR/unused_io_amount.rs:11:5 diff --git a/tests/ui/unused_peekable.stderr b/tests/ui/unused_peekable.stderr index d557f54179dba..54788f2fa2f4c 100644 --- a/tests/ui/unused_peekable.stderr +++ b/tests/ui/unused_peekable.stderr @@ -4,8 +4,8 @@ error: `peek` never called on `Peekable` iterator LL | let peekable = std::iter::empty::().peekable(); | ^^^^^^^^ | - = note: `-D clippy::unused-peekable` implied by `-D warnings` = help: consider removing the call to `peekable` + = note: `-D clippy::unused-peekable` implied by `-D warnings` error: `peek` never called on `Peekable` iterator --> $DIR/unused_peekable.rs:18:9 diff --git a/tests/ui/unused_self.stderr b/tests/ui/unused_self.stderr index 0534b40eabb75..23186122a9af7 100644 --- a/tests/ui/unused_self.stderr +++ b/tests/ui/unused_self.stderr @@ -4,8 +4,8 @@ error: unused `self` argument LL | fn unused_self_move(self) {} | ^^^^ | - = note: `-D clippy::unused-self` implied by `-D warnings` = help: consider refactoring to a associated function + = note: `-D clippy::unused-self` implied by `-D warnings` error: unused `self` argument --> $DIR/unused_self.rs:12:28 diff --git a/tests/ui/unwrap.stderr b/tests/ui/unwrap.stderr index 78422757819d5..e88d580f7bd28 100644 --- a/tests/ui/unwrap.stderr +++ b/tests/ui/unwrap.stderr @@ -4,8 +4,8 @@ error: used `unwrap()` on `an Option` value LL | let _ = opt.unwrap(); | ^^^^^^^^^^^^ | - = note: `-D clippy::unwrap-used` implied by `-D warnings` = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message + = note: `-D clippy::unwrap-used` implied by `-D warnings` error: used `unwrap()` on `a Result` value --> $DIR/unwrap.rs:10:13 diff --git a/tests/ui/unwrap_expect_used.stderr b/tests/ui/unwrap_expect_used.stderr index 1a19459b2c174..211d2be18342d 100644 --- a/tests/ui/unwrap_expect_used.stderr +++ b/tests/ui/unwrap_expect_used.stderr @@ -4,8 +4,8 @@ error: used `unwrap()` on `an Option` value LL | Some(3).unwrap(); | ^^^^^^^^^^^^^^^^ | - = note: `-D clippy::unwrap-used` implied by `-D warnings` = help: if this value is `None`, it will panic + = note: `-D clippy::unwrap-used` implied by `-D warnings` error: used `expect()` on `an Option` value --> $DIR/unwrap_expect_used.rs:24:5 @@ -13,8 +13,8 @@ error: used `expect()` on `an Option` value LL | Some(3).expect("Hello world!"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::expect-used` implied by `-D warnings` = help: if this value is `None`, it will panic + = note: `-D clippy::expect-used` implied by `-D warnings` error: used `unwrap()` on `a Result` value --> $DIR/unwrap_expect_used.rs:31:5 diff --git a/tests/ui/unwrap_in_result.stderr b/tests/ui/unwrap_in_result.stderr index 56bc2f2d1c00e..40e6bfe087e7d 100644 --- a/tests/ui/unwrap_in_result.stderr +++ b/tests/ui/unwrap_in_result.stderr @@ -10,13 +10,13 @@ LL | | } LL | | } | |_____^ | - = note: `-D clippy::unwrap-in-result` implied by `-D warnings` = help: unwrap and expect should not be used in a function that returns result or option note: potential non-recoverable error(s) --> $DIR/unwrap_in_result.rs:24:17 | LL | let i = i_str.parse::().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `-D clippy::unwrap-in-result` implied by `-D warnings` error: used unwrap or expect in a function that returns result or option --> $DIR/unwrap_in_result.rs:32:5 diff --git a/tests/ui/useless_conversion_try.stderr b/tests/ui/useless_conversion_try.stderr index 12e74d614717d..9aef9dda6f685 100644 --- a/tests/ui/useless_conversion_try.stderr +++ b/tests/ui/useless_conversion_try.stderr @@ -4,12 +4,12 @@ error: useless conversion to the same type: `T` LL | let _ = T::try_from(val).unwrap(); | ^^^^^^^^^^^^^^^^ | + = help: consider removing `T::try_from()` note: the lint level is defined here --> $DIR/useless_conversion_try.rs:1:9 | LL | #![deny(clippy::useless_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: consider removing `T::try_from()` error: useless conversion to the same type: `T` --> $DIR/useless_conversion_try.rs:5:5 diff --git a/tests/ui/vec_resize_to_zero.stderr b/tests/ui/vec_resize_to_zero.stderr index 7428cf62d6c42..8851e9f38be49 100644 --- a/tests/ui/vec_resize_to_zero.stderr +++ b/tests/ui/vec_resize_to_zero.stderr @@ -6,8 +6,8 @@ LL | v.resize(0, 5); | | | help: ...or you can empty the vector with: `clear()` | - = note: `-D clippy::vec-resize-to-zero` implied by `-D warnings` = help: the arguments may be inverted... + = note: `-D clippy::vec-resize-to-zero` implied by `-D warnings` error: aborting due to previous error diff --git a/tests/ui/verbose_file_reads.stderr b/tests/ui/verbose_file_reads.stderr index 550b6ab679f19..44266c7c01f39 100644 --- a/tests/ui/verbose_file_reads.stderr +++ b/tests/ui/verbose_file_reads.stderr @@ -4,8 +4,8 @@ error: use of `File::read_to_end` LL | f.read_to_end(&mut buffer)?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::verbose-file-reads` implied by `-D warnings` = help: consider using `fs::read` instead + = note: `-D clippy::verbose-file-reads` implied by `-D warnings` error: use of `File::read_to_string` --> $DIR/verbose_file_reads.rs:26:5 diff --git a/tests/ui/vtable_address_comparisons.stderr b/tests/ui/vtable_address_comparisons.stderr index 2f1be61e5df72..14748f583f0cd 100644 --- a/tests/ui/vtable_address_comparisons.stderr +++ b/tests/ui/vtable_address_comparisons.stderr @@ -4,8 +4,8 @@ error: comparing trait object pointers compares a non-unique vtable address LL | let _ = a == b; | ^^^^^^ | - = note: `-D clippy::vtable-address-comparisons` implied by `-D warnings` = help: consider extracting and comparing data pointers only + = note: `-D clippy::vtable-address-comparisons` implied by `-D warnings` error: comparing trait object pointers compares a non-unique vtable address --> $DIR/vtable_address_comparisons.rs:15:13 diff --git a/tests/ui/wild_in_or_pats.stderr b/tests/ui/wild_in_or_pats.stderr index 45b87aa0f20b9..bd5860f45ca68 100644 --- a/tests/ui/wild_in_or_pats.stderr +++ b/tests/ui/wild_in_or_pats.stderr @@ -4,8 +4,8 @@ error: wildcard pattern covers any other pattern as it will match anyway LL | "bar" | _ => { | ^^^^^^^^^ | - = note: `-D clippy::wildcard-in-or-patterns` implied by `-D warnings` = help: consider handling `_` separately + = note: `-D clippy::wildcard-in-or-patterns` implied by `-D warnings` error: wildcard pattern covers any other pattern as it will match anyway --> $DIR/wild_in_or_pats.rs:16:9 diff --git a/tests/ui/wrong_self_convention.stderr b/tests/ui/wrong_self_convention.stderr index 2e7ee51d7e11a..d002e55c57086 100644 --- a/tests/ui/wrong_self_convention.stderr +++ b/tests/ui/wrong_self_convention.stderr @@ -4,8 +4,8 @@ error: methods called `from_*` usually take no `self` LL | fn from_i32(self) {} | ^^^^ | - = note: `-D clippy::wrong-self-convention` implied by `-D warnings` = help: consider choosing a less ambiguous name + = note: `-D clippy::wrong-self-convention` implied by `-D warnings` error: methods called `from_*` usually take no `self` --> $DIR/wrong_self_convention.rs:22:21 diff --git a/tests/ui/wrong_self_convention2.stderr b/tests/ui/wrong_self_convention2.stderr index 5bdc47f91f65b..8de10e7be69c0 100644 --- a/tests/ui/wrong_self_convention2.stderr +++ b/tests/ui/wrong_self_convention2.stderr @@ -4,8 +4,8 @@ error: methods called `from_*` usually take no `self` LL | pub fn from_be_self(self) -> Self { | ^^^^ | - = note: `-D clippy::wrong-self-convention` implied by `-D warnings` = help: consider choosing a less ambiguous name + = note: `-D clippy::wrong-self-convention` implied by `-D warnings` error: methods called `from_*` usually take no `self` --> $DIR/wrong_self_convention2.rs:63:25 diff --git a/tests/ui/wrong_self_conventions_mut.stderr b/tests/ui/wrong_self_conventions_mut.stderr index 8665d8dc9a9de..3d009083cee3e 100644 --- a/tests/ui/wrong_self_conventions_mut.stderr +++ b/tests/ui/wrong_self_conventions_mut.stderr @@ -4,8 +4,8 @@ error: methods with the following characteristics: (`to_*` and `self` type is no LL | pub fn to_many(&mut self) -> Option<&mut [T]> { | ^^^^^^^^^ | - = note: `-D clippy::wrong-self-convention` implied by `-D warnings` = help: consider choosing a less ambiguous name + = note: `-D clippy::wrong-self-convention` implied by `-D warnings` error: methods with the following characteristics: (`to_*` and `*_mut`) usually take `self` by mutable reference --> $DIR/wrong_self_conventions_mut.rs:22:28 diff --git a/tests/ui/zero_div_zero.stderr b/tests/ui/zero_div_zero.stderr index 86563542e0602..2793d16064459 100644 --- a/tests/ui/zero_div_zero.stderr +++ b/tests/ui/zero_div_zero.stderr @@ -4,8 +4,8 @@ error: constant division of `0.0` with `0.0` will always result in NaN LL | let nan = 0.0 / 0.0; | ^^^^^^^^^ | - = note: `-D clippy::zero-divided-by-zero` implied by `-D warnings` = help: consider using `f64::NAN` if you would like a constant representing NaN + = note: `-D clippy::zero-divided-by-zero` implied by `-D warnings` error: constant division of `0.0` with `0.0` will always result in NaN --> $DIR/zero_div_zero.rs:5:19 diff --git a/tests/ui/zero_sized_btreemap_values.stderr b/tests/ui/zero_sized_btreemap_values.stderr index d924f33797d29..c6ba6fa76f057 100644 --- a/tests/ui/zero_sized_btreemap_values.stderr +++ b/tests/ui/zero_sized_btreemap_values.stderr @@ -4,8 +4,8 @@ error: map with zero-sized value type LL | const CONST_NOT_OK: Option> = None; | ^^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::zero-sized-map-values` implied by `-D warnings` = help: consider using a set instead + = note: `-D clippy::zero-sized-map-values` implied by `-D warnings` error: map with zero-sized value type --> $DIR/zero_sized_btreemap_values.rs:8:30 diff --git a/tests/ui/zero_sized_hashmap_values.stderr b/tests/ui/zero_sized_hashmap_values.stderr index 79770bf90d701..75bdeb42ec0d4 100644 --- a/tests/ui/zero_sized_hashmap_values.stderr +++ b/tests/ui/zero_sized_hashmap_values.stderr @@ -4,8 +4,8 @@ error: map with zero-sized value type LL | const CONST_NOT_OK: Option> = None; | ^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::zero-sized-map-values` implied by `-D warnings` = help: consider using a set instead + = note: `-D clippy::zero-sized-map-values` implied by `-D warnings` error: map with zero-sized value type --> $DIR/zero_sized_hashmap_values.rs:8:30 From 3757a0e903b781fe77092e166210c2089594c929 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Sat, 1 Oct 2022 11:57:34 +0200 Subject: [PATCH 078/114] avoid doc-link-with-quotes in code blocks --- clippy_lints/src/doc.rs | 70 ++++++++++++++++++----- clippy_lints/src/doc_link_with_quotes.rs | 60 ------------------- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/lib.register_pedantic.rs | 2 +- clippy_lints/src/lib.rs | 2 - tests/ui/doc_link_with_quotes.rs | 7 ++- tests/ui/doc_link_with_quotes.stderr | 6 +- 7 files changed, 67 insertions(+), 82 deletions(-) delete mode 100644 clippy_lints/src/doc_link_with_quotes.rs diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index fd143a9d77c10..36dc7e3396b82 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -198,6 +198,29 @@ declare_clippy_lint! { "presence of `fn main() {` in code examples" } +declare_clippy_lint! { + /// ### What it does + /// Detects the syntax `['foo']` in documentation comments (notice quotes instead of backticks) + /// outside of code blocks + /// ### Why is this bad? + /// It is likely a typo when defining an intra-doc link + /// + /// ### Example + /// ```rust + /// /// See also: ['foo'] + /// fn bar() {} + /// ``` + /// Use instead: + /// ```rust + /// /// See also: [`foo`] + /// fn bar() {} + /// ``` + #[clippy::version = "1.63.0"] + pub DOC_LINK_WITH_QUOTES, + pedantic, + "possible typo for an intra-doc link" +} + #[expect(clippy::module_name_repetitions)] #[derive(Clone)] pub struct DocMarkdown { @@ -214,9 +237,14 @@ impl DocMarkdown { } } -impl_lint_pass!(DocMarkdown => - [DOC_MARKDOWN, MISSING_SAFETY_DOC, MISSING_ERRORS_DOC, MISSING_PANICS_DOC, NEEDLESS_DOCTEST_MAIN] -); +impl_lint_pass!(DocMarkdown => [ + DOC_LINK_WITH_QUOTES, + DOC_MARKDOWN, + MISSING_SAFETY_DOC, + MISSING_ERRORS_DOC, + MISSING_PANICS_DOC, + NEEDLESS_DOCTEST_MAIN +]); impl<'tcx> LateLintPass<'tcx> for DocMarkdown { fn check_crate(&mut self, cx: &LateContext<'tcx>) { @@ -432,7 +460,7 @@ pub fn strip_doc_comment_decoration(doc: &str, comment_kind: CommentKind, span: (no_stars, sizes) } -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Default)] struct DocHeaders { safety: bool, errors: bool, @@ -476,11 +504,7 @@ fn check_attrs<'a>(cx: &LateContext<'_>, valid_idents: &FxHashSet, attrs } if doc.is_empty() { - return DocHeaders { - safety: false, - errors: false, - panics: false, - }; + return DocHeaders::default(); } let mut cb = fake_broken_link_callback; @@ -521,11 +545,7 @@ fn check_doc<'a, Events: Iterator, Range, Range, Range, + in_link: bool, + trimmed_text: &str, + span: Span, + range: &Range, + begin: usize, + text_len: usize, +) { + if in_link && trimmed_text.starts_with('\'') && trimmed_text.ends_with('\'') { + // fix the span to only point at the text within the link + let lo = span.lo() + BytePos::from_usize(range.start - begin); + span_lint( + cx, + DOC_LINK_WITH_QUOTES, + span.with_lo(lo).with_hi(lo + BytePos::from_usize(text_len)), + "possible intra-doc link using quotes instead of backticks", + ); + } +} + fn get_current_span(spans: &[(usize, Span)], idx: usize) -> (usize, Span) { let index = match spans.binary_search_by(|c| c.0.cmp(&idx)) { Ok(o) => o, diff --git a/clippy_lints/src/doc_link_with_quotes.rs b/clippy_lints/src/doc_link_with_quotes.rs deleted file mode 100644 index 0ff1d2755daf6..0000000000000 --- a/clippy_lints/src/doc_link_with_quotes.rs +++ /dev/null @@ -1,60 +0,0 @@ -use clippy_utils::diagnostics::span_lint; -use itertools::Itertools; -use rustc_ast::{AttrKind, Attribute}; -use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; - -declare_clippy_lint! { - /// ### What it does - /// Detects the syntax `['foo']` in documentation comments (notice quotes instead of backticks) - /// outside of code blocks - /// ### Why is this bad? - /// It is likely a typo when defining an intra-doc link - /// - /// ### Example - /// ```rust - /// /// See also: ['foo'] - /// fn bar() {} - /// ``` - /// Use instead: - /// ```rust - /// /// See also: [`foo`] - /// fn bar() {} - /// ``` - #[clippy::version = "1.63.0"] - pub DOC_LINK_WITH_QUOTES, - pedantic, - "possible typo for an intra-doc link" -} -declare_lint_pass!(DocLinkWithQuotes => [DOC_LINK_WITH_QUOTES]); - -impl EarlyLintPass for DocLinkWithQuotes { - fn check_attribute(&mut self, ctx: &EarlyContext<'_>, attr: &Attribute) { - if let AttrKind::DocComment(_, symbol) = attr.kind { - if contains_quote_link(symbol.as_str()) { - span_lint( - ctx, - DOC_LINK_WITH_QUOTES, - attr.span, - "possible intra-doc link using quotes instead of backticks", - ); - } - } - } -} - -fn contains_quote_link(s: &str) -> bool { - let mut in_backticks = false; - let mut found_opening = false; - - for c in s.chars().tuple_windows::<(char, char)>() { - match c { - ('`', _) => in_backticks = !in_backticks, - ('[', '\'') if !in_backticks => found_opening = true, - ('\'', ']') if !in_backticks && found_opening => return true, - _ => {}, - } - } - - false -} diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index ee08d802ccfbf..0d850f1d9240d 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -118,12 +118,12 @@ store.register_lints(&[ 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, - doc_link_with_quotes::DOC_LINK_WITH_QUOTES, double_parens::DOUBLE_PARENS, drop_forget_ref::DROP_COPY, drop_forget_ref::DROP_NON_DROP, diff --git a/clippy_lints/src/lib.register_pedantic.rs b/clippy_lints/src/lib.register_pedantic.rs index 4eaabfbcc5fab..dd3e2b7d29c14 100644 --- a/clippy_lints/src/lib.register_pedantic.rs +++ b/clippy_lints/src/lib.register_pedantic.rs @@ -20,10 +20,10 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ 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(doc_link_with_quotes::DOC_LINK_WITH_QUOTES), LintId::of(empty_enum::EMPTY_ENUM), LintId::of(enum_variants::MODULE_NAME_REPETITIONS), LintId::of(eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index fde8aa9f92173..c5f0fd5fe5ed2 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -204,7 +204,6 @@ mod disallowed_names; mod disallowed_script_idents; mod disallowed_types; mod doc; -mod doc_link_with_quotes; mod double_parens; mod drop_forget_ref; mod duplicate_mod; @@ -864,7 +863,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(|| Box::new(single_char_lifetime_names::SingleCharLifetimeNames)); store.register_late_pass(move |_| Box::new(manual_bits::ManualBits::new(msrv))); store.register_late_pass(|_| Box::new(default_union_representation::DefaultUnionRepresentation)); - store.register_early_pass(|| Box::new(doc_link_with_quotes::DocLinkWithQuotes)); store.register_late_pass(|_| Box::::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))); diff --git a/tests/ui/doc_link_with_quotes.rs b/tests/ui/doc_link_with_quotes.rs index ab52fb1a4a69e..17c04c34e2461 100644 --- a/tests/ui/doc_link_with_quotes.rs +++ b/tests/ui/doc_link_with_quotes.rs @@ -4,9 +4,14 @@ fn main() { foo() } -/// Calls ['bar'] +/// Calls ['bar'] uselessly pub fn foo() { bar() } +/// # Examples +/// This demonstrates issue \#8961 +/// ``` +/// let _ = vec!['w', 'a', 't']; +/// ``` pub fn bar() {} diff --git a/tests/ui/doc_link_with_quotes.stderr b/tests/ui/doc_link_with_quotes.stderr index bf6d57d8afe8c..ea730e667d65b 100644 --- a/tests/ui/doc_link_with_quotes.stderr +++ b/tests/ui/doc_link_with_quotes.stderr @@ -1,8 +1,8 @@ error: possible intra-doc link using quotes instead of backticks - --> $DIR/doc_link_with_quotes.rs:7:1 + --> $DIR/doc_link_with_quotes.rs:7:12 | -LL | /// Calls ['bar'] - | ^^^^^^^^^^^^^^^^^ +LL | /// Calls ['bar'] uselessly + | ^^^^^ | = note: `-D clippy::doc-link-with-quotes` implied by `-D warnings` From 418b30b499144b0acd71b2d4c4dfe2f6931fa8c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 1 Oct 2022 00:52:25 +0200 Subject: [PATCH 079/114] rustc_tool_utils bump version in anticipation of a new release cc https://github.com/rust-lang/rust-clippy/issues/9553 --- Cargo.toml | 2 +- rustc_tools_util/Cargo.toml | 2 +- rustc_tools_util/README.md | 8 ++++---- rustc_tools_util/src/lib.rs | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b1bec0c46cad3..dbf0dd3380625 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,7 +56,7 @@ tokio = { version = "1", features = ["io-util"] } rustc-semver = "1.1" [build-dependencies] -rustc_tools_util = { version = "0.2", path = "rustc_tools_util" } +rustc_tools_util = { version = "0.2.1", path = "rustc_tools_util" } [features] deny-warnings = ["clippy_lints/deny-warnings"] diff --git a/rustc_tools_util/Cargo.toml b/rustc_tools_util/Cargo.toml index 9554d4d6c003c..89c3d6aaa89e7 100644 --- a/rustc_tools_util/Cargo.toml +++ b/rustc_tools_util/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustc_tools_util" -version = "0.2.0" +version = "0.2.1" description = "small helper to generate version information for git packages" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" diff --git a/rustc_tools_util/README.md b/rustc_tools_util/README.md index 01891b51d3b0f..e947f9c7e66ed 100644 --- a/rustc_tools_util/README.md +++ b/rustc_tools_util/README.md @@ -6,17 +6,17 @@ for packages installed from a git repo ## Usage Add a `build.rs` file to your repo and list it in `Cargo.toml` -```` +````toml build = "build.rs" ```` List rustc_tools_util as regular AND build dependency. -```` +````toml [dependencies] -rustc_tools_util = "0.1" +rustc_tools_util = "0.2.1" [build-dependencies] -rustc_tools_util = "0.1" +rustc_tools_util = "0.2.1" ```` In `build.rs`, generate the data in your `main()` diff --git a/rustc_tools_util/src/lib.rs b/rustc_tools_util/src/lib.rs index 0f98860167010..01d25c53126fd 100644 --- a/rustc_tools_util/src/lib.rs +++ b/rustc_tools_util/src/lib.rs @@ -137,7 +137,7 @@ mod test { let vi = get_version_info!(); assert_eq!(vi.major, 0); assert_eq!(vi.minor, 2); - assert_eq!(vi.patch, 0); + assert_eq!(vi.patch, 1); assert_eq!(vi.crate_name, "rustc_tools_util"); // hard to make positive tests for these since they will always change assert!(vi.commit_hash.is_none()); @@ -147,7 +147,7 @@ mod test { #[test] fn test_display_local() { let vi = get_version_info!(); - assert_eq!(vi.to_string(), "rustc_tools_util 0.2.0"); + assert_eq!(vi.to_string(), "rustc_tools_util 0.2.1"); } #[test] @@ -156,7 +156,7 @@ mod test { let s = format!("{vi:?}"); assert_eq!( s, - "VersionInfo { crate_name: \"rustc_tools_util\", major: 0, minor: 2, patch: 0 }" + "VersionInfo { crate_name: \"rustc_tools_util\", major: 0, minor: 2, patch: 1 }" ); } } From ce609c661b99015df63cf20a4d72d69fdfbf5836 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 1 Oct 2022 16:40:10 +0200 Subject: [PATCH 080/114] use rustc_tools_util dependency from crates.io instead of this repo. Fixes #9553 --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index dbf0dd3380625..5223dca073fd7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ path = "src/driver.rs" [dependencies] clippy_lints = { path = "clippy_lints" } semver = "1.0" -rustc_tools_util = { path = "rustc_tools_util" } +rustc_tools_util = "0.2.1" tempfile = { version = "3.2", optional = true } termize = "0.1" @@ -56,7 +56,7 @@ tokio = { version = "1", features = ["io-util"] } rustc-semver = "1.1" [build-dependencies] -rustc_tools_util = { version = "0.2.1", path = "rustc_tools_util" } +rustc_tools_util = "0.2.1" [features] deny-warnings = ["clippy_lints/deny-warnings"] From eef5d477b59a3b68bca9c1f3a5334229fc0ad9b6 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Sat, 1 Oct 2022 17:55:22 +0200 Subject: [PATCH 081/114] use `is_integer_literal` more --- clippy_lints/src/bool_to_int_with_if.rs | 21 ++-------- clippy_lints/src/checked_conversions.rs | 14 +------ clippy_lints/src/from_str_radix_10.rs | 4 +- clippy_lints/src/implicit_saturating_sub.rs | 18 ++------ clippy_lints/src/methods/get_last_with_len.rs | 6 +-- clippy_lints/src/misc.rs | 6 +-- .../src/operators/arithmetic_side_effects.rs | 28 +++++-------- .../src/operators/numeric_arithmetic.rs | 9 ++-- .../src/slow_vector_initialization.rs | 12 +++--- .../src/transmute/transmuting_null.rs | 41 +++++++------------ clippy_lints/src/uninit_vec.rs | 15 +------ 11 files changed, 52 insertions(+), 122 deletions(-) diff --git a/clippy_lints/src/bool_to_int_with_if.rs b/clippy_lints/src/bool_to_int_with_if.rs index 51e98cda84519..001d74c260545 100644 --- a/clippy_lints/src/bool_to_int_with_if.rs +++ b/clippy_lints/src/bool_to_int_with_if.rs @@ -3,7 +3,7 @@ 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, sugg::Sugg}; +use clippy_utils::{diagnostics::span_lint_and_then, is_else_clause, is_integer_literal, sugg::Sugg}; use rustc_errors::Applicability; declare_clippy_lint! { @@ -56,13 +56,9 @@ fn check_if_else<'tcx>(ctx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx && let Some(then_lit) = int_literal(then) && let Some(else_lit) = int_literal(else_) { - let inverted = if - check_int_literal_equals_val(then_lit, 1) - && check_int_literal_equals_val(else_lit, 0) { + let inverted = if is_integer_literal(then_lit, 1) && is_integer_literal(else_lit, 0) { false - } else if - check_int_literal_equals_val(then_lit, 0) - && check_int_literal_equals_val(else_lit, 1) { + } else if is_integer_literal(then_lit, 0) && is_integer_literal(else_lit, 1) { true } else { // Expression isn't boolean, exit @@ -123,14 +119,3 @@ fn int_literal<'tcx>(expr: &'tcx rustc_hir::Expr<'tcx>) -> Option<&'tcx rustc_hi None } } - -fn check_int_literal_equals_val<'tcx>(expr: &'tcx rustc_hir::Expr<'tcx>, expected_value: u128) -> bool { - if let ExprKind::Lit(lit) = &expr.kind - && let LitKind::Int(val, _) = lit.node - && val == expected_value - { - true - } else { - false - } -} diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs index 1d113c7cbee6c..78e9921f036f3 100644 --- a/clippy_lints/src/checked_conversions.rs +++ b/clippy_lints/src/checked_conversions.rs @@ -2,9 +2,8 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{in_constant, meets_msrv, msrvs, SpanlessEq}; +use clippy_utils::{in_constant, is_integer_literal, meets_msrv, msrvs, SpanlessEq}; use if_chain::if_chain; -use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -223,16 +222,7 @@ fn check_lower_bound<'tcx>(expr: &'tcx Expr<'tcx>) -> Option> { /// Check for `expr >= 0` fn check_lower_bound_zero<'a>(candidate: &'a Expr<'_>, check: &'a Expr<'_>) -> Option> { - if_chain! { - if let ExprKind::Lit(ref lit) = &check.kind; - if let LitKind::Int(0, _) = &lit.node; - - then { - Some(Conversion::new_any(candidate)) - } else { - None - } - } + is_integer_literal(check, 0).then(|| Conversion::new_any(candidate)) } /// Check for `expr >= (to_type::MIN as from_type)` diff --git a/clippy_lints/src/from_str_radix_10.rs b/clippy_lints/src/from_str_radix_10.rs index 2a82473be8c5e..cf8b7acd66d22 100644 --- a/clippy_lints/src/from_str_radix_10.rs +++ b/clippy_lints/src/from_str_radix_10.rs @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_integer_literal; use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; @@ -60,8 +61,7 @@ impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 { if pathseg.ident.name.as_str() == "from_str_radix"; // check if the second argument is a primitive `10` - if let ExprKind::Lit(lit) = &radix.kind; - if let rustc_ast::ast::LitKind::Int(10, _) = lit.node; + if is_integer_literal(radix, 10); then { let expr = if let ExprKind::AddrOf(_, _, expr) = &src.kind { diff --git a/clippy_lints/src/implicit_saturating_sub.rs b/clippy_lints/src/implicit_saturating_sub.rs index f0dbe17d83a5c..48edbf6ae576c 100644 --- a/clippy_lints/src/implicit_saturating_sub.rs +++ b/clippy_lints/src/implicit_saturating_sub.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::{higher, peel_blocks_with_stmt, SpanlessEq}; +use clippy_utils::{higher, is_integer_literal, peel_blocks_with_stmt, SpanlessEq}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -131,17 +131,8 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub { fn subtracts_one<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<&'a Expr<'a>> { match peel_blocks_with_stmt(expr).kind { ExprKind::AssignOp(ref op1, target, value) => { - if_chain! { - if BinOpKind::Sub == op1.node; - // Check if literal being subtracted is one - if let ExprKind::Lit(ref lit1) = value.kind; - if let LitKind::Int(1, _) = lit1.node; - then { - Some(target) - } else { - None - } - } + // Check if literal being subtracted is one + (BinOpKind::Sub == op1.node && is_integer_literal(value, 1)).then_some(target) }, ExprKind::Assign(target, value, _) => { if_chain! { @@ -150,8 +141,7 @@ fn subtracts_one<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<&'a Exp if SpanlessEq::new(cx).eq_expr(left1, target); - if let ExprKind::Lit(ref lit1) = right1.kind; - if let LitKind::Int(1, _) = lit1.node; + if is_integer_literal(right1, 1); then { Some(target) } else { diff --git a/clippy_lints/src/methods/get_last_with_len.rs b/clippy_lints/src/methods/get_last_with_len.rs index 02aada87202c2..3bdc154df0495 100644 --- a/clippy_lints/src/methods/get_last_with_len.rs +++ b/clippy_lints/src/methods/get_last_with_len.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::SpanlessEq; -use rustc_ast::LitKind; +use clippy_utils::{is_integer_literal, SpanlessEq}; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; @@ -26,8 +25,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: && lhs_path.ident.name == sym::len // RHS of subtraction is 1 - && let ExprKind::Lit(rhs_lit) = &rhs.kind - && let LitKind::Int(1, ..) = rhs_lit.node + && is_integer_literal(rhs, 1) // check that recv == lhs_recv `recv.get(lhs_recv.len() - 1)` && SpanlessEq::new(cx).eq_expr(recv, lhs_recv) diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 381458b91e679..516dee20f8b15 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_hir_and_then}; use clippy_utils::source::{snippet, snippet_opt}; use if_chain::if_chain; -use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{ @@ -15,7 +14,7 @@ use rustc_span::hygiene::DesugaringKind; use rustc_span::source_map::{ExpnKind, Span}; use clippy_utils::sugg::Sugg; -use clippy_utils::{get_parent_expr, in_constant, iter_input_pats, last_path_segment, SpanlessEq}; +use clippy_utils::{get_parent_expr, in_constant, is_integer_literal, iter_input_pats, last_path_segment, SpanlessEq}; declare_clippy_lint! { /// ### What it does @@ -314,8 +313,7 @@ fn non_macro_local(cx: &LateContext<'_>, res: def::Res) -> bool { fn check_cast(cx: &LateContext<'_>, span: Span, e: &Expr<'_>, ty: &hir::Ty<'_>) { if_chain! { if let TyKind::Ptr(ref mut_ty) = ty.kind; - if let ExprKind::Lit(ref lit) = e.kind; - if let LitKind::Int(0, _) = lit.node; + if is_integer_literal(e, 0); if !in_constant(cx, e.hir_id); then { let (msg, sugg_fn) = match mut_ty.mutbl { diff --git a/clippy_lints/src/operators/arithmetic_side_effects.rs b/clippy_lints/src/operators/arithmetic_side_effects.rs index c8a374d90b559..1f22fbd538724 100644 --- a/clippy_lints/src/operators/arithmetic_side_effects.rs +++ b/clippy_lints/src/operators/arithmetic_side_effects.rs @@ -44,25 +44,19 @@ 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, expr: &hir::Expr<'_>) -> bool { - if let hir::BinOpKind::Add | hir::BinOpKind::Sub = op.node - && let hir::ExprKind::Lit(ref lit) = expr.kind - && let ast::LitKind::Int(0, _) = lit.node + if let hir::ExprKind::Lit(ref lit) = expr.kind && + let ast::LitKind::Int(value, _) = lit.node { - return true; - } - if let hir::BinOpKind::Div | hir::BinOpKind::Rem = op.node - && let hir::ExprKind::Lit(ref lit) = expr.kind - && !matches!(lit.node, ast::LitKind::Int(0, _)) - { - return true; - } - if let hir::BinOpKind::Mul = op.node - && let hir::ExprKind::Lit(ref lit) = expr.kind - && let ast::LitKind::Int(0 | 1, _) = lit.node - { - return true; + match (&op.node, value) { + (hir::BinOpKind::Add | hir::BinOpKind::Sub, 0) | + (hir::BinOpKind::Mul, 0 | 1) => true, + (hir::BinOpKind::Div | hir::BinOpKind::Rem, 0) => false, + (hir::BinOpKind::Div | hir::BinOpKind::Rem, _) => true, + _ => false, + } + } else { + false } - false } /// Checks if the given `expr` has any of the inner `allowed` elements. diff --git a/clippy_lints/src/operators/numeric_arithmetic.rs b/clippy_lints/src/operators/numeric_arithmetic.rs index b6097710dc689..0830a106f5568 100644 --- a/clippy_lints/src/operators/numeric_arithmetic.rs +++ b/clippy_lints/src/operators/numeric_arithmetic.rs @@ -1,5 +1,6 @@ use clippy_utils::consts::constant_simple; use clippy_utils::diagnostics::span_lint; +use clippy_utils::is_integer_literal; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::source_map::Span; @@ -50,11 +51,9 @@ impl Context { hir::BinOpKind::Div | hir::BinOpKind::Rem => match &r.kind { hir::ExprKind::Lit(_lit) => (), hir::ExprKind::Unary(hir::UnOp::Neg, expr) => { - if let hir::ExprKind::Lit(lit) = &expr.kind { - if let rustc_ast::ast::LitKind::Int(1, _) = lit.node { - span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected"); - self.expr_id = Some(expr.hir_id); - } + if is_integer_literal(expr, 1) { + span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected"); + self.expr_id = Some(expr.hir_id); } }, _ => { diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index e57ab8cd7a3ac..6e5d88e1b59de 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -1,9 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{get_enclosing_block, is_expr_path_def_path, path_to_local, path_to_local_id, paths, SpanlessEq}; +use clippy_utils::{ + get_enclosing_block, is_expr_path_def_path, is_integer_literal, path_to_local, path_to_local_id, paths, SpanlessEq, +}; use if_chain::if_chain; -use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_block, walk_expr, walk_stmt, Visitor}; use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, PatKind, QPath, Stmt, StmtKind}; @@ -219,8 +220,7 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> { && path_to_local_id(self_arg, self.vec_alloc.local_id) && path.ident.name == sym!(resize) // Check that is filled with 0 - && let ExprKind::Lit(ref lit) = fill_arg.kind - && let LitKind::Int(0, _) = lit.node { + && is_integer_literal(fill_arg, 0) { // Check that len expression is equals to `with_capacity` expression if SpanlessEq::new(self.cx).eq_expr(len_arg, self.vec_alloc.len_expr) { self.slow_expression = Some(InitializationType::Resize(expr)); @@ -255,9 +255,7 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> { if_chain! { if let ExprKind::Call(fn_expr, [repeat_arg]) = expr.kind; if is_expr_path_def_path(self.cx, fn_expr, &paths::ITER_REPEAT); - if let ExprKind::Lit(ref lit) = repeat_arg.kind; - if let LitKind::Int(0, _) = lit.node; - + if is_integer_literal(repeat_arg, 0); then { true } else { diff --git a/clippy_lints/src/transmute/transmuting_null.rs b/clippy_lints/src/transmute/transmuting_null.rs index d8e349af7af8e..19ce5ae72c24e 100644 --- a/clippy_lints/src/transmute/transmuting_null.rs +++ b/clippy_lints/src/transmute/transmuting_null.rs @@ -1,8 +1,6 @@ use clippy_utils::consts::{constant_context, Constant}; use clippy_utils::diagnostics::span_lint; -use clippy_utils::is_path_diagnostic_item; -use if_chain::if_chain; -use rustc_ast::LitKind; +use clippy_utils::{is_integer_literal, is_path_diagnostic_item}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::Ty; @@ -19,37 +17,28 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t // Catching transmute over constants that resolve to `null`. let mut const_eval_context = constant_context(cx, cx.typeck_results()); - if_chain! { - if let ExprKind::Path(ref _qpath) = arg.kind; - if let Some(Constant::RawPtr(x)) = const_eval_context.expr(arg); - if x == 0; - then { - span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG); - return true; - } + if let ExprKind::Path(ref _qpath) = arg.kind && + let Some(Constant::RawPtr(x)) = const_eval_context.expr(arg) && + x == 0 + { + span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG); + return true; } // Catching: // `std::mem::transmute(0 as *const i32)` - if_chain! { - if let ExprKind::Cast(inner_expr, _cast_ty) = arg.kind; - if let ExprKind::Lit(ref lit) = inner_expr.kind; - if let LitKind::Int(0, _) = lit.node; - then { - span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG); - return true; - } + if let ExprKind::Cast(inner_expr, _cast_ty) = arg.kind && is_integer_literal(inner_expr, 0) { + span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG); + return true; } // Catching: // `std::mem::transmute(std::ptr::null::())` - if_chain! { - if let ExprKind::Call(func1, []) = arg.kind; - if is_path_diagnostic_item(cx, func1, sym::ptr_null); - then { - span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG); - return true; - } + if let ExprKind::Call(func1, []) = arg.kind && + is_path_diagnostic_item(cx, func1, sym::ptr_null) + { + span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG); + return true; } // FIXME: diff --git a/clippy_lints/src/uninit_vec.rs b/clippy_lints/src/uninit_vec.rs index bde7c318f448c..1ab0162a88134 100644 --- a/clippy_lints/src/uninit_vec.rs +++ b/clippy_lints/src/uninit_vec.rs @@ -1,8 +1,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::higher::{get_vec_init_kind, VecInitKind}; use clippy_utils::ty::{is_type_diagnostic_item, is_uninit_value_valid_for_ty}; -use clippy_utils::{is_lint_allowed, path_to_local_id, peel_hir_expr_while, SpanlessEq}; -use rustc_ast::ast::LitKind; +use clippy_utils::{is_integer_literal, is_lint_allowed, path_to_local_id, peel_hir_expr_while, SpanlessEq}; use rustc_hir::{Block, Expr, ExprKind, HirId, PatKind, PathSegment, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; @@ -216,7 +215,7 @@ fn extract_set_len_self<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Opt let self_type = cx.typeck_results().expr_ty(self_expr).peel_refs(); if is_type_diagnostic_item(cx, self_type, sym::Vec) && path.ident.name.as_str() == "set_len" - && !is_literal_zero(arg) + && !is_integer_literal(arg, 0) { Some((self_expr, expr.span)) } else { @@ -226,13 +225,3 @@ fn extract_set_len_self<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Opt _ => None, } } - -fn is_literal_zero(arg: &Expr<'_>) -> bool { - if let ExprKind::Lit(lit) = &arg.kind - && let LitKind::Int(0, _) = lit.node - { - true - } else { - false - } -} From b22118457245cdd074daaaaea950ec49397f8712 Mon Sep 17 00:00:00 2001 From: Jacob Kiesel Date: Thu, 15 Sep 2022 20:50:28 -0600 Subject: [PATCH 082/114] Implement manual_clamp lint --- CHANGELOG.md | 1 + clippy_lints/src/lib.register_all.rs | 1 + clippy_lints/src/lib.register_complexity.rs | 1 + clippy_lints/src/lib.register_lints.rs | 1 + clippy_lints/src/lib.rs | 2 + clippy_lints/src/manual_clamp.rs | 715 ++++++++++++++++++++ clippy_lints/src/utils/conf.rs | 2 +- clippy_utils/src/msrvs.rs | 2 +- src/docs.rs | 1 + src/docs/manual_clamp.txt | 46 ++ tests/ui/manual_clamp.rs | 304 +++++++++ tests/ui/manual_clamp.stderr | 375 ++++++++++ tests/ui/min_max.rs | 1 + tests/ui/min_max.stderr | 26 +- tests/ui/min_rust_version_attr.rs | 12 + tests/ui/min_rust_version_attr.stderr | 8 +- 16 files changed, 1479 insertions(+), 19 deletions(-) create mode 100644 clippy_lints/src/manual_clamp.rs create mode 100644 src/docs/manual_clamp.txt create mode 100644 tests/ui/manual_clamp.rs create mode 100644 tests/ui/manual_clamp.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index ef6140152ffca..9f12a67359624 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3985,6 +3985,7 @@ Released 2018-09-13 [`manual_assert`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_assert [`manual_async_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn [`manual_bits`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_bits +[`manual_clamp`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_clamp [`manual_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter_map [`manual_find`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find [`manual_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find_map diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index 435411642a75c..9ad2a88eb26ca 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -125,6 +125,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ 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), diff --git a/clippy_lints/src/lib.register_complexity.rs b/clippy_lints/src/lib.register_complexity.rs index 185189a6af5b6..a58d066fa6b67 100644 --- a/clippy_lints/src/lib.register_complexity.rs +++ b/clippy_lints/src/lib.register_complexity.rs @@ -22,6 +22,7 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec! 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), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index ee08d802ccfbf..f3ddac49ace1b 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -245,6 +245,7 @@ store.register_lints(&[ 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, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index fde8aa9f92173..4da3c9ece6654 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -268,6 +268,7 @@ mod main_recursion; mod manual_assert; mod manual_async_fn; mod manual_bits; +mod manual_clamp; mod manual_instant_elapsed; mod manual_non_exhaustive; mod manual_rem_euclid; @@ -899,6 +900,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::::default()); store.register_late_pass(|_| Box::new(manual_instant_elapsed::ManualInstantElapsed)); 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)); store.register_late_pass(|_| Box::new(unused_peekable::UnusedPeekable)); store.register_early_pass(|| Box::new(multi_assignments::MultiAssignments)); diff --git a/clippy_lints/src/manual_clamp.rs b/clippy_lints/src/manual_clamp.rs new file mode 100644 index 0000000000000..ac5c24ee604bd --- /dev/null +++ b/clippy_lints/src/manual_clamp.rs @@ -0,0 +1,715 @@ +use itertools::Itertools; +use rustc_errors::Diagnostic; +use rustc_hir::{ + def::Res, Arm, BinOpKind, Block, Expr, ExprKind, Guard, HirId, PatKind, PathSegment, PrimTy, QPath, StmtKind, +}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::Ty; +use rustc_semver::RustcVersion; +use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::{symbol::sym, Span}; +use std::ops::Deref; + +use clippy_utils::{ + diagnostics::{span_lint_and_then, span_lint_hir_and_then}, + eq_expr_value, get_trait_def_id, + higher::If, + is_diag_trait_item, is_trait_method, meets_msrv, msrvs, path_res, path_to_local_id, paths, peel_blocks, + peel_blocks_with_stmt, + sugg::Sugg, + ty::implements_trait, + visitors::is_const_evaluatable, + MaybePath, +}; +use rustc_errors::Applicability; + +declare_clippy_lint! { + /// ### What it does + /// Identifies good opportunities for a clamp function from std or core, and suggests using it. + /// + /// ### Why is this bad? + /// clamp is much shorter, easier to read, and doesn't use any control flow. + /// + /// ### Known issue(s) + /// If the clamped variable is NaN this suggestion will cause the code to propagate NaN + /// rather than returning either `max` or `min`. + /// + /// `clamp` functions will panic if `max < min`, `max.is_nan()`, or `min.is_nan()`. + /// Some may consider panicking in these situations to be desirable, but it also may + /// introduce panicking where there wasn't any before. + /// + /// ### Examples + /// ```rust + /// # let (input, min, max) = (0, -2, 1); + /// if input > max { + /// max + /// } else if input < min { + /// min + /// } else { + /// input + /// } + /// # ; + /// ``` + /// + /// ```rust + /// # let (input, min, max) = (0, -2, 1); + /// input.max(min).min(max) + /// # ; + /// ``` + /// + /// ```rust + /// # let (input, min, max) = (0, -2, 1); + /// match input { + /// x if x > max => max, + /// x if x < min => min, + /// x => x, + /// } + /// # ; + /// ``` + /// + /// ```rust + /// # let (input, min, max) = (0, -2, 1); + /// let mut x = input; + /// if x < min { x = min; } + /// if x > max { x = max; } + /// ``` + /// Use instead: + /// ```rust + /// # let (input, min, max) = (0, -2, 1); + /// input.clamp(min, max) + /// # ; + /// ``` + #[clippy::version = "1.66.0"] + pub MANUAL_CLAMP, + complexity, + "using a clamp pattern instead of the clamp function" +} +impl_lint_pass!(ManualClamp => [MANUAL_CLAMP]); + +pub struct ManualClamp { + msrv: Option, +} + +impl ManualClamp { + pub fn new(msrv: Option) -> Self { + Self { msrv } + } +} + +#[derive(Debug)] +struct ClampSuggestion<'tcx> { + params: InputMinMax<'tcx>, + span: Span, + make_assignment: Option<&'tcx Expr<'tcx>>, + hir_with_ignore_attr: Option, +} + +#[derive(Debug)] +struct InputMinMax<'tcx> { + input: &'tcx Expr<'tcx>, + min: &'tcx Expr<'tcx>, + max: &'tcx Expr<'tcx>, + is_float: bool, +} + +impl<'tcx> LateLintPass<'tcx> for ManualClamp { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { + if !meets_msrv(self.msrv, msrvs::CLAMP) { + return; + } + if !expr.span.from_expansion() { + let suggestion = is_if_elseif_else_pattern(cx, expr) + .or_else(|| is_max_min_pattern(cx, expr)) + .or_else(|| is_call_max_min_pattern(cx, expr)) + .or_else(|| is_match_pattern(cx, expr)) + .or_else(|| is_if_elseif_pattern(cx, expr)); + if let Some(suggestion) = suggestion { + emit_suggestion(cx, &suggestion); + } + } + } + + fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) { + if !meets_msrv(self.msrv, msrvs::CLAMP) { + return; + } + for suggestion in is_two_if_pattern(cx, block) { + emit_suggestion(cx, &suggestion); + } + } + extract_msrv_attr!(LateContext); +} + +fn emit_suggestion<'tcx>(cx: &LateContext<'tcx>, suggestion: &ClampSuggestion<'tcx>) { + let ClampSuggestion { + params: InputMinMax { + input, + min, + max, + is_float, + }, + span, + make_assignment, + hir_with_ignore_attr, + } = suggestion; + let input = Sugg::hir(cx, input, "..").maybe_par(); + let min = Sugg::hir(cx, min, ".."); + let max = Sugg::hir(cx, max, ".."); + let semicolon = if make_assignment.is_some() { ";" } else { "" }; + let assignment = if let Some(assignment) = make_assignment { + let assignment = Sugg::hir(cx, assignment, ".."); + format!("{assignment} = ") + } else { + String::new() + }; + let suggestion = format!("{assignment}{input}.clamp({min}, {max}){semicolon}"); + let msg = "clamp-like pattern without using clamp function"; + let lint_builder = |d: &mut Diagnostic| { + d.span_suggestion(*span, "replace with clamp", suggestion, Applicability::MaybeIncorrect); + if *is_float { + d.note("clamp will panic if max < min, min.is_nan(), or max.is_nan()") + .note("clamp returns NaN if the input is NaN"); + } else { + d.note("clamp will panic if max < min"); + } + }; + if let Some(hir_id) = hir_with_ignore_attr { + span_lint_hir_and_then(cx, MANUAL_CLAMP, *hir_id, *span, msg, lint_builder); + } else { + span_lint_and_then(cx, MANUAL_CLAMP, *span, msg, lint_builder); + } +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +enum TypeClampability { + Float, + Ord, +} + +impl TypeClampability { + fn is_clampable<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option { + if ty.is_floating_point() { + Some(TypeClampability::Float) + } else if get_trait_def_id(cx, &paths::ORD).map_or(false, |id| implements_trait(cx, ty, id, &[])) { + Some(TypeClampability::Ord) + } else { + None + } + } + + fn is_float(self) -> bool { + matches!(self, TypeClampability::Float) + } +} + +/// Targets patterns like +/// +/// ``` +/// # let (input, min, max) = (0, -3, 12); +/// +/// if input < min { +/// min +/// } else if input > max { +/// max +/// } else { +/// input +/// } +/// # ; +/// ``` +fn is_if_elseif_else_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option> { + if let Some(If { + cond, + then, + r#else: Some(else_if), + }) = If::hir(expr) + && let Some(If { + cond: else_if_cond, + then: else_if_then, + r#else: Some(else_body), + }) = If::hir(peel_blocks(else_if)) + { + let params = is_clamp_meta_pattern( + cx, + &BinaryOp::new(peel_blocks(cond))?, + &BinaryOp::new(peel_blocks(else_if_cond))?, + peel_blocks(then), + peel_blocks(else_if_then), + None, + )?; + // Contents of the else should be the resolved input. + if !eq_expr_value(cx, params.input, peel_blocks(else_body)) { + return None; + } + Some(ClampSuggestion { + params, + span: expr.span, + make_assignment: None, + hir_with_ignore_attr: None, + }) + } else { + None + } +} + +/// Targets patterns like +/// +/// ``` +/// # let (input, min_value, max_value) = (0, -3, 12); +/// +/// input.max(min_value).min(max_value) +/// # ; +/// ``` +fn is_max_min_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option> { + if let ExprKind::MethodCall(seg_second, receiver, [arg_second], _) = &expr.kind + && (cx.typeck_results().expr_ty_adjusted(receiver).is_floating_point() || is_trait_method(cx, expr, sym::Ord)) + && let ExprKind::MethodCall(seg_first, input, [arg_first], _) = &receiver.kind + && (cx.typeck_results().expr_ty_adjusted(input).is_floating_point() || is_trait_method(cx, receiver, sym::Ord)) + { + let is_float = cx.typeck_results().expr_ty_adjusted(input).is_floating_point(); + let (min, max) = match (seg_first.ident.as_str(), seg_second.ident.as_str()) { + ("min", "max") => (arg_second, arg_first), + ("max", "min") => (arg_first, arg_second), + _ => return None, + }; + Some(ClampSuggestion { + params: InputMinMax { input, min, max, is_float }, + span: expr.span, + make_assignment: None, + hir_with_ignore_attr: None, + }) + } else { + None + } +} + +/// Targets patterns like +/// +/// ``` +/// # let (input, min_value, max_value) = (0, -3, 12); +/// # use std::cmp::{max, min}; +/// min(max(input, min_value), max_value) +/// # ; +/// ``` +fn is_call_max_min_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option> { + fn segment<'tcx>(cx: &LateContext<'_>, func: &Expr<'tcx>) -> Option> { + match func.kind { + ExprKind::Path(QPath::Resolved(None, path)) => { + let id = path.res.opt_def_id()?; + match cx.tcx.get_diagnostic_name(id) { + Some(sym::cmp_min) => Some(FunctionType::CmpMin), + Some(sym::cmp_max) => Some(FunctionType::CmpMax), + _ if is_diag_trait_item(cx, id, sym::Ord) => { + Some(FunctionType::OrdOrFloat(path.segments.last().expect("infallible"))) + }, + _ => None, + } + }, + ExprKind::Path(QPath::TypeRelative(ty, seg)) => { + matches!(path_res(cx, ty), Res::PrimTy(PrimTy::Float(_))).then(|| FunctionType::OrdOrFloat(seg)) + }, + _ => None, + } + } + + enum FunctionType<'tcx> { + CmpMin, + CmpMax, + OrdOrFloat(&'tcx PathSegment<'tcx>), + } + + fn check<'tcx>( + cx: &LateContext<'tcx>, + outer_fn: &'tcx Expr<'tcx>, + inner_call: &'tcx Expr<'tcx>, + outer_arg: &'tcx Expr<'tcx>, + span: Span, + ) -> Option> { + if let ExprKind::Call(inner_fn, &[ref first, ref second]) = &inner_call.kind + && let Some(inner_seg) = segment(cx, inner_fn) + && let Some(outer_seg) = segment(cx, outer_fn) + { + let (input, inner_arg) = match (is_const_evaluatable(cx, first), is_const_evaluatable(cx, second)) { + (true, false) => (second, first), + (false, true) => (first, second), + _ => return None, + }; + let is_float = cx.typeck_results().expr_ty_adjusted(input).is_floating_point(); + let (min, max) = match (inner_seg, outer_seg) { + (FunctionType::CmpMin, FunctionType::CmpMax) => (outer_arg, inner_arg), + (FunctionType::CmpMax, FunctionType::CmpMin) => (inner_arg, outer_arg), + (FunctionType::OrdOrFloat(first_segment), FunctionType::OrdOrFloat(second_segment)) => { + match (first_segment.ident.as_str(), second_segment.ident.as_str()) { + ("min", "max") => (outer_arg, inner_arg), + ("max", "min") => (inner_arg, outer_arg), + _ => return None, + } + } + _ => return None, + }; + Some(ClampSuggestion { + params: InputMinMax { input, min, max, is_float }, + span, + make_assignment: None, + hir_with_ignore_attr: None, + }) + } else { + None + } + } + + if let ExprKind::Call(outer_fn, [first, second]) = &expr.kind { + check(cx, outer_fn, first, second, expr.span).or_else(|| check(cx, outer_fn, second, first, expr.span)) + } else { + None + } +} + +/// Targets patterns like +/// +/// ``` +/// # let (input, min, max) = (0, -3, 12); +/// +/// match input { +/// input if input > max => max, +/// input if input < min => min, +/// input => input, +/// } +/// # ; +/// ``` +fn is_match_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option> { + if let ExprKind::Match(value, &[ref first_arm, ref second_arm, ref last_arm], rustc_hir::MatchSource::Normal) = + &expr.kind + { + // Find possible min/max branches + let minmax_values = |a: &'tcx Arm<'tcx>| { + if let PatKind::Binding(_, var_hir_id, _, None) = &a.pat.kind + && let Some(Guard::If(e)) = a.guard { + Some((e, var_hir_id, a.body)) + } else { + None + } + }; + let (first, first_hir_id, first_expr) = minmax_values(first_arm)?; + let (second, second_hir_id, second_expr) = minmax_values(second_arm)?; + let first = BinaryOp::new(first)?; + let second = BinaryOp::new(second)?; + if let PatKind::Binding(_, binding, _, None) = &last_arm.pat.kind + && path_to_local_id(peel_blocks_with_stmt(last_arm.body), *binding) + && last_arm.guard.is_none() + { + // Proceed as normal + } else { + return None; + } + if let Some(params) = is_clamp_meta_pattern( + cx, + &first, + &second, + first_expr, + second_expr, + Some((*first_hir_id, *second_hir_id)), + ) { + return Some(ClampSuggestion { + params: InputMinMax { + input: value, + min: params.min, + max: params.max, + is_float: params.is_float, + }, + span: expr.span, + make_assignment: None, + hir_with_ignore_attr: None, + }); + } + } + None +} + +/// Targets patterns like +/// +/// ``` +/// # let (input, min, max) = (0, -3, 12); +/// +/// let mut x = input; +/// if x < min { x = min; } +/// if x > max { x = max; } +/// ``` +fn is_two_if_pattern<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) -> Vec> { + block_stmt_with_last(block) + .tuple_windows() + .filter_map(|(maybe_set_first, maybe_set_second)| { + if let StmtKind::Expr(first_expr) = *maybe_set_first + && let StmtKind::Expr(second_expr) = *maybe_set_second + && let Some(If { cond: first_cond, then: first_then, r#else: None }) = If::hir(first_expr) + && let Some(If { cond: second_cond, then: second_then, r#else: None }) = If::hir(second_expr) + && let ExprKind::Assign( + maybe_input_first_path, + maybe_min_max_first, + _ + ) = peel_blocks_with_stmt(first_then).kind + && let ExprKind::Assign( + maybe_input_second_path, + maybe_min_max_second, + _ + ) = peel_blocks_with_stmt(second_then).kind + && eq_expr_value(cx, maybe_input_first_path, maybe_input_second_path) + && let Some(first_bin) = BinaryOp::new(first_cond) + && let Some(second_bin) = BinaryOp::new(second_cond) + && let Some(input_min_max) = is_clamp_meta_pattern( + cx, + &first_bin, + &second_bin, + maybe_min_max_first, + maybe_min_max_second, + None + ) + { + Some(ClampSuggestion { + params: InputMinMax { + input: maybe_input_first_path, + min: input_min_max.min, + max: input_min_max.max, + is_float: input_min_max.is_float, + }, + span: first_expr.span.to(second_expr.span), + make_assignment: Some(maybe_input_first_path), + hir_with_ignore_attr: Some(first_expr.hir_id()), + }) + } else { + None + } + }) + .collect() +} + +/// Targets patterns like +/// +/// ``` +/// # let (mut input, min, max) = (0, -3, 12); +/// +/// if input < min { +/// input = min; +/// } else if input > max { +/// input = max; +/// } +/// ``` +fn is_if_elseif_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option> { + if let Some(If { + cond, + then, + r#else: Some(else_if), + }) = If::hir(expr) + && let Some(If { + cond: else_if_cond, + then: else_if_then, + r#else: None, + }) = If::hir(peel_blocks(else_if)) + && let ExprKind::Assign( + maybe_input_first_path, + maybe_min_max_first, + _ + ) = peel_blocks_with_stmt(then).kind + && let ExprKind::Assign( + maybe_input_second_path, + maybe_min_max_second, + _ + ) = peel_blocks_with_stmt(else_if_then).kind + { + let params = is_clamp_meta_pattern( + cx, + &BinaryOp::new(peel_blocks(cond))?, + &BinaryOp::new(peel_blocks(else_if_cond))?, + peel_blocks(maybe_min_max_first), + peel_blocks(maybe_min_max_second), + None, + )?; + if !eq_expr_value(cx, maybe_input_first_path, maybe_input_second_path) { + return None; + } + Some(ClampSuggestion { + params, + span: expr.span, + make_assignment: Some(maybe_input_first_path), + hir_with_ignore_attr: None, + }) + } else { + None + } +} + +/// `ExprKind::Binary` but more narrowly typed +#[derive(Debug, Clone, Copy)] +struct BinaryOp<'tcx> { + op: BinOpKind, + left: &'tcx Expr<'tcx>, + right: &'tcx Expr<'tcx>, +} + +impl<'tcx> BinaryOp<'tcx> { + fn new(e: &'tcx Expr<'tcx>) -> Option> { + match &e.kind { + ExprKind::Binary(op, left, right) => Some(BinaryOp { + op: op.node, + left, + right, + }), + _ => None, + } + } + + fn flip(&self) -> Self { + Self { + op: match self.op { + BinOpKind::Le => BinOpKind::Ge, + BinOpKind::Lt => BinOpKind::Gt, + BinOpKind::Ge => BinOpKind::Le, + BinOpKind::Gt => BinOpKind::Lt, + other => other, + }, + left: self.right, + right: self.left, + } + } +} + +/// The clamp meta pattern is a pattern shared between many (but not all) patterns. +/// In summary, this pattern consists of two if statements that meet many criteria, +/// - binary operators that are one of [`>`, `<`, `>=`, `<=`]. +/// - Both binary statements must have a shared argument +/// - Which can appear on the left or right side of either statement +/// - The binary operators must define a finite range for the shared argument. To put this in +/// the terms of Rust `std` library, the following ranges are acceptable +/// - `Range` +/// - `RangeInclusive` +/// And all other range types are not accepted. For the purposes of `clamp` it's irrelevant +/// whether the range is inclusive or not, the output is the same. +/// - The result of each if statement must be equal to the argument unique to that if statement. The +/// result can not be the shared argument in either case. +fn is_clamp_meta_pattern<'tcx>( + cx: &LateContext<'tcx>, + first_bin: &BinaryOp<'tcx>, + second_bin: &BinaryOp<'tcx>, + first_expr: &'tcx Expr<'tcx>, + second_expr: &'tcx Expr<'tcx>, + // This parameters is exclusively for the match pattern. + // It exists because the variable bindings used in that pattern + // refer to the variable bound in the match arm, not the variable + // bound outside of it. Fortunately due to context we know this has to + // be the input variable, not the min or max. + input_hir_ids: Option<(HirId, HirId)>, +) -> Option> { + fn check<'tcx>( + cx: &LateContext<'tcx>, + first_bin: &BinaryOp<'tcx>, + second_bin: &BinaryOp<'tcx>, + first_expr: &'tcx Expr<'tcx>, + second_expr: &'tcx Expr<'tcx>, + input_hir_ids: Option<(HirId, HirId)>, + is_float: bool, + ) -> Option> { + match (&first_bin.op, &second_bin.op) { + (BinOpKind::Ge | BinOpKind::Gt, BinOpKind::Le | BinOpKind::Lt) => { + let (min, max) = (second_expr, first_expr); + let refers_to_input = match input_hir_ids { + Some((first_hir_id, second_hir_id)) => { + path_to_local_id(peel_blocks(first_bin.left), first_hir_id) + && path_to_local_id(peel_blocks(second_bin.left), second_hir_id) + }, + None => eq_expr_value(cx, first_bin.left, second_bin.left), + }; + (refers_to_input + && eq_expr_value(cx, first_bin.right, first_expr) + && eq_expr_value(cx, second_bin.right, second_expr)) + .then_some(InputMinMax { + input: first_bin.left, + min, + max, + is_float, + }) + }, + _ => None, + } + } + // First filter out any expressions with side effects + let exprs = [ + first_bin.left, + first_bin.right, + second_bin.left, + second_bin.right, + first_expr, + second_expr, + ]; + let clampability = TypeClampability::is_clampable(cx, cx.typeck_results().expr_ty(first_expr))?; + let is_float = clampability.is_float(); + if exprs.iter().any(|e| peel_blocks(e).can_have_side_effects()) { + return None; + } + if !(is_ord_op(first_bin.op) && is_ord_op(second_bin.op)) { + return None; + } + let cases = [ + (*first_bin, *second_bin), + (first_bin.flip(), second_bin.flip()), + (first_bin.flip(), *second_bin), + (*first_bin, second_bin.flip()), + ]; + + cases.into_iter().find_map(|(first, second)| { + check(cx, &first, &second, first_expr, second_expr, input_hir_ids, is_float).or_else(|| { + check( + cx, + &second, + &first, + second_expr, + first_expr, + input_hir_ids.map(|(l, r)| (r, l)), + is_float, + ) + }) + }) +} + +fn block_stmt_with_last<'tcx>(block: &'tcx Block<'tcx>) -> impl Iterator> { + block + .stmts + .iter() + .map(|s| MaybeBorrowedStmtKind::Borrowed(&s.kind)) + .chain( + block + .expr + .as_ref() + .map(|e| MaybeBorrowedStmtKind::Owned(StmtKind::Expr(e))), + ) +} + +fn is_ord_op(op: BinOpKind) -> bool { + matches!(op, BinOpKind::Ge | BinOpKind::Gt | BinOpKind::Le | BinOpKind::Lt) +} + +/// Really similar to Cow, but doesn't have a `Clone` requirement. +#[derive(Debug)] +enum MaybeBorrowedStmtKind<'a> { + Borrowed(&'a StmtKind<'a>), + Owned(StmtKind<'a>), +} + +impl<'a> Clone for MaybeBorrowedStmtKind<'a> { + fn clone(&self) -> Self { + match self { + Self::Borrowed(t) => Self::Borrowed(t), + Self::Owned(StmtKind::Expr(e)) => Self::Owned(StmtKind::Expr(e)), + Self::Owned(_) => unreachable!("Owned should only ever contain a StmtKind::Expr."), + } + } +} + +impl<'a> Deref for MaybeBorrowedStmtKind<'a> { + type Target = StmtKind<'a>; + + fn deref(&self) -> &Self::Target { + match self { + Self::Borrowed(t) => t, + Self::Owned(t) => t, + } + } +} diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index a8265b50f273f..2b336e87ef76e 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -213,7 +213,7 @@ define_Conf! { /// /// Suppress lints whenever the suggested change would cause breakage for other crates. (avoid_breaking_exported_api: bool = true), - /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS. + /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP. /// /// The minimum rust version that the project supports (msrv: Option = None), diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index 904091c57e837..8b843732a236b 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -17,7 +17,7 @@ msrv_aliases! { 1,53,0 { OR_PATTERNS, MANUAL_BITS, BTREE_MAP_RETAIN, BTREE_SET_RETAIN, ARRAY_INTO_ITERATOR } 1,52,0 { STR_SPLIT_ONCE, REM_EUCLID_CONST } 1,51,0 { BORROW_AS_PTR, UNSIGNED_ABS } - 1,50,0 { BOOL_THEN } + 1,50,0 { BOOL_THEN, CLAMP } 1,47,0 { TAU } 1,46,0 { CONST_IF_MATCH } 1,45,0 { STR_STRIP_PREFIX } diff --git a/src/docs.rs b/src/docs.rs index 166be0618ffdd..39540e4b04892 100644 --- a/src/docs.rs +++ b/src/docs.rs @@ -255,6 +255,7 @@ docs! { "manual_assert", "manual_async_fn", "manual_bits", + "manual_clamp", "manual_filter_map", "manual_find", "manual_find_map", diff --git a/src/docs/manual_clamp.txt b/src/docs/manual_clamp.txt new file mode 100644 index 0000000000000..8993f6683adfe --- /dev/null +++ b/src/docs/manual_clamp.txt @@ -0,0 +1,46 @@ +### What it does +Identifies good opportunities for a clamp function from std or core, and suggests using it. + +### Why is this bad? +clamp is much shorter, easier to read, and doesn't use any control flow. + +### Known issue(s) +If the clamped variable is NaN this suggestion will cause the code to propagate NaN +rather than returning either `max` or `min`. + +`clamp` functions will panic if `max < min`, `max.is_nan()`, or `min.is_nan()`. +Some may consider panicking in these situations to be desirable, but it also may +introduce panicking where there wasn't any before. + +### Examples +``` +if input > max { + max +} else if input < min { + min +} else { + input +} +``` + +``` +input.max(min).min(max) +``` + +``` +match input { + x if x > max => max, + x if x < min => min, + x => x, +} +``` + +``` +let mut x = input; +if x < min { x = min; } +if x > max { x = max; } +``` +Use instead: +``` +input.clamp(min, max) +``` \ No newline at end of file diff --git a/tests/ui/manual_clamp.rs b/tests/ui/manual_clamp.rs new file mode 100644 index 0000000000000..54fd888af99fa --- /dev/null +++ b/tests/ui/manual_clamp.rs @@ -0,0 +1,304 @@ +#![warn(clippy::manual_clamp)] +#![allow( + unused, + dead_code, + clippy::unnecessary_operation, + clippy::no_effect, + clippy::if_same_then_else +)] + +use std::cmp::{max as cmp_max, min as cmp_min}; + +const CONST_MAX: i32 = 10; +const CONST_MIN: i32 = 4; + +const CONST_F64_MAX: f64 = 10.0; +const CONST_F64_MIN: f64 = 4.0; + +fn main() { + let (input, min, max) = (0, -2, 3); + // Lint + let x0 = if max < input { + max + } else if min > input { + min + } else { + input + }; + + let x1 = if input > max { + max + } else if input < min { + min + } else { + input + }; + + let x2 = if input < min { + min + } else if input > max { + max + } else { + input + }; + + let x3 = if min > input { + min + } else if max < input { + max + } else { + input + }; + + let x4 = input.max(min).min(max); + + let x5 = input.min(max).max(min); + + let x6 = match input { + x if x > max => max, + x if x < min => min, + x => x, + }; + + let x7 = match input { + x if x < min => min, + x if x > max => max, + x => x, + }; + + let x8 = match input { + x if max < x => max, + x if min > x => min, + x => x, + }; + + let mut x9 = input; + if x9 < min { + x9 = min; + } + if x9 > max { + x9 = max; + } + + let x10 = match input { + x if min > x => min, + x if max < x => max, + x => x, + }; + + let mut x11 = input; + let _ = 1; + if x11 > max { + x11 = max; + } + if x11 < min { + x11 = min; + } + + let mut x12 = input; + if min > x12 { + x12 = min; + } + if max < x12 { + x12 = max; + } + + let mut x13 = input; + if max < x13 { + x13 = max; + } + if min > x13 { + x13 = min; + } + + let x14 = if input > CONST_MAX { + CONST_MAX + } else if input < CONST_MIN { + CONST_MIN + } else { + input + }; + { + let (input, min, max) = (0.0f64, -2.0, 3.0); + let x15 = if input > max { + max + } else if input < min { + min + } else { + input + }; + } + { + let input: i32 = cmp_min_max(1); + // These can only be detected if exactly one of the arguments to the inner function is const. + let x16 = cmp_max(cmp_min(input, CONST_MAX), CONST_MIN); + let x17 = cmp_min(cmp_max(input, CONST_MIN), CONST_MAX); + let x18 = cmp_max(CONST_MIN, cmp_min(input, CONST_MAX)); + let x19 = cmp_min(CONST_MAX, cmp_max(input, CONST_MIN)); + let x20 = cmp_max(cmp_min(CONST_MAX, input), CONST_MIN); + let x21 = cmp_min(cmp_max(CONST_MIN, input), CONST_MAX); + let x22 = cmp_max(CONST_MIN, cmp_min(CONST_MAX, input)); + let x23 = cmp_min(CONST_MAX, cmp_max(CONST_MIN, input)); + let input: f64 = cmp_min_max(1) as f64; + let x24 = f64::max(f64::min(input, CONST_F64_MAX), CONST_F64_MIN); + let x25 = f64::min(f64::max(input, CONST_F64_MIN), CONST_F64_MAX); + let x26 = f64::max(CONST_F64_MIN, f64::min(input, CONST_F64_MAX)); + let x27 = f64::min(CONST_F64_MAX, f64::max(input, CONST_F64_MIN)); + let x28 = f64::max(f64::min(CONST_F64_MAX, input), CONST_F64_MIN); + let x29 = f64::min(f64::max(CONST_F64_MIN, input), CONST_F64_MAX); + let x30 = f64::max(CONST_F64_MIN, f64::min(CONST_F64_MAX, input)); + let x31 = f64::min(CONST_F64_MAX, f64::max(CONST_F64_MIN, input)); + } + let mut x32 = input; + if x32 < min { + x32 = min; + } else if x32 > max { + x32 = max; + } + + // It's important this be the last set of statements + let mut x33 = input; + if max < x33 { + x33 = max; + } + if min > x33 { + x33 = min; + } +} + +// This code intentionally nonsense. +fn no_lint() { + let (input, min, max) = (0, -2, 3); + let x0 = if max < input { + max + } else if min > input { + max + } else { + min + }; + + let x1 = if input > max { + max + } else if input > min { + min + } else { + max + }; + + let x2 = if max < min { + min + } else if input > max { + input + } else { + input + }; + + let x3 = if min > input { + input + } else if max < input { + max + } else { + max + }; + + let x6 = match input { + x if x < max => x, + x if x < min => x, + x => x, + }; + + let x7 = match input { + x if x < min => max, + x if x > max => min, + x => x, + }; + + let x8 = match input { + x if max > x => max, + x if min > x => min, + x => x, + }; + + let mut x9 = input; + if x9 > min { + x9 = min; + } + if x9 > max { + x9 = max; + } + + let x10 = match input { + x if min > x => min, + x if max < x => max, + x => min, + }; + + let mut x11 = input; + if x11 > max { + x11 = min; + } + if x11 < min { + x11 = max; + } + + let mut x12 = input; + if min > x12 { + x12 = max * 3; + } + if max < x12 { + x12 = min; + } + + let mut x13 = input; + if max < x13 { + let x13 = max; + } + if min > x13 { + x13 = min; + } + let mut x14 = input; + if x14 < min { + x14 = 3; + } else if x14 > max { + x14 = max; + } + { + let input: i32 = cmp_min_max(1); + // These can only be detected if exactly one of the arguments to the inner function is const. + let x16 = cmp_max(cmp_max(input, CONST_MAX), CONST_MIN); + let x17 = cmp_min(cmp_min(input, CONST_MIN), CONST_MAX); + let x18 = cmp_max(CONST_MIN, cmp_max(input, CONST_MAX)); + let x19 = cmp_min(CONST_MAX, cmp_min(input, CONST_MIN)); + let x20 = cmp_max(cmp_max(CONST_MAX, input), CONST_MIN); + let x21 = cmp_min(cmp_min(CONST_MIN, input), CONST_MAX); + let x22 = cmp_max(CONST_MIN, cmp_max(CONST_MAX, input)); + let x23 = cmp_min(CONST_MAX, cmp_min(CONST_MIN, input)); + let input: f64 = cmp_min_max(1) as f64; + let x24 = f64::max(f64::max(input, CONST_F64_MAX), CONST_F64_MIN); + let x25 = f64::min(f64::min(input, CONST_F64_MIN), CONST_F64_MAX); + let x26 = f64::max(CONST_F64_MIN, f64::max(input, CONST_F64_MAX)); + let x27 = f64::min(CONST_F64_MAX, f64::min(input, CONST_F64_MIN)); + let x28 = f64::max(f64::max(CONST_F64_MAX, input), CONST_F64_MIN); + let x29 = f64::min(f64::min(CONST_F64_MIN, input), CONST_F64_MAX); + let x30 = f64::max(CONST_F64_MIN, f64::max(CONST_F64_MAX, input)); + let x31 = f64::min(CONST_F64_MAX, f64::min(CONST_F64_MIN, input)); + let x32 = f64::min(CONST_F64_MAX, f64::min(CONST_F64_MIN, CONST_F64_MAX)); + } +} + +fn dont_tell_me_what_to_do() { + let (input, min, max) = (0, -2, 3); + let mut x_never = input; + #[allow(clippy::manual_clamp)] + if x_never < min { + x_never = min; + } + if x_never > max { + x_never = max; + } +} + +/// Just to ensure this isn't const evaled +fn cmp_min_max(input: i32) -> i32 { + input * 3 +} diff --git a/tests/ui/manual_clamp.stderr b/tests/ui/manual_clamp.stderr new file mode 100644 index 0000000000000..25650483595dd --- /dev/null +++ b/tests/ui/manual_clamp.stderr @@ -0,0 +1,375 @@ +error: clamp-like pattern without using clamp function + --> $DIR/manual_clamp.rs:76:5 + | +LL | / if x9 < min { +LL | | x9 = min; +LL | | } +LL | | if x9 > max { +LL | | x9 = max; +LL | | } + | |_____^ help: replace with clamp: `x9 = x9.clamp(min, max);` + | + = note: `-D clippy::manual-clamp` implied by `-D warnings` + = note: clamp will panic if max < min + +error: clamp-like pattern without using clamp function + --> $DIR/manual_clamp.rs:91:5 + | +LL | / if x11 > max { +LL | | x11 = max; +LL | | } +LL | | if x11 < min { +LL | | x11 = min; +LL | | } + | |_____^ help: replace with clamp: `x11 = x11.clamp(min, max);` + | + = note: clamp will panic if max < min + +error: clamp-like pattern without using clamp function + --> $DIR/manual_clamp.rs:99:5 + | +LL | / if min > x12 { +LL | | x12 = min; +LL | | } +LL | | if max < x12 { +LL | | x12 = max; +LL | | } + | |_____^ help: replace with clamp: `x12 = x12.clamp(min, max);` + | + = note: clamp will panic if max < min + +error: clamp-like pattern without using clamp function + --> $DIR/manual_clamp.rs:107:5 + | +LL | / if max < x13 { +LL | | x13 = max; +LL | | } +LL | | if min > x13 { +LL | | x13 = min; +LL | | } + | |_____^ help: replace with clamp: `x13 = x13.clamp(min, max);` + | + = note: clamp will panic if max < min + +error: clamp-like pattern without using clamp function + --> $DIR/manual_clamp.rs:161:5 + | +LL | / if max < x33 { +LL | | x33 = max; +LL | | } +LL | | if min > x33 { +LL | | x33 = min; +LL | | } + | |_____^ help: replace with clamp: `x33 = x33.clamp(min, max);` + | + = note: clamp will panic if max < min + +error: clamp-like pattern without using clamp function + --> $DIR/manual_clamp.rs:21:14 + | +LL | let x0 = if max < input { + | ______________^ +LL | | max +LL | | } else if min > input { +LL | | min +LL | | } else { +LL | | input +LL | | }; + | |_____^ help: replace with clamp: `input.clamp(min, max)` + | + = note: clamp will panic if max < min + +error: clamp-like pattern without using clamp function + --> $DIR/manual_clamp.rs:29:14 + | +LL | let x1 = if input > max { + | ______________^ +LL | | max +LL | | } else if input < min { +LL | | min +LL | | } else { +LL | | input +LL | | }; + | |_____^ help: replace with clamp: `input.clamp(min, max)` + | + = note: clamp will panic if max < min + +error: clamp-like pattern without using clamp function + --> $DIR/manual_clamp.rs:37:14 + | +LL | let x2 = if input < min { + | ______________^ +LL | | min +LL | | } else if input > max { +LL | | max +LL | | } else { +LL | | input +LL | | }; + | |_____^ help: replace with clamp: `input.clamp(min, max)` + | + = note: clamp will panic if max < min + +error: clamp-like pattern without using clamp function + --> $DIR/manual_clamp.rs:45:14 + | +LL | let x3 = if min > input { + | ______________^ +LL | | min +LL | | } else if max < input { +LL | | max +LL | | } else { +LL | | input +LL | | }; + | |_____^ help: replace with clamp: `input.clamp(min, max)` + | + = note: clamp will panic if max < min + +error: clamp-like pattern without using clamp function + --> $DIR/manual_clamp.rs:53:14 + | +LL | let x4 = input.max(min).min(max); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(min, max)` + | + = note: clamp will panic if max < min + +error: clamp-like pattern without using clamp function + --> $DIR/manual_clamp.rs:55:14 + | +LL | let x5 = input.min(max).max(min); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(min, max)` + | + = note: clamp will panic if max < min + +error: clamp-like pattern without using clamp function + --> $DIR/manual_clamp.rs:57:14 + | +LL | let x6 = match input { + | ______________^ +LL | | x if x > max => max, +LL | | x if x < min => min, +LL | | x => x, +LL | | }; + | |_____^ help: replace with clamp: `input.clamp(min, max)` + | + = note: clamp will panic if max < min + +error: clamp-like pattern without using clamp function + --> $DIR/manual_clamp.rs:63:14 + | +LL | let x7 = match input { + | ______________^ +LL | | x if x < min => min, +LL | | x if x > max => max, +LL | | x => x, +LL | | }; + | |_____^ help: replace with clamp: `input.clamp(min, max)` + | + = note: clamp will panic if max < min + +error: clamp-like pattern without using clamp function + --> $DIR/manual_clamp.rs:69:14 + | +LL | let x8 = match input { + | ______________^ +LL | | x if max < x => max, +LL | | x if min > x => min, +LL | | x => x, +LL | | }; + | |_____^ help: replace with clamp: `input.clamp(min, max)` + | + = note: clamp will panic if max < min + +error: clamp-like pattern without using clamp function + --> $DIR/manual_clamp.rs:83:15 + | +LL | let x10 = match input { + | _______________^ +LL | | x if min > x => min, +LL | | x if max < x => max, +LL | | x => x, +LL | | }; + | |_____^ help: replace with clamp: `input.clamp(min, max)` + | + = note: clamp will panic if max < min + +error: clamp-like pattern without using clamp function + --> $DIR/manual_clamp.rs:114:15 + | +LL | let x14 = if input > CONST_MAX { + | _______________^ +LL | | CONST_MAX +LL | | } else if input < CONST_MIN { +LL | | CONST_MIN +LL | | } else { +LL | | input +LL | | }; + | |_____^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` + | + = note: clamp will panic if max < min + +error: clamp-like pattern without using clamp function + --> $DIR/manual_clamp.rs:123:19 + | +LL | let x15 = if input > max { + | ___________________^ +LL | | max +LL | | } else if input < min { +LL | | min +LL | | } else { +LL | | input +LL | | }; + | |_________^ help: replace with clamp: `input.clamp(min, max)` + | + = note: clamp will panic if max < min, min.is_nan(), or max.is_nan() + = note: clamp returns NaN if the input is NaN + +error: clamp-like pattern without using clamp function + --> $DIR/manual_clamp.rs:134:19 + | +LL | let x16 = cmp_max(cmp_min(input, CONST_MAX), CONST_MIN); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` + | + = note: clamp will panic if max < min + +error: clamp-like pattern without using clamp function + --> $DIR/manual_clamp.rs:135:19 + | +LL | let x17 = cmp_min(cmp_max(input, CONST_MIN), CONST_MAX); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` + | + = note: clamp will panic if max < min + +error: clamp-like pattern without using clamp function + --> $DIR/manual_clamp.rs:136:19 + | +LL | let x18 = cmp_max(CONST_MIN, cmp_min(input, CONST_MAX)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` + | + = note: clamp will panic if max < min + +error: clamp-like pattern without using clamp function + --> $DIR/manual_clamp.rs:137:19 + | +LL | let x19 = cmp_min(CONST_MAX, cmp_max(input, CONST_MIN)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` + | + = note: clamp will panic if max < min + +error: clamp-like pattern without using clamp function + --> $DIR/manual_clamp.rs:138:19 + | +LL | let x20 = cmp_max(cmp_min(CONST_MAX, input), CONST_MIN); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` + | + = note: clamp will panic if max < min + +error: clamp-like pattern without using clamp function + --> $DIR/manual_clamp.rs:139:19 + | +LL | let x21 = cmp_min(cmp_max(CONST_MIN, input), CONST_MAX); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` + | + = note: clamp will panic if max < min + +error: clamp-like pattern without using clamp function + --> $DIR/manual_clamp.rs:140:19 + | +LL | let x22 = cmp_max(CONST_MIN, cmp_min(CONST_MAX, input)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` + | + = note: clamp will panic if max < min + +error: clamp-like pattern without using clamp function + --> $DIR/manual_clamp.rs:141:19 + | +LL | let x23 = cmp_min(CONST_MAX, cmp_max(CONST_MIN, input)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` + | + = note: clamp will panic if max < min + +error: clamp-like pattern without using clamp function + --> $DIR/manual_clamp.rs:143:19 + | +LL | let x24 = f64::max(f64::min(input, CONST_F64_MAX), CONST_F64_MIN); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)` + | + = note: clamp will panic if max < min, min.is_nan(), or max.is_nan() + = note: clamp returns NaN if the input is NaN + +error: clamp-like pattern without using clamp function + --> $DIR/manual_clamp.rs:144:19 + | +LL | let x25 = f64::min(f64::max(input, CONST_F64_MIN), CONST_F64_MAX); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)` + | + = note: clamp will panic if max < min, min.is_nan(), or max.is_nan() + = note: clamp returns NaN if the input is NaN + +error: clamp-like pattern without using clamp function + --> $DIR/manual_clamp.rs:145:19 + | +LL | let x26 = f64::max(CONST_F64_MIN, f64::min(input, CONST_F64_MAX)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)` + | + = note: clamp will panic if max < min, min.is_nan(), or max.is_nan() + = note: clamp returns NaN if the input is NaN + +error: clamp-like pattern without using clamp function + --> $DIR/manual_clamp.rs:146:19 + | +LL | let x27 = f64::min(CONST_F64_MAX, f64::max(input, CONST_F64_MIN)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)` + | + = note: clamp will panic if max < min, min.is_nan(), or max.is_nan() + = note: clamp returns NaN if the input is NaN + +error: clamp-like pattern without using clamp function + --> $DIR/manual_clamp.rs:147:19 + | +LL | let x28 = f64::max(f64::min(CONST_F64_MAX, input), CONST_F64_MIN); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)` + | + = note: clamp will panic if max < min, min.is_nan(), or max.is_nan() + = note: clamp returns NaN if the input is NaN + +error: clamp-like pattern without using clamp function + --> $DIR/manual_clamp.rs:148:19 + | +LL | let x29 = f64::min(f64::max(CONST_F64_MIN, input), CONST_F64_MAX); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)` + | + = note: clamp will panic if max < min, min.is_nan(), or max.is_nan() + = note: clamp returns NaN if the input is NaN + +error: clamp-like pattern without using clamp function + --> $DIR/manual_clamp.rs:149:19 + | +LL | let x30 = f64::max(CONST_F64_MIN, f64::min(CONST_F64_MAX, input)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)` + | + = note: clamp will panic if max < min, min.is_nan(), or max.is_nan() + = note: clamp returns NaN if the input is NaN + +error: clamp-like pattern without using clamp function + --> $DIR/manual_clamp.rs:150:19 + | +LL | let x31 = f64::min(CONST_F64_MAX, f64::max(CONST_F64_MIN, input)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)` + | + = note: clamp will panic if max < min, min.is_nan(), or max.is_nan() + = note: clamp returns NaN if the input is NaN + +error: clamp-like pattern without using clamp function + --> $DIR/manual_clamp.rs:153:5 + | +LL | / if x32 < min { +LL | | x32 = min; +LL | | } else if x32 > max { +LL | | x32 = max; +LL | | } + | |_____^ help: replace with clamp: `x32 = x32.clamp(min, max);` + | + = note: clamp will panic if max < min + +error: aborting due to 34 previous errors + diff --git a/tests/ui/min_max.rs b/tests/ui/min_max.rs index b2bc97f4744a5..24e52afd69170 100644 --- a/tests/ui/min_max.rs +++ b/tests/ui/min_max.rs @@ -1,4 +1,5 @@ #![warn(clippy::all)] +#![allow(clippy::manual_clamp)] use std::cmp::max as my_max; use std::cmp::min as my_min; diff --git a/tests/ui/min_max.stderr b/tests/ui/min_max.stderr index c70b77eabbd85..069d9068657eb 100644 --- a/tests/ui/min_max.stderr +++ b/tests/ui/min_max.stderr @@ -1,5 +1,5 @@ error: this `min`/`max` combination leads to constant result - --> $DIR/min_max.rs:23:5 + --> $DIR/min_max.rs:24:5 | LL | min(1, max(3, x)); | ^^^^^^^^^^^^^^^^^ @@ -7,73 +7,73 @@ LL | min(1, max(3, x)); = note: `-D clippy::min-max` implied by `-D warnings` error: this `min`/`max` combination leads to constant result - --> $DIR/min_max.rs:24:5 + --> $DIR/min_max.rs:25:5 | LL | min(max(3, x), 1); | ^^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> $DIR/min_max.rs:25:5 + --> $DIR/min_max.rs:26:5 | LL | max(min(x, 1), 3); | ^^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> $DIR/min_max.rs:26:5 + --> $DIR/min_max.rs:27:5 | LL | max(3, min(x, 1)); | ^^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> $DIR/min_max.rs:28:5 + --> $DIR/min_max.rs:29:5 | LL | my_max(3, my_min(x, 1)); | ^^^^^^^^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> $DIR/min_max.rs:38:5 + --> $DIR/min_max.rs:39:5 | LL | min("Apple", max("Zoo", s)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> $DIR/min_max.rs:39:5 + --> $DIR/min_max.rs:40:5 | LL | max(min(s, "Apple"), "Zoo"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> $DIR/min_max.rs:44:5 + --> $DIR/min_max.rs:45:5 | LL | x.min(1).max(3); | ^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> $DIR/min_max.rs:45:5 + --> $DIR/min_max.rs:46:5 | LL | x.max(3).min(1); | ^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> $DIR/min_max.rs:46:5 + --> $DIR/min_max.rs:47:5 | LL | f.max(3f32).min(1f32); | ^^^^^^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> $DIR/min_max.rs:52:5 + --> $DIR/min_max.rs:53:5 | LL | max(x.min(1), 3); | ^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> $DIR/min_max.rs:55:5 + --> $DIR/min_max.rs:56:5 | LL | s.max("Zoo").min("Apple"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> $DIR/min_max.rs:56:5 + --> $DIR/min_max.rs:57:5 | LL | s.min("Apple").max("Zoo"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/min_rust_version_attr.rs b/tests/ui/min_rust_version_attr.rs index 44e407bd1ab2b..c4c6391bb4c1d 100644 --- a/tests/ui/min_rust_version_attr.rs +++ b/tests/ui/min_rust_version_attr.rs @@ -160,6 +160,17 @@ fn manual_rem_euclid() { let _: i32 = ((x % 4) + 4) % 4; } +fn manual_clamp() { + let (input, min, max) = (0, -1, 2); + let _ = if input < min { + min + } else if input > max { + max + } else { + input + }; +} + fn main() { filter_map_next(); checked_conversion(); @@ -180,6 +191,7 @@ fn main() { err_expect(); cast_abs_to_unsigned(); manual_rem_euclid(); + manual_clamp(); } mod just_under_msrv { diff --git a/tests/ui/min_rust_version_attr.stderr b/tests/ui/min_rust_version_attr.stderr index b1c23b539ffde..faabb0e4386dd 100644 --- a/tests/ui/min_rust_version_attr.stderr +++ b/tests/ui/min_rust_version_attr.stderr @@ -1,12 +1,12 @@ error: stripping a prefix manually - --> $DIR/min_rust_version_attr.rs:204:24 + --> $DIR/min_rust_version_attr.rs:216:24 | LL | assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!"); | ^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::manual-strip` implied by `-D warnings` note: the prefix was tested here - --> $DIR/min_rust_version_attr.rs:203:9 + --> $DIR/min_rust_version_attr.rs:215:9 | LL | if s.starts_with("hello, ") { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -17,13 +17,13 @@ LL ~ assert_eq!(.to_uppercase(), "WORLD!"); | error: stripping a prefix manually - --> $DIR/min_rust_version_attr.rs:216:24 + --> $DIR/min_rust_version_attr.rs:228:24 | LL | assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!"); | ^^^^^^^^^^^^^^^^^^^^ | note: the prefix was tested here - --> $DIR/min_rust_version_attr.rs:215:9 + --> $DIR/min_rust_version_attr.rs:227:9 | LL | if s.starts_with("hello, ") { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From 5a54db1286b1cc535ae2f4ac6ec44310d354aabf Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Sat, 1 Oct 2022 22:24:48 +0000 Subject: [PATCH 083/114] Remove unused .fixed files --- tests/ui/manual_assert.fixed | 45 ------------------------- tests/ui/option_take_on_temporary.fixed | 15 --------- 2 files changed, 60 deletions(-) delete mode 100644 tests/ui/manual_assert.fixed delete mode 100644 tests/ui/option_take_on_temporary.fixed diff --git a/tests/ui/manual_assert.fixed b/tests/ui/manual_assert.fixed deleted file mode 100644 index a2393674fe612..0000000000000 --- a/tests/ui/manual_assert.fixed +++ /dev/null @@ -1,45 +0,0 @@ -// revisions: edition2018 edition2021 -// [edition2018] edition:2018 -// [edition2021] edition:2021 -// run-rustfix - -#![warn(clippy::manual_assert)] -#![allow(clippy::nonminimal_bool)] - -fn main() { - let a = vec![1, 2, 3]; - let c = Some(2); - if !a.is_empty() - && a.len() == 3 - && c.is_some() - && !a.is_empty() - && a.len() == 3 - && !a.is_empty() - && a.len() == 3 - && !a.is_empty() - && a.len() == 3 - { - panic!("qaqaq{:?}", a); - } - assert!(a.is_empty(), "qaqaq{:?}", a); - assert!(a.is_empty(), "qwqwq"); - if a.len() == 3 { - println!("qwq"); - println!("qwq"); - println!("qwq"); - } - if let Some(b) = c { - panic!("orz {}", b); - } - if a.len() == 3 { - panic!("qaqaq"); - } else { - println!("qwq"); - } - let b = vec![1, 2, 3]; - assert!(!b.is_empty(), "panic1"); - assert!(!(b.is_empty() && a.is_empty()), "panic2"); - assert!(!(a.is_empty() && !b.is_empty()), "panic3"); - assert!(!(b.is_empty() || a.is_empty()), "panic4"); - assert!(!(a.is_empty() || !b.is_empty()), "panic5"); -} diff --git a/tests/ui/option_take_on_temporary.fixed b/tests/ui/option_take_on_temporary.fixed deleted file mode 100644 index 29691e81666f7..0000000000000 --- a/tests/ui/option_take_on_temporary.fixed +++ /dev/null @@ -1,15 +0,0 @@ -// run-rustfix - -fn main() { - println!("Testing non erroneous option_take_on_temporary"); - let mut option = Some(1); - let _ = Box::new(move || option.take().unwrap()); - - println!("Testing non erroneous option_take_on_temporary"); - let x = Some(3); - x.as_ref(); - - println!("Testing erroneous option_take_on_temporary"); - let x = Some(3); - x.as_ref(); -} From a834ac980066a294537ba0787a01e943a1b7a308 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Sat, 1 Oct 2022 22:25:01 +0000 Subject: [PATCH 084/114] Only run x86 asm doctests on x86 --- clippy_lints/src/asm_syntax.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/clippy_lints/src/asm_syntax.rs b/clippy_lints/src/asm_syntax.rs index ad31d708f64d5..9717aa9e981fb 100644 --- a/clippy_lints/src/asm_syntax.rs +++ b/clippy_lints/src/asm_syntax.rs @@ -64,6 +64,7 @@ declare_clippy_lint! { /// /// ```rust,no_run /// # #![feature(asm)] + /// # #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] /// # unsafe { let ptr = "".as_ptr(); /// # use std::arch::asm; /// asm!("lea {}, [{}]", lateout(reg) _, in(reg) ptr); @@ -72,6 +73,7 @@ declare_clippy_lint! { /// Use instead: /// ```rust,no_run /// # #![feature(asm)] + /// # #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] /// # unsafe { let ptr = "".as_ptr(); /// # use std::arch::asm; /// asm!("lea ({}), {}", in(reg) ptr, lateout(reg) _, options(att_syntax)); @@ -103,6 +105,7 @@ declare_clippy_lint! { /// /// ```rust,no_run /// # #![feature(asm)] + /// # #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] /// # unsafe { let ptr = "".as_ptr(); /// # use std::arch::asm; /// asm!("lea ({}), {}", in(reg) ptr, lateout(reg) _, options(att_syntax)); @@ -111,6 +114,7 @@ declare_clippy_lint! { /// Use instead: /// ```rust,no_run /// # #![feature(asm)] + /// # #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] /// # unsafe { let ptr = "".as_ptr(); /// # use std::arch::asm; /// asm!("lea {}, [{}]", lateout(reg) _, in(reg) ptr); From 52a68dc097cc8064a7464598bca959f2706aab18 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Sat, 1 Oct 2022 21:54:22 +0000 Subject: [PATCH 085/114] lint nested patterns and slice patterns in `needless_borrowed_reference` --- clippy_lints/src/manual_clamp.rs | 6 +- clippy_lints/src/map_unit_fn.rs | 4 +- clippy_lints/src/methods/manual_ok_or.rs | 2 +- clippy_lints/src/needless_borrowed_ref.rs | 121 ++++++++++++++-------- src/docs/needless_borrowed_reference.txt | 18 +--- tests/ui/needless_borrowed_ref.fixed | 41 ++++++-- tests/ui/needless_borrowed_ref.rs | 41 ++++++-- tests/ui/needless_borrowed_ref.stderr | 121 +++++++++++++++++++++- 8 files changed, 266 insertions(+), 88 deletions(-) diff --git a/clippy_lints/src/manual_clamp.rs b/clippy_lints/src/manual_clamp.rs index ac5c24ee604bd..ece4df95505ce 100644 --- a/clippy_lints/src/manual_clamp.rs +++ b/clippy_lints/src/manual_clamp.rs @@ -324,7 +324,7 @@ fn is_call_max_min_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) outer_arg: &'tcx Expr<'tcx>, span: Span, ) -> Option> { - if let ExprKind::Call(inner_fn, &[ref first, ref second]) = &inner_call.kind + if let ExprKind::Call(inner_fn, [first, second]) = &inner_call.kind && let Some(inner_seg) = segment(cx, inner_fn) && let Some(outer_seg) = segment(cx, outer_fn) { @@ -377,9 +377,7 @@ fn is_call_max_min_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) /// # ; /// ``` fn is_match_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option> { - if let ExprKind::Match(value, &[ref first_arm, ref second_arm, ref last_arm], rustc_hir::MatchSource::Normal) = - &expr.kind - { + if let ExprKind::Match(value, [first_arm, second_arm, last_arm], rustc_hir::MatchSource::Normal) = &expr.kind { // Find possible min/max branches let minmax_values = |a: &'tcx Arm<'tcx>| { if let PatKind::Binding(_, var_hir_id, _, None) = &a.pat.kind diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs index df5684541e907..32da37a862d8c 100644 --- a/clippy_lints/src/map_unit_fn.rs +++ b/clippy_lints/src/map_unit_fn.rs @@ -131,12 +131,12 @@ fn reduce_unit_expression<'a>(cx: &LateContext<'_>, expr: &'a hir::Expr<'_>) -> }, hir::ExprKind::Block(block, _) => { match (block.stmts, block.expr.as_ref()) { - (&[], Some(inner_expr)) => { + ([], Some(inner_expr)) => { // If block only contains an expression, // reduce `{ X }` to `X` reduce_unit_expression(cx, inner_expr) }, - (&[ref inner_stmt], None) => { + ([inner_stmt], None) => { // If block only contains statements, // reduce `{ X; }` to `X` or `X;` match inner_stmt.kind { diff --git a/clippy_lints/src/methods/manual_ok_or.rs b/clippy_lints/src/methods/manual_ok_or.rs index c5c0ace7729c4..d9fb4382181a2 100644 --- a/clippy_lints/src/methods/manual_ok_or.rs +++ b/clippy_lints/src/methods/manual_ok_or.rs @@ -55,7 +55,7 @@ fn is_ok_wrapping(cx: &LateContext<'_>, map_expr: &Expr<'_>) -> bool { if let ExprKind::Closure(&Closure { body, .. }) = map_expr.kind; let body = cx.tcx.hir().body(body); if let PatKind::Binding(_, param_id, ..) = body.params[0].pat.kind; - if let ExprKind::Call(Expr { kind: ExprKind::Path(ok_path), .. }, &[ref ok_arg]) = body.value.kind; + if let ExprKind::Call(Expr { kind: ExprKind::Path(ok_path), .. }, [ok_arg]) = body.value.kind; if is_lang_ctor(cx, ok_path, ResultOk); then { path_to_local_id(ok_arg, param_id) } else { false } } diff --git a/clippy_lints/src/needless_borrowed_ref.rs b/clippy_lints/src/needless_borrowed_ref.rs index b8855e5adbff4..10c3ff026b6d6 100644 --- a/clippy_lints/src/needless_borrowed_ref.rs +++ b/clippy_lints/src/needless_borrowed_ref.rs @@ -1,6 +1,4 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::snippet_with_applicability; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BindingAnnotation, Mutability, Node, Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -8,36 +6,26 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { /// ### What it does - /// Checks for bindings that destructure a reference and borrow the inner + /// Checks for bindings that needlessly destructure a reference and borrow the inner /// value with `&ref`. /// /// ### Why is this bad? /// This pattern has no effect in almost all cases. /// - /// ### Known problems - /// In some cases, `&ref` is needed to avoid a lifetime mismatch error. - /// Example: - /// ```rust - /// fn foo(a: &Option, b: &Option) { - /// match (a, b) { - /// (None, &ref c) | (&ref c, None) => (), - /// (&Some(ref c), _) => (), - /// }; - /// } - /// ``` - /// /// ### Example /// ```rust /// let mut v = Vec::::new(); - /// # #[allow(unused)] /// v.iter_mut().filter(|&ref a| a.is_empty()); + /// + /// if let &[ref first, ref second] = v.as_slice() {} /// ``` /// /// Use instead: /// ```rust /// let mut v = Vec::::new(); - /// # #[allow(unused)] /// v.iter_mut().filter(|a| a.is_empty()); + /// + /// if let [first, second] = v.as_slice() {} /// ``` #[clippy::version = "pre 1.29.0"] pub NEEDLESS_BORROWED_REFERENCE, @@ -54,34 +42,83 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowedRef { return; } - if_chain! { - // Only lint immutable refs, because `&mut ref T` may be useful. - if let PatKind::Ref(sub_pat, Mutability::Not) = pat.kind; + // 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) { + let Node::Pat(pat) = node else { break }; + + if matches!(pat.kind, PatKind::Or(_)) { + return; + } + } + + // Only lint immutable refs, because `&mut ref T` may be useful. + let PatKind::Ref(sub_pat, Mutability::Not) = pat.kind else { return }; + match sub_pat.kind { // Check sub_pat got a `ref` keyword (excluding `ref mut`). - if let PatKind::Binding(BindingAnnotation::REF, .., spanned_name, _) = sub_pat.kind; - let parent_id = cx.tcx.hir().get_parent_node(pat.hir_id); - if let Some(parent_node) = cx.tcx.hir().find(parent_id); - then { - // do not recurse within patterns, as they may have other references - // XXXManishearth we can relax this constraint if we only check patterns - // with a single ref pattern inside them - if let Node::Pat(_) = parent_node { - return; + PatKind::Binding(BindingAnnotation::REF, _, ident, None) => { + span_lint_and_then( + cx, + NEEDLESS_BORROWED_REFERENCE, + pat.span, + "this pattern takes a reference on something that is being dereferenced", + |diag| { + // `&ref ident` + // ^^^^^ + let span = pat.span.until(ident.span); + diag.span_suggestion_verbose( + span, + "try removing the `&ref` part", + String::new(), + Applicability::MachineApplicable, + ); + }, + ); + }, + // Slices where each element is `ref`: `&[ref a, ref b, ..., ref z]` + PatKind::Slice( + before, + None + | Some(Pat { + kind: PatKind::Wild, .. + }), + 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; + } } - let mut applicability = Applicability::MachineApplicable; - span_lint_and_then(cx, NEEDLESS_BORROWED_REFERENCE, pat.span, - "this pattern takes a reference on something that is being de-referenced", - |diag| { - let hint = snippet_with_applicability(cx, spanned_name.span, "..", &mut applicability).into_owned(); - diag.span_suggestion( - pat.span, - "try removing the `&ref` part and just keep", - hint, - applicability, - ); - }); - } + + 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, + ); + }, + ); + } + }, + _ => {}, } } } diff --git a/src/docs/needless_borrowed_reference.txt b/src/docs/needless_borrowed_reference.txt index 55faa0cf57195..152459ba1c9d7 100644 --- a/src/docs/needless_borrowed_reference.txt +++ b/src/docs/needless_borrowed_reference.txt @@ -1,30 +1,22 @@ ### What it does -Checks for bindings that destructure a reference and borrow the inner +Checks for bindings that needlessly destructure a reference and borrow the inner value with `&ref`. ### Why is this bad? This pattern has no effect in almost all cases. -### Known problems -In some cases, `&ref` is needed to avoid a lifetime mismatch error. -Example: -``` -fn foo(a: &Option, b: &Option) { - match (a, b) { - (None, &ref c) | (&ref c, None) => (), - (&Some(ref c), _) => (), - }; -} -``` - ### Example ``` let mut v = Vec::::new(); v.iter_mut().filter(|&ref a| a.is_empty()); + +if let &[ref first, ref second] = v.as_slice() {} ``` Use instead: ``` let mut v = Vec::::new(); v.iter_mut().filter(|a| a.is_empty()); + +if let [first, second] = v.as_slice() {} ``` \ No newline at end of file diff --git a/tests/ui/needless_borrowed_ref.fixed b/tests/ui/needless_borrowed_ref.fixed index a0937a2c5f62f..bcb4eb2dd48a6 100644 --- a/tests/ui/needless_borrowed_ref.fixed +++ b/tests/ui/needless_borrowed_ref.fixed @@ -1,17 +1,38 @@ // run-rustfix -#[warn(clippy::needless_borrowed_reference)] -#[allow(unused_variables)] -fn main() { +#![warn(clippy::needless_borrowed_reference)] +#![allow(unused, clippy::needless_borrow)] + +fn main() {} + +fn should_lint(array: [u8; 4], slice: &[u8], slice_of_refs: &[&u8], vec: Vec) { let mut v = Vec::::new(); let _ = v.iter_mut().filter(|a| a.is_empty()); - // ^ should be linted let var = 3; let thingy = Some(&var); - if let Some(&ref v) = thingy { - // ^ should be linted - } + if let Some(v) = thingy {} + + if let &[a, ref b] = slice_of_refs {} + + let [a, ..] = &array; + let [a, b, ..] = &array; + + if let [a, b] = slice {} + if let [a, b] = &vec[..] {} + + if let [a, b, ..] = slice {} + if let [a, .., b] = slice {} + if let [.., a, b] = slice {} +} + +fn should_not_lint(array: [u8; 4], slice: &[u8], slice_of_refs: &[&u8], vec: Vec) { + if let [ref a] = slice {} + if let &[ref a, b] = slice {} + if let &[ref a, .., b] = slice {} + + // must not be removed as variables must be bound consistently across | patterns + if let (&[ref a], _) | ([], ref a) = (slice_of_refs, &1u8) {} let mut var2 = 5; let thingy2 = Some(&mut var2); @@ -28,17 +49,15 @@ fn main() { } } -#[allow(dead_code)] enum Animal { Cat(u64), Dog(u64), } -#[allow(unused_variables)] -#[allow(dead_code)] fn foo(a: &Animal, b: &Animal) { match (a, b) { - (&Animal::Cat(v), &ref k) | (&ref k, &Animal::Cat(v)) => (), // lifetime mismatch error if there is no '&ref' + // lifetime mismatch error if there is no '&ref' before `feature(nll)` stabilization in 1.63 + (&Animal::Cat(v), &ref k) | (&ref k, &Animal::Cat(v)) => (), // ^ and ^ should **not** be linted (&Animal::Dog(ref a), &Animal::Dog(_)) => (), // ^ should **not** be linted } diff --git a/tests/ui/needless_borrowed_ref.rs b/tests/ui/needless_borrowed_ref.rs index 500ac448f0d58..f6de1a6d83d1b 100644 --- a/tests/ui/needless_borrowed_ref.rs +++ b/tests/ui/needless_borrowed_ref.rs @@ -1,17 +1,38 @@ // run-rustfix -#[warn(clippy::needless_borrowed_reference)] -#[allow(unused_variables)] -fn main() { +#![warn(clippy::needless_borrowed_reference)] +#![allow(unused, clippy::needless_borrow)] + +fn main() {} + +fn should_lint(array: [u8; 4], slice: &[u8], slice_of_refs: &[&u8], vec: Vec) { let mut v = Vec::::new(); let _ = v.iter_mut().filter(|&ref a| a.is_empty()); - // ^ should be linted let var = 3; let thingy = Some(&var); - if let Some(&ref v) = thingy { - // ^ should be linted - } + if let Some(&ref v) = thingy {} + + if let &[&ref a, ref b] = slice_of_refs {} + + let &[ref a, ..] = &array; + let &[ref a, ref b, ..] = &array; + + if let &[ref a, ref b] = slice {} + if let &[ref a, ref b] = &vec[..] {} + + if let &[ref a, ref b, ..] = slice {} + if let &[ref a, .., ref b] = slice {} + if let &[.., ref a, ref b] = slice {} +} + +fn should_not_lint(array: [u8; 4], slice: &[u8], slice_of_refs: &[&u8], vec: Vec) { + if let [ref a] = slice {} + if let &[ref a, b] = slice {} + if let &[ref a, .., b] = slice {} + + // must not be removed as variables must be bound consistently across | patterns + if let (&[ref a], _) | ([], ref a) = (slice_of_refs, &1u8) {} let mut var2 = 5; let thingy2 = Some(&mut var2); @@ -28,17 +49,15 @@ fn main() { } } -#[allow(dead_code)] enum Animal { Cat(u64), Dog(u64), } -#[allow(unused_variables)] -#[allow(dead_code)] fn foo(a: &Animal, b: &Animal) { match (a, b) { - (&Animal::Cat(v), &ref k) | (&ref k, &Animal::Cat(v)) => (), // lifetime mismatch error if there is no '&ref' + // lifetime mismatch error if there is no '&ref' before `feature(nll)` stabilization in 1.63 + (&Animal::Cat(v), &ref k) | (&ref k, &Animal::Cat(v)) => (), // ^ and ^ should **not** be linted (&Animal::Dog(ref a), &Animal::Dog(_)) => (), // ^ should **not** be linted } diff --git a/tests/ui/needless_borrowed_ref.stderr b/tests/ui/needless_borrowed_ref.stderr index 0a5cfb3db0b11..7453542e673f3 100644 --- a/tests/ui/needless_borrowed_ref.stderr +++ b/tests/ui/needless_borrowed_ref.stderr @@ -1,10 +1,123 @@ -error: this pattern takes a reference on something that is being de-referenced - --> $DIR/needless_borrowed_ref.rs:7:34 +error: this pattern takes a reference on something that is being dereferenced + --> $DIR/needless_borrowed_ref.rs:10:34 | LL | let _ = v.iter_mut().filter(|&ref a| a.is_empty()); - | ^^^^^^ help: try removing the `&ref` part and just keep: `a` + | ^^^^^^ | = note: `-D clippy::needless-borrowed-reference` implied by `-D warnings` +help: try removing the `&ref` part + | +LL - let _ = v.iter_mut().filter(|&ref a| a.is_empty()); +LL + let _ = v.iter_mut().filter(|a| a.is_empty()); + | + +error: this pattern takes a reference on something that is being dereferenced + --> $DIR/needless_borrowed_ref.rs:14:17 + | +LL | if let Some(&ref v) = thingy {} + | ^^^^^^ + | +help: try removing the `&ref` part + | +LL - if let Some(&ref v) = thingy {} +LL + if let Some(v) = thingy {} + | + +error: this pattern takes a reference on something that is being dereferenced + --> $DIR/needless_borrowed_ref.rs:16:14 + | +LL | if let &[&ref a, ref b] = slice_of_refs {} + | ^^^^^^ + | +help: try removing the `&ref` part + | +LL - if let &[&ref a, ref b] = slice_of_refs {} +LL + if let &[a, ref b] = slice_of_refs {} + | + +error: dereferencing a slice pattern where every element takes a reference + --> $DIR/needless_borrowed_ref.rs:18:9 + | +LL | let &[ref a, ..] = &array; + | ^^^^^^^^^^^^ + | +help: try removing the `&` and `ref` parts + | +LL - let &[ref a, ..] = &array; +LL + let [a, ..] = &array; + | + +error: dereferencing a slice pattern where every element takes a reference + --> $DIR/needless_borrowed_ref.rs:19:9 + | +LL | let &[ref a, ref b, ..] = &array; + | ^^^^^^^^^^^^^^^^^^^ + | +help: try removing the `&` and `ref` parts + | +LL - let &[ref a, ref b, ..] = &array; +LL + let [a, b, ..] = &array; + | + +error: dereferencing a slice pattern where every element takes a reference + --> $DIR/needless_borrowed_ref.rs:21:12 + | +LL | if let &[ref a, ref b] = slice {} + | ^^^^^^^^^^^^^^^ + | +help: try removing the `&` and `ref` parts + | +LL - if let &[ref a, ref b] = slice {} +LL + if let [a, b] = slice {} + | + +error: dereferencing a slice pattern where every element takes a reference + --> $DIR/needless_borrowed_ref.rs:22:12 + | +LL | if let &[ref a, ref b] = &vec[..] {} + | ^^^^^^^^^^^^^^^ + | +help: try removing the `&` and `ref` parts + | +LL - if let &[ref a, ref b] = &vec[..] {} +LL + if let [a, b] = &vec[..] {} + | + +error: dereferencing a slice pattern where every element takes a reference + --> $DIR/needless_borrowed_ref.rs:24:12 + | +LL | if let &[ref a, ref b, ..] = slice {} + | ^^^^^^^^^^^^^^^^^^^ + | +help: try removing the `&` and `ref` parts + | +LL - if let &[ref a, ref b, ..] = slice {} +LL + if let [a, b, ..] = slice {} + | + +error: dereferencing a slice pattern where every element takes a reference + --> $DIR/needless_borrowed_ref.rs:25:12 + | +LL | if let &[ref a, .., ref b] = slice {} + | ^^^^^^^^^^^^^^^^^^^ + | +help: try removing the `&` and `ref` parts + | +LL - if let &[ref a, .., ref b] = slice {} +LL + if let [a, .., b] = slice {} + | + +error: dereferencing a slice pattern where every element takes a reference + --> $DIR/needless_borrowed_ref.rs:26:12 + | +LL | if let &[.., ref a, ref b] = slice {} + | ^^^^^^^^^^^^^^^^^^^ + | +help: try removing the `&` and `ref` parts + | +LL - if let &[.., ref a, ref b] = slice {} +LL + if let [.., a, b] = slice {} + | -error: aborting due to previous error +error: aborting due to 10 previous errors From 90b446fd387a3c405b4dc3c5c2bd0bfce4a6fb21 Mon Sep 17 00:00:00 2001 From: kraktus Date: Sun, 2 Oct 2022 14:30:26 +0200 Subject: [PATCH 086/114] [`unnecessary_cast`] add parenthesis when negative number uses a method --- clippy_lints/src/casts/unnecessary_cast.rs | 33 ++++++++++++++++------ tests/ui/unnecessary_cast.fixed | 6 ++++ tests/ui/unnecessary_cast.rs | 6 ++++ tests/ui/unnecessary_cast.stderr | 14 ++++++++- 4 files changed, 50 insertions(+), 9 deletions(-) diff --git a/clippy_lints/src/casts/unnecessary_cast.rs b/clippy_lints/src/casts/unnecessary_cast.rs index ea29f5d12c677..031cedb907203 100644 --- a/clippy_lints/src/casts/unnecessary_cast.rs +++ b/clippy_lints/src/casts/unnecessary_cast.rs @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::get_parent_expr; use clippy_utils::numeric_literal::NumericLiteral; use clippy_utils::source::snippet_opt; use if_chain::if_chain; @@ -85,22 +86,38 @@ pub(super) fn check<'tcx>( false } -fn lint_unnecessary_cast(cx: &LateContext<'_>, expr: &Expr<'_>, literal_str: &str, cast_from: Ty<'_>, cast_to: Ty<'_>) { +fn lint_unnecessary_cast( + cx: &LateContext<'_>, + expr: &Expr<'_>, + raw_literal_str: &str, + cast_from: Ty<'_>, + cast_to: Ty<'_>, +) { let literal_kind_name = if cast_from.is_integral() { "integer" } else { "float" }; - let replaced_literal; - let matchless = if literal_str.contains(['(', ')']) { - replaced_literal = literal_str.replace(['(', ')'], ""); - &replaced_literal - } else { - literal_str + // first we remove all matches so `-(1)` become `-1`, and remove trailing dots, so `1.` become `1` + let literal_str = raw_literal_str + .replace(['(', ')'], "") + .trim_end_matches('.') + .to_string(); + // we know need to check if the parent is a method call, to add parenthesis accordingly (eg: + // (-1).foo() instead of -1.foo()) + let sugg = if let Some(parent_expr) = get_parent_expr(cx, expr) + && let ExprKind::MethodCall(..) = parent_expr.kind + && literal_str.starts_with('-') + { + format!("({literal_str}_{cast_to})") + + } else { + format!("{literal_str}_{cast_to}") }; + span_lint_and_sugg( cx, UNNECESSARY_CAST, expr.span, &format!("casting {literal_kind_name} literal to `{cast_to}` is unnecessary"), "try", - format!("{}_{cast_to}", matchless.trim_end_matches('.')), + sugg, Applicability::MachineApplicable, ); } diff --git a/tests/ui/unnecessary_cast.fixed b/tests/ui/unnecessary_cast.fixed index ee9f157342d48..70ec3e943807d 100644 --- a/tests/ui/unnecessary_cast.fixed +++ b/tests/ui/unnecessary_cast.fixed @@ -97,4 +97,10 @@ mod fixable { let _ = -(1 + 1) as i64; } + + fn issue_9563() { + let _: f64 = (-8.0_f64).exp(); + #[allow(clippy::precedence)] + let _: f64 = -8.0_f64.exp(); // should suggest `-8.0_f64.exp()` here not to change code behavior + } } diff --git a/tests/ui/unnecessary_cast.rs b/tests/ui/unnecessary_cast.rs index 5b70412424c06..36c1a87fab6e8 100644 --- a/tests/ui/unnecessary_cast.rs +++ b/tests/ui/unnecessary_cast.rs @@ -97,4 +97,10 @@ mod fixable { let _ = -(1 + 1) as i64; } + + fn issue_9563() { + let _: f64 = (-8.0 as f64).exp(); + #[allow(clippy::precedence)] + let _: f64 = -(8.0 as f64).exp(); // should suggest `-8.0_f64.exp()` here not to change code behavior + } } diff --git a/tests/ui/unnecessary_cast.stderr b/tests/ui/unnecessary_cast.stderr index f7829ff3b0efd..a52b92c339c86 100644 --- a/tests/ui/unnecessary_cast.stderr +++ b/tests/ui/unnecessary_cast.stderr @@ -162,5 +162,17 @@ error: casting integer literal to `i64` is unnecessary LL | let _: i64 = -(1) as i64; | ^^^^^^^^^^^ help: try: `-1_i64` -error: aborting due to 27 previous errors +error: casting float literal to `f64` is unnecessary + --> $DIR/unnecessary_cast.rs:102:22 + | +LL | let _: f64 = (-8.0 as f64).exp(); + | ^^^^^^^^^^^^^ help: try: `(-8.0_f64)` + +error: casting float literal to `f64` is unnecessary + --> $DIR/unnecessary_cast.rs:104:23 + | +LL | let _: f64 = -(8.0 as f64).exp(); // should suggest `-8.0_f64.exp()` here not to change code behavior + | ^^^^^^^^^^^^ help: try: `8.0_f64` + +error: aborting due to 29 previous errors From 2c04c1a188124402e85d78bc78c4e07bf87014d0 Mon Sep 17 00:00:00 2001 From: kraktus Date: Wed, 14 Sep 2022 11:58:41 +0200 Subject: [PATCH 087/114] [`manual_assert`]: Preserve comments in the suggestion --- clippy_lints/src/manual_assert.rs | 40 ++++++---- clippy_utils/src/lib.rs | 23 ++++++ tests/ui/manual_assert.edition2018.fixed | 16 +++- tests/ui/manual_assert.edition2018.stderr | 90 ++++++++++++++++++----- tests/ui/manual_assert.edition2021.fixed | 16 +++- tests/ui/manual_assert.edition2021.stderr | 90 ++++++++++++++++++----- tests/ui/manual_assert.rs | 13 ++++ 7 files changed, 237 insertions(+), 51 deletions(-) diff --git a/clippy_lints/src/manual_assert.rs b/clippy_lints/src/manual_assert.rs index 26b53ab5d6837..9934c06e72388 100644 --- a/clippy_lints/src/manual_assert.rs +++ b/clippy_lints/src/manual_assert.rs @@ -1,9 +1,10 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; +use crate::rustc_lint::LintContext; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::{root_macro_call, FormatArgsExpn}; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{peel_blocks_with_stmt, sugg}; +use clippy_utils::{peel_blocks_with_stmt, span_extract_comment, sugg}; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, UnOp}; +use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; @@ -50,20 +51,33 @@ impl<'tcx> LateLintPass<'tcx> for ManualAssert { let mut applicability = Applicability::MachineApplicable; let format_args_snip = snippet_with_applicability(cx, format_args.inputs_span(), "..", &mut applicability); let cond = cond.peel_drop_temps(); - let (cond, not) = match cond.kind { - ExprKind::Unary(UnOp::Not, e) => (e, ""), - _ => (cond, "!"), - }; - let cond_sugg = sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_par(); - let sugg = format!("assert!({not}{cond_sugg}, {format_args_snip});"); - span_lint_and_sugg( + let mut comments = span_extract_comment(cx.sess().source_map(), expr.span); + if !comments.is_empty() { + comments += "\n"; + } + // we need to negate the expression because `assert!` panics when is `false`, wherease original pattern panicked when evaluating to `true` + let cond_sugg = !sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability); + let sugg = format!("assert!({cond_sugg}, {format_args_snip});"); + // we show to the user the suggestion without the comments, but when applicating the fix, include the comments in the block + span_lint_and_then( cx, MANUAL_ASSERT, expr.span, "only a `panic!` in `if`-then statement", - "try", - sugg, - Applicability::MachineApplicable, + |diag| { + // comments can be noisy, do not show them to the user + diag.tool_only_span_suggestion( + expr.span.shrink_to_lo(), + "add comments back", + comments, + applicability); + diag.span_suggestion( + expr.span, + "try instead", + sugg, + applicability); + } + ); } } diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index c2c52d08a3c12..d67ceaec0358a 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -2295,6 +2295,29 @@ pub fn span_contains_comment(sm: &SourceMap, span: Span) -> bool { }); } +/// Return all the comments a given span contains +/// Comments are returned wrapped with their relevant delimiters +pub fn span_extract_comment(sm: &SourceMap, span: Span) -> String { + let snippet = sm.span_to_snippet(span).unwrap_or_default(); + let mut comments_buf: Vec = Vec::new(); + let mut index: usize = 0; + + for token in tokenize(&snippet) { + let token_range = index..(index + token.len as usize); + index += token.len as usize; + match token.kind { + TokenKind::BlockComment { .. } | TokenKind::LineComment { .. } => { + if let Some(comment) = snippet.get(token_range) { + comments_buf.push(comment.to_string()); + } + }, + _ => (), + } + } + + comments_buf.join("\n") +} + macro_rules! op_utils { ($($name:ident $assign:ident)*) => { /// Binary operation traits like `LangItem::Add` diff --git a/tests/ui/manual_assert.edition2018.fixed b/tests/ui/manual_assert.edition2018.fixed index 65598f1eaccc5..b5ccc07e49e25 100644 --- a/tests/ui/manual_assert.edition2018.fixed +++ b/tests/ui/manual_assert.edition2018.fixed @@ -5,6 +5,7 @@ #![warn(clippy::manual_assert)] #![allow(clippy::nonminimal_bool)] +#![allow(dead_code)] macro_rules! one { () => { @@ -27,8 +28,8 @@ fn main() { { panic!("qaqaq{:?}", a); } - assert!(a.is_empty(), "qaqaq{:?}", a); - assert!(a.is_empty(), "qwqwq"); + assert!(!(!a.is_empty()), "qaqaq{:?}", a); + assert!(!(!a.is_empty()), "qwqwq"); if a.len() == 3 { println!("qwq"); println!("qwq"); @@ -50,3 +51,14 @@ fn main() { assert!(!(a.is_empty() || !b.is_empty()), "panic5"); assert!(!a.is_empty(), "with expansion {}", one!()); } + +fn issue7730() { + // Suggestion should preserve comment + // comment +/* this is a + multiline + comment */ +/// Doc comment +// comment after `panic!` +assert!(!true, "panic with comment"); +} diff --git a/tests/ui/manual_assert.edition2018.stderr b/tests/ui/manual_assert.edition2018.stderr index a0f31afd6ebfe..df22e0114be04 100644 --- a/tests/ui/manual_assert.edition2018.stderr +++ b/tests/ui/manual_assert.edition2018.stderr @@ -1,68 +1,124 @@ error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:30:5 + --> $DIR/manual_assert.rs:31:5 | LL | / if !a.is_empty() { LL | | panic!("qaqaq{:?}", a); LL | | } - | |_____^ help: try: `assert!(a.is_empty(), "qaqaq{:?}", a);` + | |_____^ | = note: `-D clippy::manual-assert` implied by `-D warnings` +help: try instead + | +LL | assert!(!(!a.is_empty()), "qaqaq{:?}", a); + | error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:33:5 + --> $DIR/manual_assert.rs:34:5 | LL | / if !a.is_empty() { LL | | panic!("qwqwq"); LL | | } - | |_____^ help: try: `assert!(a.is_empty(), "qwqwq");` + | |_____^ + | +help: try instead + | +LL | assert!(!(!a.is_empty()), "qwqwq"); + | error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:50:5 + --> $DIR/manual_assert.rs:51:5 | LL | / if b.is_empty() { LL | | panic!("panic1"); LL | | } - | |_____^ help: try: `assert!(!b.is_empty(), "panic1");` + | |_____^ + | +help: try instead + | +LL | assert!(!b.is_empty(), "panic1"); + | error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:53:5 + --> $DIR/manual_assert.rs:54:5 | LL | / if b.is_empty() && a.is_empty() { LL | | panic!("panic2"); LL | | } - | |_____^ help: try: `assert!(!(b.is_empty() && a.is_empty()), "panic2");` + | |_____^ + | +help: try instead + | +LL | assert!(!(b.is_empty() && a.is_empty()), "panic2"); + | error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:56:5 + --> $DIR/manual_assert.rs:57:5 | LL | / if a.is_empty() && !b.is_empty() { LL | | panic!("panic3"); LL | | } - | |_____^ help: try: `assert!(!(a.is_empty() && !b.is_empty()), "panic3");` + | |_____^ + | +help: try instead + | +LL | assert!(!(a.is_empty() && !b.is_empty()), "panic3"); + | error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:59:5 + --> $DIR/manual_assert.rs:60:5 | LL | / if b.is_empty() || a.is_empty() { LL | | panic!("panic4"); LL | | } - | |_____^ help: try: `assert!(!(b.is_empty() || a.is_empty()), "panic4");` + | |_____^ + | +help: try instead + | +LL | assert!(!(b.is_empty() || a.is_empty()), "panic4"); + | error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:62:5 + --> $DIR/manual_assert.rs:63:5 | LL | / if a.is_empty() || !b.is_empty() { LL | | panic!("panic5"); LL | | } - | |_____^ help: try: `assert!(!(a.is_empty() || !b.is_empty()), "panic5");` + | |_____^ + | +help: try instead + | +LL | assert!(!(a.is_empty() || !b.is_empty()), "panic5"); + | error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:65:5 + --> $DIR/manual_assert.rs:66:5 | LL | / if a.is_empty() { LL | | panic!("with expansion {}", one!()) LL | | } - | |_____^ help: try: `assert!(!a.is_empty(), "with expansion {}", one!());` + | |_____^ + | +help: try instead + | +LL | assert!(!a.is_empty(), "with expansion {}", one!()); + | + +error: only a `panic!` in `if`-then statement + --> $DIR/manual_assert.rs:73:5 + | +LL | / if true { +LL | | // comment +LL | | /* this is a +LL | | multiline +... | +LL | | panic!("panic with comment") // comment after `panic!` +LL | | } + | |_____^ + | +help: try instead + | +LL | assert!(!true, "panic with comment"); + | -error: aborting due to 8 previous errors +error: aborting due to 9 previous errors diff --git a/tests/ui/manual_assert.edition2021.fixed b/tests/ui/manual_assert.edition2021.fixed index 65598f1eaccc5..b5ccc07e49e25 100644 --- a/tests/ui/manual_assert.edition2021.fixed +++ b/tests/ui/manual_assert.edition2021.fixed @@ -5,6 +5,7 @@ #![warn(clippy::manual_assert)] #![allow(clippy::nonminimal_bool)] +#![allow(dead_code)] macro_rules! one { () => { @@ -27,8 +28,8 @@ fn main() { { panic!("qaqaq{:?}", a); } - assert!(a.is_empty(), "qaqaq{:?}", a); - assert!(a.is_empty(), "qwqwq"); + assert!(!(!a.is_empty()), "qaqaq{:?}", a); + assert!(!(!a.is_empty()), "qwqwq"); if a.len() == 3 { println!("qwq"); println!("qwq"); @@ -50,3 +51,14 @@ fn main() { assert!(!(a.is_empty() || !b.is_empty()), "panic5"); assert!(!a.is_empty(), "with expansion {}", one!()); } + +fn issue7730() { + // Suggestion should preserve comment + // comment +/* this is a + multiline + comment */ +/// Doc comment +// comment after `panic!` +assert!(!true, "panic with comment"); +} diff --git a/tests/ui/manual_assert.edition2021.stderr b/tests/ui/manual_assert.edition2021.stderr index a0f31afd6ebfe..df22e0114be04 100644 --- a/tests/ui/manual_assert.edition2021.stderr +++ b/tests/ui/manual_assert.edition2021.stderr @@ -1,68 +1,124 @@ error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:30:5 + --> $DIR/manual_assert.rs:31:5 | LL | / if !a.is_empty() { LL | | panic!("qaqaq{:?}", a); LL | | } - | |_____^ help: try: `assert!(a.is_empty(), "qaqaq{:?}", a);` + | |_____^ | = note: `-D clippy::manual-assert` implied by `-D warnings` +help: try instead + | +LL | assert!(!(!a.is_empty()), "qaqaq{:?}", a); + | error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:33:5 + --> $DIR/manual_assert.rs:34:5 | LL | / if !a.is_empty() { LL | | panic!("qwqwq"); LL | | } - | |_____^ help: try: `assert!(a.is_empty(), "qwqwq");` + | |_____^ + | +help: try instead + | +LL | assert!(!(!a.is_empty()), "qwqwq"); + | error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:50:5 + --> $DIR/manual_assert.rs:51:5 | LL | / if b.is_empty() { LL | | panic!("panic1"); LL | | } - | |_____^ help: try: `assert!(!b.is_empty(), "panic1");` + | |_____^ + | +help: try instead + | +LL | assert!(!b.is_empty(), "panic1"); + | error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:53:5 + --> $DIR/manual_assert.rs:54:5 | LL | / if b.is_empty() && a.is_empty() { LL | | panic!("panic2"); LL | | } - | |_____^ help: try: `assert!(!(b.is_empty() && a.is_empty()), "panic2");` + | |_____^ + | +help: try instead + | +LL | assert!(!(b.is_empty() && a.is_empty()), "panic2"); + | error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:56:5 + --> $DIR/manual_assert.rs:57:5 | LL | / if a.is_empty() && !b.is_empty() { LL | | panic!("panic3"); LL | | } - | |_____^ help: try: `assert!(!(a.is_empty() && !b.is_empty()), "panic3");` + | |_____^ + | +help: try instead + | +LL | assert!(!(a.is_empty() && !b.is_empty()), "panic3"); + | error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:59:5 + --> $DIR/manual_assert.rs:60:5 | LL | / if b.is_empty() || a.is_empty() { LL | | panic!("panic4"); LL | | } - | |_____^ help: try: `assert!(!(b.is_empty() || a.is_empty()), "panic4");` + | |_____^ + | +help: try instead + | +LL | assert!(!(b.is_empty() || a.is_empty()), "panic4"); + | error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:62:5 + --> $DIR/manual_assert.rs:63:5 | LL | / if a.is_empty() || !b.is_empty() { LL | | panic!("panic5"); LL | | } - | |_____^ help: try: `assert!(!(a.is_empty() || !b.is_empty()), "panic5");` + | |_____^ + | +help: try instead + | +LL | assert!(!(a.is_empty() || !b.is_empty()), "panic5"); + | error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:65:5 + --> $DIR/manual_assert.rs:66:5 | LL | / if a.is_empty() { LL | | panic!("with expansion {}", one!()) LL | | } - | |_____^ help: try: `assert!(!a.is_empty(), "with expansion {}", one!());` + | |_____^ + | +help: try instead + | +LL | assert!(!a.is_empty(), "with expansion {}", one!()); + | + +error: only a `panic!` in `if`-then statement + --> $DIR/manual_assert.rs:73:5 + | +LL | / if true { +LL | | // comment +LL | | /* this is a +LL | | multiline +... | +LL | | panic!("panic with comment") // comment after `panic!` +LL | | } + | |_____^ + | +help: try instead + | +LL | assert!(!true, "panic with comment"); + | -error: aborting due to 8 previous errors +error: aborting due to 9 previous errors diff --git a/tests/ui/manual_assert.rs b/tests/ui/manual_assert.rs index 4d2706dd62113..e9dd81a758a8e 100644 --- a/tests/ui/manual_assert.rs +++ b/tests/ui/manual_assert.rs @@ -5,6 +5,7 @@ #![warn(clippy::manual_assert)] #![allow(clippy::nonminimal_bool)] +#![allow(dead_code)] macro_rules! one { () => { @@ -66,3 +67,15 @@ fn main() { panic!("with expansion {}", one!()) } } + +fn issue7730() { + // Suggestion should preserve comment + if true { + // comment + /* this is a + multiline + comment */ + /// Doc comment + panic!("panic with comment") // comment after `panic!` + } +} From a35734c172ba95a6d8758c7c5bb6601bcd3a5485 Mon Sep 17 00:00:00 2001 From: kraktus Date: Fri, 16 Sep 2022 21:38:56 +0200 Subject: [PATCH 088/114] revert `manual_assert` suggestion refactor Because `Sugg` helper does not simplify multiple negations --- clippy_lints/src/manual_assert.rs | 11 +++++++---- tests/ui/manual_assert.edition2018.fixed | 4 ++-- tests/ui/manual_assert.edition2018.stderr | 4 ++-- tests/ui/manual_assert.edition2021.fixed | 4 ++-- tests/ui/manual_assert.edition2021.stderr | 4 ++-- 5 files changed, 15 insertions(+), 12 deletions(-) diff --git a/clippy_lints/src/manual_assert.rs b/clippy_lints/src/manual_assert.rs index 9934c06e72388..cbc9c4ca6ad04 100644 --- a/clippy_lints/src/manual_assert.rs +++ b/clippy_lints/src/manual_assert.rs @@ -4,7 +4,7 @@ use clippy_utils::macros::{root_macro_call, FormatArgsExpn}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::{peel_blocks_with_stmt, span_extract_comment, sugg}; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind}; +use rustc_hir::{Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; @@ -55,9 +55,12 @@ impl<'tcx> LateLintPass<'tcx> for ManualAssert { if !comments.is_empty() { comments += "\n"; } - // we need to negate the expression because `assert!` panics when is `false`, wherease original pattern panicked when evaluating to `true` - let cond_sugg = !sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability); - let sugg = format!("assert!({cond_sugg}, {format_args_snip});"); + let (cond, not) = match cond.kind { + ExprKind::Unary(UnOp::Not, e) => (e, ""), + _ => (cond, "!"), + }; + let cond_sugg = sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_par(); + let sugg = format!("assert!({not}{cond_sugg}, {format_args_snip});"); // we show to the user the suggestion without the comments, but when applicating the fix, include the comments in the block span_lint_and_then( cx, diff --git a/tests/ui/manual_assert.edition2018.fixed b/tests/ui/manual_assert.edition2018.fixed index b5ccc07e49e25..81e38e1bf7959 100644 --- a/tests/ui/manual_assert.edition2018.fixed +++ b/tests/ui/manual_assert.edition2018.fixed @@ -28,8 +28,8 @@ fn main() { { panic!("qaqaq{:?}", a); } - assert!(!(!a.is_empty()), "qaqaq{:?}", a); - assert!(!(!a.is_empty()), "qwqwq"); + assert!(a.is_empty(), "qaqaq{:?}", a); + assert!(a.is_empty(), "qwqwq"); if a.len() == 3 { println!("qwq"); println!("qwq"); diff --git a/tests/ui/manual_assert.edition2018.stderr b/tests/ui/manual_assert.edition2018.stderr index df22e0114be04..e71bf428382c1 100644 --- a/tests/ui/manual_assert.edition2018.stderr +++ b/tests/ui/manual_assert.edition2018.stderr @@ -9,7 +9,7 @@ LL | | } = note: `-D clippy::manual-assert` implied by `-D warnings` help: try instead | -LL | assert!(!(!a.is_empty()), "qaqaq{:?}", a); +LL | assert!(a.is_empty(), "qaqaq{:?}", a); | error: only a `panic!` in `if`-then statement @@ -22,7 +22,7 @@ LL | | } | help: try instead | -LL | assert!(!(!a.is_empty()), "qwqwq"); +LL | assert!(a.is_empty(), "qwqwq"); | error: only a `panic!` in `if`-then statement diff --git a/tests/ui/manual_assert.edition2021.fixed b/tests/ui/manual_assert.edition2021.fixed index b5ccc07e49e25..81e38e1bf7959 100644 --- a/tests/ui/manual_assert.edition2021.fixed +++ b/tests/ui/manual_assert.edition2021.fixed @@ -28,8 +28,8 @@ fn main() { { panic!("qaqaq{:?}", a); } - assert!(!(!a.is_empty()), "qaqaq{:?}", a); - assert!(!(!a.is_empty()), "qwqwq"); + assert!(a.is_empty(), "qaqaq{:?}", a); + assert!(a.is_empty(), "qwqwq"); if a.len() == 3 { println!("qwq"); println!("qwq"); diff --git a/tests/ui/manual_assert.edition2021.stderr b/tests/ui/manual_assert.edition2021.stderr index df22e0114be04..e71bf428382c1 100644 --- a/tests/ui/manual_assert.edition2021.stderr +++ b/tests/ui/manual_assert.edition2021.stderr @@ -9,7 +9,7 @@ LL | | } = note: `-D clippy::manual-assert` implied by `-D warnings` help: try instead | -LL | assert!(!(!a.is_empty()), "qaqaq{:?}", a); +LL | assert!(a.is_empty(), "qaqaq{:?}", a); | error: only a `panic!` in `if`-then statement @@ -22,7 +22,7 @@ LL | | } | help: try instead | -LL | assert!(!(!a.is_empty()), "qwqwq"); +LL | assert!(a.is_empty(), "qwqwq"); | error: only a `panic!` in `if`-then statement From 22be60b4f07bcfc8e72976b4d9f2cd1f9cae29d5 Mon Sep 17 00:00:00 2001 From: kraktus Date: Sun, 2 Oct 2022 12:35:02 +0200 Subject: [PATCH 089/114] fix indentation --- clippy_lints/src/manual_assert.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/manual_assert.rs b/clippy_lints/src/manual_assert.rs index cbc9c4ca6ad04..825ec84b4a812 100644 --- a/clippy_lints/src/manual_assert.rs +++ b/clippy_lints/src/manual_assert.rs @@ -56,9 +56,9 @@ impl<'tcx> LateLintPass<'tcx> for ManualAssert { comments += "\n"; } let (cond, not) = match cond.kind { - ExprKind::Unary(UnOp::Not, e) => (e, ""), - _ => (cond, "!"), - }; + ExprKind::Unary(UnOp::Not, e) => (e, ""), + _ => (cond, "!"), + }; let cond_sugg = sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_par(); let sugg = format!("assert!({not}{cond_sugg}, {format_args_snip});"); // we show to the user the suggestion without the comments, but when applicating the fix, include the comments in the block From 3ab02aa3596567292406fb6e44e650dedcb25297 Mon Sep 17 00:00:00 2001 From: kraktus Date: Sun, 2 Oct 2022 15:25:50 +0200 Subject: [PATCH 090/114] fix tests --- tests/ui/manual_assert.edition2018.fixed | 7 +++---- tests/ui/manual_assert.edition2018.stderr | 22 +++++++++++----------- tests/ui/manual_assert.edition2021.fixed | 7 +++---- tests/ui/manual_assert.edition2021.stderr | 22 +++++++++++----------- tests/ui/manual_assert.rs | 7 +++---- 5 files changed, 31 insertions(+), 34 deletions(-) diff --git a/tests/ui/manual_assert.edition2018.fixed b/tests/ui/manual_assert.edition2018.fixed index 81e38e1bf7959..84f6855f3387b 100644 --- a/tests/ui/manual_assert.edition2018.fixed +++ b/tests/ui/manual_assert.edition2018.fixed @@ -4,8 +4,7 @@ // run-rustfix #![warn(clippy::manual_assert)] -#![allow(clippy::nonminimal_bool)] -#![allow(dead_code)] +#![allow(dead_code, unused_doc_comments, clippy::nonminimal_bool)] macro_rules! one { () => { @@ -52,7 +51,7 @@ fn main() { assert!(!a.is_empty(), "with expansion {}", one!()); } -fn issue7730() { +fn issue7730(a: u8) { // Suggestion should preserve comment // comment /* this is a @@ -60,5 +59,5 @@ fn issue7730() { comment */ /// Doc comment // comment after `panic!` -assert!(!true, "panic with comment"); +assert!(!(a > 2), "panic with comment"); } diff --git a/tests/ui/manual_assert.edition2018.stderr b/tests/ui/manual_assert.edition2018.stderr index e71bf428382c1..dbd21be2da9e1 100644 --- a/tests/ui/manual_assert.edition2018.stderr +++ b/tests/ui/manual_assert.edition2018.stderr @@ -1,5 +1,5 @@ error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:31:5 + --> $DIR/manual_assert.rs:30:5 | LL | / if !a.is_empty() { LL | | panic!("qaqaq{:?}", a); @@ -13,7 +13,7 @@ LL | assert!(a.is_empty(), "qaqaq{:?}", a); | error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:34:5 + --> $DIR/manual_assert.rs:33:5 | LL | / if !a.is_empty() { LL | | panic!("qwqwq"); @@ -26,7 +26,7 @@ LL | assert!(a.is_empty(), "qwqwq"); | error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:51:5 + --> $DIR/manual_assert.rs:50:5 | LL | / if b.is_empty() { LL | | panic!("panic1"); @@ -39,7 +39,7 @@ LL | assert!(!b.is_empty(), "panic1"); | error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:54:5 + --> $DIR/manual_assert.rs:53:5 | LL | / if b.is_empty() && a.is_empty() { LL | | panic!("panic2"); @@ -52,7 +52,7 @@ LL | assert!(!(b.is_empty() && a.is_empty()), "panic2"); | error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:57:5 + --> $DIR/manual_assert.rs:56:5 | LL | / if a.is_empty() && !b.is_empty() { LL | | panic!("panic3"); @@ -65,7 +65,7 @@ LL | assert!(!(a.is_empty() && !b.is_empty()), "panic3"); | error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:60:5 + --> $DIR/manual_assert.rs:59:5 | LL | / if b.is_empty() || a.is_empty() { LL | | panic!("panic4"); @@ -78,7 +78,7 @@ LL | assert!(!(b.is_empty() || a.is_empty()), "panic4"); | error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:63:5 + --> $DIR/manual_assert.rs:62:5 | LL | / if a.is_empty() || !b.is_empty() { LL | | panic!("panic5"); @@ -91,7 +91,7 @@ LL | assert!(!(a.is_empty() || !b.is_empty()), "panic5"); | error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:66:5 + --> $DIR/manual_assert.rs:65:5 | LL | / if a.is_empty() { LL | | panic!("with expansion {}", one!()) @@ -104,9 +104,9 @@ LL | assert!(!a.is_empty(), "with expansion {}", one!()); | error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:73:5 + --> $DIR/manual_assert.rs:72:5 | -LL | / if true { +LL | / if a > 2 { LL | | // comment LL | | /* this is a LL | | multiline @@ -117,7 +117,7 @@ LL | | } | help: try instead | -LL | assert!(!true, "panic with comment"); +LL | assert!(!(a > 2), "panic with comment"); | error: aborting due to 9 previous errors diff --git a/tests/ui/manual_assert.edition2021.fixed b/tests/ui/manual_assert.edition2021.fixed index 81e38e1bf7959..84f6855f3387b 100644 --- a/tests/ui/manual_assert.edition2021.fixed +++ b/tests/ui/manual_assert.edition2021.fixed @@ -4,8 +4,7 @@ // run-rustfix #![warn(clippy::manual_assert)] -#![allow(clippy::nonminimal_bool)] -#![allow(dead_code)] +#![allow(dead_code, unused_doc_comments, clippy::nonminimal_bool)] macro_rules! one { () => { @@ -52,7 +51,7 @@ fn main() { assert!(!a.is_empty(), "with expansion {}", one!()); } -fn issue7730() { +fn issue7730(a: u8) { // Suggestion should preserve comment // comment /* this is a @@ -60,5 +59,5 @@ fn issue7730() { comment */ /// Doc comment // comment after `panic!` -assert!(!true, "panic with comment"); +assert!(!(a > 2), "panic with comment"); } diff --git a/tests/ui/manual_assert.edition2021.stderr b/tests/ui/manual_assert.edition2021.stderr index e71bf428382c1..dbd21be2da9e1 100644 --- a/tests/ui/manual_assert.edition2021.stderr +++ b/tests/ui/manual_assert.edition2021.stderr @@ -1,5 +1,5 @@ error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:31:5 + --> $DIR/manual_assert.rs:30:5 | LL | / if !a.is_empty() { LL | | panic!("qaqaq{:?}", a); @@ -13,7 +13,7 @@ LL | assert!(a.is_empty(), "qaqaq{:?}", a); | error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:34:5 + --> $DIR/manual_assert.rs:33:5 | LL | / if !a.is_empty() { LL | | panic!("qwqwq"); @@ -26,7 +26,7 @@ LL | assert!(a.is_empty(), "qwqwq"); | error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:51:5 + --> $DIR/manual_assert.rs:50:5 | LL | / if b.is_empty() { LL | | panic!("panic1"); @@ -39,7 +39,7 @@ LL | assert!(!b.is_empty(), "panic1"); | error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:54:5 + --> $DIR/manual_assert.rs:53:5 | LL | / if b.is_empty() && a.is_empty() { LL | | panic!("panic2"); @@ -52,7 +52,7 @@ LL | assert!(!(b.is_empty() && a.is_empty()), "panic2"); | error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:57:5 + --> $DIR/manual_assert.rs:56:5 | LL | / if a.is_empty() && !b.is_empty() { LL | | panic!("panic3"); @@ -65,7 +65,7 @@ LL | assert!(!(a.is_empty() && !b.is_empty()), "panic3"); | error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:60:5 + --> $DIR/manual_assert.rs:59:5 | LL | / if b.is_empty() || a.is_empty() { LL | | panic!("panic4"); @@ -78,7 +78,7 @@ LL | assert!(!(b.is_empty() || a.is_empty()), "panic4"); | error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:63:5 + --> $DIR/manual_assert.rs:62:5 | LL | / if a.is_empty() || !b.is_empty() { LL | | panic!("panic5"); @@ -91,7 +91,7 @@ LL | assert!(!(a.is_empty() || !b.is_empty()), "panic5"); | error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:66:5 + --> $DIR/manual_assert.rs:65:5 | LL | / if a.is_empty() { LL | | panic!("with expansion {}", one!()) @@ -104,9 +104,9 @@ LL | assert!(!a.is_empty(), "with expansion {}", one!()); | error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:73:5 + --> $DIR/manual_assert.rs:72:5 | -LL | / if true { +LL | / if a > 2 { LL | | // comment LL | | /* this is a LL | | multiline @@ -117,7 +117,7 @@ LL | | } | help: try instead | -LL | assert!(!true, "panic with comment"); +LL | assert!(!(a > 2), "panic with comment"); | error: aborting due to 9 previous errors diff --git a/tests/ui/manual_assert.rs b/tests/ui/manual_assert.rs index e9dd81a758a8e..14abf94965af0 100644 --- a/tests/ui/manual_assert.rs +++ b/tests/ui/manual_assert.rs @@ -4,8 +4,7 @@ // run-rustfix #![warn(clippy::manual_assert)] -#![allow(clippy::nonminimal_bool)] -#![allow(dead_code)] +#![allow(dead_code, unused_doc_comments, clippy::nonminimal_bool)] macro_rules! one { () => { @@ -68,9 +67,9 @@ fn main() { } } -fn issue7730() { +fn issue7730(a: u8) { // Suggestion should preserve comment - if true { + if a > 2 { // comment /* this is a multiline From 081f73954b24e87bbbd95ed20f9a504680b21d46 Mon Sep 17 00:00:00 2001 From: TennyZhuang Date: Sun, 2 Oct 2022 17:12:08 +0800 Subject: [PATCH 091/114] let unnecessary_cast work for trivial non_literal expressions Signed-off-by: TennyZhuang --- clippy_lints/src/casts/unnecessary_cast.rs | 15 ++++++++++++++- tests/ui/unnecessary_cast.fixed | 8 ++++++++ tests/ui/unnecessary_cast.rs | 8 ++++++++ tests/ui/unnecessary_cast.stderr | 8 +++++++- 4 files changed, 37 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/casts/unnecessary_cast.rs b/clippy_lints/src/casts/unnecessary_cast.rs index 031cedb907203..071fab1165d4d 100644 --- a/clippy_lints/src/casts/unnecessary_cast.rs +++ b/clippy_lints/src/casts/unnecessary_cast.rs @@ -31,8 +31,10 @@ pub(super) fn check<'tcx>( } } + let cast_str = snippet_opt(cx, cast_expr.span).unwrap_or_default(); + if let Some(lit) = get_numeric_literal(cast_expr) { - let literal_str = snippet_opt(cx, cast_expr.span).unwrap_or_default(); + let literal_str = cast_str; if_chain! { if let LitKind::Int(n, _) = lit.node; @@ -81,6 +83,17 @@ pub(super) fn check<'tcx>( } }, } + } else if cast_from.kind() == cast_to.kind() && !in_external_macro(cx.sess(), expr.span) { + span_lint_and_sugg( + cx, + UNNECESSARY_CAST, + expr.span, + &format!("casting to the same type is unnecessary (`{cast_from}` -> `{cast_to}`)"), + "try", + cast_str, + Applicability::MachineApplicable, + ); + return true; } false diff --git a/tests/ui/unnecessary_cast.fixed b/tests/ui/unnecessary_cast.fixed index 70ec3e943807d..94dc96427263c 100644 --- a/tests/ui/unnecessary_cast.fixed +++ b/tests/ui/unnecessary_cast.fixed @@ -103,4 +103,12 @@ mod fixable { #[allow(clippy::precedence)] let _: f64 = -8.0_f64.exp(); // should suggest `-8.0_f64.exp()` here not to change code behavior } + + fn issue_9562_non_literal() { + fn foo() -> f32 { + 0. + } + + let _num = foo(); + } } diff --git a/tests/ui/unnecessary_cast.rs b/tests/ui/unnecessary_cast.rs index 36c1a87fab6e8..e5150256f69ac 100644 --- a/tests/ui/unnecessary_cast.rs +++ b/tests/ui/unnecessary_cast.rs @@ -103,4 +103,12 @@ mod fixable { #[allow(clippy::precedence)] let _: f64 = -(8.0 as f64).exp(); // should suggest `-8.0_f64.exp()` here not to change code behavior } + + fn issue_9562_non_literal() { + fn foo() -> f32 { + 0. + } + + let _num = foo() as f32; + } } diff --git a/tests/ui/unnecessary_cast.stderr b/tests/ui/unnecessary_cast.stderr index a52b92c339c86..e5c3dd5e53f87 100644 --- a/tests/ui/unnecessary_cast.stderr +++ b/tests/ui/unnecessary_cast.stderr @@ -174,5 +174,11 @@ error: casting float literal to `f64` is unnecessary LL | let _: f64 = -(8.0 as f64).exp(); // should suggest `-8.0_f64.exp()` here not to change code behavior | ^^^^^^^^^^^^ help: try: `8.0_f64` -error: aborting due to 29 previous errors +error: casting to the same type is unnecessary (`f32` -> `f32`) + --> $DIR/unnecessary_cast.rs:112:20 + | +LL | let _num = foo() as f32; + | ^^^^^^^^^^^^ help: try: `foo()` + +error: aborting due to 30 previous errors From f2043989ca5fc829de1bed045460366a030e8904 Mon Sep 17 00:00:00 2001 From: TennyZhuang Date: Sun, 2 Oct 2022 17:53:58 +0800 Subject: [PATCH 092/114] ignore the lint on some test files Signed-off-by: TennyZhuang --- tests/ui/floating_point_exp.fixed | 1 + tests/ui/floating_point_exp.rs | 1 + tests/ui/floating_point_exp.stderr | 10 ++--- tests/ui/floating_point_log.fixed | 2 +- tests/ui/floating_point_log.rs | 2 +- tests/ui/floating_point_logbase.fixed | 1 + tests/ui/floating_point_logbase.rs | 1 + tests/ui/floating_point_logbase.stderr | 10 ++--- tests/ui/floating_point_powf.fixed | 1 + tests/ui/floating_point_powf.rs | 1 + tests/ui/floating_point_powf.stderr | 62 +++++++++++++------------- tests/ui/floating_point_powi.fixed | 1 + tests/ui/floating_point_powi.rs | 1 + tests/ui/floating_point_powi.stderr | 10 ++--- tests/ui/manual_bits.fixed | 3 +- tests/ui/manual_bits.rs | 3 +- tests/ui/manual_bits.stderr | 58 ++++++++++++------------ tests/ui/ptr_offset_with_cast.fixed | 1 + tests/ui/ptr_offset_with_cast.rs | 1 + tests/ui/ptr_offset_with_cast.stderr | 4 +- 20 files changed, 93 insertions(+), 81 deletions(-) diff --git a/tests/ui/floating_point_exp.fixed b/tests/ui/floating_point_exp.fixed index c86a502d15f09..b9e3d89c2b29d 100644 --- a/tests/ui/floating_point_exp.fixed +++ b/tests/ui/floating_point_exp.fixed @@ -1,5 +1,6 @@ // run-rustfix #![warn(clippy::imprecise_flops)] +#![allow(clippy::unnecessary_cast)] fn main() { let x = 2f32; diff --git a/tests/ui/floating_point_exp.rs b/tests/ui/floating_point_exp.rs index e59589f912a21..ef008dd9be055 100644 --- a/tests/ui/floating_point_exp.rs +++ b/tests/ui/floating_point_exp.rs @@ -1,5 +1,6 @@ // run-rustfix #![warn(clippy::imprecise_flops)] +#![allow(clippy::unnecessary_cast)] fn main() { let x = 2f32; diff --git a/tests/ui/floating_point_exp.stderr b/tests/ui/floating_point_exp.stderr index f84eede19872a..b92fae56e421c 100644 --- a/tests/ui/floating_point_exp.stderr +++ b/tests/ui/floating_point_exp.stderr @@ -1,5 +1,5 @@ error: (e.pow(x) - 1) can be computed more accurately - --> $DIR/floating_point_exp.rs:6:13 + --> $DIR/floating_point_exp.rs:7:13 | LL | let _ = x.exp() - 1.0; | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` @@ -7,25 +7,25 @@ LL | let _ = x.exp() - 1.0; = note: `-D clippy::imprecise-flops` implied by `-D warnings` error: (e.pow(x) - 1) can be computed more accurately - --> $DIR/floating_point_exp.rs:7:13 + --> $DIR/floating_point_exp.rs:8:13 | LL | let _ = x.exp() - 1.0 + 2.0; | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` error: (e.pow(x) - 1) can be computed more accurately - --> $DIR/floating_point_exp.rs:8:13 + --> $DIR/floating_point_exp.rs:9:13 | LL | let _ = (x as f32).exp() - 1.0 + 2.0; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).exp_m1()` error: (e.pow(x) - 1) can be computed more accurately - --> $DIR/floating_point_exp.rs:14:13 + --> $DIR/floating_point_exp.rs:15:13 | LL | let _ = x.exp() - 1.0; | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` error: (e.pow(x) - 1) can be computed more accurately - --> $DIR/floating_point_exp.rs:15:13 + --> $DIR/floating_point_exp.rs:16:13 | LL | let _ = x.exp() - 1.0 + 2.0; | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` diff --git a/tests/ui/floating_point_log.fixed b/tests/ui/floating_point_log.fixed index 4def9300bb7d2..ee54064616007 100644 --- a/tests/ui/floating_point_log.fixed +++ b/tests/ui/floating_point_log.fixed @@ -1,5 +1,5 @@ // run-rustfix -#![allow(dead_code, clippy::double_parens)] +#![allow(dead_code, clippy::double_parens, clippy::unnecessary_cast)] #![warn(clippy::suboptimal_flops, clippy::imprecise_flops)] const TWO: f32 = 2.0; diff --git a/tests/ui/floating_point_log.rs b/tests/ui/floating_point_log.rs index 1e04caa7d2a86..0590670a50bc7 100644 --- a/tests/ui/floating_point_log.rs +++ b/tests/ui/floating_point_log.rs @@ -1,5 +1,5 @@ // run-rustfix -#![allow(dead_code, clippy::double_parens)] +#![allow(dead_code, clippy::double_parens, clippy::unnecessary_cast)] #![warn(clippy::suboptimal_flops, clippy::imprecise_flops)] const TWO: f32 = 2.0; diff --git a/tests/ui/floating_point_logbase.fixed b/tests/ui/floating_point_logbase.fixed index 936462f94066f..7347bf72cbea6 100644 --- a/tests/ui/floating_point_logbase.fixed +++ b/tests/ui/floating_point_logbase.fixed @@ -1,5 +1,6 @@ // run-rustfix #![warn(clippy::suboptimal_flops)] +#![allow(clippy::unnecessary_cast)] fn main() { let x = 3f32; diff --git a/tests/ui/floating_point_logbase.rs b/tests/ui/floating_point_logbase.rs index 0b56fa8fa41fa..ba5b8d4069283 100644 --- a/tests/ui/floating_point_logbase.rs +++ b/tests/ui/floating_point_logbase.rs @@ -1,5 +1,6 @@ // run-rustfix #![warn(clippy::suboptimal_flops)] +#![allow(clippy::unnecessary_cast)] fn main() { let x = 3f32; diff --git a/tests/ui/floating_point_logbase.stderr b/tests/ui/floating_point_logbase.stderr index 384e3554cbbe1..9d736b5e1a274 100644 --- a/tests/ui/floating_point_logbase.stderr +++ b/tests/ui/floating_point_logbase.stderr @@ -1,5 +1,5 @@ error: log base can be expressed more clearly - --> $DIR/floating_point_logbase.rs:7:13 + --> $DIR/floating_point_logbase.rs:8:13 | LL | let _ = x.ln() / y.ln(); | ^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` @@ -7,25 +7,25 @@ LL | let _ = x.ln() / y.ln(); = note: `-D clippy::suboptimal-flops` implied by `-D warnings` error: log base can be expressed more clearly - --> $DIR/floating_point_logbase.rs:8:13 + --> $DIR/floating_point_logbase.rs:9:13 | LL | let _ = (x as f32).ln() / y.ln(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).log(y)` error: log base can be expressed more clearly - --> $DIR/floating_point_logbase.rs:9:13 + --> $DIR/floating_point_logbase.rs:10:13 | LL | let _ = x.log2() / y.log2(); | ^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` error: log base can be expressed more clearly - --> $DIR/floating_point_logbase.rs:10:13 + --> $DIR/floating_point_logbase.rs:11:13 | LL | let _ = x.log10() / y.log10(); | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` error: log base can be expressed more clearly - --> $DIR/floating_point_logbase.rs:11:13 + --> $DIR/floating_point_logbase.rs:12:13 | LL | let _ = x.log(5f32) / y.log(5f32); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` diff --git a/tests/ui/floating_point_powf.fixed b/tests/ui/floating_point_powf.fixed index e7ef45634dff4..f7f93de29577d 100644 --- a/tests/ui/floating_point_powf.fixed +++ b/tests/ui/floating_point_powf.fixed @@ -1,5 +1,6 @@ // run-rustfix #![warn(clippy::suboptimal_flops, clippy::imprecise_flops)] +#![allow(clippy::unnecessary_cast)] fn main() { let x = 3f32; diff --git a/tests/ui/floating_point_powf.rs b/tests/ui/floating_point_powf.rs index d749aa2d48a41..499fc0e15e478 100644 --- a/tests/ui/floating_point_powf.rs +++ b/tests/ui/floating_point_powf.rs @@ -1,5 +1,6 @@ // run-rustfix #![warn(clippy::suboptimal_flops, clippy::imprecise_flops)] +#![allow(clippy::unnecessary_cast)] fn main() { let x = 3f32; diff --git a/tests/ui/floating_point_powf.stderr b/tests/ui/floating_point_powf.stderr index e9693de8fc909..7c9d50db2f78e 100644 --- a/tests/ui/floating_point_powf.stderr +++ b/tests/ui/floating_point_powf.stderr @@ -1,5 +1,5 @@ error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:6:13 + --> $DIR/floating_point_powf.rs:7:13 | LL | let _ = 2f32.powf(x); | ^^^^^^^^^^^^ help: consider using: `x.exp2()` @@ -7,43 +7,43 @@ LL | let _ = 2f32.powf(x); = note: `-D clippy::suboptimal-flops` implied by `-D warnings` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:7:13 + --> $DIR/floating_point_powf.rs:8:13 | LL | let _ = 2f32.powf(3.1); | ^^^^^^^^^^^^^^ help: consider using: `3.1f32.exp2()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:8:13 + --> $DIR/floating_point_powf.rs:9:13 | LL | let _ = 2f32.powf(-3.1); | ^^^^^^^^^^^^^^^ help: consider using: `(-3.1f32).exp2()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:9:13 + --> $DIR/floating_point_powf.rs:10:13 | LL | let _ = std::f32::consts::E.powf(x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.exp()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:10:13 + --> $DIR/floating_point_powf.rs:11:13 | LL | let _ = std::f32::consts::E.powf(3.1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `3.1f32.exp()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:11:13 + --> $DIR/floating_point_powf.rs:12:13 | LL | let _ = std::f32::consts::E.powf(-3.1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(-3.1f32).exp()` error: square-root of a number can be computed more efficiently and accurately - --> $DIR/floating_point_powf.rs:12:13 + --> $DIR/floating_point_powf.rs:13:13 | LL | let _ = x.powf(1.0 / 2.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `x.sqrt()` error: cube-root of a number can be computed more accurately - --> $DIR/floating_point_powf.rs:13:13 + --> $DIR/floating_point_powf.rs:14:13 | LL | let _ = x.powf(1.0 / 3.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `x.cbrt()` @@ -51,139 +51,139 @@ LL | let _ = x.powf(1.0 / 3.0); = note: `-D clippy::imprecise-flops` implied by `-D warnings` error: cube-root of a number can be computed more accurately - --> $DIR/floating_point_powf.rs:14:13 + --> $DIR/floating_point_powf.rs:15:13 | LL | let _ = (x as f32).powf(1.0 / 3.0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).cbrt()` error: exponentiation with integer powers can be computed more efficiently - --> $DIR/floating_point_powf.rs:15:13 + --> $DIR/floating_point_powf.rs:16:13 | LL | let _ = x.powf(3.0); | ^^^^^^^^^^^ help: consider using: `x.powi(3)` error: exponentiation with integer powers can be computed more efficiently - --> $DIR/floating_point_powf.rs:16:13 + --> $DIR/floating_point_powf.rs:17:13 | LL | let _ = x.powf(-2.0); | ^^^^^^^^^^^^ help: consider using: `x.powi(-2)` error: exponentiation with integer powers can be computed more efficiently - --> $DIR/floating_point_powf.rs:17:13 + --> $DIR/floating_point_powf.rs:18:13 | LL | let _ = x.powf(16_777_215.0); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(16_777_215)` error: exponentiation with integer powers can be computed more efficiently - --> $DIR/floating_point_powf.rs:18:13 + --> $DIR/floating_point_powf.rs:19:13 | LL | let _ = x.powf(-16_777_215.0); | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(-16_777_215)` error: exponentiation with integer powers can be computed more efficiently - --> $DIR/floating_point_powf.rs:19:13 + --> $DIR/floating_point_powf.rs:20:13 | LL | let _ = (x as f32).powf(-16_777_215.0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).powi(-16_777_215)` error: exponentiation with integer powers can be computed more efficiently - --> $DIR/floating_point_powf.rs:20:13 + --> $DIR/floating_point_powf.rs:21:13 | LL | let _ = (x as f32).powf(3.0); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).powi(3)` error: cube-root of a number can be computed more accurately - --> $DIR/floating_point_powf.rs:21:13 + --> $DIR/floating_point_powf.rs:22:13 | LL | let _ = (1.5_f32 + 1.0).powf(1.0 / 3.0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(1.5_f32 + 1.0).cbrt()` error: cube-root of a number can be computed more accurately - --> $DIR/floating_point_powf.rs:22:13 + --> $DIR/floating_point_powf.rs:23:13 | LL | let _ = 1.5_f64.powf(1.0 / 3.0); | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1.5_f64.cbrt()` error: square-root of a number can be computed more efficiently and accurately - --> $DIR/floating_point_powf.rs:23:13 + --> $DIR/floating_point_powf.rs:24:13 | LL | let _ = 1.5_f64.powf(1.0 / 2.0); | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1.5_f64.sqrt()` error: exponentiation with integer powers can be computed more efficiently - --> $DIR/floating_point_powf.rs:24:13 + --> $DIR/floating_point_powf.rs:25:13 | LL | let _ = 1.5_f64.powf(3.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `1.5_f64.powi(3)` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:33:13 + --> $DIR/floating_point_powf.rs:34:13 | LL | let _ = 2f64.powf(x); | ^^^^^^^^^^^^ help: consider using: `x.exp2()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:34:13 + --> $DIR/floating_point_powf.rs:35:13 | LL | let _ = 2f64.powf(3.1); | ^^^^^^^^^^^^^^ help: consider using: `3.1f64.exp2()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:35:13 + --> $DIR/floating_point_powf.rs:36:13 | LL | let _ = 2f64.powf(-3.1); | ^^^^^^^^^^^^^^^ help: consider using: `(-3.1f64).exp2()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:36:13 + --> $DIR/floating_point_powf.rs:37:13 | LL | let _ = std::f64::consts::E.powf(x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.exp()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:37:13 + --> $DIR/floating_point_powf.rs:38:13 | LL | let _ = std::f64::consts::E.powf(3.1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `3.1f64.exp()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:38:13 + --> $DIR/floating_point_powf.rs:39:13 | LL | let _ = std::f64::consts::E.powf(-3.1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(-3.1f64).exp()` error: square-root of a number can be computed more efficiently and accurately - --> $DIR/floating_point_powf.rs:39:13 + --> $DIR/floating_point_powf.rs:40:13 | LL | let _ = x.powf(1.0 / 2.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `x.sqrt()` error: cube-root of a number can be computed more accurately - --> $DIR/floating_point_powf.rs:40:13 + --> $DIR/floating_point_powf.rs:41:13 | LL | let _ = x.powf(1.0 / 3.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `x.cbrt()` error: exponentiation with integer powers can be computed more efficiently - --> $DIR/floating_point_powf.rs:41:13 + --> $DIR/floating_point_powf.rs:42:13 | LL | let _ = x.powf(3.0); | ^^^^^^^^^^^ help: consider using: `x.powi(3)` error: exponentiation with integer powers can be computed more efficiently - --> $DIR/floating_point_powf.rs:42:13 + --> $DIR/floating_point_powf.rs:43:13 | LL | let _ = x.powf(-2.0); | ^^^^^^^^^^^^ help: consider using: `x.powi(-2)` error: exponentiation with integer powers can be computed more efficiently - --> $DIR/floating_point_powf.rs:43:13 + --> $DIR/floating_point_powf.rs:44:13 | LL | let _ = x.powf(-2_147_483_648.0); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(-2_147_483_648)` error: exponentiation with integer powers can be computed more efficiently - --> $DIR/floating_point_powf.rs:44:13 + --> $DIR/floating_point_powf.rs:45:13 | LL | let _ = x.powf(2_147_483_647.0); | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2_147_483_647)` diff --git a/tests/ui/floating_point_powi.fixed b/tests/ui/floating_point_powi.fixed index 5758db7c6c82d..68c81316930ce 100644 --- a/tests/ui/floating_point_powi.fixed +++ b/tests/ui/floating_point_powi.fixed @@ -1,5 +1,6 @@ // run-rustfix #![warn(clippy::suboptimal_flops)] +#![allow(clippy::unnecessary_cast)] fn main() { let one = 1; diff --git a/tests/ui/floating_point_powi.rs b/tests/ui/floating_point_powi.rs index 5926bf1b00042..96101a487ee88 100644 --- a/tests/ui/floating_point_powi.rs +++ b/tests/ui/floating_point_powi.rs @@ -1,5 +1,6 @@ // run-rustfix #![warn(clippy::suboptimal_flops)] +#![allow(clippy::unnecessary_cast)] fn main() { let one = 1; diff --git a/tests/ui/floating_point_powi.stderr b/tests/ui/floating_point_powi.stderr index a3c74544212b2..a651954a5f81b 100644 --- a/tests/ui/floating_point_powi.stderr +++ b/tests/ui/floating_point_powi.stderr @@ -1,5 +1,5 @@ error: multiply and add expressions can be calculated more efficiently and accurately - --> $DIR/floating_point_powi.rs:9:13 + --> $DIR/floating_point_powi.rs:10:13 | LL | let _ = x.powi(2) + y; | ^^^^^^^^^^^^^ help: consider using: `x.mul_add(x, y)` @@ -7,25 +7,25 @@ LL | let _ = x.powi(2) + y; = note: `-D clippy::suboptimal-flops` implied by `-D warnings` error: multiply and add expressions can be calculated more efficiently and accurately - --> $DIR/floating_point_powi.rs:10:13 + --> $DIR/floating_point_powi.rs:11:13 | LL | let _ = x + y.powi(2); | ^^^^^^^^^^^^^ help: consider using: `y.mul_add(y, x)` error: multiply and add expressions can be calculated more efficiently and accurately - --> $DIR/floating_point_powi.rs:11:13 + --> $DIR/floating_point_powi.rs:12:13 | LL | let _ = x + (y as f32).powi(2); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(y as f32).mul_add(y as f32, x)` error: multiply and add expressions can be calculated more efficiently and accurately - --> $DIR/floating_point_powi.rs:12:13 + --> $DIR/floating_point_powi.rs:13:13 | LL | let _ = (x.powi(2) + y).sqrt(); | ^^^^^^^^^^^^^^^ help: consider using: `x.mul_add(x, y)` error: multiply and add expressions can be calculated more efficiently and accurately - --> $DIR/floating_point_powi.rs:13:13 + --> $DIR/floating_point_powi.rs:14:13 | LL | let _ = (x + y.powi(2)).sqrt(); | ^^^^^^^^^^^^^^^ help: consider using: `y.mul_add(y, x)` diff --git a/tests/ui/manual_bits.fixed b/tests/ui/manual_bits.fixed index 386360dbdcdb8..e7f8cd878ca78 100644 --- a/tests/ui/manual_bits.fixed +++ b/tests/ui/manual_bits.fixed @@ -6,7 +6,8 @@ clippy::useless_conversion, path_statements, unused_must_use, - clippy::unnecessary_operation + clippy::unnecessary_operation, + clippy::unnecessary_cast )] use std::mem::{size_of, size_of_val}; diff --git a/tests/ui/manual_bits.rs b/tests/ui/manual_bits.rs index 62638f047eb01..7b1d15495287a 100644 --- a/tests/ui/manual_bits.rs +++ b/tests/ui/manual_bits.rs @@ -6,7 +6,8 @@ clippy::useless_conversion, path_statements, unused_must_use, - clippy::unnecessary_operation + clippy::unnecessary_operation, + clippy::unnecessary_cast )] use std::mem::{size_of, size_of_val}; diff --git a/tests/ui/manual_bits.stderr b/tests/ui/manual_bits.stderr index 69c591a203d3f..652fafbc41d81 100644 --- a/tests/ui/manual_bits.stderr +++ b/tests/ui/manual_bits.stderr @@ -1,5 +1,5 @@ error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:15:5 + --> $DIR/manual_bits.rs:16:5 | LL | size_of::() * 8; | ^^^^^^^^^^^^^^^^^^^ help: consider using: `i8::BITS as usize` @@ -7,169 +7,169 @@ LL | size_of::() * 8; = note: `-D clippy::manual-bits` implied by `-D warnings` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:16:5 + --> $DIR/manual_bits.rs:17:5 | LL | size_of::() * 8; | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `i16::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:17:5 + --> $DIR/manual_bits.rs:18:5 | LL | size_of::() * 8; | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `i32::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:18:5 + --> $DIR/manual_bits.rs:19:5 | LL | size_of::() * 8; | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `i64::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:19:5 + --> $DIR/manual_bits.rs:20:5 | LL | size_of::() * 8; | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `i128::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:20:5 + --> $DIR/manual_bits.rs:21:5 | LL | size_of::() * 8; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `isize::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:22:5 + --> $DIR/manual_bits.rs:23:5 | LL | size_of::() * 8; | ^^^^^^^^^^^^^^^^^^^ help: consider using: `u8::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:23:5 + --> $DIR/manual_bits.rs:24:5 | LL | size_of::() * 8; | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `u16::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:24:5 + --> $DIR/manual_bits.rs:25:5 | LL | size_of::() * 8; | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `u32::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:25:5 + --> $DIR/manual_bits.rs:26:5 | LL | size_of::() * 8; | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `u64::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:26:5 + --> $DIR/manual_bits.rs:27:5 | LL | size_of::() * 8; | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `u128::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:27:5 + --> $DIR/manual_bits.rs:28:5 | LL | size_of::() * 8; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `usize::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:29:5 + --> $DIR/manual_bits.rs:30:5 | LL | 8 * size_of::(); | ^^^^^^^^^^^^^^^^^^^ help: consider using: `i8::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:30:5 + --> $DIR/manual_bits.rs:31:5 | LL | 8 * size_of::(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `i16::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:31:5 + --> $DIR/manual_bits.rs:32:5 | LL | 8 * size_of::(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `i32::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:32:5 + --> $DIR/manual_bits.rs:33:5 | LL | 8 * size_of::(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `i64::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:33:5 + --> $DIR/manual_bits.rs:34:5 | LL | 8 * size_of::(); | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `i128::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:34:5 + --> $DIR/manual_bits.rs:35:5 | LL | 8 * size_of::(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `isize::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:36:5 + --> $DIR/manual_bits.rs:37:5 | LL | 8 * size_of::(); | ^^^^^^^^^^^^^^^^^^^ help: consider using: `u8::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:37:5 + --> $DIR/manual_bits.rs:38:5 | LL | 8 * size_of::(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `u16::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:38:5 + --> $DIR/manual_bits.rs:39:5 | LL | 8 * size_of::(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `u32::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:39:5 + --> $DIR/manual_bits.rs:40:5 | LL | 8 * size_of::(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `u64::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:40:5 + --> $DIR/manual_bits.rs:41:5 | LL | 8 * size_of::(); | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `u128::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:41:5 + --> $DIR/manual_bits.rs:42:5 | LL | 8 * size_of::(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `usize::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:51:5 + --> $DIR/manual_bits.rs:52:5 | LL | size_of::() * 8; | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `Word::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:55:18 + --> $DIR/manual_bits.rs:56:18 | LL | let _: u32 = (size_of::() * 8) as u32; | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `u128::BITS` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:56:18 + --> $DIR/manual_bits.rs:57:18 | LL | let _: u32 = (size_of::() * 8).try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `u128::BITS` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:57:13 + --> $DIR/manual_bits.rs:58:13 | LL | let _ = (size_of::() * 8).pow(5); | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(u128::BITS as usize)` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:58:14 + --> $DIR/manual_bits.rs:59:14 | LL | let _ = &(size_of::() * 8); | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(u128::BITS as usize)` diff --git a/tests/ui/ptr_offset_with_cast.fixed b/tests/ui/ptr_offset_with_cast.fixed index 718e391e8bf69..c57e2990fb951 100644 --- a/tests/ui/ptr_offset_with_cast.fixed +++ b/tests/ui/ptr_offset_with_cast.fixed @@ -1,4 +1,5 @@ // run-rustfix +#![allow(clippy::unnecessary_cast)] fn main() { let vec = vec![b'a', b'b', b'c']; diff --git a/tests/ui/ptr_offset_with_cast.rs b/tests/ui/ptr_offset_with_cast.rs index f613742c741ef..3de7997acddda 100644 --- a/tests/ui/ptr_offset_with_cast.rs +++ b/tests/ui/ptr_offset_with_cast.rs @@ -1,4 +1,5 @@ // run-rustfix +#![allow(clippy::unnecessary_cast)] fn main() { let vec = vec![b'a', b'b', b'c']; diff --git a/tests/ui/ptr_offset_with_cast.stderr b/tests/ui/ptr_offset_with_cast.stderr index fd45224ca067f..3ba40593d6444 100644 --- a/tests/ui/ptr_offset_with_cast.stderr +++ b/tests/ui/ptr_offset_with_cast.stderr @@ -1,5 +1,5 @@ error: use of `offset` with a `usize` casted to an `isize` - --> $DIR/ptr_offset_with_cast.rs:12:17 + --> $DIR/ptr_offset_with_cast.rs:13:17 | LL | let _ = ptr.offset(offset_usize as isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ptr.add(offset_usize)` @@ -7,7 +7,7 @@ LL | let _ = ptr.offset(offset_usize as isize); = note: `-D clippy::ptr-offset-with-cast` implied by `-D warnings` error: use of `wrapping_offset` with a `usize` casted to an `isize` - --> $DIR/ptr_offset_with_cast.rs:16:17 + --> $DIR/ptr_offset_with_cast.rs:17:17 | LL | let _ = ptr.wrapping_offset(offset_usize as isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ptr.wrapping_add(offset_usize)` From bff811bfdf117ac737d44452c8aa645dd516f8a0 Mon Sep 17 00:00:00 2001 From: TennyZhuang Date: Sun, 2 Oct 2022 18:41:13 +0800 Subject: [PATCH 093/114] extract common codes Signed-off-by: TennyZhuang --- clippy_lints/src/casts/unnecessary_cast.rs | 28 ++++++++-------------- 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/clippy_lints/src/casts/unnecessary_cast.rs b/clippy_lints/src/casts/unnecessary_cast.rs index 071fab1165d4d..610e8f712f497 100644 --- a/clippy_lints/src/casts/unnecessary_cast.rs +++ b/clippy_lints/src/casts/unnecessary_cast.rs @@ -34,7 +34,7 @@ pub(super) fn check<'tcx>( let cast_str = snippet_opt(cx, cast_expr.span).unwrap_or_default(); if let Some(lit) = get_numeric_literal(cast_expr) { - let literal_str = cast_str; + let literal_str = &cast_str; if_chain! { if let LitKind::Int(n, _) = lit.node; @@ -52,10 +52,12 @@ pub(super) fn check<'tcx>( match lit.node { LitKind::Int(_, LitIntType::Unsuffixed) if cast_to.is_integral() => { - lint_unnecessary_cast(cx, expr, &literal_str, cast_from, cast_to); + lint_unnecessary_cast(cx, expr, literal_str, cast_from, cast_to); + return true; }, LitKind::Float(_, LitFloatType::Unsuffixed) if cast_to.is_floating_point() => { - lint_unnecessary_cast(cx, expr, &literal_str, cast_from, cast_to); + lint_unnecessary_cast(cx, expr, literal_str, cast_from, cast_to); + return true; }, LitKind::Int(_, LitIntType::Unsuffixed) | LitKind::Float(_, LitFloatType::Unsuffixed) => {}, LitKind::Int(_, LitIntType::Signed(_) | LitIntType::Unsigned(_)) @@ -65,25 +67,15 @@ pub(super) fn check<'tcx>( if let Some(src) = snippet_opt(cx, cast_expr.span) { if let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node) { lint_unnecessary_cast(cx, expr, num_lit.integer, cast_from, cast_to); + return true; } } }, - _ => { - if cast_from.kind() == cast_to.kind() && !in_external_macro(cx.sess(), expr.span) { - span_lint_and_sugg( - cx, - UNNECESSARY_CAST, - expr.span, - &format!("casting to the same type is unnecessary (`{cast_from}` -> `{cast_to}`)"), - "try", - literal_str, - Applicability::MachineApplicable, - ); - return true; - } - }, + _ => {}, } - } else if cast_from.kind() == cast_to.kind() && !in_external_macro(cx.sess(), expr.span) { + } + + if cast_from.kind() == cast_to.kind() && !in_external_macro(cx.sess(), expr.span) { span_lint_and_sugg( cx, UNNECESSARY_CAST, From c9b93143d52ed3393602db29c1e31db03e0fdab2 Mon Sep 17 00:00:00 2001 From: TennyZhuang Date: Sun, 2 Oct 2022 19:04:33 +0800 Subject: [PATCH 094/114] fix some logics Signed-off-by: TennyZhuang --- clippy_lints/src/casts/unnecessary_cast.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/casts/unnecessary_cast.rs b/clippy_lints/src/casts/unnecessary_cast.rs index 610e8f712f497..21ed7f4844cc5 100644 --- a/clippy_lints/src/casts/unnecessary_cast.rs +++ b/clippy_lints/src/casts/unnecessary_cast.rs @@ -53,13 +53,15 @@ pub(super) fn check<'tcx>( match lit.node { LitKind::Int(_, LitIntType::Unsuffixed) if cast_to.is_integral() => { lint_unnecessary_cast(cx, expr, literal_str, cast_from, cast_to); - return true; + return false; }, LitKind::Float(_, LitFloatType::Unsuffixed) if cast_to.is_floating_point() => { lint_unnecessary_cast(cx, expr, literal_str, cast_from, cast_to); - return true; + return false; + }, + LitKind::Int(_, LitIntType::Unsuffixed) | LitKind::Float(_, LitFloatType::Unsuffixed) => { + return false; }, - LitKind::Int(_, LitIntType::Unsuffixed) | LitKind::Float(_, LitFloatType::Unsuffixed) => {}, LitKind::Int(_, LitIntType::Signed(_) | LitIntType::Unsigned(_)) | LitKind::Float(_, LitFloatType::Suffixed(_)) if cast_from.kind() == cast_to.kind() => From 8e7af6b42961d6a4b6857c06aa5139a985e0009d Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Tue, 28 Jun 2022 22:34:02 -0400 Subject: [PATCH 095/114] Replace `is_lang_ctor` with `is_res_lang_ctor` --- clippy_lints/src/if_then_some_else_none.rs | 10 +-- clippy_lints/src/loops/manual_find.rs | 9 ++- clippy_lints/src/loops/manual_flatten.rs | 12 ++-- .../src/loops/while_let_on_iterator.rs | 10 ++- clippy_lints/src/matches/collapsible_match.rs | 6 +- clippy_lints/src/matches/manual_map.rs | 30 ++++---- clippy_lints/src/matches/manual_unwrap_or.rs | 16 +++-- clippy_lints/src/matches/match_as_ref.rs | 12 ++-- clippy_lints/src/matches/needless_match.rs | 7 +- .../src/matches/redundant_pattern_match.rs | 23 +++--- clippy_lints/src/matches/try_err.rs | 5 +- clippy_lints/src/mem_replace.rs | 72 +++++++++---------- .../iter_on_single_or_empty_collections.rs | 27 ++----- clippy_lints/src/methods/manual_ok_or.rs | 34 ++++----- .../src/methods/option_map_or_none.rs | 16 +---- clippy_lints/src/methods/or_then_unwrap.rs | 5 +- .../src/methods/unnecessary_filter_map.rs | 20 +++--- clippy_lints/src/needless_question_mark.rs | 14 ++-- clippy_lints/src/option_if_let_else.rs | 10 +-- clippy_lints/src/partialeq_to_none.rs | 5 +- clippy_lints/src/question_mark.rs | 24 ++++--- clippy_lints/src/unnecessary_wraps.rs | 6 +- clippy_utils/src/lib.rs | 34 +++++---- 23 files changed, 205 insertions(+), 202 deletions(-) diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs index 0800e0644f7f3..0d6718c168a5c 100644 --- a/clippy_lints/src/if_then_some_else_none.rs +++ b/clippy_lints/src/if_then_some_else_none.rs @@ -1,7 +1,9 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::eager_or_lazy::switch_to_eager_eval; use clippy_utils::source::snippet_with_macro_callsite; -use clippy_utils::{contains_return, higher, is_else_clause, is_lang_ctor, meets_msrv, msrvs, peel_blocks}; +use clippy_utils::{ + contains_return, higher, is_else_clause, is_res_lang_ctor, meets_msrv, msrvs, path_res, peel_blocks, +}; use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_hir::{Expr, ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -76,10 +78,8 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { && let ExprKind::Block(then_block, _) = then.kind && let Some(then_expr) = then_block.expr && let ExprKind::Call(then_call, [then_arg]) = then_expr.kind - && let ExprKind::Path(ref then_call_qpath) = then_call.kind - && is_lang_ctor(cx, then_call_qpath, OptionSome) - && let ExprKind::Path(ref qpath) = peel_blocks(els).kind - && is_lang_ctor(cx, qpath, OptionNone) + && is_res_lang_ctor(cx, path_res(cx, then_call), OptionSome) + && is_res_lang_ctor(cx, path_res(cx, peel_blocks(els)), OptionNone) && !stmts_contains_early_return(then_block.stmts) { let cond_snip = snippet_with_macro_callsite(cx, cond.span, "[condition]"); diff --git a/clippy_lints/src/loops/manual_find.rs b/clippy_lints/src/loops/manual_find.rs index 09b2376d5c04a..4bb9936e9cde7 100644 --- a/clippy_lints/src/loops/manual_find.rs +++ b/clippy_lints/src/loops/manual_find.rs @@ -1,7 +1,7 @@ use super::utils::make_iterator_snippet; use super::MANUAL_FIND; use clippy_utils::{ - diagnostics::span_lint_and_then, higher, is_lang_ctor, path_res, peel_blocks_with_stmt, + diagnostics::span_lint_and_then, higher, is_res_lang_ctor, path_res, peel_blocks_with_stmt, source::snippet_with_applicability, ty::implements_trait, }; use if_chain::if_chain; @@ -30,8 +30,8 @@ pub(super) fn check<'tcx>( if let [stmt] = block.stmts; if let StmtKind::Semi(semi) = stmt.kind; if let ExprKind::Ret(Some(ret_value)) = semi.kind; - if let ExprKind::Call(Expr { kind: ExprKind::Path(ctor), .. }, [inner_ret]) = ret_value.kind; - if is_lang_ctor(cx, ctor, LangItem::OptionSome); + if let ExprKind::Call(ctor, [inner_ret]) = ret_value.kind; + if is_res_lang_ctor(cx, path_res(cx, ctor), LangItem::OptionSome); if path_res(cx, inner_ret) == Res::Local(binding_id); if let Some((last_stmt, last_ret)) = last_stmt_and_ret(cx, expr); then { @@ -143,8 +143,7 @@ fn last_stmt_and_ret<'tcx>( if let Some((_, Node::Block(block))) = parent_iter.next(); if let Some((last_stmt, last_ret)) = extract(block); if last_stmt.hir_id == node_hir; - if let ExprKind::Path(path) = &last_ret.kind; - if is_lang_ctor(cx, path, LangItem::OptionNone); + if is_res_lang_ctor(cx, path_res(cx, last_ret), LangItem::OptionNone); if let Some((_, Node::Expr(_block))) = parent_iter.next(); // This includes the function header if let Some((_, func)) = parent_iter.next(); diff --git a/clippy_lints/src/loops/manual_flatten.rs b/clippy_lints/src/loops/manual_flatten.rs index 1b36d452647ed..8c27c09404b1b 100644 --- a/clippy_lints/src/loops/manual_flatten.rs +++ b/clippy_lints/src/loops/manual_flatten.rs @@ -3,13 +3,13 @@ use super::MANUAL_FLATTEN; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher; use clippy_utils::visitors::is_local_used; -use clippy_utils::{is_lang_ctor, path_to_local_id, peel_blocks_with_stmt}; +use clippy_utils::{path_to_local_id, peel_blocks_with_stmt}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::LangItem::{OptionSome, ResultOk}; +use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Expr, Pat, PatKind}; use rustc_lint::LateContext; -use rustc_middle::ty; +use rustc_middle::ty::{self, DefIdTree}; use rustc_span::source_map::Span; /// Check for unnecessary `if let` usage in a for loop where only the `Some` or `Ok` variant of the @@ -30,8 +30,10 @@ pub(super) fn check<'tcx>( if path_to_local_id(let_expr, pat_hir_id); // Ensure the `if let` statement is for the `Some` variant of `Option` or the `Ok` variant of `Result` if let PatKind::TupleStruct(ref qpath, _, _) = let_pat.kind; - let some_ctor = is_lang_ctor(cx, qpath, OptionSome); - let ok_ctor = is_lang_ctor(cx, qpath, ResultOk); + if let Res::Def(DefKind::Ctor(..), ctor_id) = cx.qpath_res(qpath, let_pat.hir_id); + if let Some(variant_id) = cx.tcx.opt_parent(ctor_id); + let some_ctor = cx.tcx.lang_items().option_some_variant() == Some(variant_id); + let ok_ctor = cx.tcx.lang_items().result_ok_variant() == Some(variant_id); if some_ctor || ok_ctor; // Ensure expr in `if let` is not used afterwards if !is_local_used(cx, if_then, pat_hir_id); diff --git a/clippy_lints/src/loops/while_let_on_iterator.rs b/clippy_lints/src/loops/while_let_on_iterator.rs index 1c6f0264cb543..153f97e4e66c8 100644 --- a/clippy_lints/src/loops/while_let_on_iterator.rs +++ b/clippy_lints/src/loops/while_let_on_iterator.rs @@ -3,13 +3,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::higher; use clippy_utils::source::snippet_with_applicability; use clippy_utils::{ - get_enclosing_loop_or_multi_call_closure, is_refutable, is_trait_method, match_def_path, paths, - visitors::is_res_used, + get_enclosing_loop_or_multi_call_closure, is_refutable, is_res_lang_ctor, is_trait_method, visitors::is_res_used, }; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, Visitor}; -use rustc_hir::{def::Res, Closure, Expr, ExprKind, HirId, Local, Mutability, PatKind, QPath, UnOp}; +use rustc_hir::{def::Res, Closure, Expr, ExprKind, HirId, LangItem, Local, Mutability, PatKind, UnOp}; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_middle::ty::adjustment::Adjust; @@ -19,9 +18,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { let (scrutinee_expr, iter_expr_struct, iter_expr, some_pat, loop_expr) = if_chain! { if let Some(higher::WhileLet { if_then, let_pat, let_expr }) = higher::WhileLet::hir(expr); // check for `Some(..)` pattern - if let PatKind::TupleStruct(QPath::Resolved(None, pat_path), some_pat, _) = let_pat.kind; - if let Res::Def(_, pat_did) = pat_path.res; - if match_def_path(cx, pat_did, &paths::OPTION_SOME); + if let PatKind::TupleStruct(ref pat_path, some_pat, _) = let_pat.kind; + if is_res_lang_ctor(cx, cx.qpath_res(pat_path, let_pat.hir_id), LangItem::OptionSome); // check for call to `Iterator::next` if let ExprKind::MethodCall(method_name, iter_expr, [], _) = let_expr.kind; if method_name.ident.name == sym::next; diff --git a/clippy_lints/src/matches/collapsible_match.rs b/clippy_lints/src/matches/collapsible_match.rs index 07021f1bcad8d..fd14d868df348 100644 --- a/clippy_lints/src/matches/collapsible_match.rs +++ b/clippy_lints/src/matches/collapsible_match.rs @@ -1,7 +1,9 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::IfLetOrMatch; use clippy_utils::visitors::is_local_used; -use clippy_utils::{is_lang_ctor, is_unit_expr, path_to_local, peel_blocks_with_stmt, peel_ref_operators, SpanlessEq}; +use clippy_utils::{ + is_res_lang_ctor, is_unit_expr, path_to_local, peel_blocks_with_stmt, peel_ref_operators, SpanlessEq, +}; use if_chain::if_chain; use rustc_errors::MultiSpan; use rustc_hir::LangItem::OptionNone; @@ -110,7 +112,7 @@ fn arm_is_wild_like(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool { } match arm.pat.kind { PatKind::Binding(..) | PatKind::Wild => true, - PatKind::Path(ref qpath) => is_lang_ctor(cx, qpath, OptionNone), + PatKind::Path(ref qpath) => is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), OptionNone), _ => false, } } diff --git a/clippy_lints/src/matches/manual_map.rs b/clippy_lints/src/matches/manual_map.rs index 96b8339550cee..76f5e1c941c7a 100644 --- a/clippy_lints/src/matches/manual_map.rs +++ b/clippy_lints/src/matches/manual_map.rs @@ -3,8 +3,8 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::ty::{is_type_diagnostic_item, peel_mid_ty_refs_is_mutable, type_is_unsafe_function}; use clippy_utils::{ - can_move_expr_to_closure, is_else_clause, is_lang_ctor, is_lint_allowed, path_to_local_id, peel_blocks, - peel_hir_expr_refs, peel_hir_expr_while, CaptureKind, + can_move_expr_to_closure, is_else_clause, is_lint_allowed, is_res_lang_ctor, path_res, path_to_local_id, + peel_blocks, peel_hir_expr_refs, peel_hir_expr_while, CaptureKind, }; use rustc_ast::util::parser::PREC_POSTFIX; use rustc_errors::Applicability; @@ -251,9 +251,11 @@ fn try_parse_pattern<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, ctxt: Syn match pat.kind { PatKind::Wild => Some(OptionPat::Wild), PatKind::Ref(pat, _) => f(cx, pat, ref_count + 1, ctxt), - PatKind::Path(ref qpath) if is_lang_ctor(cx, qpath, OptionNone) => Some(OptionPat::None), + PatKind::Path(ref qpath) if is_res_lang_ctor(cx, cx.qpath_res(qpath, pat.hir_id), OptionNone) => { + Some(OptionPat::None) + }, PatKind::TupleStruct(ref qpath, [pattern], _) - if is_lang_ctor(cx, qpath, OptionSome) && pat.span.ctxt() == ctxt => + if is_res_lang_ctor(cx, cx.qpath_res(qpath, pat.hir_id), OptionSome) && pat.span.ctxt() == ctxt => { Some(OptionPat::Some { pattern, ref_count }) }, @@ -272,16 +274,14 @@ fn get_some_expr<'tcx>( ) -> Option> { // TODO: Allow more complex expressions. match expr.kind { - ExprKind::Call( - Expr { - kind: ExprKind::Path(ref qpath), - .. - }, - [arg], - ) if ctxt == expr.span.ctxt() && is_lang_ctor(cx, qpath, OptionSome) => Some(SomeExpr { - expr: arg, - needs_unsafe_block, - }), + ExprKind::Call(callee, [arg]) + if ctxt == expr.span.ctxt() && is_res_lang_ctor(cx, path_res(cx, callee), OptionSome) => + { + Some(SomeExpr { + expr: arg, + needs_unsafe_block, + }) + }, ExprKind::Block( Block { stmts: [], @@ -302,5 +302,5 @@ fn get_some_expr<'tcx>( // Checks for the `None` value. fn is_none_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - matches!(peel_blocks(expr).kind, ExprKind::Path(ref qpath) if is_lang_ctor(cx, qpath, OptionNone)) + is_res_lang_ctor(cx, path_res(cx, peel_blocks(expr)), OptionNone) } diff --git a/clippy_lints/src/matches/manual_unwrap_or.rs b/clippy_lints/src/matches/manual_unwrap_or.rs index 2fe7fe98a2e8f..587c926dc01c3 100644 --- a/clippy_lints/src/matches/manual_unwrap_or.rs +++ b/clippy_lints/src/matches/manual_unwrap_or.rs @@ -3,12 +3,14 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::usage::contains_return_break_continue_macro; -use clippy_utils::{is_lang_ctor, path_to_local_id, sugg}; +use clippy_utils::{is_res_lang_ctor, path_to_local_id, sugg}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk}; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::LangItem::{OptionNone, ResultErr}; use rustc_hir::{Arm, Expr, PatKind}; use rustc_lint::LateContext; +use rustc_middle::ty::DefIdTree; use rustc_span::sym; use super::MANUAL_UNWRAP_OR; @@ -59,15 +61,19 @@ fn applicable_or_arm<'a>(cx: &LateContext<'_>, arms: &'a [Arm<'a>]) -> Option<&' if arms.iter().all(|arm| arm.guard.is_none()); if let Some((idx, or_arm)) = arms.iter().enumerate().find(|(_, arm)| { match arm.pat.kind { - PatKind::Path(ref qpath) => is_lang_ctor(cx, qpath, OptionNone), + PatKind::Path(ref qpath) => is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), OptionNone), PatKind::TupleStruct(ref qpath, [pat], _) => - matches!(pat.kind, PatKind::Wild) && is_lang_ctor(cx, qpath, ResultErr), + matches!(pat.kind, PatKind::Wild) + && is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), ResultErr), _ => false, } }); let unwrap_arm = &arms[1 - idx]; if let PatKind::TupleStruct(ref qpath, [unwrap_pat], _) = unwrap_arm.pat.kind; - if is_lang_ctor(cx, qpath, OptionSome) || is_lang_ctor(cx, qpath, ResultOk); + if let Res::Def(DefKind::Ctor(..), ctor_id) = cx.qpath_res(qpath, unwrap_arm.pat.hir_id); + if let Some(variant_id) = cx.tcx.opt_parent(ctor_id); + if cx.tcx.lang_items().option_some_variant() == Some(variant_id) + || cx.tcx.lang_items().result_ok_variant() == Some(variant_id); if let PatKind::Binding(_, binding_hir_id, ..) = unwrap_pat.kind; if path_to_local_id(unwrap_arm.body, binding_hir_id); if cx.typeck_results().expr_adjustments(unwrap_arm.body).is_empty(); diff --git a/clippy_lints/src/matches/match_as_ref.rs b/clippy_lints/src/matches/match_as_ref.rs index 39d30212f36a3..2818f030b7a63 100644 --- a/clippy_lints/src/matches/match_as_ref.rs +++ b/clippy_lints/src/matches/match_as_ref.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{is_lang_ctor, peel_blocks}; +use clippy_utils::{is_res_lang_ctor, path_res, peel_blocks}; use rustc_errors::Applicability; use rustc_hir::{Arm, BindingAnnotation, ByRef, Expr, ExprKind, LangItem, Mutability, PatKind, QPath}; use rustc_lint::LateContext; @@ -59,18 +59,20 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: // Checks if arm has the form `None => None` fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool { - matches!(arm.pat.kind, PatKind::Path(ref qpath) if is_lang_ctor(cx, qpath, LangItem::OptionNone)) + matches!( + arm.pat.kind, + PatKind::Path(ref qpath) if is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), LangItem::OptionNone) + ) } // Checks if arm has the form `Some(ref v) => Some(v)` (checks for `ref` and `ref mut`) fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option { if_chain! { if let PatKind::TupleStruct(ref qpath, [first_pat, ..], _) = arm.pat.kind; - if is_lang_ctor(cx, qpath, LangItem::OptionSome); + if is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), LangItem::OptionSome); if let PatKind::Binding(BindingAnnotation(ByRef::Yes, mutabl), .., ident, _) = first_pat.kind; if let ExprKind::Call(e, [arg]) = peel_blocks(arm.body).kind; - if let ExprKind::Path(ref some_path) = e.kind; - if is_lang_ctor(cx, some_path, LangItem::OptionSome); + if is_res_lang_ctor(cx, path_res(cx, e), LangItem::OptionSome); if let ExprKind::Path(QPath::Resolved(_, path2)) = arg.kind; if path2.segments.len() == 1 && ident.name == path2.segments[0].ident.name; then { diff --git a/clippy_lints/src/matches/needless_match.rs b/clippy_lints/src/matches/needless_match.rs index 9cbffbe61f152..c4f6852aedc3d 100644 --- a/clippy_lints/src/matches/needless_match.rs +++ b/clippy_lints/src/matches/needless_match.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{is_type_diagnostic_item, same_type_and_consts}; use clippy_utils::{ - eq_expr_value, get_parent_expr_for_hir, get_parent_node, higher, is_else_clause, is_lang_ctor, over, + eq_expr_value, get_parent_expr_for_hir, get_parent_node, higher, is_else_clause, is_res_lang_ctor, over, path_res, peel_blocks_with_stmt, }; use rustc_errors::Applicability; @@ -112,10 +112,7 @@ fn check_if_let_inner(cx: &LateContext<'_>, if_let: &higher::IfLet<'_>) -> bool let ret = strip_return(else_expr); let let_expr_ty = cx.typeck_results().expr_ty(if_let.let_expr); if is_type_diagnostic_item(cx, let_expr_ty, sym::Option) { - if let ExprKind::Path(ref qpath) = ret.kind { - return is_lang_ctor(cx, qpath, OptionNone) || eq_expr_value(cx, if_let.let_expr, ret); - } - return false; + return is_res_lang_ctor(cx, path_res(cx, ret), OptionNone) || eq_expr_value(cx, if_let.let_expr, ret); } return eq_expr_value(cx, if_let.let_expr, ret); } diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs index 6d6aa43df2a7e..81bebff34c82c 100644 --- a/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/clippy_lints/src/matches/redundant_pattern_match.rs @@ -4,10 +4,11 @@ use clippy_utils::source::snippet; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{is_type_diagnostic_item, needs_ordered_drop}; use clippy_utils::visitors::any_temporaries_need_ordered_drop; -use clippy_utils::{higher, is_lang_ctor, is_trait_method}; +use clippy_utils::{higher, is_trait_method}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; +use rustc_hir::def::{DefKind, Res}; use rustc_hir::LangItem::{self, OptionNone, OptionSome, PollPending, PollReady, ResultErr, ResultOk}; use rustc_hir::{Arm, Expr, ExprKind, Node, Pat, PatKind, QPath, UnOp}; use rustc_lint::LateContext; @@ -87,15 +88,21 @@ fn find_sugg_for_if_let<'tcx>( } }, PatKind::Path(ref path) => { - let method = if is_lang_ctor(cx, path, OptionNone) { - "is_none()" - } else if is_lang_ctor(cx, path, PollPending) { - "is_pending()" + if let Res::Def(DefKind::Ctor(..), ctor_id) = cx.qpath_res(path, check_pat.hir_id) + && let Some(variant_id) = cx.tcx.opt_parent(ctor_id) + { + let method = if cx.tcx.lang_items().option_none_variant() == Some(variant_id) { + "is_none()" + } else if cx.tcx.lang_items().poll_pending_variant() == Some(variant_id) { + "is_pending()" + } else { + return; + }; + // `None` and `Pending` don't have an inner type. + (method, cx.tcx.types.unit) } else { return; - }; - // `None` and `Pending` don't have an inner type. - (method, cx.tcx.types.unit) + } }, _ => return, }; diff --git a/clippy_lints/src/matches/try_err.rs b/clippy_lints/src/matches/try_err.rs index a3ec1ff24820c..c6cba81d87189 100644 --- a/clippy_lints/src/matches/try_err.rs +++ b/clippy_lints/src/matches/try_err.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{get_parent_expr, is_lang_ctor, match_def_path, paths}; +use clippy_utils::{get_parent_expr, is_res_lang_ctor, match_def_path, path_res, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::LangItem::ResultErr; @@ -27,8 +27,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, scrutine if let ExprKind::Path(ref match_fun_path) = match_fun.kind; if matches!(match_fun_path, QPath::LangItem(LangItem::TryTraitBranch, ..)); if let ExprKind::Call(err_fun, [err_arg, ..]) = try_arg.kind; - if let ExprKind::Path(ref err_fun_path) = err_fun.kind; - if is_lang_ctor(cx, err_fun_path, ResultErr); + if is_res_lang_ctor(cx, path_res(cx, err_fun), ResultErr); if let Some(return_ty) = find_return_type(cx, &expr.kind); then { let prefix; diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index cad3ea2a176cd..0c4d9f100f7a9 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::ty::is_non_aggregate_primitive_type; -use clippy_utils::{is_default_equivalent, is_lang_ctor, meets_msrv, msrvs}; +use clippy_utils::{is_default_equivalent, is_res_lang_ctor, meets_msrv, msrvs, path_res}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::LangItem::OptionNone; @@ -102,40 +102,38 @@ impl_lint_pass!(MemReplace => [MEM_REPLACE_OPTION_WITH_NONE, MEM_REPLACE_WITH_UNINIT, MEM_REPLACE_WITH_DEFAULT]); fn check_replace_option_with_none(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<'_>, expr_span: Span) { - if let ExprKind::Path(ref replacement_qpath) = src.kind { - // Check that second argument is `Option::None` - if is_lang_ctor(cx, replacement_qpath, OptionNone) { - // Since this is a late pass (already type-checked), - // and we already know that the second argument is an - // `Option`, we do not need to check the first - // argument's type. All that's left is to get - // replacee's path. - let replaced_path = match dest.kind { - ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, replaced) => { - if let ExprKind::Path(QPath::Resolved(None, replaced_path)) = replaced.kind { - replaced_path - } else { - return; - } - }, - ExprKind::Path(QPath::Resolved(None, replaced_path)) => replaced_path, - _ => return, - }; + // Check that second argument is `Option::None` + if is_res_lang_ctor(cx, path_res(cx, src), OptionNone) { + // Since this is a late pass (already type-checked), + // and we already know that the second argument is an + // `Option`, we do not need to check the first + // argument's type. All that's left is to get + // replacee's path. + let replaced_path = match dest.kind { + ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, replaced) => { + if let ExprKind::Path(QPath::Resolved(None, replaced_path)) = replaced.kind { + replaced_path + } else { + return; + } + }, + ExprKind::Path(QPath::Resolved(None, replaced_path)) => replaced_path, + _ => return, + }; - let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - MEM_REPLACE_OPTION_WITH_NONE, - expr_span, - "replacing an `Option` with `None`", - "consider `Option::take()` instead", - format!( - "{}.take()", - snippet_with_applicability(cx, replaced_path.span, "", &mut applicability) - ), - applicability, - ); - } + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + MEM_REPLACE_OPTION_WITH_NONE, + expr_span, + "replacing an `Option` with `None`", + "consider `Option::take()` instead", + format!( + "{}.take()", + snippet_with_applicability(cx, replaced_path.span, "", &mut applicability) + ), + applicability, + ); } } @@ -203,10 +201,8 @@ fn check_replace_with_default(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr< return; } // disable lint for Option since it is covered in another lint - if let ExprKind::Path(q) = &src.kind { - if is_lang_ctor(cx, q, OptionNone) { - return; - } + if is_res_lang_ctor(cx, path_res(cx, src), OptionNone) { + return; } if is_default_equivalent(cx, src) && !in_external_macro(cx.tcx.sess, expr_span) { span_lint_and_then( diff --git a/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs b/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs index cea7b0d82ff3f..4f73b3ec42247 100644 --- a/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs +++ b/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; -use clippy_utils::{get_expr_use_or_unification_node, is_lang_ctor, is_no_std_crate}; +use clippy_utils::{get_expr_use_or_unification_node, is_no_std_crate, is_res_lang_ctor, path_res}; use rustc_errors::Applicability; use rustc_hir::LangItem::{OptionNone, OptionSome}; @@ -26,26 +26,11 @@ impl IterType { } pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, method_name: &str, recv: &Expr<'_>) { - let item = match &recv.kind { - ExprKind::Array(v) if v.len() <= 1 => v.first(), - ExprKind::Path(p) => { - if is_lang_ctor(cx, p, OptionNone) { - None - } else { - return; - } - }, - ExprKind::Call(f, some_args) if some_args.len() == 1 => { - if let ExprKind::Path(p) = &f.kind { - if is_lang_ctor(cx, p, OptionSome) { - Some(&some_args[0]) - } else { - return; - } - } else { - return; - } - }, + let item = match recv.kind { + ExprKind::Array([]) => None, + ExprKind::Array([e]) => Some(e), + ExprKind::Path(ref p) if is_res_lang_ctor(cx, cx.qpath_res(p, recv.hir_id), OptionNone) => None, + ExprKind::Call(f, [arg]) if is_res_lang_ctor(cx, path_res(cx, f), OptionSome) => Some(arg), _ => return, }; let iter_type = match method_name { diff --git a/clippy_lints/src/methods/manual_ok_or.rs b/clippy_lints/src/methods/manual_ok_or.rs index d9fb4382181a2..5b758f1e6547c 100644 --- a/clippy_lints/src/methods/manual_ok_or.rs +++ b/clippy_lints/src/methods/manual_ok_or.rs @@ -1,11 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{is_lang_ctor, path_to_local_id}; +use clippy_utils::{is_res_lang_ctor, path_res, path_to_local_id}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::LangItem::{ResultErr, ResultOk}; -use rustc_hir::{Closure, Expr, ExprKind, PatKind}; +use rustc_hir::{Expr, ExprKind, PatKind}; use rustc_lint::LateContext; use rustc_span::symbol::sym; @@ -22,8 +22,8 @@ pub(super) fn check<'tcx>( if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if let Some(impl_id) = cx.tcx.impl_of_method(method_id); if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id), sym::Option); - if let ExprKind::Call(Expr { kind: ExprKind::Path(err_path), .. }, [err_arg]) = or_expr.kind; - if is_lang_ctor(cx, err_path, ResultErr); + if let ExprKind::Call(err_path, [err_arg]) = or_expr.kind; + if is_res_lang_ctor(cx, path_res(cx, err_path), ResultErr); if is_ok_wrapping(cx, map_expr); if let Some(recv_snippet) = snippet_opt(cx, recv.span); if let Some(err_arg_snippet) = snippet_opt(cx, err_arg.span); @@ -46,17 +46,19 @@ pub(super) fn check<'tcx>( } fn is_ok_wrapping(cx: &LateContext<'_>, map_expr: &Expr<'_>) -> bool { - if let ExprKind::Path(ref qpath) = map_expr.kind { - if is_lang_ctor(cx, qpath, ResultOk) { - return true; - } - } - if_chain! { - if let ExprKind::Closure(&Closure { body, .. }) = map_expr.kind; - let body = cx.tcx.hir().body(body); - if let PatKind::Binding(_, param_id, ..) = body.params[0].pat.kind; - if let ExprKind::Call(Expr { kind: ExprKind::Path(ok_path), .. }, [ok_arg]) = body.value.kind; - if is_lang_ctor(cx, ok_path, ResultOk); - then { path_to_local_id(ok_arg, param_id) } else { false } + match map_expr.kind { + ExprKind::Path(ref qpath) if is_res_lang_ctor(cx, cx.qpath_res(qpath, map_expr.hir_id), ResultOk) => true, + ExprKind::Closure(closure) => { + let body = cx.tcx.hir().body(closure.body); + if let PatKind::Binding(_, param_id, ..) = body.params[0].pat.kind + && let ExprKind::Call(callee, [ok_arg]) = body.value.kind + && is_res_lang_ctor(cx, path_res(cx, callee), ResultOk) + { + path_to_local_id(ok_arg, param_id) + } else { + false + } + }, + _ => false, } } diff --git a/clippy_lints/src/methods/option_map_or_none.rs b/clippy_lints/src/methods/option_map_or_none.rs index 76572425346b0..3a23ecc50dc1d 100644 --- a/clippy_lints/src/methods/option_map_or_none.rs +++ b/clippy_lints/src/methods/option_map_or_none.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{is_lang_ctor, path_def_id}; +use clippy_utils::{is_res_lang_ctor, path_def_id, path_res}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::LangItem::{OptionNone, OptionSome}; @@ -51,22 +51,12 @@ pub(super) fn check<'tcx>( return; } - let default_arg_is_none = if let hir::ExprKind::Path(ref qpath) = def_arg.kind { - is_lang_ctor(cx, qpath, OptionNone) - } else { - return; - }; - - if !default_arg_is_none { + if !is_res_lang_ctor(cx, path_res(cx, def_arg), OptionNone) { // nothing to lint! return; } - let f_arg_is_some = if let hir::ExprKind::Path(ref qpath) = map_arg.kind { - is_lang_ctor(cx, qpath, OptionSome) - } else { - false - }; + let f_arg_is_some = is_res_lang_ctor(cx, path_res(cx, map_arg), OptionSome); if is_option { let self_snippet = snippet(cx, recv.span, ".."); diff --git a/clippy_lints/src/methods/or_then_unwrap.rs b/clippy_lints/src/methods/or_then_unwrap.rs index be5768c354504..55ba6e262df7e 100644 --- a/clippy_lints/src/methods/or_then_unwrap.rs +++ b/clippy_lints/src/methods/or_then_unwrap.rs @@ -1,6 +1,6 @@ use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{diagnostics::span_lint_and_sugg, is_lang_ctor}; +use clippy_utils::{diagnostics::span_lint_and_sugg, is_res_lang_ctor, path_res}; use rustc_errors::Applicability; use rustc_hir::{lang_items::LangItem, Expr, ExprKind}; use rustc_lint::LateContext; @@ -58,8 +58,7 @@ pub(super) fn check<'tcx>( fn get_content_if_ctor_matches(cx: &LateContext<'_>, expr: &Expr<'_>, item: LangItem) -> Option { if let ExprKind::Call(some_expr, [arg]) = expr.kind - && let ExprKind::Path(qpath) = &some_expr.kind - && is_lang_ctor(cx, qpath, item) + && is_res_lang_ctor(cx, path_res(cx, some_expr), item) { Some(arg.span) } else { diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs index ee16982d52487..50434a5658ac5 100644 --- a/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -2,7 +2,7 @@ use super::utils::clone_or_copy_needed; use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::is_copy; use clippy_utils::usage::mutated_variables; -use clippy_utils::{is_lang_ctor, is_trait_method, path_to_local_id}; +use clippy_utils::{is_res_lang_ctor, is_trait_method, path_res, path_to_local_id}; use rustc_hir as hir; use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::LangItem::{OptionNone, OptionSome}; @@ -61,15 +61,13 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr< // returns (found_mapping, found_filtering) fn check_expression<'tcx>(cx: &LateContext<'tcx>, arg_id: hir::HirId, expr: &'tcx hir::Expr<'_>) -> (bool, bool) { - match &expr.kind { + match expr.kind { hir::ExprKind::Call(func, args) => { - if let hir::ExprKind::Path(ref path) = func.kind { - if is_lang_ctor(cx, path, OptionSome) { - if path_to_local_id(&args[0], arg_id) { - return (false, false); - } - return (true, false); + if is_res_lang_ctor(cx, path_res(cx, func), OptionSome) { + if path_to_local_id(&args[0], arg_id) { + return (false, false); } + return (true, false); } (true, true) }, @@ -80,7 +78,7 @@ fn check_expression<'tcx>(cx: &LateContext<'tcx>, arg_id: hir::HirId, expr: &'tc hir::ExprKind::Match(_, arms, _) => { let mut found_mapping = false; let mut found_filtering = false; - for arm in *arms { + for arm in arms { let (m, f) = check_expression(cx, arg_id, arm.body); found_mapping |= m; found_filtering |= f; @@ -93,7 +91,9 @@ fn check_expression<'tcx>(cx: &LateContext<'tcx>, arg_id: hir::HirId, expr: &'tc let else_check = check_expression(cx, arg_id, else_arm); (if_check.0 | else_check.0, if_check.1 | else_check.1) }, - hir::ExprKind::Path(path) if is_lang_ctor(cx, path, OptionNone) => (false, true), + hir::ExprKind::Path(ref path) if is_res_lang_ctor(cx, cx.qpath_res(path, expr.hir_id), OptionNone) => { + (false, true) + }, _ => (true, true), } } diff --git a/clippy_lints/src/needless_question_mark.rs b/clippy_lints/src/needless_question_mark.rs index 59b6492e112c0..97c8cfbd3eb7a 100644 --- a/clippy_lints/src/needless_question_mark.rs +++ b/clippy_lints/src/needless_question_mark.rs @@ -1,11 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::is_lang_ctor; +use clippy_utils::path_res; use clippy_utils::source::snippet; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::LangItem::{OptionSome, ResultOk}; +use rustc_hir::def::{DefKind, Res}; use rustc_hir::{AsyncGeneratorKind, Block, Body, Expr, ExprKind, GeneratorKind, LangItem, MatchSource, QPath}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::DefIdTree; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { @@ -112,11 +113,12 @@ impl LateLintPass<'_> for NeedlessQuestionMark { fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { if_chain! { - if let ExprKind::Call(path, [arg]) = &expr.kind; - if let ExprKind::Path(ref qpath) = &path.kind; - let sugg_remove = if is_lang_ctor(cx, qpath, OptionSome) { + if let ExprKind::Call(path, [arg]) = expr.kind; + if let Res::Def(DefKind::Ctor(..), ctor_id) = path_res(cx, path); + if let Some(variant_id) = cx.tcx.opt_parent(ctor_id); + let sugg_remove = if cx.tcx.lang_items().option_some_variant() == Some(variant_id) { "Some()" - } else if is_lang_ctor(cx, qpath, ResultOk) { + } else if cx.tcx.lang_items().result_ok_variant() == Some(variant_id) { "Ok()" } else { return; diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index 2c1e3b855d52c..4eb42da1fed02 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::sugg::Sugg; use clippy_utils::{ - can_move_expr_to_closure, eager_or_lazy, higher, in_constant, is_else_clause, is_lang_ctor, peel_blocks, + can_move_expr_to_closure, eager_or_lazy, higher, in_constant, is_else_clause, is_res_lang_ctor, peel_blocks, peel_hir_expr_while, CaptureKind, }; use if_chain::if_chain; @@ -174,7 +174,8 @@ fn try_get_option_occurrence<'tcx>( fn try_get_inner_pat<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'tcx>) -> Option<&'tcx Pat<'tcx>> { if let PatKind::TupleStruct(ref qpath, [inner_pat], ..) = pat.kind { - if is_lang_ctor(cx, qpath, OptionSome) || is_lang_ctor(cx, qpath, ResultOk) { + let res = cx.qpath_res(qpath, pat.hir_id); + if is_res_lang_ctor(cx, res, OptionSome) || is_res_lang_ctor(cx, res, ResultOk) { return Some(inner_pat); } } @@ -226,9 +227,10 @@ fn try_convert_match<'tcx>( fn is_none_or_err_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool { match arm.pat.kind { - PatKind::Path(ref qpath) => is_lang_ctor(cx, qpath, OptionNone), + PatKind::Path(ref qpath) => is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), OptionNone), PatKind::TupleStruct(ref qpath, [first_pat], _) => { - is_lang_ctor(cx, qpath, ResultErr) && matches!(first_pat.kind, PatKind::Wild) + is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), ResultErr) + && matches!(first_pat.kind, PatKind::Wild) }, PatKind::Wild => true, _ => false, diff --git a/clippy_lints/src/partialeq_to_none.rs b/clippy_lints/src/partialeq_to_none.rs index 000b0ba7a148e..6810a24317589 100644 --- a/clippy_lints/src/partialeq_to_none.rs +++ b/clippy_lints/src/partialeq_to_none.rs @@ -1,5 +1,5 @@ use clippy_utils::{ - diagnostics::span_lint_and_sugg, is_lang_ctor, peel_hir_expr_refs, peel_ref_operators, sugg, + diagnostics::span_lint_and_sugg, is_res_lang_ctor, path_res, peel_hir_expr_refs, peel_ref_operators, sugg, ty::is_type_diagnostic_item, }; use rustc_errors::Applicability; @@ -54,8 +54,7 @@ impl<'tcx> LateLintPass<'tcx> for PartialeqToNone { // If the expression is a literal `Option::None` let is_none_ctor = |expr: &Expr<'_>| { !expr.span.from_expansion() - && matches!(&peel_hir_expr_refs(expr).0.kind, - ExprKind::Path(p) if is_lang_ctor(cx, p, LangItem::OptionNone)) + && is_res_lang_ctor(cx, path_res(cx, peel_hir_expr_refs(expr).0), LangItem::OptionNone) }; let mut applicability = Applicability::MachineApplicable; diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index 0b3d5d174804a..328371fd602f0 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -3,11 +3,12 @@ use clippy_utils::higher; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{ - eq_expr_value, get_parent_node, in_constant, is_else_clause, is_lang_ctor, path_to_local, path_to_local_id, + eq_expr_value, get_parent_node, in_constant, is_else_clause, is_res_lang_ctor, path_to_local, path_to_local_id, peel_blocks, peel_blocks_with_stmt, }; use if_chain::if_chain; use rustc_errors::Applicability; +use rustc_hir::def::Res; use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk}; use rustc_hir::{BindingAnnotation, ByRef, Expr, ExprKind, Node, PatKind, PathSegment, QPath}; use rustc_lint::{LateContext, LateLintPass}; @@ -58,7 +59,7 @@ enum IfBlockType<'hir> { /// Contains: let_pat_qpath (Xxx), let_pat_type, let_pat_sym (a), let_expr (b), if_then (c), /// if_else (d) IfLet( - &'hir QPath<'hir>, + Res, Ty<'hir>, Symbol, &'hir Expr<'hir>, @@ -126,7 +127,14 @@ fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: if ddpos.as_opt_usize().is_none(); if let PatKind::Binding(BindingAnnotation(by_ref, _), bind_id, ident, None) = field.kind; let caller_ty = cx.typeck_results().expr_ty(let_expr); - let if_block = IfBlockType::IfLet(path1, caller_ty, ident.name, let_expr, if_then, if_else); + let if_block = IfBlockType::IfLet( + cx.qpath_res(path1, let_pat.hir_id), + caller_ty, + ident.name, + let_expr, + if_then, + if_else + ); if (is_early_return(sym::Option, cx, &if_block) && path_to_local_id(peel_blocks(if_then), bind_id)) || is_early_return(sym::Result, cx, &if_block); if if_else.map(|e| eq_expr_value(cx, let_expr, peel_blocks(e))).filter(|e| *e).is_none(); @@ -165,21 +173,21 @@ fn is_early_return(smbl: Symbol, cx: &LateContext<'_>, if_block: &IfBlockType<'_ _ => false, } }, - IfBlockType::IfLet(qpath, let_expr_ty, let_pat_sym, let_expr, if_then, if_else) => { + IfBlockType::IfLet(res, let_expr_ty, let_pat_sym, let_expr, if_then, if_else) => { is_type_diagnostic_item(cx, let_expr_ty, smbl) && match smbl { sym::Option => { // We only need to check `if let Some(x) = option` not `if let None = option`, // because the later one will be suggested as `if option.is_none()` thus causing conflict. - is_lang_ctor(cx, qpath, OptionSome) + is_res_lang_ctor(cx, res, OptionSome) && if_else.is_some() && expr_return_none_or_err(smbl, cx, if_else.unwrap(), let_expr, None) }, sym::Result => { - (is_lang_ctor(cx, qpath, ResultOk) + (is_res_lang_ctor(cx, res, ResultOk) && if_else.is_some() && expr_return_none_or_err(smbl, cx, if_else.unwrap(), let_expr, Some(let_pat_sym))) - || is_lang_ctor(cx, qpath, ResultErr) + || is_res_lang_ctor(cx, res, ResultErr) && expr_return_none_or_err(smbl, cx, if_then, let_expr, Some(let_pat_sym)) }, _ => false, @@ -198,7 +206,7 @@ fn expr_return_none_or_err( match peel_blocks_with_stmt(expr).kind { ExprKind::Ret(Some(ret_expr)) => expr_return_none_or_err(smbl, cx, ret_expr, cond_expr, err_sym), ExprKind::Path(ref qpath) => match smbl { - sym::Option => is_lang_ctor(cx, qpath, OptionNone), + sym::Option => is_res_lang_ctor(cx, cx.qpath_res(qpath, expr.hir_id), OptionNone), sym::Result => path_to_local(expr).is_some() && path_to_local(expr) == path_to_local(cond_expr), _ => false, }, diff --git a/clippy_lints/src/unnecessary_wraps.rs b/clippy_lints/src/unnecessary_wraps.rs index 83ef3b0fac874..7211e6864f3a9 100644 --- a/clippy_lints/src/unnecessary_wraps.rs +++ b/clippy_lints/src/unnecessary_wraps.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; -use clippy_utils::{contains_return, is_lang_ctor, return_ty, visitors::find_all_ret_expressions}; +use clippy_utils::{contains_return, is_res_lang_ctor, path_res, return_ty, visitors::find_all_ret_expressions}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; @@ -120,9 +120,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { if !ret_expr.span.from_expansion(); // Check if a function call. if let ExprKind::Call(func, [arg]) = ret_expr.kind; - // Check if OPTION_SOME or RESULT_OK, depending on return type. - if let ExprKind::Path(qpath) = &func.kind; - if is_lang_ctor(cx, qpath, lang_item); + if is_res_lang_ctor(cx, path_res(cx, func), lang_item); // Make sure the function argument does not contain a return expression. if !contains_return(arg); then { diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index d67ceaec0358a..c7cc5d04c8599 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -238,17 +238,27 @@ pub fn in_constant(cx: &LateContext<'_>, id: HirId) -> bool { } } -/// Checks if a `QPath` resolves to a constructor of a `LangItem`. +/// Checks if a `Res` refers to a constructor of a `LangItem` /// For example, use this to check whether a function call or a pattern is `Some(..)`. -pub fn is_lang_ctor(cx: &LateContext<'_>, qpath: &QPath<'_>, lang_item: LangItem) -> bool { - if let QPath::Resolved(_, path) = qpath { - if let Res::Def(DefKind::Ctor(..), ctor_id) = path.res { - if let Ok(item_id) = cx.tcx.lang_items().require(lang_item) { - return cx.tcx.parent(ctor_id) == item_id; - } - } +pub fn is_res_lang_ctor(cx: &LateContext<'_>, res: Res, lang_item: LangItem) -> bool { + if let Res::Def(DefKind::Ctor(..), id) = res + && let Ok(lang_id) = cx.tcx.lang_items().require(lang_item) + && let Some(id) = cx.tcx.opt_parent(id) + { + id == lang_id + } else { + false + } +} + +pub fn is_res_diagnostic_ctor(cx: &LateContext<'_>, res: Res, diag_item: Symbol) -> bool { + if let Res::Def(DefKind::Ctor(..), id) = res + && let Some(id) = cx.tcx.opt_parent(id) + { + cx.tcx.is_diagnostic_item(diag_item, id) + } else { + false } - false } pub fn is_unit_expr(expr: &Expr<'_>) -> bool { @@ -738,7 +748,7 @@ pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { } }, ExprKind::Call(repl_func, _) => is_default_equivalent_call(cx, repl_func), - ExprKind::Path(qpath) => is_lang_ctor(cx, qpath, OptionNone), + ExprKind::Path(qpath) => is_res_lang_ctor(cx, cx.qpath_res(qpath, e.hir_id), OptionNone), ExprKind::AddrOf(rustc_hir::BorrowKind::Ref, _, expr) => matches!(expr.kind, ExprKind::Array([])), _ => false, } @@ -1553,7 +1563,7 @@ pub fn is_try<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<&'tc if_chain! { if let PatKind::TupleStruct(ref path, pat, ddpos) = arm.pat.kind; if ddpos.as_opt_usize().is_none(); - if is_lang_ctor(cx, path, ResultOk); + if is_res_lang_ctor(cx, cx.qpath_res(path, arm.pat.hir_id), ResultOk); if let PatKind::Binding(_, hir_id, _, None) = pat[0].kind; if path_to_local_id(arm.body, hir_id); then { @@ -1565,7 +1575,7 @@ pub fn is_try<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<&'tc fn is_err(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool { if let PatKind::TupleStruct(ref path, _, _) = arm.pat.kind { - is_lang_ctor(cx, path, ResultErr) + is_res_lang_ctor(cx, cx.qpath_res(path, arm.pat.hir_id), ResultErr) } else { false } From 162aa19793f21c99cf7ec2a8c080ee2f8843f7db Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Thu, 11 Nov 2021 14:15:01 -0500 Subject: [PATCH 096/114] Fix and improve internal lint checking for `match_type` usages * Check for `const`s and `static`s from external crates * Check for `LangItem`s * Handle inherent functions which have the same name as a field * Also check the following functions: * `match_trait_method` * `match_def_path` * `is_expr_path_def_path` * `is_qpath_def_path` * Handle checking for a constructor to a diagnostic item or `LangItem` --- clippy_lints/src/await_holding_invalid.rs | 8 +- clippy_lints/src/infinite_iter.rs | 15 +- clippy_lints/src/inherent_to_string.rs | 7 +- clippy_lints/src/lib.register_internal.rs | 2 +- clippy_lints/src/lib.register_lints.rs | 4 +- clippy_lints/src/lib.rs | 2 +- clippy_lints/src/manual_retain.rs | 2 +- clippy_lints/src/methods/filetype_is_file.rs | 7 +- .../src/methods/inefficient_to_string.rs | 2 +- clippy_lints/src/methods/manual_str_repeat.rs | 8 +- clippy_lints/src/methods/useless_asref.rs | 5 +- clippy_lints/src/minmax.rs | 4 +- .../src/non_octal_unix_permissions.rs | 5 +- .../src/slow_vector_initialization.rs | 4 +- .../src/unnecessary_owned_empty_strings.rs | 4 +- clippy_lints/src/unused_io_amount.rs | 7 +- clippy_lints/src/useless_conversion.rs | 4 +- clippy_lints/src/utils/internal_lints.rs | 277 +++++++++++++----- clippy_utils/src/lib.rs | 47 +++ clippy_utils/src/paths.rs | 3 - tests/ui-internal/auxiliary/paths.rs | 2 + tests/ui-internal/match_type_on_diag_item.rs | 39 --- .../match_type_on_diag_item.stderr | 27 -- tests/ui-internal/unnecessary_def_path.fixed | 62 ++++ tests/ui-internal/unnecessary_def_path.rs | 62 ++++ tests/ui-internal/unnecessary_def_path.stderr | 101 +++++++ 26 files changed, 534 insertions(+), 176 deletions(-) create mode 100644 tests/ui-internal/auxiliary/paths.rs delete mode 100644 tests/ui-internal/match_type_on_diag_item.rs delete mode 100644 tests/ui-internal/match_type_on_diag_item.stderr create mode 100644 tests/ui-internal/unnecessary_def_path.fixed create mode 100644 tests/ui-internal/unnecessary_def_path.rs create mode 100644 tests/ui-internal/unnecessary_def_path.stderr diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs index 1761360fb2812..24a3588ecf16f 100644 --- a/clippy_lints/src/await_holding_invalid.rs +++ b/clippy_lints/src/await_holding_invalid.rs @@ -6,7 +6,7 @@ use rustc_hir::{def::Res, AsyncGeneratorKind, Body, BodyId, GeneratorKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::GeneratorInteriorTypeCause; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::Span; +use rustc_span::{sym, Span}; use crate::utils::conf::DisallowedType; @@ -276,9 +276,9 @@ fn emit_invalid_type(cx: &LateContext<'_>, span: Span, disallowed: &DisallowedTy } fn is_mutex_guard(cx: &LateContext<'_>, def_id: DefId) -> bool { - match_def_path(cx, def_id, &paths::MUTEX_GUARD) - || match_def_path(cx, def_id, &paths::RWLOCK_READ_GUARD) - || match_def_path(cx, def_id, &paths::RWLOCK_WRITE_GUARD) + cx.tcx.is_diagnostic_item(sym::MutexGuard, def_id) + || cx.tcx.is_diagnostic_item(sym::RwLockReadGuard, def_id) + || cx.tcx.is_diagnostic_item(sym::RwLockWriteGuard, def_id) || match_def_path(cx, def_id, &paths::PARKING_LOT_MUTEX_GUARD) || match_def_path(cx, def_id, &paths::PARKING_LOT_RWLOCK_READ_GUARD) || match_def_path(cx, def_id, &paths::PARKING_LOT_RWLOCK_WRITE_GUARD) diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs index 8c2c96fa105af..d1d2db27c6fc0 100644 --- a/clippy_lints/src/infinite_iter.rs +++ b/clippy_lints/src/infinite_iter.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint; +use clippy_utils::higher; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; -use clippy_utils::{higher, match_def_path, path_def_id, paths}; use rustc_hir::{BorrowKind, Closure, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -168,9 +168,16 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { }, ExprKind::Block(block, _) => block.expr.as_ref().map_or(Finite, |e| is_infinite(cx, e)), ExprKind::Box(e) | ExprKind::AddrOf(BorrowKind::Ref, _, e) => is_infinite(cx, e), - ExprKind::Call(path, _) => path_def_id(cx, path) - .map_or(false, |id| match_def_path(cx, id, &paths::ITER_REPEAT)) - .into(), + ExprKind::Call(path, _) => { + if let ExprKind::Path(ref qpath) = path.kind { + cx.qpath_res(qpath, path.hir_id) + .opt_def_id() + .map_or(false, |id| cx.tcx.is_diagnostic_item(sym::iter_repeat, id)) + .into() + } else { + Finite + } + }, ExprKind::Struct(..) => higher::Range::hir(expr).map_or(false, |r| r.end.is_none()).into(), _ => Finite, } diff --git a/clippy_lints/src/inherent_to_string.rs b/clippy_lints/src/inherent_to_string.rs index d0e603dcf4ef5..676136df572bd 100644 --- a/clippy_lints/src/inherent_to_string.rs +++ b/clippy_lints/src/inherent_to_string.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; -use clippy_utils::{get_trait_def_id, paths, return_ty, trait_ref_of_method}; +use clippy_utils::{return_ty, trait_ref_of_method}; use if_chain::if_chain; use rustc_hir::{GenericParamKind, ImplItem, ImplItemKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -118,7 +118,10 @@ impl<'tcx> LateLintPass<'tcx> for InherentToString { } fn show_lint(cx: &LateContext<'_>, item: &ImplItem<'_>) { - let display_trait_id = get_trait_def_id(cx, &paths::DISPLAY_TRAIT).expect("Failed to get trait ID of `Display`!"); + let display_trait_id = cx + .tcx + .get_diagnostic_item(sym::Display) + .expect("Failed to get trait ID of `Display`!"); // Get the real type of 'self' let self_type = cx.tcx.fn_sig(item.def_id).input(0); diff --git a/clippy_lints/src/lib.register_internal.rs b/clippy_lints/src/lib.register_internal.rs index be63646a12f51..71dfdab369b97 100644 --- a/clippy_lints/src/lib.register_internal.rs +++ b/clippy_lints/src/lib.register_internal.rs @@ -13,10 +13,10 @@ store.register_group(true, "clippy::internal", Some("clippy_internal"), vec![ LintId::of(utils::internal_lints::INVALID_CLIPPY_VERSION_ATTRIBUTE), LintId::of(utils::internal_lints::INVALID_PATHS), LintId::of(utils::internal_lints::LINT_WITHOUT_LINT_PASS), - LintId::of(utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM), LintId::of(utils::internal_lints::MISSING_CLIPPY_VERSION_ATTRIBUTE), LintId::of(utils::internal_lints::MISSING_MSRV_ATTR_IMPL), LintId::of(utils::internal_lints::OUTER_EXPN_EXPN_DATA), LintId::of(utils::internal_lints::PRODUCE_ICE), + LintId::of(utils::internal_lints::UNNECESSARY_DEF_PATH), LintId::of(utils::internal_lints::UNNECESSARY_SYMBOL_STR), ]) diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index b8a20de9768d9..307ec40f40b3b 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -24,8 +24,6 @@ store.register_lints(&[ #[cfg(feature = "internal")] utils::internal_lints::LINT_WITHOUT_LINT_PASS, #[cfg(feature = "internal")] - utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM, - #[cfg(feature = "internal")] utils::internal_lints::MISSING_CLIPPY_VERSION_ATTRIBUTE, #[cfg(feature = "internal")] utils::internal_lints::MISSING_MSRV_ATTR_IMPL, @@ -34,6 +32,8 @@ store.register_lints(&[ #[cfg(feature = "internal")] utils::internal_lints::PRODUCE_ICE, #[cfg(feature = "internal")] + utils::internal_lints::UNNECESSARY_DEF_PATH, + #[cfg(feature = "internal")] utils::internal_lints::UNNECESSARY_SYMBOL_STR, almost_complete_letter_range::ALMOST_COMPLETE_LETTER_RANGE, approx_const::APPROX_CONSTANT, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 05a9e13c9fb6b..3b78e492baa48 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -535,7 +535,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(utils::internal_lints::InvalidPaths)); store.register_late_pass(|_| Box::::default()); store.register_late_pass(|_| Box::::default()); - store.register_late_pass(|_| Box::new(utils::internal_lints::MatchTypeOnDiagItem)); + store.register_late_pass(|_| Box::new(utils::internal_lints::UnnecessaryDefPath)); store.register_late_pass(|_| Box::new(utils::internal_lints::OuterExpnDataPass)); store.register_late_pass(|_| Box::new(utils::internal_lints::MsrvAttrImpl)); } diff --git a/clippy_lints/src/manual_retain.rs b/clippy_lints/src/manual_retain.rs index 570fe73681830..3181bc86d1793 100644 --- a/clippy_lints/src/manual_retain.rs +++ b/clippy_lints/src/manual_retain.rs @@ -92,7 +92,7 @@ fn check_into_iter( && match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER) && let hir::ExprKind::MethodCall(_, struct_expr, [], _) = &into_iter_expr.kind && let Some(into_iter_def_id) = cx.typeck_results().type_dependent_def_id(into_iter_expr.hir_id) - && match_def_path(cx, into_iter_def_id, &paths::CORE_ITER_INTO_ITER) + && cx.tcx.lang_items().require(hir::LangItem::IntoIterIntoIter).ok() == Some(into_iter_def_id) && match_acceptable_type(cx, left_expr, msrv) && SpanlessEq::new(cx).eq_expr(left_expr, struct_expr) { suggest(cx, parent_expr, left_expr, target_expr); diff --git a/clippy_lints/src/methods/filetype_is_file.rs b/clippy_lints/src/methods/filetype_is_file.rs index 60f8283c3e09d..3fef53739fbde 100644 --- a/clippy_lints/src/methods/filetype_is_file.rs +++ b/clippy_lints/src/methods/filetype_is_file.rs @@ -1,17 +1,18 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::ty::match_type; -use clippy_utils::{get_parent_expr, paths}; +use clippy_utils::get_parent_expr; +use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::source_map::Span; +use rustc_span::sym; use super::FILETYPE_IS_FILE; pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) { let ty = cx.typeck_results().expr_ty(recv); - if !match_type(cx, ty, &paths::FILE_TYPE) { + if !is_type_diagnostic_item(cx, ty, sym::FileType) { return; } diff --git a/clippy_lints/src/methods/inefficient_to_string.rs b/clippy_lints/src/methods/inefficient_to_string.rs index e5dc3711b0b47..ede3b8bb74e97 100644 --- a/clippy_lints/src/methods/inefficient_to_string.rs +++ b/clippy_lints/src/methods/inefficient_to_string.rs @@ -65,7 +65,7 @@ fn specializes_tostring(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { } if let ty::Adt(adt, substs) = ty.kind() { - match_def_path(cx, adt.did(), &paths::COW) && substs.type_at(1).is_str() + cx.tcx.is_diagnostic_item(sym::Cow, adt.did()) && substs.type_at(1).is_str() } else { false } diff --git a/clippy_lints/src/methods/manual_str_repeat.rs b/clippy_lints/src/methods/manual_str_repeat.rs index 67e504af161cd..8b6b8f1bf16cb 100644 --- a/clippy_lints/src/methods/manual_str_repeat.rs +++ b/clippy_lints/src/methods/manual_str_repeat.rs @@ -1,8 +1,8 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_path_diagnostic_item; use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::sugg::Sugg; -use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item, match_type}; -use clippy_utils::{is_expr_path_def_path, paths}; +use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; use if_chain::if_chain; use rustc_ast::LitKind; use rustc_errors::Applicability; @@ -38,7 +38,7 @@ fn parse_repeat_arg(cx: &LateContext<'_>, e: &Expr<'_>) -> Option { let ty = cx.typeck_results().expr_ty(e); if is_type_diagnostic_item(cx, ty, sym::String) || (is_type_lang_item(cx, ty, LangItem::OwnedBox) && get_ty_param(ty).map_or(false, Ty::is_str)) - || (match_type(cx, ty, &paths::COW) && get_ty_param(ty).map_or(false, Ty::is_str)) + || (is_type_diagnostic_item(cx, ty, sym::Cow) && get_ty_param(ty).map_or(false, Ty::is_str)) { Some(RepeatKind::String) } else { @@ -57,7 +57,7 @@ pub(super) fn check( ) { if_chain! { if let ExprKind::Call(repeat_fn, [repeat_arg]) = take_self_arg.kind; - if is_expr_path_def_path(cx, repeat_fn, &paths::ITER_REPEAT); + if is_path_diagnostic_item(cx, repeat_fn, sym::iter_repeat); if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(collect_expr), sym::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); diff --git a/clippy_lints/src/methods/useless_asref.rs b/clippy_lints/src/methods/useless_asref.rs index 0380a82411ae1..c1139d84e2f47 100644 --- a/clippy_lints/src/methods/useless_asref.rs +++ b/clippy_lints/src/methods/useless_asref.rs @@ -1,11 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::walk_ptrs_ty_depth; -use clippy_utils::{get_parent_expr, match_trait_method, paths}; +use clippy_utils::{get_parent_expr, is_trait_method}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; +use rustc_span::sym; use super::USELESS_ASREF; @@ -13,7 +14,7 @@ use super::USELESS_ASREF; pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, recvr: &hir::Expr<'_>) { // when we get here, we've already checked that the call name is "as_ref" or "as_mut" // check if the call is to the actual `AsRef` or `AsMut` trait - if match_trait_method(cx, expr, &paths::ASREF_TRAIT) || match_trait_method(cx, expr, &paths::ASMUT_TRAIT) { + if is_trait_method(cx, expr, sym::AsRef) || is_trait_method(cx, expr, sym::AsMut) { // check if the type after `as_ref` or `as_mut` is the same as before let rcv_ty = cx.typeck_results().expr_ty(recvr); let res_ty = cx.typeck_results().expr_ty(expr); diff --git a/clippy_lints/src/minmax.rs b/clippy_lints/src/minmax.rs index 4d8579135fc06..4f967755bfa19 100644 --- a/clippy_lints/src/minmax.rs +++ b/clippy_lints/src/minmax.rs @@ -1,6 +1,6 @@ use clippy_utils::consts::{constant_simple, Constant}; use clippy_utils::diagnostics::span_lint; -use clippy_utils::{match_trait_method, paths}; +use clippy_utils::is_trait_method; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -83,7 +83,7 @@ fn min_max<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(MinMax, Cons } }, ExprKind::MethodCall(path, receiver, args @ [_], _) => { - if cx.typeck_results().expr_ty(receiver).is_floating_point() || match_trait_method(cx, expr, &paths::ORD) { + if cx.typeck_results().expr_ty(receiver).is_floating_point() || is_trait_method(cx, expr, sym::Ord) { if path.ident.name == sym!(max) { fetch_const(cx, Some(receiver), args, MinMax::Max) } else if path.ident.name == sym!(min) { diff --git a/clippy_lints/src/non_octal_unix_permissions.rs b/clippy_lints/src/non_octal_unix_permissions.rs index 25fb4f0f4cff1..1a765b14892f6 100644 --- a/clippy_lints/src/non_octal_unix_permissions.rs +++ b/clippy_lints/src/non_octal_unix_permissions.rs @@ -1,12 +1,13 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{snippet_opt, snippet_with_applicability}; -use clippy_utils::ty::match_type; +use clippy_utils::ty::{is_type_diagnostic_item, match_type}; use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -49,7 +50,7 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions { if_chain! { if (path.ident.name == sym!(mode) && (match_type(cx, obj_ty, &paths::OPEN_OPTIONS) - || match_type(cx, obj_ty, &paths::DIR_BUILDER))) + || is_type_diagnostic_item(cx, obj_ty, sym::DirBuilder))) || (path.ident.name == sym!(set_mode) && match_type(cx, obj_ty, &paths::PERMISSIONS)); if let ExprKind::Lit(_) = param.kind; diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index 6e5d88e1b59de..760399231513f 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{ - get_enclosing_block, is_expr_path_def_path, is_integer_literal, path_to_local, path_to_local_id, paths, SpanlessEq, + get_enclosing_block, is_integer_literal, is_path_diagnostic_item, path_to_local, path_to_local_id, SpanlessEq, }; use if_chain::if_chain; use rustc_errors::Applicability; @@ -254,7 +254,7 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> { fn is_repeat_zero(&self, expr: &Expr<'_>) -> bool { if_chain! { if let ExprKind::Call(fn_expr, [repeat_arg]) = expr.kind; - if is_expr_path_def_path(self.cx, fn_expr, &paths::ITER_REPEAT); + if is_path_diagnostic_item(self.cx, fn_expr, sym::iter_repeat); if is_integer_literal(repeat_arg, 0); then { true diff --git a/clippy_lints/src/unnecessary_owned_empty_strings.rs b/clippy_lints/src/unnecessary_owned_empty_strings.rs index 8a4f4c0ad9719..016aacbf9da37 100644 --- a/clippy_lints/src/unnecessary_owned_empty_strings.rs +++ b/clippy_lints/src/unnecessary_owned_empty_strings.rs @@ -3,7 +3,7 @@ use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; -use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability}; +use rustc_hir::{BorrowKind, Expr, ExprKind, LangItem, Mutability}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -55,7 +55,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryOwnedEmptyStrings { ); } else { if_chain! { - if match_def_path(cx, fun_def_id, &paths::FROM_FROM); + if cx.tcx.lang_items().require(LangItem::FromFrom).ok() == Some(fun_def_id); if let [.., last_arg] = args; if let ExprKind::Lit(spanned) = &last_arg.kind; if let LitKind::Str(symbol, _) = spanned.node; diff --git a/clippy_lints/src/unused_io_amount.rs b/clippy_lints/src/unused_io_amount.rs index b38d71784fcfc..8bcdff66331d1 100644 --- a/clippy_lints/src/unused_io_amount.rs +++ b/clippy_lints/src/unused_io_amount.rs @@ -1,8 +1,9 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; -use clippy_utils::{is_try, match_trait_method, paths}; +use clippy_utils::{is_trait_method, is_try, match_trait_method, paths}; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -116,13 +117,13 @@ fn check_method_call(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Exp match_trait_method(cx, call, &paths::FUTURES_IO_ASYNCREADEXT) || match_trait_method(cx, call, &paths::TOKIO_IO_ASYNCREADEXT) } else { - match_trait_method(cx, call, &paths::IO_READ) + is_trait_method(cx, call, sym::IoRead) }; let write_trait = if is_await { match_trait_method(cx, call, &paths::FUTURES_IO_ASYNCWRITEEXT) || match_trait_method(cx, call, &paths::TOKIO_IO_ASYNCWRITEEXT) } else { - match_trait_method(cx, call, &paths::IO_WRITE) + is_trait_method(cx, call, sym::IoWrite) }; match (read_trait, write_trait, symbol, is_await) { diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index 50c5a832430af..a82643a59f97b 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -5,7 +5,7 @@ use clippy_utils::ty::{is_type_diagnostic_item, same_type_and_consts}; use clippy_utils::{get_parent_expr, is_trait_method, match_def_path, paths}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, HirId, MatchSource}; +use rustc_hir::{Expr, ExprKind, HirId, LangItem, MatchSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::{declare_tool_lint, impl_lint_pass}; @@ -154,7 +154,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { } if_chain! { - if match_def_path(cx, def_id, &paths::FROM_FROM); + if cx.tcx.lang_items().require(LangItem::FromFrom).ok() == Some(def_id); if same_type_and_consts(a, b); then { diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index bc3f920a087ae..6309a04c73d5d 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -2,11 +2,11 @@ use crate::utils::internal_lints::metadata_collector::is_deprecated_lint; use clippy_utils::consts::{constant_simple, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::macros::root_macro_call_first_node; -use clippy_utils::source::snippet; +use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::ty::match_type; use clippy_utils::{ - def_path_res, higher, is_else_clause, is_expn_of, is_expr_path_def_path, is_lint_allowed, match_def_path, - method_calls, paths, peel_blocks_with_stmt, SpanlessEq, + def_path_res, higher, is_else_clause, is_expn_of, is_expr_path_def_path, is_lint_allowed, match_any_def_paths, + match_def_path, method_calls, paths, peel_blocks_with_stmt, peel_hir_expr_refs, SpanlessEq, }; use if_chain::if_chain; use rustc_ast as ast; @@ -20,21 +20,24 @@ use rustc_hir::def_id::DefId; use rustc_hir::hir_id::CRATE_HIR_ID; use rustc_hir::intravisit::Visitor; use rustc_hir::{ - BinOpKind, Block, Closure, Expr, ExprKind, HirId, Item, Local, MutTy, Mutability, Node, Path, Stmt, StmtKind, Ty, + BinOpKind, Block, Closure, Expr, ExprKind, HirId, Item, Local, MutTy, Mutability, Node, Path, Stmt, StmtKind, TyKind, UnOp, }; use rustc_hir_analysis::hir_ty_to_ty; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; use rustc_middle::hir::nested_filter; -use rustc_middle::mir::interpret::ConstValue; -use rustc_middle::ty::{self, fast_reject::SimplifiedTypeGen, subst::GenericArgKind, FloatTy}; +use rustc_middle::mir::interpret::{Allocation, ConstValue, GlobalAlloc}; +use rustc_middle::ty::{ + self, fast_reject::SimplifiedTypeGen, subst::GenericArgKind, AssocKind, DefIdTree, FloatTy, Ty, +}; use rustc_semver::RustcVersion; use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Spanned; -use rustc_span::symbol::Symbol; +use rustc_span::symbol::{Ident, Symbol}; use rustc_span::{sym, BytePos, Span}; use std::borrow::{Borrow, Cow}; +use std::str; #[cfg(feature = "internal")] pub mod metadata_collector; @@ -226,11 +229,11 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for calls to `utils::match_type()` on a type diagnostic item - /// and suggests to use `utils::is_type_diagnostic_item()` instead. + /// Checks for usages of def paths when a diagnostic item or a `LangItem` could be used. /// /// ### Why is this bad? - /// `utils::is_type_diagnostic_item()` does not require hardcoded paths. + /// The path for an item is subject to change and is less efficient to look up than a + /// diagnostic item or a `LangItem`. /// /// ### Example /// ```rust,ignore @@ -241,9 +244,9 @@ declare_clippy_lint! { /// ```rust,ignore /// utils::is_type_diagnostic_item(cx, ty, sym::Vec) /// ``` - pub MATCH_TYPE_ON_DIAGNOSTIC_ITEM, + pub UNNECESSARY_DEF_PATH, internal, - "using `utils::match_type()` instead of `utils::is_type_diagnostic_item()`" + "using a def path when a diagnostic item or a `LangItem` is available" } declare_clippy_lint! { @@ -537,7 +540,7 @@ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass { } } -fn is_lint_ref_type<'tcx>(cx: &LateContext<'tcx>, ty: &Ty<'_>) -> bool { +fn is_lint_ref_type<'tcx>(cx: &LateContext<'tcx>, ty: &hir::Ty<'_>) -> bool { if let TyKind::Rptr( _, MutTy { @@ -888,89 +891,225 @@ fn suggest_note( ); } -declare_lint_pass!(MatchTypeOnDiagItem => [MATCH_TYPE_ON_DIAGNOSTIC_ITEM]); +declare_lint_pass!(UnnecessaryDefPath => [UNNECESSARY_DEF_PATH]); -impl<'tcx> LateLintPass<'tcx> for MatchTypeOnDiagItem { +#[allow(clippy::too_many_lines)] +impl<'tcx> LateLintPass<'tcx> for UnnecessaryDefPath { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { - if is_lint_allowed(cx, MATCH_TYPE_ON_DIAGNOSTIC_ITEM, expr.hir_id) { + enum Item { + LangItem(Symbol), + DiagnosticItem(Symbol), + } + static PATHS: &[&[&str]] = &[ + &["clippy_utils", "match_def_path"], + &["clippy_utils", "match_trait_method"], + &["clippy_utils", "ty", "match_type"], + &["clippy_utils", "is_expr_path_def_path"], + ]; + + if is_lint_allowed(cx, UNNECESSARY_DEF_PATH, expr.hir_id) { return; } if_chain! { - // Check if this is a call to utils::match_type() - if let ExprKind::Call(fn_path, [context, ty, ty_path]) = expr.kind; - if is_expr_path_def_path(cx, fn_path, &["clippy_utils", "ty", "match_type"]); + if let ExprKind::Call(func, [cx_arg, def_arg, args@..]) = expr.kind; + if let ExprKind::Path(path) = &func.kind; + if let Some(id) = cx.qpath_res(path, func.hir_id).opt_def_id(); + if let Some(which_path) = match_any_def_paths(cx, id, PATHS); + let item_arg = if which_path == 4 { &args[1] } else { &args[0] }; // Extract the path to the matched type - if let Some(segments) = path_to_matched_type(cx, ty_path); - let segments: Vec<&str> = segments.iter().map(Symbol::as_str).collect(); - if let Some(ty_did) = def_path_res(cx, &segments[..]).opt_def_id(); - // Check if the matched type is a diagnostic item - if let Some(item_name) = cx.tcx.get_diagnostic_name(ty_did); + if let Some(segments) = path_to_matched_type(cx, item_arg); + let segments: Vec<&str> = segments.iter().map(|sym| &**sym).collect(); + if let Some(def_id) = def_path_res(cx, &segments[..]).opt_def_id(); then { - // TODO: check paths constants from external crates. - let cx_snippet = snippet(cx, context.span, "_"); - let ty_snippet = snippet(cx, ty.span, "_"); + // def_path_res will match field names before anything else, but for this we want to match + // inherent functions first. + let def_id = if cx.tcx.def_kind(def_id) == DefKind::Field { + let method_name = *segments.last().unwrap(); + cx.tcx.def_key(def_id).parent + .and_then(|parent_idx| + cx.tcx.inherent_impls(DefId { index: parent_idx, krate: def_id.krate }).iter() + .find_map(|impl_id| cx.tcx.associated_items(*impl_id) + .find_by_name_and_kind( + cx.tcx, + Ident::from_str(method_name), + AssocKind::Fn, + *impl_id, + ) + ) + ) + .map_or(def_id, |item| item.def_id) + } else { + def_id + }; - span_lint_and_sugg( + // Check if the target item is a diagnostic item or LangItem. + let (msg, item) = if let Some(item_name) + = cx.tcx.diagnostic_items(def_id.krate).id_to_name.get(&def_id) + { + ( + "use of a def path to a diagnostic item", + Item::DiagnosticItem(*item_name), + ) + } else if let Some(lang_item) = cx.tcx.lang_items().items().iter().position(|id| *id == Some(def_id)) { + let lang_items = def_path_res(cx, &["rustc_hir", "lang_items", "LangItem"]).def_id(); + let item_name = cx.tcx.adt_def(lang_items).variants().iter().nth(lang_item).unwrap().name; + ( + "use of a def path to a `LangItem`", + Item::LangItem(item_name), + ) + } else { + return; + }; + + let has_ctor = match cx.tcx.def_kind(def_id) { + DefKind::Struct => { + let variant = cx.tcx.adt_def(def_id).non_enum_variant(); + variant.ctor_def_id.is_some() && variant.fields.iter().all(|f| f.vis.is_public()) + } + DefKind::Variant => { + let variant = cx.tcx.adt_def(cx.tcx.parent(def_id)).variant_with_id(def_id); + variant.ctor_def_id.is_some() && variant.fields.iter().all(|f| f.vis.is_public()) + } + _ => false, + }; + + let mut app = Applicability::MachineApplicable; + let cx_snip = snippet_with_applicability(cx, cx_arg.span, "..", &mut app); + let def_snip = snippet_with_applicability(cx, def_arg.span, "..", &mut app); + let (sugg, with_note) = match (which_path, item) { + // match_def_path + (0, Item::DiagnosticItem(item)) => + (format!("{cx_snip}.tcx.is_diagnostic_item(sym::{item}, {def_snip})"), has_ctor), + (0, Item::LangItem(item)) => ( + format!("{cx_snip}.tcx.lang_items().require(LangItem::{item}).ok() == Some({def_snip})"), + has_ctor + ), + // match_trait_method + (1, Item::DiagnosticItem(item)) => + (format!("is_trait_method({cx_snip}, {def_snip}, sym::{item})"), false), + // match_type + (2, Item::DiagnosticItem(item)) => + (format!("is_type_diagnostic_item({cx_snip}, {def_snip}, sym::{item})"), false), + (2, Item::LangItem(item)) => + (format!("is_type_lang_item({cx_snip}, {def_snip}, LangItem::{item})"), false), + // is_expr_path_def_path + (3, Item::DiagnosticItem(item)) if has_ctor => ( + format!( + "is_res_diag_ctor({cx_snip}, path_res({cx_snip}, {def_snip}), sym::{item})", + ), + false, + ), + (3, Item::LangItem(item)) if has_ctor => ( + format!( + "is_res_lang_ctor({cx_snip}, path_res({cx_snip}, {def_snip}), LangItem::{item})", + ), + false, + ), + (3, Item::DiagnosticItem(item)) => + (format!("is_path_diagnostic_item({cx_snip}, {def_snip}, sym::{item})"), false), + (3, Item::LangItem(item)) => ( + format!( + "path_res({cx_snip}, {def_snip}).opt_def_id()\ + .map_or(false, |id| {cx_snip}.tcx.lang_items().require(LangItem::{item}).ok() == Some(id))", + ), + false, + ), + _ => return, + }; + + span_lint_and_then( cx, - MATCH_TYPE_ON_DIAGNOSTIC_ITEM, + UNNECESSARY_DEF_PATH, expr.span, - "usage of `clippy_utils::ty::match_type()` on a type diagnostic item", - "try", - format!("clippy_utils::ty::is_type_diagnostic_item({cx_snippet}, {ty_snippet}, sym::{item_name})"), - Applicability::MaybeIncorrect, + msg, + |diag| { + diag.span_suggestion(expr.span, "try", sugg, app); + if with_note { + diag.help( + "if this `DefId` came from a constructor expression or pattern then the \ + parent `DefId` should be used instead" + ); + } + }, ); } } } } -fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option> { - use rustc_hir::ItemKind; - - match &expr.kind { - ExprKind::AddrOf(.., expr) => return path_to_matched_type(cx, expr), - ExprKind::Path(qpath) => match cx.qpath_res(qpath, expr.hir_id) { +fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option> { + match peel_hir_expr_refs(expr).0.kind { + ExprKind::Path(ref qpath) => match cx.qpath_res(qpath, expr.hir_id) { Res::Local(hir_id) => { let parent_id = cx.tcx.hir().get_parent_node(hir_id); - if let Some(Node::Local(local)) = cx.tcx.hir().find(parent_id) { - if let Some(init) = local.init { - return path_to_matched_type(cx, init); - } + if let Some(Node::Local(Local { init: Some(init), .. })) = cx.tcx.hir().find(parent_id) { + path_to_matched_type(cx, init) + } else { + None } }, - Res::Def(DefKind::Const | DefKind::Static(..), def_id) => { - if let Some(Node::Item(item)) = cx.tcx.hir().get_if_local(def_id) { - if let ItemKind::Const(.., body_id) | ItemKind::Static(.., body_id) = item.kind { - let body = cx.tcx.hir().body(body_id); - return path_to_matched_type(cx, body.value); - } - } + Res::Def(DefKind::Static(_), def_id) => read_mir_alloc_def_path( + cx, + cx.tcx.eval_static_initializer(def_id).ok()?.inner(), + cx.tcx.type_of(def_id), + ), + Res::Def(DefKind::Const, def_id) => match cx.tcx.const_eval_poly(def_id).ok()? { + ConstValue::ByRef { alloc, offset } if offset.bytes() == 0 => { + read_mir_alloc_def_path(cx, alloc.inner(), cx.tcx.type_of(def_id)) + }, + _ => None, }, - _ => {}, + _ => None, }, - ExprKind::Array(exprs) => { - let segments: Vec = exprs - .iter() - .filter_map(|expr| { - if let ExprKind::Lit(lit) = &expr.kind { - if let LitKind::Str(sym, _) = lit.node { - return Some(sym); - } + ExprKind::Array(exprs) => exprs + .iter() + .map(|expr| { + if let ExprKind::Lit(lit) = &expr.kind { + if let LitKind::Str(sym, _) = lit.node { + return Some((*sym.as_str()).to_owned()); } + } - None - }) - .collect(); - - if segments.len() == exprs.len() { - return Some(segments); - } - }, - _ => {}, + None + }) + .collect(), + _ => None, } +} - None +fn read_mir_alloc_def_path<'tcx>(cx: &LateContext<'tcx>, alloc: &'tcx Allocation, ty: Ty<'_>) -> Option> { + let (alloc, ty) = if let ty::Ref(_, ty, Mutability::Not) = *ty.kind() { + let &alloc = alloc.provenance().values().next()?; + if let GlobalAlloc::Memory(alloc) = cx.tcx.global_alloc(alloc) { + (alloc.inner(), ty) + } else { + return None; + } + } else { + (alloc, ty) + }; + + if let ty::Array(ty, _) | ty::Slice(ty) = *ty.kind() + && let ty::Ref(_, ty, Mutability::Not) = *ty.kind() + && ty.is_str() + { + alloc + .provenance() + .values() + .map(|&alloc| { + if let GlobalAlloc::Memory(alloc) = cx.tcx.global_alloc(alloc) { + let alloc = alloc.inner(); + str::from_utf8(alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len())) + .ok().map(ToOwned::to_owned) + } else { + None + } + }) + .collect() + } else { + None + } } // This is not a complete resolver for paths. It works on all the paths currently used in the paths diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index c7cc5d04c8599..8f67fa109fc70 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -261,6 +261,46 @@ pub fn is_res_diagnostic_ctor(cx: &LateContext<'_>, res: Res, diag_item: Symbol) } } +/// Checks if a `QPath` resolves to a constructor of a diagnostic item. +pub fn is_diagnostic_ctor(cx: &LateContext<'_>, qpath: &QPath<'_>, diagnostic_item: Symbol) -> bool { + if let QPath::Resolved(_, path) = qpath { + if let Res::Def(DefKind::Ctor(..), ctor_id) = path.res { + return cx.tcx.is_diagnostic_item(diagnostic_item, cx.tcx.parent(ctor_id)); + } + } + false +} + +/// Checks if the `DefId` matches the given diagnostic item or it's constructor. +pub fn is_diagnostic_item_or_ctor(cx: &LateContext<'_>, did: DefId, item: Symbol) -> bool { + let did = match cx.tcx.def_kind(did) { + DefKind::Ctor(..) => cx.tcx.parent(did), + // Constructors for types in external crates seem to have `DefKind::Variant` + DefKind::Variant => match cx.tcx.opt_parent(did) { + Some(did) if matches!(cx.tcx.def_kind(did), DefKind::Variant) => did, + _ => did, + }, + _ => did, + }; + + cx.tcx.is_diagnostic_item(item, did) +} + +/// Checks if the `DefId` matches the given `LangItem` or it's constructor. +pub fn is_lang_item_or_ctor(cx: &LateContext<'_>, did: DefId, item: LangItem) -> bool { + let did = match cx.tcx.def_kind(did) { + DefKind::Ctor(..) => cx.tcx.parent(did), + // Constructors for types in external crates seem to have `DefKind::Variant` + DefKind::Variant => match cx.tcx.opt_parent(did) { + Some(did) if matches!(cx.tcx.def_kind(did), DefKind::Variant) => did, + _ => did, + }, + _ => did, + }; + + cx.tcx.lang_items().require(item).map_or(false, |id| id == did) +} + pub fn is_unit_expr(expr: &Expr<'_>) -> bool { matches!( expr.kind, @@ -496,6 +536,13 @@ pub fn def_path_res(cx: &LateContext<'_>, path: &[&str]) -> Res { .copied() .find(|assoc_def_id| tcx.item_name(*assoc_def_id).as_str() == name) .map(|assoc_def_id| Res::Def(tcx.def_kind(assoc_def_id), assoc_def_id)), + DefKind::Struct | DefKind::Union => tcx + .adt_def(def_id) + .non_enum_variant() + .fields + .iter() + .find(|f| f.name.as_str() == name) + .map(|f| Res::Def(DefKind::Field, f.did)), _ => None, } } diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 07170e2df12ab..13938645fc3e5 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -34,7 +34,6 @@ pub const DEFAULT_TRAIT_METHOD: [&str; 4] = ["core", "default", "Default", "defa pub const DEREF_MUT_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "DerefMut", "deref_mut"]; /// Preferably use the diagnostic item `sym::deref_method` where possible pub const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"]; -pub const DIR_BUILDER: [&str; 3] = ["std", "fs", "DirBuilder"]; pub const DISPLAY_TRAIT: [&str; 3] = ["core", "fmt", "Display"]; #[cfg(feature = "internal")] pub const EARLY_CONTEXT: [&str; 2] = ["rustc_lint", "EarlyContext"]; @@ -64,8 +63,6 @@ pub const IDENT_AS_STR: [&str; 4] = ["rustc_span", "symbol", "Ident", "as_str"]; pub const INDEX: [&str; 3] = ["core", "ops", "Index"]; pub const INDEX_MUT: [&str; 3] = ["core", "ops", "IndexMut"]; pub const INSERT_STR: [&str; 4] = ["alloc", "string", "String", "insert_str"]; -pub const IO_READ: [&str; 3] = ["std", "io", "Read"]; -pub const IO_WRITE: [&str; 3] = ["std", "io", "Write"]; pub const ITER_COUNT: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "count"]; pub const ITER_EMPTY: [&str; 5] = ["core", "iter", "sources", "empty", "Empty"]; pub const ITER_REPEAT: [&str; 5] = ["core", "iter", "sources", "repeat", "repeat"]; diff --git a/tests/ui-internal/auxiliary/paths.rs b/tests/ui-internal/auxiliary/paths.rs new file mode 100644 index 0000000000000..52fcaec4df32e --- /dev/null +++ b/tests/ui-internal/auxiliary/paths.rs @@ -0,0 +1,2 @@ +pub static OPTION: [&str; 3] = ["core", "option", "Option"]; +pub const RESULT: &[&str] = &["core", "result", "Result"]; diff --git a/tests/ui-internal/match_type_on_diag_item.rs b/tests/ui-internal/match_type_on_diag_item.rs deleted file mode 100644 index 4b41ff15e80f9..0000000000000 --- a/tests/ui-internal/match_type_on_diag_item.rs +++ /dev/null @@ -1,39 +0,0 @@ -#![deny(clippy::internal)] -#![allow(clippy::missing_clippy_version_attribute)] -#![feature(rustc_private)] - -extern crate clippy_utils; -extern crate rustc_hir; -extern crate rustc_lint; -extern crate rustc_middle; - -#[macro_use] -extern crate rustc_session; -use clippy_utils::{paths, ty::match_type}; -use rustc_hir::Expr; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::Ty; - -declare_lint! { - pub TEST_LINT, - Warn, - "" -} - -declare_lint_pass!(Pass => [TEST_LINT]); - -static OPTION: [&str; 3] = ["core", "option", "Option"]; - -impl<'tcx> LateLintPass<'tcx> for Pass { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr) { - let ty = cx.typeck_results().expr_ty(expr); - - let _ = match_type(cx, ty, &OPTION); - let _ = match_type(cx, ty, &["core", "result", "Result"]); - - let rc_path = &["alloc", "rc", "Rc"]; - let _ = clippy_utils::ty::match_type(cx, ty, rc_path); - } -} - -fn main() {} diff --git a/tests/ui-internal/match_type_on_diag_item.stderr b/tests/ui-internal/match_type_on_diag_item.stderr deleted file mode 100644 index e3cb6b6c22ead..0000000000000 --- a/tests/ui-internal/match_type_on_diag_item.stderr +++ /dev/null @@ -1,27 +0,0 @@ -error: usage of `clippy_utils::ty::match_type()` on a type diagnostic item - --> $DIR/match_type_on_diag_item.rs:31:17 - | -LL | let _ = match_type(cx, ty, &OPTION); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clippy_utils::ty::is_type_diagnostic_item(cx, ty, sym::Option)` - | -note: the lint level is defined here - --> $DIR/match_type_on_diag_item.rs:1:9 - | -LL | #![deny(clippy::internal)] - | ^^^^^^^^^^^^^^^^ - = note: `#[deny(clippy::match_type_on_diagnostic_item)]` implied by `#[deny(clippy::internal)]` - -error: usage of `clippy_utils::ty::match_type()` on a type diagnostic item - --> $DIR/match_type_on_diag_item.rs:32:17 - | -LL | let _ = match_type(cx, ty, &["core", "result", "Result"]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clippy_utils::ty::is_type_diagnostic_item(cx, ty, sym::Result)` - -error: usage of `clippy_utils::ty::match_type()` on a type diagnostic item - --> $DIR/match_type_on_diag_item.rs:35:17 - | -LL | let _ = clippy_utils::ty::match_type(cx, ty, rc_path); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clippy_utils::ty::is_type_diagnostic_item(cx, ty, sym::Rc)` - -error: aborting due to 3 previous errors - diff --git a/tests/ui-internal/unnecessary_def_path.fixed b/tests/ui-internal/unnecessary_def_path.fixed new file mode 100644 index 0000000000000..4c050332f2cc9 --- /dev/null +++ b/tests/ui-internal/unnecessary_def_path.fixed @@ -0,0 +1,62 @@ +// run-rustfix +// aux-build:paths.rs +#![deny(clippy::internal)] +#![feature(rustc_private)] + +extern crate clippy_utils; +extern crate paths; +extern crate rustc_hir; +extern crate rustc_lint; +extern crate rustc_middle; +extern crate rustc_span; + +#[allow(unused)] +use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item, match_type}; +#[allow(unused)] +use clippy_utils::{ + is_expr_path_def_path, is_path_diagnostic_item, is_res_diagnostic_ctor, is_res_lang_ctor, is_trait_method, + match_def_path, match_trait_method, path_res, +}; + +#[allow(unused)] +use rustc_hir::LangItem; +#[allow(unused)] +use rustc_span::sym; + +use rustc_hir::def_id::DefId; +use rustc_hir::Expr; +use rustc_lint::LateContext; +use rustc_middle::ty::Ty; + +#[allow(unused)] +static OPTION: [&str; 3] = ["core", "option", "Option"]; +#[allow(unused)] +const RESULT: &[&str] = &["core", "result", "Result"]; + +fn _f<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, did: DefId, expr: &Expr<'_>) { + let _ = is_type_diagnostic_item(cx, ty, sym::Option); + let _ = is_type_diagnostic_item(cx, ty, sym::Result); + let _ = is_type_diagnostic_item(cx, ty, sym::Result); + + #[allow(unused)] + let rc_path = &["alloc", "rc", "Rc"]; + let _ = is_type_diagnostic_item(cx, ty, sym::Rc); + + let _ = is_type_diagnostic_item(cx, ty, sym::Option); + let _ = is_type_diagnostic_item(cx, ty, sym::Result); + + let _ = is_type_lang_item(cx, ty, LangItem::OwnedBox); + let _ = is_type_diagnostic_item(cx, ty, sym::maybe_uninit_uninit); + + let _ = cx.tcx.lang_items().require(LangItem::OwnedBox).ok() == Some(did); + let _ = cx.tcx.is_diagnostic_item(sym::Option, did); + let _ = cx.tcx.lang_items().require(LangItem::OptionSome).ok() == Some(did); + + let _ = is_trait_method(cx, expr, sym::AsRef); + + let _ = is_path_diagnostic_item(cx, expr, sym::Option); + let _ = path_res(cx, expr).opt_def_id().map_or(false, |id| cx.tcx.lang_items().require(LangItem::IteratorNext).ok() == Some(id)); + let _ = is_res_lang_ctor(cx, path_res(cx, expr), LangItem::OptionSome); +} + +fn main() {} diff --git a/tests/ui-internal/unnecessary_def_path.rs b/tests/ui-internal/unnecessary_def_path.rs new file mode 100644 index 0000000000000..6506f1f164ac6 --- /dev/null +++ b/tests/ui-internal/unnecessary_def_path.rs @@ -0,0 +1,62 @@ +// run-rustfix +// aux-build:paths.rs +#![deny(clippy::internal)] +#![feature(rustc_private)] + +extern crate clippy_utils; +extern crate paths; +extern crate rustc_hir; +extern crate rustc_lint; +extern crate rustc_middle; +extern crate rustc_span; + +#[allow(unused)] +use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item, match_type}; +#[allow(unused)] +use clippy_utils::{ + is_expr_path_def_path, is_path_diagnostic_item, is_res_diagnostic_ctor, is_res_lang_ctor, is_trait_method, + match_def_path, match_trait_method, path_res, +}; + +#[allow(unused)] +use rustc_hir::LangItem; +#[allow(unused)] +use rustc_span::sym; + +use rustc_hir::def_id::DefId; +use rustc_hir::Expr; +use rustc_lint::LateContext; +use rustc_middle::ty::Ty; + +#[allow(unused)] +static OPTION: [&str; 3] = ["core", "option", "Option"]; +#[allow(unused)] +const RESULT: &[&str] = &["core", "result", "Result"]; + +fn _f<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, did: DefId, expr: &Expr<'_>) { + let _ = match_type(cx, ty, &OPTION); + let _ = match_type(cx, ty, RESULT); + let _ = match_type(cx, ty, &["core", "result", "Result"]); + + #[allow(unused)] + let rc_path = &["alloc", "rc", "Rc"]; + let _ = clippy_utils::ty::match_type(cx, ty, rc_path); + + let _ = match_type(cx, ty, &paths::OPTION); + let _ = match_type(cx, ty, paths::RESULT); + + let _ = match_type(cx, ty, &["alloc", "boxed", "Box"]); + let _ = match_type(cx, ty, &["core", "mem", "maybe_uninit", "MaybeUninit", "uninit"]); + + let _ = match_def_path(cx, did, &["alloc", "boxed", "Box"]); + let _ = match_def_path(cx, did, &["core", "option", "Option"]); + let _ = match_def_path(cx, did, &["core", "option", "Option", "Some"]); + + let _ = match_trait_method(cx, expr, &["core", "convert", "AsRef"]); + + let _ = is_expr_path_def_path(cx, expr, &["core", "option", "Option"]); + let _ = is_expr_path_def_path(cx, expr, &["core", "iter", "traits", "Iterator", "next"]); + let _ = is_expr_path_def_path(cx, expr, &["core", "option", "Option", "Some"]); +} + +fn main() {} diff --git a/tests/ui-internal/unnecessary_def_path.stderr b/tests/ui-internal/unnecessary_def_path.stderr new file mode 100644 index 0000000000000..a99a8f71fa6a7 --- /dev/null +++ b/tests/ui-internal/unnecessary_def_path.stderr @@ -0,0 +1,101 @@ +error: use of a def path to a diagnostic item + --> $DIR/unnecessary_def_path.rs:37:13 + | +LL | let _ = match_type(cx, ty, &OPTION); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Option)` + | +note: the lint level is defined here + --> $DIR/unnecessary_def_path.rs:3:9 + | +LL | #![deny(clippy::internal)] + | ^^^^^^^^^^^^^^^^ + = note: `#[deny(clippy::unnecessary_def_path)]` implied by `#[deny(clippy::internal)]` + +error: use of a def path to a diagnostic item + --> $DIR/unnecessary_def_path.rs:38:13 + | +LL | let _ = match_type(cx, ty, RESULT); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Result)` + +error: use of a def path to a diagnostic item + --> $DIR/unnecessary_def_path.rs:39:13 + | +LL | let _ = match_type(cx, ty, &["core", "result", "Result"]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Result)` + +error: use of a def path to a diagnostic item + --> $DIR/unnecessary_def_path.rs:43:13 + | +LL | let _ = clippy_utils::ty::match_type(cx, ty, rc_path); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Rc)` + +error: use of a def path to a diagnostic item + --> $DIR/unnecessary_def_path.rs:45:13 + | +LL | let _ = match_type(cx, ty, &paths::OPTION); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Option)` + +error: use of a def path to a diagnostic item + --> $DIR/unnecessary_def_path.rs:46:13 + | +LL | let _ = match_type(cx, ty, paths::RESULT); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Result)` + +error: use of a def path to a `LangItem` + --> $DIR/unnecessary_def_path.rs:48:13 + | +LL | let _ = match_type(cx, ty, &["alloc", "boxed", "Box"]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_lang_item(cx, ty, LangItem::OwnedBox)` + +error: use of a def path to a diagnostic item + --> $DIR/unnecessary_def_path.rs:49:13 + | +LL | let _ = match_type(cx, ty, &["core", "mem", "maybe_uninit", "MaybeUninit", "uninit"]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::maybe_uninit_uninit)` + +error: use of a def path to a `LangItem` + --> $DIR/unnecessary_def_path.rs:51:13 + | +LL | let _ = match_def_path(cx, did, &["alloc", "boxed", "Box"]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cx.tcx.lang_items().require(LangItem::OwnedBox).ok() == Some(did)` + +error: use of a def path to a diagnostic item + --> $DIR/unnecessary_def_path.rs:52:13 + | +LL | let _ = match_def_path(cx, did, &["core", "option", "Option"]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cx.tcx.is_diagnostic_item(sym::Option, did)` + +error: use of a def path to a `LangItem` + --> $DIR/unnecessary_def_path.rs:53:13 + | +LL | let _ = match_def_path(cx, did, &["core", "option", "Option", "Some"]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cx.tcx.lang_items().require(LangItem::OptionSome).ok() == Some(did)` + | + = help: if this `DefId` came from a constructor expression or pattern then the parent `DefId` should be used instead + +error: use of a def path to a diagnostic item + --> $DIR/unnecessary_def_path.rs:55:13 + | +LL | let _ = match_trait_method(cx, expr, &["core", "convert", "AsRef"]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_trait_method(cx, expr, sym::AsRef)` + +error: use of a def path to a diagnostic item + --> $DIR/unnecessary_def_path.rs:57:13 + | +LL | let _ = is_expr_path_def_path(cx, expr, &["core", "option", "Option"]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_path_diagnostic_item(cx, expr, sym::Option)` + +error: use of a def path to a `LangItem` + --> $DIR/unnecessary_def_path.rs:58:13 + | +LL | let _ = is_expr_path_def_path(cx, expr, &["core", "iter", "traits", "Iterator", "next"]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `path_res(cx, expr).opt_def_id().map_or(false, |id| cx.tcx.lang_items().require(LangItem::IteratorNext).ok() == Some(id))` + +error: use of a def path to a `LangItem` + --> $DIR/unnecessary_def_path.rs:59:13 + | +LL | let _ = is_expr_path_def_path(cx, expr, &["core", "option", "Option", "Some"]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_res_lang_ctor(cx, path_res(cx, expr), LangItem::OptionSome)` + +error: aborting due to 15 previous errors + From eb3970285b8993b0f154839056ff7b3daba37840 Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Sun, 2 Oct 2022 15:13:22 -0400 Subject: [PATCH 097/114] fallout: fix tests to allow uninlined_format_args In order to switch `clippy::uninlined_format_args` from pedantic to style, all existing tests must not raise a warning. I did not want to change the actual tests, so this is a relatively minor change that: * add `#![allow(clippy::uninlined_format_args)]` where needed * normalizes all allow/deny/warn attributes * all allow attributes are grouped together * sorted alphabetically * the `clippy::*` attributes are listed separate from the other ones. * deny and warn attributes are listed before the allowed ones changelog: none --- .../conf_deprecated_key.rs | 2 + .../conf_deprecated_key.stderr | 2 +- tests/ui/assign_ops2.rs | 2 + tests/ui/assign_ops2.stderr | 20 +-- tests/ui/auxiliary/proc_macro_attr.rs | 2 +- tests/ui/bind_instead_of_map.fixed | 1 + tests/ui/bind_instead_of_map.rs | 1 + tests/ui/bind_instead_of_map.stderr | 6 +- tests/ui/borrow_box.rs | 5 +- tests/ui/borrow_box.stderr | 20 +-- .../branches_sharing_code/shared_at_bottom.rs | 3 +- .../shared_at_bottom.stderr | 20 +-- .../ui/branches_sharing_code/shared_at_top.rs | 5 +- .../shared_at_top.stderr | 28 ++-- .../shared_at_top_and_bottom.rs | 3 +- .../shared_at_top_and_bottom.stderr | 26 ++-- .../branches_sharing_code/valid_if_blocks.rs | 5 +- .../valid_if_blocks.stderr | 26 ++-- tests/ui/cast_abs_to_unsigned.fixed | 1 + tests/ui/cast_abs_to_unsigned.rs | 1 + tests/ui/cast_abs_to_unsigned.stderr | 34 ++--- tests/ui/collapsible_match.rs | 3 +- tests/ui/collapsible_match.stderr | 40 ++--- tests/ui/crashes/ice-4775.rs | 2 + tests/ui/crashes/regressions.rs | 2 +- tests/ui/default_trait_access.fixed | 4 +- tests/ui/default_trait_access.rs | 4 +- tests/ui/default_trait_access.stderr | 2 +- tests/ui/eta.fixed | 12 +- tests/ui/eta.rs | 12 +- tests/ui/expect_fun_call.fixed | 3 +- tests/ui/expect_fun_call.rs | 3 +- tests/ui/expect_fun_call.stderr | 26 ++-- tests/ui/explicit_counter_loop.rs | 1 + tests/ui/explicit_counter_loop.stderr | 18 +-- tests/ui/explicit_deref_methods.fixed | 10 +- tests/ui/explicit_deref_methods.rs | 10 +- tests/ui/explicit_write.fixed | 3 +- tests/ui/explicit_write.rs | 3 +- tests/ui/explicit_write.stderr | 26 ++-- tests/ui/fallible_impl_from.rs | 1 + tests/ui/fallible_impl_from.stderr | 16 +- tests/ui/for_loop_fixable.fixed | 2 +- tests/ui/for_loop_fixable.rs | 2 +- tests/ui/for_loops_over_fallibles.rs | 1 + tests/ui/for_loops_over_fallibles.stderr | 22 +-- tests/ui/format.fixed | 6 +- tests/ui/format.rs | 6 +- tests/ui/format_args.fixed | 12 +- tests/ui/format_args.rs | 12 +- tests/ui/format_args.stderr | 46 +++--- tests/ui/format_args_unfixable.rs | 6 +- tests/ui/format_args_unfixable.stderr | 36 ++--- tests/ui/functions.rs | 4 +- tests/ui/identity_op.fixed | 4 +- tests/ui/identity_op.rs | 4 +- .../if_let_slice_binding.rs | 1 + .../if_let_slice_binding.stderr | 20 +-- tests/ui/infinite_iter.rs | 2 + tests/ui/infinite_iter.stderr | 32 ++-- tests/ui/issue_2356.fixed | 1 + tests/ui/issue_2356.rs | 1 + tests/ui/issue_2356.stderr | 2 +- tests/ui/issue_4266.rs | 1 + tests/ui/issue_4266.stderr | 6 +- tests/ui/item_after_statement.rs | 1 + tests/ui/item_after_statement.stderr | 6 +- tests/ui/manual_assert.edition2018.fixed | 3 +- tests/ui/manual_assert.edition2018.stderr | 18 +-- tests/ui/manual_assert.edition2021.fixed | 3 +- tests/ui/manual_assert.edition2021.stderr | 18 +-- tests/ui/manual_assert.rs | 3 +- tests/ui/manual_find_fixable.fixed | 4 +- tests/ui/manual_find_fixable.rs | 4 +- tests/ui/manual_flatten.rs | 2 +- tests/ui/map_unwrap_or.rs | 2 +- tests/ui/match_ref_pats.fixed | 3 +- tests/ui/match_ref_pats.rs | 3 +- tests/ui/match_ref_pats.stderr | 10 +- tests/ui/match_result_ok.fixed | 3 +- tests/ui/match_result_ok.rs | 3 +- tests/ui/match_result_ok.stderr | 6 +- tests/ui/match_same_arms2.rs | 6 +- tests/ui/match_same_arms2.stderr | 46 +++--- tests/ui/match_single_binding.fixed | 4 +- tests/ui/match_single_binding.rs | 4 +- tests/ui/match_single_binding2.fixed | 2 +- tests/ui/match_single_binding2.rs | 2 +- tests/ui/mut_mut.rs | 4 +- tests/ui/needless_borrow.fixed | 4 +- tests/ui/needless_borrow.rs | 4 +- tests/ui/needless_collect_indirect.rs | 2 + tests/ui/needless_collect_indirect.stderr | 32 ++-- tests/ui/needless_continue.rs | 1 + tests/ui/needless_continue.stderr | 16 +- tests/ui/needless_for_each_fixable.fixed | 7 +- tests/ui/needless_for_each_fixable.rs | 7 +- tests/ui/needless_for_each_fixable.stderr | 16 +- tests/ui/needless_for_each_unfixable.rs | 2 +- tests/ui/needless_late_init.fixed | 5 +- tests/ui/needless_late_init.rs | 5 +- tests/ui/needless_late_init.stderr | 32 ++-- tests/ui/needless_pass_by_value.rs | 9 +- tests/ui/needless_pass_by_value.stderr | 52 +++---- tests/ui/needless_range_loop.rs | 1 + tests/ui/needless_range_loop.stderr | 28 ++-- tests/ui/no_effect.rs | 6 +- tests/ui/no_effect.stderr | 60 ++++---- tests/ui/option_map_unit_fn_fixable.fixed | 3 +- tests/ui/option_map_unit_fn_fixable.rs | 3 +- tests/ui/option_map_unit_fn_fixable.stderr | 38 ++--- tests/ui/or_fun_call.fixed | 3 +- tests/ui/or_fun_call.rs | 3 +- tests/ui/or_fun_call.stderr | 52 +++---- tests/ui/panic_in_result_fn_assertions.rs | 2 +- .../ui/panic_in_result_fn_debug_assertions.rs | 2 +- tests/ui/patterns.fixed | 3 +- tests/ui/patterns.rs | 3 +- tests/ui/patterns.stderr | 6 +- tests/ui/print_literal.rs | 1 + tests/ui/print_literal.stderr | 24 +-- tests/ui/recursive_format_impl.rs | 5 +- tests/ui/recursive_format_impl.stderr | 20 +-- tests/ui/redundant_clone.fixed | 4 +- tests/ui/redundant_clone.rs | 4 +- .../redundant_pattern_matching_ipaddr.fixed | 11 +- tests/ui/redundant_pattern_matching_ipaddr.rs | 11 +- .../redundant_pattern_matching_ipaddr.stderr | 36 ++--- .../redundant_pattern_matching_result.fixed | 11 +- tests/ui/redundant_pattern_matching_result.rs | 11 +- .../redundant_pattern_matching_result.stderr | 44 +++--- tests/ui/result_map_unit_fn_fixable.fixed | 2 +- tests/ui/result_map_unit_fn_fixable.rs | 2 +- tests/ui/reversed_empty_ranges_fixable.fixed | 1 + tests/ui/reversed_empty_ranges_fixable.rs | 1 + tests/ui/reversed_empty_ranges_fixable.stderr | 8 +- .../reversed_empty_ranges_loops_fixable.fixed | 1 + .../ui/reversed_empty_ranges_loops_fixable.rs | 1 + ...reversed_empty_ranges_loops_fixable.stderr | 12 +- .../reversed_empty_ranges_loops_unfixable.rs | 1 + ...versed_empty_ranges_loops_unfixable.stderr | 4 +- tests/ui/same_functions_in_if_condition.rs | 12 +- .../ui/same_functions_in_if_condition.stderr | 24 +-- tests/ui/semicolon_if_nothing_returned.rs | 2 +- tests/ui/significant_drop_in_scrutinee.rs | 7 +- tests/ui/significant_drop_in_scrutinee.stderr | 52 +++---- tests/ui/single_match.rs | 1 + tests/ui/single_match.stderr | 32 ++-- tests/ui/single_match_else.rs | 4 +- tests/ui/single_match_else.stderr | 10 +- tests/ui/toplevel_ref_arg.fixed | 2 +- tests/ui/toplevel_ref_arg.rs | 2 +- tests/ui/trivially_copy_pass_by_ref.rs | 7 +- tests/ui/trivially_copy_pass_by_ref.stderr | 38 ++--- tests/ui/uninlined_format_args.fixed | 10 +- tests/ui/uninlined_format_args.rs | 10 +- tests/ui/uninlined_format_args.stderr | 142 +++++++++--------- tests/ui/unit_arg.rs | 15 +- tests/ui/unit_arg.stderr | 20 +-- tests/ui/unit_arg_empty_blocks.fixed | 3 +- tests/ui/unit_arg_empty_blocks.rs | 3 +- tests/ui/unit_arg_empty_blocks.stderr | 8 +- tests/ui/unnecessary_clone.rs | 4 +- tests/ui/unnecessary_join.fixed | 2 +- tests/ui/unnecessary_join.rs | 2 +- tests/ui/used_underscore_binding.rs | 3 +- tests/ui/used_underscore_binding.stderr | 12 +- tests/ui/useless_asref.fixed | 3 +- tests/ui/useless_asref.rs | 3 +- tests/ui/useless_asref.stderr | 24 +-- tests/ui/vec.fixed | 2 +- tests/ui/vec.rs | 2 +- tests/ui/while_let_loop.rs | 1 + tests/ui/while_let_loop.stderr | 10 +- tests/ui/while_let_on_iterator.fixed | 10 +- tests/ui/while_let_on_iterator.rs | 10 +- tests/ui/while_let_on_iterator.stderr | 52 +++---- tests/ui/wildcard_enum_match_arm.fixed | 10 +- tests/ui/wildcard_enum_match_arm.rs | 10 +- tests/ui/wildcard_enum_match_arm.stderr | 14 +- tests/ui/write_literal.rs | 2 +- 181 files changed, 1021 insertions(+), 984 deletions(-) diff --git a/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.rs b/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.rs index b4e677ea124b7..7f1c512d7c97b 100644 --- a/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.rs +++ b/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.rs @@ -1,3 +1,5 @@ +#![allow(clippy::uninlined_format_args)] + fn main() {} #[warn(clippy::cognitive_complexity)] diff --git a/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr b/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr index 4c560299ebdd1..fe6303717b593 100644 --- a/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr +++ b/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr @@ -3,7 +3,7 @@ warning: error reading Clippy's configuration file `$DIR/clippy.toml`: deprecate warning: error reading Clippy's configuration file `$DIR/clippy.toml`: deprecated field `blacklisted-names`. Please use `disallowed-names` instead error: the function has a cognitive complexity of (3/2) - --> $DIR/conf_deprecated_key.rs:4:4 + --> $DIR/conf_deprecated_key.rs:6:4 | LL | fn cognitive_complexity() { | ^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/assign_ops2.rs b/tests/ui/assign_ops2.rs index f6d3a8fa3f0d7..2c876a96c55da 100644 --- a/tests/ui/assign_ops2.rs +++ b/tests/ui/assign_ops2.rs @@ -1,3 +1,5 @@ +#![allow(clippy::uninlined_format_args)] + #[allow(unused_assignments)] #[warn(clippy::misrefactored_assign_op, clippy::assign_op_pattern)] fn main() { diff --git a/tests/ui/assign_ops2.stderr b/tests/ui/assign_ops2.stderr index 04b1dc93d4a42..25e74602244df 100644 --- a/tests/ui/assign_ops2.stderr +++ b/tests/ui/assign_ops2.stderr @@ -1,5 +1,5 @@ error: variable appears on both sides of an assignment operation - --> $DIR/assign_ops2.rs:5:5 + --> $DIR/assign_ops2.rs:7:5 | LL | a += a + 1; | ^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | a = a + a + 1; | ~~~~~~~~~~~~~ error: variable appears on both sides of an assignment operation - --> $DIR/assign_ops2.rs:6:5 + --> $DIR/assign_ops2.rs:8:5 | LL | a += 1 + a; | ^^^^^^^^^^ @@ -30,7 +30,7 @@ LL | a = a + 1 + a; | ~~~~~~~~~~~~~ error: variable appears on both sides of an assignment operation - --> $DIR/assign_ops2.rs:7:5 + --> $DIR/assign_ops2.rs:9:5 | LL | a -= a - 1; | ^^^^^^^^^^ @@ -45,7 +45,7 @@ LL | a = a - (a - 1); | ~~~~~~~~~~~~~~~ error: variable appears on both sides of an assignment operation - --> $DIR/assign_ops2.rs:8:5 + --> $DIR/assign_ops2.rs:10:5 | LL | a *= a * 99; | ^^^^^^^^^^^ @@ -60,7 +60,7 @@ LL | a = a * a * 99; | ~~~~~~~~~~~~~~ error: variable appears on both sides of an assignment operation - --> $DIR/assign_ops2.rs:9:5 + --> $DIR/assign_ops2.rs:11:5 | LL | a *= 42 * a; | ^^^^^^^^^^^ @@ -75,7 +75,7 @@ LL | a = a * 42 * a; | ~~~~~~~~~~~~~~ error: variable appears on both sides of an assignment operation - --> $DIR/assign_ops2.rs:10:5 + --> $DIR/assign_ops2.rs:12:5 | LL | a /= a / 2; | ^^^^^^^^^^ @@ -90,7 +90,7 @@ LL | a = a / (a / 2); | ~~~~~~~~~~~~~~~ error: variable appears on both sides of an assignment operation - --> $DIR/assign_ops2.rs:11:5 + --> $DIR/assign_ops2.rs:13:5 | LL | a %= a % 5; | ^^^^^^^^^^ @@ -105,7 +105,7 @@ LL | a = a % (a % 5); | ~~~~~~~~~~~~~~~ error: variable appears on both sides of an assignment operation - --> $DIR/assign_ops2.rs:12:5 + --> $DIR/assign_ops2.rs:14:5 | LL | a &= a & 1; | ^^^^^^^^^^ @@ -120,7 +120,7 @@ LL | a = a & a & 1; | ~~~~~~~~~~~~~ error: variable appears on both sides of an assignment operation - --> $DIR/assign_ops2.rs:13:5 + --> $DIR/assign_ops2.rs:15:5 | LL | a *= a * a; | ^^^^^^^^^^ @@ -135,7 +135,7 @@ LL | a = a * a * a; | ~~~~~~~~~~~~~ error: manual implementation of an assign operation - --> $DIR/assign_ops2.rs:50:5 + --> $DIR/assign_ops2.rs:52:5 | LL | buf = buf + cows.clone(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `buf += cows.clone()` diff --git a/tests/ui/auxiliary/proc_macro_attr.rs b/tests/ui/auxiliary/proc_macro_attr.rs index ae2cc2492f414..4914f14b58ff7 100644 --- a/tests/ui/auxiliary/proc_macro_attr.rs +++ b/tests/ui/auxiliary/proc_macro_attr.rs @@ -4,7 +4,7 @@ #![crate_type = "proc-macro"] #![feature(repr128, proc_macro_hygiene, proc_macro_quote, box_patterns)] #![allow(incomplete_features)] -#![allow(clippy::useless_conversion)] +#![allow(clippy::useless_conversion, clippy::uninlined_format_args)] extern crate proc_macro; extern crate quote; diff --git a/tests/ui/bind_instead_of_map.fixed b/tests/ui/bind_instead_of_map.fixed index 5815550d7a6a1..d94e2ac6072d4 100644 --- a/tests/ui/bind_instead_of_map.fixed +++ b/tests/ui/bind_instead_of_map.fixed @@ -1,5 +1,6 @@ // run-rustfix #![deny(clippy::bind_instead_of_map)] +#![allow(clippy::uninlined_format_args)] // need a main anyway, use it get rid of unused warnings too pub fn main() { diff --git a/tests/ui/bind_instead_of_map.rs b/tests/ui/bind_instead_of_map.rs index 623b100a4ce7e..86f31f58284aa 100644 --- a/tests/ui/bind_instead_of_map.rs +++ b/tests/ui/bind_instead_of_map.rs @@ -1,5 +1,6 @@ // run-rustfix #![deny(clippy::bind_instead_of_map)] +#![allow(clippy::uninlined_format_args)] // need a main anyway, use it get rid of unused warnings too pub fn main() { diff --git a/tests/ui/bind_instead_of_map.stderr b/tests/ui/bind_instead_of_map.stderr index 24c6b7f9ef32b..b6a81d21bb200 100644 --- a/tests/ui/bind_instead_of_map.stderr +++ b/tests/ui/bind_instead_of_map.stderr @@ -1,5 +1,5 @@ error: using `Option.and_then(Some)`, which is a no-op - --> $DIR/bind_instead_of_map.rs:8:13 + --> $DIR/bind_instead_of_map.rs:9:13 | LL | let _ = x.and_then(Some); | ^^^^^^^^^^^^^^^^ help: use the expression directly: `x` @@ -11,13 +11,13 @@ LL | #![deny(clippy::bind_instead_of_map)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: using `Option.and_then(|x| Some(y))`, which is more succinctly expressed as `map(|x| y)` - --> $DIR/bind_instead_of_map.rs:9:13 + --> $DIR/bind_instead_of_map.rs:10:13 | LL | let _ = x.and_then(|o| Some(o + 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `x.map(|o| o + 1)` error: using `Result.and_then(Ok)`, which is a no-op - --> $DIR/bind_instead_of_map.rs:15:13 + --> $DIR/bind_instead_of_map.rs:16:13 | LL | let _ = x.and_then(Ok); | ^^^^^^^^^^^^^^ help: use the expression directly: `x` diff --git a/tests/ui/borrow_box.rs b/tests/ui/borrow_box.rs index 35ed87b0f182f..3b5b6bf4c9502 100644 --- a/tests/ui/borrow_box.rs +++ b/tests/ui/borrow_box.rs @@ -1,7 +1,6 @@ #![deny(clippy::borrowed_box)] -#![allow(clippy::disallowed_names)] -#![allow(unused_variables)] -#![allow(dead_code)] +#![allow(dead_code, unused_variables)] +#![allow(clippy::uninlined_format_args, clippy::disallowed_names)] use std::fmt::Display; diff --git a/tests/ui/borrow_box.stderr b/tests/ui/borrow_box.stderr index 3eac32815be3f..99cb60a1ead9b 100644 --- a/tests/ui/borrow_box.stderr +++ b/tests/ui/borrow_box.stderr @@ -1,5 +1,5 @@ error: you seem to be trying to use `&Box`. Consider using just `&T` - --> $DIR/borrow_box.rs:21:14 + --> $DIR/borrow_box.rs:20:14 | LL | let foo: &Box; | ^^^^^^^^^^ help: try: `&bool` @@ -11,55 +11,55 @@ LL | #![deny(clippy::borrowed_box)] | ^^^^^^^^^^^^^^^^^^^^ error: you seem to be trying to use `&Box`. Consider using just `&T` - --> $DIR/borrow_box.rs:25:10 + --> $DIR/borrow_box.rs:24:10 | LL | foo: &'a Box, | ^^^^^^^^^^^^^ help: try: `&'a bool` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> $DIR/borrow_box.rs:29:17 + --> $DIR/borrow_box.rs:28:17 | LL | fn test4(a: &Box); | ^^^^^^^^^^ help: try: `&bool` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> $DIR/borrow_box.rs:95:25 + --> $DIR/borrow_box.rs:94:25 | LL | pub fn test14(_display: &Box) {} | ^^^^^^^^^^^^^^^^^ help: try: `&dyn Display` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> $DIR/borrow_box.rs:96:25 + --> $DIR/borrow_box.rs:95:25 | LL | pub fn test15(_display: &Box) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&(dyn Display + Send)` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> $DIR/borrow_box.rs:97:29 + --> $DIR/borrow_box.rs:96:29 | LL | pub fn test16<'a>(_display: &'a Box) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&'a (dyn Display + 'a)` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> $DIR/borrow_box.rs:99:25 + --> $DIR/borrow_box.rs:98:25 | LL | pub fn test17(_display: &Box) {} | ^^^^^^^^^^^^^^^^^^ help: try: `&impl Display` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> $DIR/borrow_box.rs:100:25 + --> $DIR/borrow_box.rs:99:25 | LL | pub fn test18(_display: &Box) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&(impl Display + Send)` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> $DIR/borrow_box.rs:101:29 + --> $DIR/borrow_box.rs:100:29 | LL | pub fn test19<'a>(_display: &'a Box) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&'a (impl Display + 'a)` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> $DIR/borrow_box.rs:106:25 + --> $DIR/borrow_box.rs:105:25 | LL | pub fn test20(_display: &Box<(dyn Display + Send)>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&(dyn Display + Send)` diff --git a/tests/ui/branches_sharing_code/shared_at_bottom.rs b/tests/ui/branches_sharing_code/shared_at_bottom.rs index 12f550d9c9a80..6a63008b5a74b 100644 --- a/tests/ui/branches_sharing_code/shared_at_bottom.rs +++ b/tests/ui/branches_sharing_code/shared_at_bottom.rs @@ -1,5 +1,6 @@ -#![allow(dead_code, clippy::equatable_if_let)] #![deny(clippy::if_same_then_else, clippy::branches_sharing_code)] +#![allow(dead_code)] +#![allow(clippy::equatable_if_let, clippy::uninlined_format_args)] // This tests the branches_sharing_code lint at the end of blocks diff --git a/tests/ui/branches_sharing_code/shared_at_bottom.stderr b/tests/ui/branches_sharing_code/shared_at_bottom.stderr index 5e1a68d216ea8..a6d6c0c93ab5c 100644 --- a/tests/ui/branches_sharing_code/shared_at_bottom.stderr +++ b/tests/ui/branches_sharing_code/shared_at_bottom.stderr @@ -1,5 +1,5 @@ error: all if blocks contain the same code at the end - --> $DIR/shared_at_bottom.rs:30:5 + --> $DIR/shared_at_bottom.rs:31:5 | LL | / let result = false; LL | | println!("Block end!"); @@ -8,7 +8,7 @@ LL | | }; | |_____^ | note: the lint level is defined here - --> $DIR/shared_at_bottom.rs:2:36 + --> $DIR/shared_at_bottom.rs:1:36 | LL | #![deny(clippy::if_same_then_else, clippy::branches_sharing_code)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -22,7 +22,7 @@ LL ~ result; | error: all if blocks contain the same code at the end - --> $DIR/shared_at_bottom.rs:48:5 + --> $DIR/shared_at_bottom.rs:49:5 | LL | / println!("Same end of block"); LL | | } @@ -35,7 +35,7 @@ LL + println!("Same end of block"); | error: all if blocks contain the same code at the end - --> $DIR/shared_at_bottom.rs:65:5 + --> $DIR/shared_at_bottom.rs:66:5 | LL | / println!( LL | | "I'm moveable because I know: `outer_scope_value`: '{}'", @@ -54,7 +54,7 @@ LL + ); | error: all if blocks contain the same code at the end - --> $DIR/shared_at_bottom.rs:77:9 + --> $DIR/shared_at_bottom.rs:78:9 | LL | / println!("Hello World"); LL | | } @@ -67,7 +67,7 @@ LL + println!("Hello World"); | error: all if blocks contain the same code at the end - --> $DIR/shared_at_bottom.rs:93:5 + --> $DIR/shared_at_bottom.rs:94:5 | LL | / let later_used_value = "A string value"; LL | | println!("{}", later_used_value); @@ -84,7 +84,7 @@ LL + println!("{}", later_used_value); | error: all if blocks contain the same code at the end - --> $DIR/shared_at_bottom.rs:106:5 + --> $DIR/shared_at_bottom.rs:107:5 | LL | / let simple_examples = "I now identify as a &str :)"; LL | | println!("This is the new simple_example: {}", simple_examples); @@ -100,7 +100,7 @@ LL + println!("This is the new simple_example: {}", simple_examples); | error: all if blocks contain the same code at the end - --> $DIR/shared_at_bottom.rs:171:5 + --> $DIR/shared_at_bottom.rs:172:5 | LL | / x << 2 LL | | }; @@ -114,7 +114,7 @@ LL ~ x << 2; | error: all if blocks contain the same code at the end - --> $DIR/shared_at_bottom.rs:178:5 + --> $DIR/shared_at_bottom.rs:179:5 | LL | / x * 4 LL | | } @@ -128,7 +128,7 @@ LL + x * 4 | error: all if blocks contain the same code at the end - --> $DIR/shared_at_bottom.rs:190:44 + --> $DIR/shared_at_bottom.rs:191:44 | LL | if x == 17 { b = 1; a = 0x99; } else { a = 0x99; } | ^^^^^^^^^^^ diff --git a/tests/ui/branches_sharing_code/shared_at_top.rs b/tests/ui/branches_sharing_code/shared_at_top.rs index bdeb0a39558db..9e0b99f166651 100644 --- a/tests/ui/branches_sharing_code/shared_at_top.rs +++ b/tests/ui/branches_sharing_code/shared_at_top.rs @@ -1,5 +1,6 @@ -#![allow(dead_code, clippy::mixed_read_write_in_expression)] -#![deny(clippy::if_same_then_else, clippy::branches_sharing_code)] +#![deny(clippy::branches_sharing_code, clippy::if_same_then_else)] +#![allow(dead_code)] +#![allow(clippy::mixed_read_write_in_expression, clippy::uninlined_format_args)] // This tests the branches_sharing_code lint at the start of blocks diff --git a/tests/ui/branches_sharing_code/shared_at_top.stderr b/tests/ui/branches_sharing_code/shared_at_top.stderr index d890b12ecbb4c..fe912ab7560d5 100644 --- a/tests/ui/branches_sharing_code/shared_at_top.stderr +++ b/tests/ui/branches_sharing_code/shared_at_top.stderr @@ -1,15 +1,15 @@ error: all if blocks contain the same code at the start - --> $DIR/shared_at_top.rs:10:5 + --> $DIR/shared_at_top.rs:11:5 | LL | / if true { LL | | println!("Hello World!"); | |_________________________________^ | note: the lint level is defined here - --> $DIR/shared_at_top.rs:2:36 + --> $DIR/shared_at_top.rs:1:9 | -LL | #![deny(clippy::if_same_then_else, clippy::branches_sharing_code)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![deny(clippy::branches_sharing_code, clippy::if_same_then_else)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider moving these statements before the if | LL ~ println!("Hello World!"); @@ -17,7 +17,7 @@ LL + if true { | error: all if blocks contain the same code at the start - --> $DIR/shared_at_top.rs:19:5 + --> $DIR/shared_at_top.rs:20:5 | LL | / if x == 0 { LL | | let y = 9; @@ -35,7 +35,7 @@ LL + if x == 0 { | error: all if blocks contain the same code at the start - --> $DIR/shared_at_top.rs:40:5 + --> $DIR/shared_at_top.rs:41:5 | LL | / let _ = if x == 7 { LL | | let y = 16; @@ -48,7 +48,7 @@ LL + let _ = if x == 7 { | error: all if blocks contain the same code at the start - --> $DIR/shared_at_top.rs:58:5 + --> $DIR/shared_at_top.rs:59:5 | LL | / if x == 10 { LL | | let used_value_name = "Different type"; @@ -64,7 +64,7 @@ LL + if x == 10 { | error: all if blocks contain the same code at the start - --> $DIR/shared_at_top.rs:72:5 + --> $DIR/shared_at_top.rs:73:5 | LL | / if x == 11 { LL | | let can_be_overridden = "Move me"; @@ -80,7 +80,7 @@ LL + if x == 11 { | error: all if blocks contain the same code at the start - --> $DIR/shared_at_top.rs:88:5 + --> $DIR/shared_at_top.rs:89:5 | LL | / if x == 2020 { LL | | println!("This should trigger the `SHARED_CODE_IN_IF_BLOCKS` lint."); @@ -95,7 +95,7 @@ LL + if x == 2020 { | error: this `if` has identical blocks - --> $DIR/shared_at_top.rs:96:18 + --> $DIR/shared_at_top.rs:97:18 | LL | if x == 2019 { | __________________^ @@ -104,12 +104,12 @@ LL | | } else { | |_____^ | note: the lint level is defined here - --> $DIR/shared_at_top.rs:2:9 + --> $DIR/shared_at_top.rs:1:40 | -LL | #![deny(clippy::if_same_then_else, clippy::branches_sharing_code)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![deny(clippy::branches_sharing_code, clippy::if_same_then_else)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: same as this - --> $DIR/shared_at_top.rs:98:12 + --> $DIR/shared_at_top.rs:99:12 | LL | } else { | ____________^ diff --git a/tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs b/tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs index deefdad32c9dd..93b8c6e10dae6 100644 --- a/tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs +++ b/tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs @@ -1,5 +1,6 @@ +#![deny(clippy::branches_sharing_code, clippy::if_same_then_else)] #![allow(dead_code)] -#![deny(clippy::if_same_then_else, clippy::branches_sharing_code)] +#![allow(clippy::uninlined_format_args)] // branches_sharing_code at the top and bottom of the if blocks diff --git a/tests/ui/branches_sharing_code/shared_at_top_and_bottom.stderr b/tests/ui/branches_sharing_code/shared_at_top_and_bottom.stderr index a270f637f2b91..d36a2b67900c0 100644 --- a/tests/ui/branches_sharing_code/shared_at_top_and_bottom.stderr +++ b/tests/ui/branches_sharing_code/shared_at_top_and_bottom.stderr @@ -1,5 +1,5 @@ error: all if blocks contain the same code at both the start and the end - --> $DIR/shared_at_top_and_bottom.rs:16:5 + --> $DIR/shared_at_top_and_bottom.rs:17:5 | LL | / if x == 7 { LL | | let t = 7; @@ -8,12 +8,12 @@ LL | | let _overlap_end = 2 * t; | |_________________________________^ | note: the lint level is defined here - --> $DIR/shared_at_top_and_bottom.rs:2:36 + --> $DIR/shared_at_top_and_bottom.rs:1:9 | -LL | #![deny(clippy::if_same_then_else, clippy::branches_sharing_code)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![deny(clippy::branches_sharing_code, clippy::if_same_then_else)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: this code is shared at the end - --> $DIR/shared_at_top_and_bottom.rs:28:5 + --> $DIR/shared_at_top_and_bottom.rs:29:5 | LL | / let _u = 9; LL | | } @@ -32,7 +32,7 @@ LL + let _u = 9; | error: all if blocks contain the same code at both the start and the end - --> $DIR/shared_at_top_and_bottom.rs:32:5 + --> $DIR/shared_at_top_and_bottom.rs:33:5 | LL | / if x == 99 { LL | | let r = 7; @@ -41,7 +41,7 @@ LL | | let _overlap_middle = r * r; | |____________________________________^ | note: this code is shared at the end - --> $DIR/shared_at_top_and_bottom.rs:43:5 + --> $DIR/shared_at_top_and_bottom.rs:44:5 | LL | / let _overlap_end = r * r * r; LL | | let z = "end"; @@ -63,7 +63,7 @@ LL + let z = "end"; | error: all if blocks contain the same code at both the start and the end - --> $DIR/shared_at_top_and_bottom.rs:61:5 + --> $DIR/shared_at_top_and_bottom.rs:62:5 | LL | / if (x > 7 && y < 13) || (x + y) % 2 == 1 { LL | | let a = 0xcafe; @@ -72,7 +72,7 @@ LL | | let e_id = gen_id(a, b); | |________________________________^ | note: this code is shared at the end - --> $DIR/shared_at_top_and_bottom.rs:81:5 + --> $DIR/shared_at_top_and_bottom.rs:82:5 | LL | / let pack = DataPack { LL | | id: e_id, @@ -102,14 +102,14 @@ LL + process_data(pack); | error: all if blocks contain the same code at both the start and the end - --> $DIR/shared_at_top_and_bottom.rs:94:5 + --> $DIR/shared_at_top_and_bottom.rs:95:5 | LL | / let _ = if x == 7 { LL | | let _ = 19; | |___________________^ | note: this code is shared at the end - --> $DIR/shared_at_top_and_bottom.rs:103:5 + --> $DIR/shared_at_top_and_bottom.rs:104:5 | LL | / x << 2 LL | | }; @@ -127,14 +127,14 @@ LL ~ x << 2; | error: all if blocks contain the same code at both the start and the end - --> $DIR/shared_at_top_and_bottom.rs:106:5 + --> $DIR/shared_at_top_and_bottom.rs:107:5 | LL | / if x == 9 { LL | | let _ = 17; | |___________________^ | note: this code is shared at the end - --> $DIR/shared_at_top_and_bottom.rs:115:5 + --> $DIR/shared_at_top_and_bottom.rs:116:5 | LL | / x * 4 LL | | } diff --git a/tests/ui/branches_sharing_code/valid_if_blocks.rs b/tests/ui/branches_sharing_code/valid_if_blocks.rs index a26141be23733..2d6055eb6c422 100644 --- a/tests/ui/branches_sharing_code/valid_if_blocks.rs +++ b/tests/ui/branches_sharing_code/valid_if_blocks.rs @@ -1,5 +1,6 @@ -#![allow(dead_code, clippy::mixed_read_write_in_expression)] -#![deny(clippy::if_same_then_else, clippy::branches_sharing_code)] +#![deny(clippy::branches_sharing_code, clippy::if_same_then_else)] +#![allow(dead_code)] +#![allow(clippy::mixed_read_write_in_expression, clippy::uninlined_format_args)] // This tests valid if blocks that shouldn't trigger the lint diff --git a/tests/ui/branches_sharing_code/valid_if_blocks.stderr b/tests/ui/branches_sharing_code/valid_if_blocks.stderr index a815995e71721..95fee9efcfb5a 100644 --- a/tests/ui/branches_sharing_code/valid_if_blocks.stderr +++ b/tests/ui/branches_sharing_code/valid_if_blocks.stderr @@ -1,5 +1,5 @@ error: this `if` has identical blocks - --> $DIR/valid_if_blocks.rs:104:14 + --> $DIR/valid_if_blocks.rs:105:14 | LL | if false { | ______________^ @@ -7,12 +7,12 @@ LL | | } else { | |_____^ | note: the lint level is defined here - --> $DIR/valid_if_blocks.rs:2:9 + --> $DIR/valid_if_blocks.rs:1:40 | -LL | #![deny(clippy::if_same_then_else, clippy::branches_sharing_code)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![deny(clippy::branches_sharing_code, clippy::if_same_then_else)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: same as this - --> $DIR/valid_if_blocks.rs:105:12 + --> $DIR/valid_if_blocks.rs:106:12 | LL | } else { | ____________^ @@ -20,7 +20,7 @@ LL | | } | |_____^ error: this `if` has identical blocks - --> $DIR/valid_if_blocks.rs:115:15 + --> $DIR/valid_if_blocks.rs:116:15 | LL | if x == 0 { | _______________^ @@ -31,7 +31,7 @@ LL | | } else { | |_____^ | note: same as this - --> $DIR/valid_if_blocks.rs:119:12 + --> $DIR/valid_if_blocks.rs:120:12 | LL | } else { | ____________^ @@ -42,19 +42,19 @@ LL | | } | |_____^ error: this `if` has identical blocks - --> $DIR/valid_if_blocks.rs:126:23 + --> $DIR/valid_if_blocks.rs:127:23 | LL | let _ = if x == 6 { 7 } else { 7 }; | ^^^^^ | note: same as this - --> $DIR/valid_if_blocks.rs:126:34 + --> $DIR/valid_if_blocks.rs:127:34 | LL | let _ = if x == 6 { 7 } else { 7 }; | ^^^^^ error: this `if` has identical blocks - --> $DIR/valid_if_blocks.rs:132:23 + --> $DIR/valid_if_blocks.rs:133:23 | LL | } else if x == 68 { | _______________________^ @@ -66,7 +66,7 @@ LL | | } else { | |_____^ | note: same as this - --> $DIR/valid_if_blocks.rs:137:12 + --> $DIR/valid_if_blocks.rs:138:12 | LL | } else { | ____________^ @@ -78,7 +78,7 @@ LL | | }; | |_____^ error: this `if` has identical blocks - --> $DIR/valid_if_blocks.rs:146:23 + --> $DIR/valid_if_blocks.rs:147:23 | LL | } else if x == 68 { | _______________________^ @@ -88,7 +88,7 @@ LL | | } else { | |_____^ | note: same as this - --> $DIR/valid_if_blocks.rs:149:12 + --> $DIR/valid_if_blocks.rs:150:12 | LL | } else { | ____________^ diff --git a/tests/ui/cast_abs_to_unsigned.fixed b/tests/ui/cast_abs_to_unsigned.fixed index 7ecefd7b13439..a37f3fec20f1e 100644 --- a/tests/ui/cast_abs_to_unsigned.fixed +++ b/tests/ui/cast_abs_to_unsigned.fixed @@ -1,5 +1,6 @@ // run-rustfix #![warn(clippy::cast_abs_to_unsigned)] +#![allow(clippy::uninlined_format_args)] fn main() { let x: i32 = -42; diff --git a/tests/ui/cast_abs_to_unsigned.rs b/tests/ui/cast_abs_to_unsigned.rs index 30c603fca9a14..5706930af5a05 100644 --- a/tests/ui/cast_abs_to_unsigned.rs +++ b/tests/ui/cast_abs_to_unsigned.rs @@ -1,5 +1,6 @@ // run-rustfix #![warn(clippy::cast_abs_to_unsigned)] +#![allow(clippy::uninlined_format_args)] fn main() { let x: i32 = -42; diff --git a/tests/ui/cast_abs_to_unsigned.stderr b/tests/ui/cast_abs_to_unsigned.stderr index 0455377452676..7cea11c183d23 100644 --- a/tests/ui/cast_abs_to_unsigned.stderr +++ b/tests/ui/cast_abs_to_unsigned.stderr @@ -1,5 +1,5 @@ error: casting the result of `i32::abs()` to u32 - --> $DIR/cast_abs_to_unsigned.rs:6:18 + --> $DIR/cast_abs_to_unsigned.rs:7:18 | LL | let y: u32 = x.abs() as u32; | ^^^^^^^^^^^^^^ help: replace with: `x.unsigned_abs()` @@ -7,97 +7,97 @@ LL | let y: u32 = x.abs() as u32; = note: `-D clippy::cast-abs-to-unsigned` implied by `-D warnings` error: casting the result of `i32::abs()` to usize - --> $DIR/cast_abs_to_unsigned.rs:10:20 + --> $DIR/cast_abs_to_unsigned.rs:11:20 | LL | let _: usize = a.abs() as usize; | ^^^^^^^ help: replace with: `a.unsigned_abs()` error: casting the result of `i32::abs()` to usize - --> $DIR/cast_abs_to_unsigned.rs:11:20 + --> $DIR/cast_abs_to_unsigned.rs:12:20 | LL | let _: usize = a.abs() as _; | ^^^^^^^ help: replace with: `a.unsigned_abs()` error: casting the result of `i32::abs()` to usize - --> $DIR/cast_abs_to_unsigned.rs:12:13 + --> $DIR/cast_abs_to_unsigned.rs:13:13 | LL | let _ = a.abs() as usize; | ^^^^^^^ help: replace with: `a.unsigned_abs()` error: casting the result of `i64::abs()` to usize - --> $DIR/cast_abs_to_unsigned.rs:15:13 + --> $DIR/cast_abs_to_unsigned.rs:16:13 | LL | let _ = a.abs() as usize; | ^^^^^^^ help: replace with: `a.unsigned_abs()` error: casting the result of `i64::abs()` to u8 - --> $DIR/cast_abs_to_unsigned.rs:16:13 + --> $DIR/cast_abs_to_unsigned.rs:17:13 | LL | let _ = a.abs() as u8; | ^^^^^^^ help: replace with: `a.unsigned_abs()` error: casting the result of `i64::abs()` to u16 - --> $DIR/cast_abs_to_unsigned.rs:17:13 + --> $DIR/cast_abs_to_unsigned.rs:18:13 | LL | let _ = a.abs() as u16; | ^^^^^^^ help: replace with: `a.unsigned_abs()` error: casting the result of `i64::abs()` to u32 - --> $DIR/cast_abs_to_unsigned.rs:18:13 + --> $DIR/cast_abs_to_unsigned.rs:19:13 | LL | let _ = a.abs() as u32; | ^^^^^^^ help: replace with: `a.unsigned_abs()` error: casting the result of `i64::abs()` to u64 - --> $DIR/cast_abs_to_unsigned.rs:19:13 + --> $DIR/cast_abs_to_unsigned.rs:20:13 | LL | let _ = a.abs() as u64; | ^^^^^^^^^^^^^^ help: replace with: `a.unsigned_abs()` error: casting the result of `i64::abs()` to u128 - --> $DIR/cast_abs_to_unsigned.rs:20:13 + --> $DIR/cast_abs_to_unsigned.rs:21:13 | LL | let _ = a.abs() as u128; | ^^^^^^^ help: replace with: `a.unsigned_abs()` error: casting the result of `isize::abs()` to usize - --> $DIR/cast_abs_to_unsigned.rs:23:13 + --> $DIR/cast_abs_to_unsigned.rs:24:13 | LL | let _ = a.abs() as usize; | ^^^^^^^^^^^^^^^^ help: replace with: `a.unsigned_abs()` error: casting the result of `isize::abs()` to u8 - --> $DIR/cast_abs_to_unsigned.rs:24:13 + --> $DIR/cast_abs_to_unsigned.rs:25:13 | LL | let _ = a.abs() as u8; | ^^^^^^^ help: replace with: `a.unsigned_abs()` error: casting the result of `isize::abs()` to u16 - --> $DIR/cast_abs_to_unsigned.rs:25:13 + --> $DIR/cast_abs_to_unsigned.rs:26:13 | LL | let _ = a.abs() as u16; | ^^^^^^^ help: replace with: `a.unsigned_abs()` error: casting the result of `isize::abs()` to u32 - --> $DIR/cast_abs_to_unsigned.rs:26:13 + --> $DIR/cast_abs_to_unsigned.rs:27:13 | LL | let _ = a.abs() as u32; | ^^^^^^^ help: replace with: `a.unsigned_abs()` error: casting the result of `isize::abs()` to u64 - --> $DIR/cast_abs_to_unsigned.rs:27:13 + --> $DIR/cast_abs_to_unsigned.rs:28:13 | LL | let _ = a.abs() as u64; | ^^^^^^^ help: replace with: `a.unsigned_abs()` error: casting the result of `isize::abs()` to u128 - --> $DIR/cast_abs_to_unsigned.rs:28:13 + --> $DIR/cast_abs_to_unsigned.rs:29:13 | LL | let _ = a.abs() as u128; | ^^^^^^^ help: replace with: `a.unsigned_abs()` error: casting the result of `i64::abs()` to u32 - --> $DIR/cast_abs_to_unsigned.rs:30:13 + --> $DIR/cast_abs_to_unsigned.rs:31:13 | LL | let _ = (x as i64 - y as i64).abs() as u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `(x as i64 - y as i64).unsigned_abs()` diff --git a/tests/ui/collapsible_match.rs b/tests/ui/collapsible_match.rs index 603ae7dc9eb11..7d53e08345d30 100644 --- a/tests/ui/collapsible_match.rs +++ b/tests/ui/collapsible_match.rs @@ -1,9 +1,10 @@ #![warn(clippy::collapsible_match)] #![allow( + clippy::equatable_if_let, clippy::needless_return, clippy::no_effect, clippy::single_match, - clippy::equatable_if_let + clippy::uninlined_format_args )] fn lint_cases(opt_opt: Option>, res_opt: Result, String>) { diff --git a/tests/ui/collapsible_match.stderr b/tests/ui/collapsible_match.stderr index 5f18b69350295..ba2b2e777a10c 100644 --- a/tests/ui/collapsible_match.stderr +++ b/tests/ui/collapsible_match.stderr @@ -1,5 +1,5 @@ error: this `match` can be collapsed into the outer `match` - --> $DIR/collapsible_match.rs:12:20 + --> $DIR/collapsible_match.rs:13:20 | LL | Ok(val) => match val { | ____________________^ @@ -10,7 +10,7 @@ LL | | }, | = note: `-D clippy::collapsible-match` implied by `-D warnings` help: the outer pattern can be modified to include the inner pattern - --> $DIR/collapsible_match.rs:12:12 + --> $DIR/collapsible_match.rs:13:12 | LL | Ok(val) => match val { | ^^^ replace this binding @@ -18,7 +18,7 @@ LL | Some(n) => foo(n), | ^^^^^^^ with this pattern error: this `match` can be collapsed into the outer `match` - --> $DIR/collapsible_match.rs:21:20 + --> $DIR/collapsible_match.rs:22:20 | LL | Ok(val) => match val { | ____________________^ @@ -28,7 +28,7 @@ LL | | }, | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> $DIR/collapsible_match.rs:21:12 + --> $DIR/collapsible_match.rs:22:12 | LL | Ok(val) => match val { | ^^^ replace this binding @@ -36,7 +36,7 @@ LL | Some(n) => foo(n), | ^^^^^^^ with this pattern error: this `if let` can be collapsed into the outer `if let` - --> $DIR/collapsible_match.rs:30:9 + --> $DIR/collapsible_match.rs:31:9 | LL | / if let Some(n) = val { LL | | take(n); @@ -44,7 +44,7 @@ LL | | } | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> $DIR/collapsible_match.rs:29:15 + --> $DIR/collapsible_match.rs:30:15 | LL | if let Ok(val) = res_opt { | ^^^ replace this binding @@ -52,7 +52,7 @@ LL | if let Some(n) = val { | ^^^^^^^ with this pattern error: this `if let` can be collapsed into the outer `if let` - --> $DIR/collapsible_match.rs:37:9 + --> $DIR/collapsible_match.rs:38:9 | LL | / if let Some(n) = val { LL | | take(n); @@ -62,7 +62,7 @@ LL | | } | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> $DIR/collapsible_match.rs:36:15 + --> $DIR/collapsible_match.rs:37:15 | LL | if let Ok(val) = res_opt { | ^^^ replace this binding @@ -70,7 +70,7 @@ LL | if let Some(n) = val { | ^^^^^^^ with this pattern error: this `match` can be collapsed into the outer `if let` - --> $DIR/collapsible_match.rs:48:9 + --> $DIR/collapsible_match.rs:49:9 | LL | / match val { LL | | Some(n) => foo(n), @@ -79,7 +79,7 @@ LL | | } | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> $DIR/collapsible_match.rs:47:15 + --> $DIR/collapsible_match.rs:48:15 | LL | if let Ok(val) = res_opt { | ^^^ replace this binding @@ -88,7 +88,7 @@ LL | Some(n) => foo(n), | ^^^^^^^ with this pattern error: this `if let` can be collapsed into the outer `match` - --> $DIR/collapsible_match.rs:57:13 + --> $DIR/collapsible_match.rs:58:13 | LL | / if let Some(n) = val { LL | | take(n); @@ -96,7 +96,7 @@ LL | | } | |_____________^ | help: the outer pattern can be modified to include the inner pattern - --> $DIR/collapsible_match.rs:56:12 + --> $DIR/collapsible_match.rs:57:12 | LL | Ok(val) => { | ^^^ replace this binding @@ -104,7 +104,7 @@ LL | if let Some(n) = val { | ^^^^^^^ with this pattern error: this `match` can be collapsed into the outer `if let` - --> $DIR/collapsible_match.rs:66:9 + --> $DIR/collapsible_match.rs:67:9 | LL | / match val { LL | | Some(n) => foo(n), @@ -113,7 +113,7 @@ LL | | } | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> $DIR/collapsible_match.rs:65:15 + --> $DIR/collapsible_match.rs:66:15 | LL | if let Ok(val) = res_opt { | ^^^ replace this binding @@ -122,7 +122,7 @@ LL | Some(n) => foo(n), | ^^^^^^^ with this pattern error: this `if let` can be collapsed into the outer `match` - --> $DIR/collapsible_match.rs:77:13 + --> $DIR/collapsible_match.rs:78:13 | LL | / if let Some(n) = val { LL | | take(n); @@ -132,7 +132,7 @@ LL | | } | |_____________^ | help: the outer pattern can be modified to include the inner pattern - --> $DIR/collapsible_match.rs:76:12 + --> $DIR/collapsible_match.rs:77:12 | LL | Ok(val) => { | ^^^ replace this binding @@ -140,7 +140,7 @@ LL | if let Some(n) = val { | ^^^^^^^ with this pattern error: this `match` can be collapsed into the outer `match` - --> $DIR/collapsible_match.rs:88:20 + --> $DIR/collapsible_match.rs:89:20 | LL | Ok(val) => match val { | ____________________^ @@ -150,7 +150,7 @@ LL | | }, | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> $DIR/collapsible_match.rs:88:12 + --> $DIR/collapsible_match.rs:89:12 | LL | Ok(val) => match val { | ^^^ replace this binding @@ -158,7 +158,7 @@ LL | Some(n) => foo(n), | ^^^^^^^ with this pattern error: this `match` can be collapsed into the outer `match` - --> $DIR/collapsible_match.rs:97:22 + --> $DIR/collapsible_match.rs:98:22 | LL | Some(val) => match val { | ______________________^ @@ -168,7 +168,7 @@ LL | | }, | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> $DIR/collapsible_match.rs:97:14 + --> $DIR/collapsible_match.rs:98:14 | LL | Some(val) => match val { | ^^^ replace this binding diff --git a/tests/ui/crashes/ice-4775.rs b/tests/ui/crashes/ice-4775.rs index 405e3039e7d0c..f693aafd1cbb6 100644 --- a/tests/ui/crashes/ice-4775.rs +++ b/tests/ui/crashes/ice-4775.rs @@ -1,3 +1,5 @@ +#![allow(clippy::uninlined_format_args)] + pub struct ArrayWrapper([usize; N]); impl ArrayWrapper<{ N }> { diff --git a/tests/ui/crashes/regressions.rs b/tests/ui/crashes/regressions.rs index 55a8b403407cd..b34997d4ee0ba 100644 --- a/tests/ui/crashes/regressions.rs +++ b/tests/ui/crashes/regressions.rs @@ -1,4 +1,4 @@ -#![allow(clippy::disallowed_names)] +#![allow(clippy::disallowed_names, clippy::uninlined_format_args)] pub fn foo(bar: *const u8) { println!("{:#p}", bar); diff --git a/tests/ui/default_trait_access.fixed b/tests/ui/default_trait_access.fixed index fce66eb175963..eedd43619392d 100644 --- a/tests/ui/default_trait_access.fixed +++ b/tests/ui/default_trait_access.fixed @@ -1,8 +1,8 @@ // run-rustfix // aux-build: proc_macro_with_span.rs - -#![allow(unused_imports, dead_code)] #![deny(clippy::default_trait_access)] +#![allow(dead_code, unused_imports)] +#![allow(clippy::uninlined_format_args)] extern crate proc_macro_with_span; diff --git a/tests/ui/default_trait_access.rs b/tests/ui/default_trait_access.rs index 3e8e898b7bc61..11d4bc5c5f022 100644 --- a/tests/ui/default_trait_access.rs +++ b/tests/ui/default_trait_access.rs @@ -1,8 +1,8 @@ // run-rustfix // aux-build: proc_macro_with_span.rs - -#![allow(unused_imports, dead_code)] #![deny(clippy::default_trait_access)] +#![allow(dead_code, unused_imports)] +#![allow(clippy::uninlined_format_args)] extern crate proc_macro_with_span; diff --git a/tests/ui/default_trait_access.stderr b/tests/ui/default_trait_access.stderr index 3493de37a55be..49b2dde3f1e8c 100644 --- a/tests/ui/default_trait_access.stderr +++ b/tests/ui/default_trait_access.stderr @@ -5,7 +5,7 @@ LL | let s1: String = Default::default(); | ^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()` | note: the lint level is defined here - --> $DIR/default_trait_access.rs:5:9 + --> $DIR/default_trait_access.rs:3:9 | LL | #![deny(clippy::default_trait_access)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/eta.fixed b/tests/ui/eta.fixed index e257b3b3afa6f..a9cc80aaaf623 100644 --- a/tests/ui/eta.fixed +++ b/tests/ui/eta.fixed @@ -1,14 +1,14 @@ // run-rustfix - +#![warn(clippy::redundant_closure, clippy::redundant_closure_for_method_calls)] +#![allow(unused)] #![allow( - unused, - clippy::no_effect, - clippy::redundant_closure_call, + clippy::needless_borrow, clippy::needless_pass_by_value, + clippy::no_effect, clippy::option_map_unit_fn, - clippy::needless_borrow + clippy::redundant_closure_call, + clippy::uninlined_format_args )] -#![warn(clippy::redundant_closure, clippy::redundant_closure_for_method_calls)] use std::path::{Path, PathBuf}; diff --git a/tests/ui/eta.rs b/tests/ui/eta.rs index 486a251f30b0e..cc99906ccd667 100644 --- a/tests/ui/eta.rs +++ b/tests/ui/eta.rs @@ -1,14 +1,14 @@ // run-rustfix - +#![warn(clippy::redundant_closure, clippy::redundant_closure_for_method_calls)] +#![allow(unused)] #![allow( - unused, - clippy::no_effect, - clippy::redundant_closure_call, + clippy::needless_borrow, clippy::needless_pass_by_value, + clippy::no_effect, clippy::option_map_unit_fn, - clippy::needless_borrow + clippy::redundant_closure_call, + clippy::uninlined_format_args )] -#![warn(clippy::redundant_closure, clippy::redundant_closure_for_method_calls)] use std::path::{Path, PathBuf}; diff --git a/tests/ui/expect_fun_call.fixed b/tests/ui/expect_fun_call.fixed index 53e45d28bded9..c118403b77320 100644 --- a/tests/ui/expect_fun_call.fixed +++ b/tests/ui/expect_fun_call.fixed @@ -1,7 +1,6 @@ // run-rustfix - #![warn(clippy::expect_fun_call)] -#![allow(clippy::to_string_in_format_args)] +#![allow(clippy::to_string_in_format_args, clippy::uninlined_format_args)] /// Checks implementation of the `EXPECT_FUN_CALL` lint diff --git a/tests/ui/expect_fun_call.rs b/tests/ui/expect_fun_call.rs index 22e530b80349d..7f4a8bc7aa68d 100644 --- a/tests/ui/expect_fun_call.rs +++ b/tests/ui/expect_fun_call.rs @@ -1,7 +1,6 @@ // run-rustfix - #![warn(clippy::expect_fun_call)] -#![allow(clippy::to_string_in_format_args)] +#![allow(clippy::to_string_in_format_args, clippy::uninlined_format_args)] /// Checks implementation of the `EXPECT_FUN_CALL` lint diff --git a/tests/ui/expect_fun_call.stderr b/tests/ui/expect_fun_call.stderr index aca15935fca06..e76c03ecf16ef 100644 --- a/tests/ui/expect_fun_call.stderr +++ b/tests/ui/expect_fun_call.stderr @@ -1,5 +1,5 @@ error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:35:26 + --> $DIR/expect_fun_call.rs:34:26 | LL | with_none_and_format.expect(&format!("Error {}: fake error", error_code)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("Error {}: fake error", error_code))` @@ -7,73 +7,73 @@ LL | with_none_and_format.expect(&format!("Error {}: fake error", error_code = note: `-D clippy::expect-fun-call` implied by `-D warnings` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:38:26 + --> $DIR/expect_fun_call.rs:37:26 | LL | with_none_and_as_str.expect(format!("Error {}: fake error", error_code).as_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("Error {}: fake error", error_code))` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:41:37 + --> $DIR/expect_fun_call.rs:40:37 | LL | with_none_and_format_with_macro.expect(format!("Error {}: fake error", one!()).as_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("Error {}: fake error", one!()))` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:51:25 + --> $DIR/expect_fun_call.rs:50:25 | LL | with_err_and_format.expect(&format!("Error {}: fake error", error_code)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| panic!("Error {}: fake error", error_code))` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:54:25 + --> $DIR/expect_fun_call.rs:53:25 | LL | with_err_and_as_str.expect(format!("Error {}: fake error", error_code).as_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| panic!("Error {}: fake error", error_code))` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:66:17 + --> $DIR/expect_fun_call.rs:65:17 | LL | Some("foo").expect(format!("{} {}", 1, 2).as_ref()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("{} {}", 1, 2))` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:87:21 + --> $DIR/expect_fun_call.rs:86:21 | LL | Some("foo").expect(&get_string()); | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_string()) })` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:88:21 + --> $DIR/expect_fun_call.rs:87:21 | LL | Some("foo").expect(get_string().as_ref()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_string()) })` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:89:21 + --> $DIR/expect_fun_call.rs:88:21 | LL | Some("foo").expect(get_string().as_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_string()) })` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:91:21 + --> $DIR/expect_fun_call.rs:90:21 | LL | Some("foo").expect(get_static_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_static_str()) })` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:92:21 + --> $DIR/expect_fun_call.rs:91:21 | LL | Some("foo").expect(get_non_static_str(&0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_non_static_str(&0).to_string()) })` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:96:16 + --> $DIR/expect_fun_call.rs:95:16 | LL | Some(true).expect(&format!("key {}, {}", 1, 2)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("key {}, {}", 1, 2))` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:102:17 + --> $DIR/expect_fun_call.rs:101:17 | LL | opt_ref.expect(&format!("{:?}", opt_ref)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("{:?}", opt_ref))` diff --git a/tests/ui/explicit_counter_loop.rs b/tests/ui/explicit_counter_loop.rs index aa966761febdf..6eddc01e2c471 100644 --- a/tests/ui/explicit_counter_loop.rs +++ b/tests/ui/explicit_counter_loop.rs @@ -1,4 +1,5 @@ #![warn(clippy::explicit_counter_loop)] +#![allow(clippy::uninlined_format_args)] fn main() { let mut vec = vec![1, 2, 3, 4]; diff --git a/tests/ui/explicit_counter_loop.stderr b/tests/ui/explicit_counter_loop.stderr index f9f8407d57755..d3f3c626bbdfd 100644 --- a/tests/ui/explicit_counter_loop.stderr +++ b/tests/ui/explicit_counter_loop.stderr @@ -1,5 +1,5 @@ error: the variable `_index` is used as a loop counter - --> $DIR/explicit_counter_loop.rs:6:5 + --> $DIR/explicit_counter_loop.rs:7:5 | LL | for _v in &vec { | ^^^^^^^^^^^^^^ help: consider using: `for (_index, _v) in vec.iter().enumerate()` @@ -7,49 +7,49 @@ LL | for _v in &vec { = note: `-D clippy::explicit-counter-loop` implied by `-D warnings` error: the variable `_index` is used as a loop counter - --> $DIR/explicit_counter_loop.rs:12:5 + --> $DIR/explicit_counter_loop.rs:13:5 | LL | for _v in &vec { | ^^^^^^^^^^^^^^ help: consider using: `for (_index, _v) in vec.iter().enumerate()` error: the variable `_index` is used as a loop counter - --> $DIR/explicit_counter_loop.rs:17:5 + --> $DIR/explicit_counter_loop.rs:18:5 | LL | for _v in &mut vec { | ^^^^^^^^^^^^^^^^^^ help: consider using: `for (_index, _v) in vec.iter_mut().enumerate()` error: the variable `_index` is used as a loop counter - --> $DIR/explicit_counter_loop.rs:22:5 + --> $DIR/explicit_counter_loop.rs:23:5 | LL | for _v in vec { | ^^^^^^^^^^^^^ help: consider using: `for (_index, _v) in vec.into_iter().enumerate()` error: the variable `count` is used as a loop counter - --> $DIR/explicit_counter_loop.rs:61:9 + --> $DIR/explicit_counter_loop.rs:62:9 | LL | for ch in text.chars() { | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `for (count, ch) in text.chars().enumerate()` error: the variable `count` is used as a loop counter - --> $DIR/explicit_counter_loop.rs:72:9 + --> $DIR/explicit_counter_loop.rs:73:9 | LL | for ch in text.chars() { | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `for (count, ch) in text.chars().enumerate()` error: the variable `count` is used as a loop counter - --> $DIR/explicit_counter_loop.rs:130:9 + --> $DIR/explicit_counter_loop.rs:131:9 | LL | for _i in 3..10 { | ^^^^^^^^^^^^^^^ help: consider using: `for (count, _i) in (3..10).enumerate()` error: the variable `idx_usize` is used as a loop counter - --> $DIR/explicit_counter_loop.rs:170:9 + --> $DIR/explicit_counter_loop.rs:171:9 | LL | for _item in slice { | ^^^^^^^^^^^^^^^^^^ help: consider using: `for (idx_usize, _item) in slice.iter().enumerate()` error: the variable `idx_u32` is used as a loop counter - --> $DIR/explicit_counter_loop.rs:182:9 + --> $DIR/explicit_counter_loop.rs:183:9 | LL | for _item in slice { | ^^^^^^^^^^^^^^^^^^ help: consider using: `for (idx_u32, _item) in (0_u32..).zip(slice.iter())` diff --git a/tests/ui/explicit_deref_methods.fixed b/tests/ui/explicit_deref_methods.fixed index 523cae183ee6e..6d32bbece1e57 100644 --- a/tests/ui/explicit_deref_methods.fixed +++ b/tests/ui/explicit_deref_methods.fixed @@ -1,13 +1,13 @@ // run-rustfix - +#![warn(clippy::explicit_deref_methods)] +#![allow(unused_variables)] #![allow( - unused_variables, + clippy::borrow_deref_ref, clippy::clone_double_ref, + clippy::explicit_auto_deref, clippy::needless_borrow, - clippy::borrow_deref_ref, - clippy::explicit_auto_deref + clippy::uninlined_format_args )] -#![warn(clippy::explicit_deref_methods)] use std::ops::{Deref, DerefMut}; diff --git a/tests/ui/explicit_deref_methods.rs b/tests/ui/explicit_deref_methods.rs index 0bbc1ae57cdf6..779909e42380c 100644 --- a/tests/ui/explicit_deref_methods.rs +++ b/tests/ui/explicit_deref_methods.rs @@ -1,13 +1,13 @@ // run-rustfix - +#![warn(clippy::explicit_deref_methods)] +#![allow(unused_variables)] #![allow( - unused_variables, + clippy::borrow_deref_ref, clippy::clone_double_ref, + clippy::explicit_auto_deref, clippy::needless_borrow, - clippy::borrow_deref_ref, - clippy::explicit_auto_deref + clippy::uninlined_format_args )] -#![warn(clippy::explicit_deref_methods)] use std::ops::{Deref, DerefMut}; diff --git a/tests/ui/explicit_write.fixed b/tests/ui/explicit_write.fixed index 35283725619ae..862c3fea9ee82 100644 --- a/tests/ui/explicit_write.fixed +++ b/tests/ui/explicit_write.fixed @@ -1,6 +1,7 @@ // run-rustfix -#![allow(unused_imports)] #![warn(clippy::explicit_write)] +#![allow(unused_imports)] +#![allow(clippy::uninlined_format_args)] fn stdout() -> String { String::new() diff --git a/tests/ui/explicit_write.rs b/tests/ui/explicit_write.rs index be864a55b663f..41d7c2255738c 100644 --- a/tests/ui/explicit_write.rs +++ b/tests/ui/explicit_write.rs @@ -1,6 +1,7 @@ // run-rustfix -#![allow(unused_imports)] #![warn(clippy::explicit_write)] +#![allow(unused_imports)] +#![allow(clippy::uninlined_format_args)] fn stdout() -> String { String::new() diff --git a/tests/ui/explicit_write.stderr b/tests/ui/explicit_write.stderr index ff05f4343d77d..457e9c6271809 100644 --- a/tests/ui/explicit_write.stderr +++ b/tests/ui/explicit_write.stderr @@ -1,5 +1,5 @@ error: use of `write!(stdout(), ...).unwrap()` - --> $DIR/explicit_write.rs:23:9 + --> $DIR/explicit_write.rs:24:9 | LL | write!(std::io::stdout(), "test").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `print!("test")` @@ -7,73 +7,73 @@ LL | write!(std::io::stdout(), "test").unwrap(); = note: `-D clippy::explicit-write` implied by `-D warnings` error: use of `write!(stderr(), ...).unwrap()` - --> $DIR/explicit_write.rs:24:9 + --> $DIR/explicit_write.rs:25:9 | LL | write!(std::io::stderr(), "test").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprint!("test")` error: use of `writeln!(stdout(), ...).unwrap()` - --> $DIR/explicit_write.rs:25:9 + --> $DIR/explicit_write.rs:26:9 | LL | writeln!(std::io::stdout(), "test").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `println!("test")` error: use of `writeln!(stderr(), ...).unwrap()` - --> $DIR/explicit_write.rs:26:9 + --> $DIR/explicit_write.rs:27:9 | LL | writeln!(std::io::stderr(), "test").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprintln!("test")` error: use of `stdout().write_fmt(...).unwrap()` - --> $DIR/explicit_write.rs:27:9 + --> $DIR/explicit_write.rs:28:9 | LL | std::io::stdout().write_fmt(format_args!("test")).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `print!("test")` error: use of `stderr().write_fmt(...).unwrap()` - --> $DIR/explicit_write.rs:28:9 + --> $DIR/explicit_write.rs:29:9 | LL | std::io::stderr().write_fmt(format_args!("test")).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprint!("test")` error: use of `writeln!(stdout(), ...).unwrap()` - --> $DIR/explicit_write.rs:31:9 + --> $DIR/explicit_write.rs:32:9 | LL | writeln!(std::io::stdout(), "test/ntest").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `println!("test/ntest")` error: use of `writeln!(stderr(), ...).unwrap()` - --> $DIR/explicit_write.rs:32:9 + --> $DIR/explicit_write.rs:33:9 | LL | writeln!(std::io::stderr(), "test/ntest").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprintln!("test/ntest")` error: use of `writeln!(stderr(), ...).unwrap()` - --> $DIR/explicit_write.rs:35:9 + --> $DIR/explicit_write.rs:36:9 | LL | writeln!(std::io::stderr(), "with {}", value).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprintln!("with {}", value)` error: use of `writeln!(stderr(), ...).unwrap()` - --> $DIR/explicit_write.rs:36:9 + --> $DIR/explicit_write.rs:37:9 | LL | writeln!(std::io::stderr(), "with {} {}", 2, value).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprintln!("with {} {}", 2, value)` error: use of `writeln!(stderr(), ...).unwrap()` - --> $DIR/explicit_write.rs:37:9 + --> $DIR/explicit_write.rs:38:9 | LL | writeln!(std::io::stderr(), "with {value}").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprintln!("with {value}")` error: use of `writeln!(stderr(), ...).unwrap()` - --> $DIR/explicit_write.rs:38:9 + --> $DIR/explicit_write.rs:39:9 | LL | writeln!(std::io::stderr(), "macro arg {}", one!()).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprintln!("macro arg {}", one!())` error: use of `writeln!(stderr(), ...).unwrap()` - --> $DIR/explicit_write.rs:40:9 + --> $DIR/explicit_write.rs:41:9 | LL | writeln!(std::io::stderr(), "{:w$}", value, w = width).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprintln!("{:w$}", value, w = width)` diff --git a/tests/ui/fallible_impl_from.rs b/tests/ui/fallible_impl_from.rs index 5d5af4e463297..fb6e8ec706b17 100644 --- a/tests/ui/fallible_impl_from.rs +++ b/tests/ui/fallible_impl_from.rs @@ -1,4 +1,5 @@ #![deny(clippy::fallible_impl_from)] +#![allow(clippy::uninlined_format_args)] // docs example struct Foo(i32); diff --git a/tests/ui/fallible_impl_from.stderr b/tests/ui/fallible_impl_from.stderr index d637dbce5d792..47bdd4e84c839 100644 --- a/tests/ui/fallible_impl_from.stderr +++ b/tests/ui/fallible_impl_from.stderr @@ -1,5 +1,5 @@ error: consider implementing `TryFrom` instead - --> $DIR/fallible_impl_from.rs:5:1 + --> $DIR/fallible_impl_from.rs:6:1 | LL | / impl From for Foo { LL | | fn from(s: String) -> Self { @@ -15,13 +15,13 @@ LL | #![deny(clippy::fallible_impl_from)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail note: potential failure(s) - --> $DIR/fallible_impl_from.rs:7:13 + --> $DIR/fallible_impl_from.rs:8:13 | LL | Foo(s.parse().unwrap()) | ^^^^^^^^^^^^^^^^^^ error: consider implementing `TryFrom` instead - --> $DIR/fallible_impl_from.rs:26:1 + --> $DIR/fallible_impl_from.rs:27:1 | LL | / impl From for Invalid { LL | | fn from(i: usize) -> Invalid { @@ -34,14 +34,14 @@ LL | | } | = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail note: potential failure(s) - --> $DIR/fallible_impl_from.rs:29:13 + --> $DIR/fallible_impl_from.rs:30:13 | LL | panic!(); | ^^^^^^^^ = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) error: consider implementing `TryFrom` instead - --> $DIR/fallible_impl_from.rs:35:1 + --> $DIR/fallible_impl_from.rs:36:1 | LL | / impl From> for Invalid { LL | | fn from(s: Option) -> Invalid { @@ -54,7 +54,7 @@ LL | | } | = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail note: potential failure(s) - --> $DIR/fallible_impl_from.rs:37:17 + --> $DIR/fallible_impl_from.rs:38:17 | LL | let s = s.unwrap(); | ^^^^^^^^^^ @@ -68,7 +68,7 @@ LL | panic!("{:?}", s); = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) error: consider implementing `TryFrom` instead - --> $DIR/fallible_impl_from.rs:53:1 + --> $DIR/fallible_impl_from.rs:54:1 | LL | / impl<'a> From<&'a mut as ProjStrTrait>::ProjString> for Invalid { LL | | fn from(s: &'a mut as ProjStrTrait>::ProjString) -> Invalid { @@ -81,7 +81,7 @@ LL | | } | = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail note: potential failure(s) - --> $DIR/fallible_impl_from.rs:55:12 + --> $DIR/fallible_impl_from.rs:56:12 | LL | if s.parse::().ok().unwrap() != 42 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/for_loop_fixable.fixed b/tests/ui/for_loop_fixable.fixed index aa69781d15a6b..e9dd38fe40e65 100644 --- a/tests/ui/for_loop_fixable.fixed +++ b/tests/ui/for_loop_fixable.fixed @@ -1,6 +1,6 @@ // run-rustfix - #![allow(dead_code, unused)] +#![allow(clippy::uninlined_format_args)] use std::collections::*; diff --git a/tests/ui/for_loop_fixable.rs b/tests/ui/for_loop_fixable.rs index 7c063d99511d8..534fb4dd4ef28 100644 --- a/tests/ui/for_loop_fixable.rs +++ b/tests/ui/for_loop_fixable.rs @@ -1,6 +1,6 @@ // run-rustfix - #![allow(dead_code, unused)] +#![allow(clippy::uninlined_format_args)] use std::collections::*; diff --git a/tests/ui/for_loops_over_fallibles.rs b/tests/ui/for_loops_over_fallibles.rs index 3390111d0a8fe..4b2a9297d084e 100644 --- a/tests/ui/for_loops_over_fallibles.rs +++ b/tests/ui/for_loops_over_fallibles.rs @@ -1,4 +1,5 @@ #![warn(clippy::for_loops_over_fallibles)] +#![allow(clippy::uninlined_format_args)] fn for_loops_over_fallibles() { let option = Some(1); diff --git a/tests/ui/for_loops_over_fallibles.stderr b/tests/ui/for_loops_over_fallibles.stderr index 8c8c022243aeb..5f5a81d24cfde 100644 --- a/tests/ui/for_loops_over_fallibles.stderr +++ b/tests/ui/for_loops_over_fallibles.stderr @@ -1,5 +1,5 @@ error: for loop over `option`, which is an `Option`. This is more readably written as an `if let` statement - --> $DIR/for_loops_over_fallibles.rs:9:14 + --> $DIR/for_loops_over_fallibles.rs:10:14 | LL | for x in option { | ^^^^^^ @@ -8,7 +8,7 @@ LL | for x in option { = help: consider replacing `for x in option` with `if let Some(x) = option` error: for loop over `option`, which is an `Option`. This is more readably written as an `if let` statement - --> $DIR/for_loops_over_fallibles.rs:14:14 + --> $DIR/for_loops_over_fallibles.rs:15:14 | LL | for x in option.iter() { | ^^^^^^ @@ -16,7 +16,7 @@ LL | for x in option.iter() { = help: consider replacing `for x in option.iter()` with `if let Some(x) = option` error: for loop over `result`, which is a `Result`. This is more readably written as an `if let` statement - --> $DIR/for_loops_over_fallibles.rs:19:14 + --> $DIR/for_loops_over_fallibles.rs:20:14 | LL | for x in result { | ^^^^^^ @@ -24,7 +24,7 @@ LL | for x in result { = help: consider replacing `for x in result` with `if let Ok(x) = result` error: for loop over `result`, which is a `Result`. This is more readably written as an `if let` statement - --> $DIR/for_loops_over_fallibles.rs:24:14 + --> $DIR/for_loops_over_fallibles.rs:25:14 | LL | for x in result.iter_mut() { | ^^^^^^ @@ -32,7 +32,7 @@ LL | for x in result.iter_mut() { = help: consider replacing `for x in result.iter_mut()` with `if let Ok(x) = result` error: for loop over `result`, which is a `Result`. This is more readably written as an `if let` statement - --> $DIR/for_loops_over_fallibles.rs:29:14 + --> $DIR/for_loops_over_fallibles.rs:30:14 | LL | for x in result.into_iter() { | ^^^^^^ @@ -40,7 +40,7 @@ LL | for x in result.into_iter() { = help: consider replacing `for x in result.into_iter()` with `if let Ok(x) = result` error: for loop over `option.ok_or("x not found")`, which is a `Result`. This is more readably written as an `if let` statement - --> $DIR/for_loops_over_fallibles.rs:33:14 + --> $DIR/for_loops_over_fallibles.rs:34:14 | LL | for x in option.ok_or("x not found") { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -48,7 +48,7 @@ LL | for x in option.ok_or("x not found") { = help: consider replacing `for x in option.ok_or("x not found")` with `if let Ok(x) = option.ok_or("x not found")` error: you are iterating over `Iterator::next()` which is an Option; this will compile but is probably not what you want - --> $DIR/for_loops_over_fallibles.rs:39:14 + --> $DIR/for_loops_over_fallibles.rs:40:14 | LL | for x in v.iter().next() { | ^^^^^^^^^^^^^^^ @@ -56,7 +56,7 @@ LL | for x in v.iter().next() { = note: `#[deny(clippy::iter_next_loop)]` on by default error: for loop over `v.iter().next().and(Some(0))`, which is an `Option`. This is more readably written as an `if let` statement - --> $DIR/for_loops_over_fallibles.rs:44:14 + --> $DIR/for_loops_over_fallibles.rs:45:14 | LL | for x in v.iter().next().and(Some(0)) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -64,7 +64,7 @@ LL | for x in v.iter().next().and(Some(0)) { = help: consider replacing `for x in v.iter().next().and(Some(0))` with `if let Some(x) = v.iter().next().and(Some(0))` error: for loop over `v.iter().next().ok_or("x not found")`, which is a `Result`. This is more readably written as an `if let` statement - --> $DIR/for_loops_over_fallibles.rs:48:14 + --> $DIR/for_loops_over_fallibles.rs:49:14 | LL | for x in v.iter().next().ok_or("x not found") { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -72,7 +72,7 @@ LL | for x in v.iter().next().ok_or("x not found") { = help: consider replacing `for x in v.iter().next().ok_or("x not found")` with `if let Ok(x) = v.iter().next().ok_or("x not found")` error: this loop never actually loops - --> $DIR/for_loops_over_fallibles.rs:60:5 + --> $DIR/for_loops_over_fallibles.rs:61:5 | LL | / while let Some(x) = option { LL | | println!("{}", x); @@ -83,7 +83,7 @@ LL | | } = note: `#[deny(clippy::never_loop)]` on by default error: this loop never actually loops - --> $DIR/for_loops_over_fallibles.rs:66:5 + --> $DIR/for_loops_over_fallibles.rs:67:5 | LL | / while let Ok(x) = result { LL | | println!("{}", x); diff --git a/tests/ui/format.fixed b/tests/ui/format.fixed index e0c5f692740a1..beedf2c1db292 100644 --- a/tests/ui/format.fixed +++ b/tests/ui/format.fixed @@ -1,13 +1,13 @@ // run-rustfix - +#![warn(clippy::useless_format)] #![allow( unused_tuple_struct_fields, clippy::print_literal, clippy::redundant_clone, clippy::to_string_in_format_args, - clippy::needless_borrow + clippy::needless_borrow, + clippy::uninlined_format_args )] -#![warn(clippy::useless_format)] struct Foo(pub String); diff --git a/tests/ui/format.rs b/tests/ui/format.rs index ff83cd64bf09c..e805f18188989 100644 --- a/tests/ui/format.rs +++ b/tests/ui/format.rs @@ -1,13 +1,13 @@ // run-rustfix - +#![warn(clippy::useless_format)] #![allow( unused_tuple_struct_fields, clippy::print_literal, clippy::redundant_clone, clippy::to_string_in_format_args, - clippy::needless_borrow + clippy::needless_borrow, + clippy::uninlined_format_args )] -#![warn(clippy::useless_format)] struct Foo(pub String); diff --git a/tests/ui/format_args.fixed b/tests/ui/format_args.fixed index e1c2d4d70be4f..24cf0847dd588 100644 --- a/tests/ui/format_args.fixed +++ b/tests/ui/format_args.fixed @@ -1,10 +1,12 @@ // run-rustfix - -#![allow(unused)] -#![allow(clippy::assertions_on_constants)] -#![allow(clippy::eq_op)] -#![allow(clippy::print_literal)] #![warn(clippy::to_string_in_format_args)] +#![allow(unused)] +#![allow( + clippy::assertions_on_constants, + clippy::eq_op, + clippy::print_literal, + clippy::uninlined_format_args +)] use std::io::{stdout, Write}; use std::ops::Deref; diff --git a/tests/ui/format_args.rs b/tests/ui/format_args.rs index b9a4d66c28ad9..753babf0afdc7 100644 --- a/tests/ui/format_args.rs +++ b/tests/ui/format_args.rs @@ -1,10 +1,12 @@ // run-rustfix - -#![allow(unused)] -#![allow(clippy::assertions_on_constants)] -#![allow(clippy::eq_op)] -#![allow(clippy::print_literal)] #![warn(clippy::to_string_in_format_args)] +#![allow(unused)] +#![allow( + clippy::assertions_on_constants, + clippy::eq_op, + clippy::print_literal, + clippy::uninlined_format_args +)] use std::io::{stdout, Write}; use std::ops::Deref; diff --git a/tests/ui/format_args.stderr b/tests/ui/format_args.stderr index aa6e3659b43b5..68b0bb9e089e1 100644 --- a/tests/ui/format_args.stderr +++ b/tests/ui/format_args.stderr @@ -1,5 +1,5 @@ error: `to_string` applied to a type that implements `Display` in `format!` args - --> $DIR/format_args.rs:74:72 + --> $DIR/format_args.rs:76:72 | LL | let _ = format!("error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this @@ -7,133 +7,133 @@ LL | let _ = format!("error: something failed at {}", Location::caller().to_ = note: `-D clippy::to-string-in-format-args` implied by `-D warnings` error: `to_string` applied to a type that implements `Display` in `write!` args - --> $DIR/format_args.rs:78:27 + --> $DIR/format_args.rs:80:27 | LL | Location::caller().to_string() | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `writeln!` args - --> $DIR/format_args.rs:83:27 + --> $DIR/format_args.rs:85:27 | LL | Location::caller().to_string() | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `print!` args - --> $DIR/format_args.rs:85:63 + --> $DIR/format_args.rs:87:63 | LL | print!("error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `println!` args - --> $DIR/format_args.rs:86:65 + --> $DIR/format_args.rs:88:65 | LL | println!("error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `eprint!` args - --> $DIR/format_args.rs:87:64 + --> $DIR/format_args.rs:89:64 | LL | eprint!("error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `eprintln!` args - --> $DIR/format_args.rs:88:66 + --> $DIR/format_args.rs:90:66 | LL | eprintln!("error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `format_args!` args - --> $DIR/format_args.rs:89:77 + --> $DIR/format_args.rs:91:77 | LL | let _ = format_args!("error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `assert!` args - --> $DIR/format_args.rs:90:70 + --> $DIR/format_args.rs:92:70 | LL | assert!(true, "error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `assert_eq!` args - --> $DIR/format_args.rs:91:73 + --> $DIR/format_args.rs:93:73 | LL | assert_eq!(0, 0, "error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `assert_ne!` args - --> $DIR/format_args.rs:92:73 + --> $DIR/format_args.rs:94:73 | LL | assert_ne!(0, 0, "error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `panic!` args - --> $DIR/format_args.rs:93:63 + --> $DIR/format_args.rs:95:63 | LL | panic!("error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `println!` args - --> $DIR/format_args.rs:94:20 + --> $DIR/format_args.rs:96:20 | LL | println!("{}", X(1).to_string()); | ^^^^^^^^^^^^^^^^ help: use this: `*X(1)` error: `to_string` applied to a type that implements `Display` in `println!` args - --> $DIR/format_args.rs:95:20 + --> $DIR/format_args.rs:97:20 | LL | println!("{}", Y(&X(1)).to_string()); | ^^^^^^^^^^^^^^^^^^^^ help: use this: `***Y(&X(1))` error: `to_string` applied to a type that implements `Display` in `println!` args - --> $DIR/format_args.rs:96:24 + --> $DIR/format_args.rs:98:24 | LL | println!("{}", Z(1).to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `println!` args - --> $DIR/format_args.rs:97:20 + --> $DIR/format_args.rs:99:20 | LL | println!("{}", x.to_string()); | ^^^^^^^^^^^^^ help: use this: `**x` error: `to_string` applied to a type that implements `Display` in `println!` args - --> $DIR/format_args.rs:98:20 + --> $DIR/format_args.rs:100:20 | LL | println!("{}", x_ref.to_string()); | ^^^^^^^^^^^^^^^^^ help: use this: `***x_ref` error: `to_string` applied to a type that implements `Display` in `println!` args - --> $DIR/format_args.rs:100:39 + --> $DIR/format_args.rs:102:39 | LL | println!("{foo}{bar}", foo = "foo".to_string(), bar = "bar"); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `println!` args - --> $DIR/format_args.rs:101:52 + --> $DIR/format_args.rs:103:52 | LL | println!("{foo}{bar}", foo = "foo", bar = "bar".to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `println!` args - --> $DIR/format_args.rs:102:39 + --> $DIR/format_args.rs:104:39 | LL | println!("{foo}{bar}", bar = "bar".to_string(), foo = "foo"); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `println!` args - --> $DIR/format_args.rs:103:52 + --> $DIR/format_args.rs:105:52 | LL | println!("{foo}{bar}", bar = "bar", foo = "foo".to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `format!` args - --> $DIR/format_args.rs:142:38 + --> $DIR/format_args.rs:144:38 | LL | let x = format!("{} {}", a, b.to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `println!` args - --> $DIR/format_args.rs:156:24 + --> $DIR/format_args.rs:158:24 | LL | println!("{}", original[..10].to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use this: `&original[..10]` diff --git a/tests/ui/format_args_unfixable.rs b/tests/ui/format_args_unfixable.rs index b24ddf7321e40..eb0ac15bfbf12 100644 --- a/tests/ui/format_args_unfixable.rs +++ b/tests/ui/format_args_unfixable.rs @@ -1,7 +1,5 @@ -#![allow(clippy::assertions_on_constants)] -#![allow(clippy::eq_op)] -#![warn(clippy::format_in_format_args)] -#![warn(clippy::to_string_in_format_args)] +#![warn(clippy::format_in_format_args, clippy::to_string_in_format_args)] +#![allow(clippy::assertions_on_constants, clippy::eq_op, clippy::uninlined_format_args)] use std::io::{stdout, Error, ErrorKind, Write}; use std::ops::Deref; diff --git a/tests/ui/format_args_unfixable.stderr b/tests/ui/format_args_unfixable.stderr index 4476218ad58e9..10e03b6975df4 100644 --- a/tests/ui/format_args_unfixable.stderr +++ b/tests/ui/format_args_unfixable.stderr @@ -1,5 +1,5 @@ error: `format!` in `println!` args - --> $DIR/format_args_unfixable.rs:27:5 + --> $DIR/format_args_unfixable.rs:25:5 | LL | println!("error: {}", format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | println!("error: {}", format!("something failed at {}", Location::calle = help: or consider changing `format!` to `format_args!` error: `format!` in `println!` args - --> $DIR/format_args_unfixable.rs:28:5 + --> $DIR/format_args_unfixable.rs:26:5 | LL | println!("{}: {}", error, format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -18,7 +18,7 @@ LL | println!("{}: {}", error, format!("something failed at {}", Location::c = help: or consider changing `format!` to `format_args!` error: `format!` in `println!` args - --> $DIR/format_args_unfixable.rs:29:5 + --> $DIR/format_args_unfixable.rs:27:5 | LL | println!("{:?}: {}", error, format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -27,7 +27,7 @@ LL | println!("{:?}: {}", error, format!("something failed at {}", Location: = help: or consider changing `format!` to `format_args!` error: `format!` in `println!` args - --> $DIR/format_args_unfixable.rs:30:5 + --> $DIR/format_args_unfixable.rs:28:5 | LL | println!("{{}}: {}", format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -36,7 +36,7 @@ LL | println!("{{}}: {}", format!("something failed at {}", Location::caller = help: or consider changing `format!` to `format_args!` error: `format!` in `println!` args - --> $DIR/format_args_unfixable.rs:31:5 + --> $DIR/format_args_unfixable.rs:29:5 | LL | println!(r#"error: "{}""#, format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -45,7 +45,7 @@ LL | println!(r#"error: "{}""#, format!("something failed at {}", Location:: = help: or consider changing `format!` to `format_args!` error: `format!` in `println!` args - --> $DIR/format_args_unfixable.rs:32:5 + --> $DIR/format_args_unfixable.rs:30:5 | LL | println!("error: {}", format!(r#"something failed at "{}""#, Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -54,7 +54,7 @@ LL | println!("error: {}", format!(r#"something failed at "{}""#, Location:: = help: or consider changing `format!` to `format_args!` error: `format!` in `println!` args - --> $DIR/format_args_unfixable.rs:33:5 + --> $DIR/format_args_unfixable.rs:31:5 | LL | println!("error: {}", format!("something failed at {} {0}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -63,7 +63,7 @@ LL | println!("error: {}", format!("something failed at {} {0}", Location::c = help: or consider changing `format!` to `format_args!` error: `format!` in `format!` args - --> $DIR/format_args_unfixable.rs:34:13 + --> $DIR/format_args_unfixable.rs:32:13 | LL | let _ = format!("error: {}", format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -72,7 +72,7 @@ LL | let _ = format!("error: {}", format!("something failed at {}", Location = help: or consider changing `format!` to `format_args!` error: `format!` in `write!` args - --> $DIR/format_args_unfixable.rs:35:13 + --> $DIR/format_args_unfixable.rs:33:13 | LL | let _ = write!( | _____________^ @@ -86,7 +86,7 @@ LL | | ); = help: or consider changing `format!` to `format_args!` error: `format!` in `writeln!` args - --> $DIR/format_args_unfixable.rs:40:13 + --> $DIR/format_args_unfixable.rs:38:13 | LL | let _ = writeln!( | _____________^ @@ -100,7 +100,7 @@ LL | | ); = help: or consider changing `format!` to `format_args!` error: `format!` in `print!` args - --> $DIR/format_args_unfixable.rs:45:5 + --> $DIR/format_args_unfixable.rs:43:5 | LL | print!("error: {}", format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -109,7 +109,7 @@ LL | print!("error: {}", format!("something failed at {}", Location::caller( = help: or consider changing `format!` to `format_args!` error: `format!` in `eprint!` args - --> $DIR/format_args_unfixable.rs:46:5 + --> $DIR/format_args_unfixable.rs:44:5 | LL | eprint!("error: {}", format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -118,7 +118,7 @@ LL | eprint!("error: {}", format!("something failed at {}", Location::caller = help: or consider changing `format!` to `format_args!` error: `format!` in `eprintln!` args - --> $DIR/format_args_unfixable.rs:47:5 + --> $DIR/format_args_unfixable.rs:45:5 | LL | eprintln!("error: {}", format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -127,7 +127,7 @@ LL | eprintln!("error: {}", format!("something failed at {}", Location::call = help: or consider changing `format!` to `format_args!` error: `format!` in `format_args!` args - --> $DIR/format_args_unfixable.rs:48:13 + --> $DIR/format_args_unfixable.rs:46:13 | LL | let _ = format_args!("error: {}", format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -136,7 +136,7 @@ LL | let _ = format_args!("error: {}", format!("something failed at {}", Loc = help: or consider changing `format!` to `format_args!` error: `format!` in `assert!` args - --> $DIR/format_args_unfixable.rs:49:5 + --> $DIR/format_args_unfixable.rs:47:5 | LL | assert!(true, "error: {}", format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -145,7 +145,7 @@ LL | assert!(true, "error: {}", format!("something failed at {}", Location:: = help: or consider changing `format!` to `format_args!` error: `format!` in `assert_eq!` args - --> $DIR/format_args_unfixable.rs:50:5 + --> $DIR/format_args_unfixable.rs:48:5 | LL | assert_eq!(0, 0, "error: {}", format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -154,7 +154,7 @@ LL | assert_eq!(0, 0, "error: {}", format!("something failed at {}", Locatio = help: or consider changing `format!` to `format_args!` error: `format!` in `assert_ne!` args - --> $DIR/format_args_unfixable.rs:51:5 + --> $DIR/format_args_unfixable.rs:49:5 | LL | assert_ne!(0, 0, "error: {}", format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -163,7 +163,7 @@ LL | assert_ne!(0, 0, "error: {}", format!("something failed at {}", Locatio = help: or consider changing `format!` to `format_args!` error: `format!` in `panic!` args - --> $DIR/format_args_unfixable.rs:52:5 + --> $DIR/format_args_unfixable.rs:50:5 | LL | panic!("error: {}", format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/functions.rs b/tests/ui/functions.rs index 5521870eaecf7..18149bfbc3fe0 100644 --- a/tests/ui/functions.rs +++ b/tests/ui/functions.rs @@ -1,6 +1,6 @@ #![warn(clippy::all)] -#![allow(dead_code)] -#![allow(unused_unsafe, clippy::missing_safety_doc)] +#![allow(dead_code, unused_unsafe)] +#![allow(clippy::missing_safety_doc, clippy::uninlined_format_args)] // TOO_MANY_ARGUMENTS fn good(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool) {} diff --git a/tests/ui/identity_op.fixed b/tests/ui/identity_op.fixed index fa564e23cd275..e7b9a78c5dbc3 100644 --- a/tests/ui/identity_op.fixed +++ b/tests/ui/identity_op.fixed @@ -1,13 +1,13 @@ // run-rustfix - #![warn(clippy::identity_op)] +#![allow(unused)] #![allow( clippy::eq_op, clippy::no_effect, clippy::unnecessary_operation, clippy::op_ref, clippy::double_parens, - unused + clippy::uninlined_format_args )] use std::fmt::Write as _; diff --git a/tests/ui/identity_op.rs b/tests/ui/identity_op.rs index 3d06d2a73b628..9a435cdbb753f 100644 --- a/tests/ui/identity_op.rs +++ b/tests/ui/identity_op.rs @@ -1,13 +1,13 @@ // run-rustfix - #![warn(clippy::identity_op)] +#![allow(unused)] #![allow( clippy::eq_op, clippy::no_effect, clippy::unnecessary_operation, clippy::op_ref, clippy::double_parens, - unused + clippy::uninlined_format_args )] use std::fmt::Write as _; diff --git a/tests/ui/index_refutable_slice/if_let_slice_binding.rs b/tests/ui/index_refutable_slice/if_let_slice_binding.rs index c2c0c520dc62d..0a3374d11b03f 100644 --- a/tests/ui/index_refutable_slice/if_let_slice_binding.rs +++ b/tests/ui/index_refutable_slice/if_let_slice_binding.rs @@ -1,4 +1,5 @@ #![deny(clippy::index_refutable_slice)] +#![allow(clippy::uninlined_format_args)] enum SomeEnum { One(T), diff --git a/tests/ui/index_refutable_slice/if_let_slice_binding.stderr b/tests/ui/index_refutable_slice/if_let_slice_binding.stderr index a607df9b87660..0a13ac1354e57 100644 --- a/tests/ui/index_refutable_slice/if_let_slice_binding.stderr +++ b/tests/ui/index_refutable_slice/if_let_slice_binding.stderr @@ -1,5 +1,5 @@ error: this binding can be a slice pattern to avoid indexing - --> $DIR/if_let_slice_binding.rs:13:17 + --> $DIR/if_let_slice_binding.rs:14:17 | LL | if let Some(slice) = slice { | ^^^^^ @@ -19,7 +19,7 @@ LL | println!("{}", slice_0); | ~~~~~~~ error: this binding can be a slice pattern to avoid indexing - --> $DIR/if_let_slice_binding.rs:19:17 + --> $DIR/if_let_slice_binding.rs:20:17 | LL | if let Some(slice) = slice { | ^^^^^ @@ -34,7 +34,7 @@ LL | println!("{}", slice_0); | ~~~~~~~ error: this binding can be a slice pattern to avoid indexing - --> $DIR/if_let_slice_binding.rs:25:17 + --> $DIR/if_let_slice_binding.rs:26:17 | LL | if let Some(slice) = slice { | ^^^^^ @@ -50,7 +50,7 @@ LL ~ println!("{}", slice_0); | error: this binding can be a slice pattern to avoid indexing - --> $DIR/if_let_slice_binding.rs:32:26 + --> $DIR/if_let_slice_binding.rs:33:26 | LL | if let SomeEnum::One(slice) | SomeEnum::Three(slice) = slice_wrapped { | ^^^^^ @@ -65,7 +65,7 @@ LL | println!("{}", slice_0); | ~~~~~~~ error: this binding can be a slice pattern to avoid indexing - --> $DIR/if_let_slice_binding.rs:39:29 + --> $DIR/if_let_slice_binding.rs:40:29 | LL | if let (SomeEnum::Three(a), Some(b)) = (a_wrapped, b_wrapped) { | ^ @@ -80,7 +80,7 @@ LL | println!("{} -> {}", a_2, b[1]); | ~~~ error: this binding can be a slice pattern to avoid indexing - --> $DIR/if_let_slice_binding.rs:39:38 + --> $DIR/if_let_slice_binding.rs:40:38 | LL | if let (SomeEnum::Three(a), Some(b)) = (a_wrapped, b_wrapped) { | ^ @@ -95,7 +95,7 @@ LL | println!("{} -> {}", a[2], b_1); | ~~~ error: this binding can be a slice pattern to avoid indexing - --> $DIR/if_let_slice_binding.rs:46:21 + --> $DIR/if_let_slice_binding.rs:47:21 | LL | if let Some(ref slice) = slice { | ^^^^^ @@ -110,7 +110,7 @@ LL | println!("{:?}", slice_1); | ~~~~~~~ error: this binding can be a slice pattern to avoid indexing - --> $DIR/if_let_slice_binding.rs:54:17 + --> $DIR/if_let_slice_binding.rs:55:17 | LL | if let Some(slice) = &slice { | ^^^^^ @@ -125,7 +125,7 @@ LL | println!("{:?}", slice_0); | ~~~~~~~ error: this binding can be a slice pattern to avoid indexing - --> $DIR/if_let_slice_binding.rs:123:17 + --> $DIR/if_let_slice_binding.rs:124:17 | LL | if let Some(slice) = wrap.inner { | ^^^^^ @@ -140,7 +140,7 @@ LL | println!("This is awesome! {}", slice_0); | ~~~~~~~ error: this binding can be a slice pattern to avoid indexing - --> $DIR/if_let_slice_binding.rs:130:17 + --> $DIR/if_let_slice_binding.rs:131:17 | LL | if let Some(slice) = wrap.inner { | ^^^^^ diff --git a/tests/ui/infinite_iter.rs b/tests/ui/infinite_iter.rs index a1e5fad0c621f..622644f675d35 100644 --- a/tests/ui/infinite_iter.rs +++ b/tests/ui/infinite_iter.rs @@ -1,3 +1,5 @@ +#![allow(clippy::uninlined_format_args)] + use std::iter::repeat; fn square_is_lower_64(x: &u32) -> bool { x * x < 64 diff --git a/tests/ui/infinite_iter.stderr b/tests/ui/infinite_iter.stderr index ba277e36339ad..b911163f715e7 100644 --- a/tests/ui/infinite_iter.stderr +++ b/tests/ui/infinite_iter.stderr @@ -1,29 +1,29 @@ error: infinite iteration detected - --> $DIR/infinite_iter.rs:9:5 + --> $DIR/infinite_iter.rs:11:5 | LL | repeat(0_u8).collect::>(); // infinite iter | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/infinite_iter.rs:7:8 + --> $DIR/infinite_iter.rs:9:8 | LL | #[deny(clippy::infinite_iter)] | ^^^^^^^^^^^^^^^^^^^^^ error: infinite iteration detected - --> $DIR/infinite_iter.rs:10:5 + --> $DIR/infinite_iter.rs:12:5 | LL | (0..8_u32).take_while(square_is_lower_64).cycle().count(); // infinite iter | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: infinite iteration detected - --> $DIR/infinite_iter.rs:11:5 + --> $DIR/infinite_iter.rs:13:5 | LL | (0..8_u64).chain(0..).max(); // infinite iter | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: infinite iteration detected - --> $DIR/infinite_iter.rs:16:5 + --> $DIR/infinite_iter.rs:18:5 | LL | / (0..8_u32) LL | | .rev() @@ -33,37 +33,37 @@ LL | | .for_each(|x| println!("{}", x)); // infinite iter | |________________________________________^ error: infinite iteration detected - --> $DIR/infinite_iter.rs:22:5 + --> $DIR/infinite_iter.rs:24:5 | LL | (0_usize..).flat_map(|x| 0..x).product::(); // infinite iter | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: infinite iteration detected - --> $DIR/infinite_iter.rs:23:5 + --> $DIR/infinite_iter.rs:25:5 | LL | (0_u64..).filter(|x| x % 2 == 0).last(); // infinite iter | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: possible infinite iteration detected - --> $DIR/infinite_iter.rs:30:5 + --> $DIR/infinite_iter.rs:32:5 | LL | (0..).zip((0..).take_while(square_is_lower_64)).count(); // maybe infinite iter | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/infinite_iter.rs:28:8 + --> $DIR/infinite_iter.rs:30:8 | LL | #[deny(clippy::maybe_infinite_iter)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: possible infinite iteration detected - --> $DIR/infinite_iter.rs:31:5 + --> $DIR/infinite_iter.rs:33:5 | LL | repeat(42).take_while(|x| *x == 42).chain(0..42).max(); // maybe infinite iter | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: possible infinite iteration detected - --> $DIR/infinite_iter.rs:32:5 + --> $DIR/infinite_iter.rs:34:5 | LL | / (1..) LL | | .scan(0, |state, x| { @@ -74,31 +74,31 @@ LL | | .min(); // maybe infinite iter | |______________^ error: possible infinite iteration detected - --> $DIR/infinite_iter.rs:38:5 + --> $DIR/infinite_iter.rs:40:5 | LL | (0..).find(|x| *x == 24); // maybe infinite iter | ^^^^^^^^^^^^^^^^^^^^^^^^ error: possible infinite iteration detected - --> $DIR/infinite_iter.rs:39:5 + --> $DIR/infinite_iter.rs:41:5 | LL | (0..).position(|x| x == 24); // maybe infinite iter | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: possible infinite iteration detected - --> $DIR/infinite_iter.rs:40:5 + --> $DIR/infinite_iter.rs:42:5 | LL | (0..).any(|x| x == 24); // maybe infinite iter | ^^^^^^^^^^^^^^^^^^^^^^ error: possible infinite iteration detected - --> $DIR/infinite_iter.rs:41:5 + --> $DIR/infinite_iter.rs:43:5 | LL | (0..).all(|x| x == 24); // maybe infinite iter | ^^^^^^^^^^^^^^^^^^^^^^ error: infinite iteration detected - --> $DIR/infinite_iter.rs:63:31 + --> $DIR/infinite_iter.rs:65:31 | LL | let _: HashSet = (0..).collect(); // Infinite iter | ^^^^^^^^^^^^^^^ diff --git a/tests/ui/issue_2356.fixed b/tests/ui/issue_2356.fixed index 942e99fa8787b..a73ee0fb2e594 100644 --- a/tests/ui/issue_2356.fixed +++ b/tests/ui/issue_2356.fixed @@ -1,6 +1,7 @@ // run-rustfix #![deny(clippy::while_let_on_iterator)] #![allow(unused_mut)] +#![allow(clippy::uninlined_format_args)] use std::iter::Iterator; diff --git a/tests/ui/issue_2356.rs b/tests/ui/issue_2356.rs index b000234ea5966..9dd9069609b14 100644 --- a/tests/ui/issue_2356.rs +++ b/tests/ui/issue_2356.rs @@ -1,6 +1,7 @@ // run-rustfix #![deny(clippy::while_let_on_iterator)] #![allow(unused_mut)] +#![allow(clippy::uninlined_format_args)] use std::iter::Iterator; diff --git a/tests/ui/issue_2356.stderr b/tests/ui/issue_2356.stderr index 4e3ff7522e0bb..a24b0b32e4708 100644 --- a/tests/ui/issue_2356.stderr +++ b/tests/ui/issue_2356.stderr @@ -1,5 +1,5 @@ error: this loop could be written as a `for` loop - --> $DIR/issue_2356.rs:17:9 + --> $DIR/issue_2356.rs:18:9 | LL | while let Some(e) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for e in it` diff --git a/tests/ui/issue_4266.rs b/tests/ui/issue_4266.rs index d9d48189bd74e..8e0620e52b65f 100644 --- a/tests/ui/issue_4266.rs +++ b/tests/ui/issue_4266.rs @@ -1,4 +1,5 @@ #![allow(dead_code)] +#![allow(clippy::uninlined_format_args)] async fn sink1<'a>(_: &'a str) {} // lint async fn sink1_elided(_: &str) {} // ok diff --git a/tests/ui/issue_4266.stderr b/tests/ui/issue_4266.stderr index e5042aaa776b4..a61253c641e08 100644 --- a/tests/ui/issue_4266.stderr +++ b/tests/ui/issue_4266.stderr @@ -1,5 +1,5 @@ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/issue_4266.rs:3:1 + --> $DIR/issue_4266.rs:4:1 | LL | async fn sink1<'a>(_: &'a str) {} // lint | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,13 +7,13 @@ LL | async fn sink1<'a>(_: &'a str) {} // lint = note: `-D clippy::needless-lifetimes` implied by `-D warnings` error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/issue_4266.rs:7:1 + --> $DIR/issue_4266.rs:8:1 | LL | async fn one_to_one<'a>(s: &'a str) -> &'a str { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: methods called `new` usually take no `self` - --> $DIR/issue_4266.rs:27:22 + --> $DIR/issue_4266.rs:28:22 | LL | pub async fn new(&mut self) -> Self { | ^^^^^^^^^ diff --git a/tests/ui/item_after_statement.rs b/tests/ui/item_after_statement.rs index d439ca1e4e1a1..5e92dcab1f5a2 100644 --- a/tests/ui/item_after_statement.rs +++ b/tests/ui/item_after_statement.rs @@ -1,4 +1,5 @@ #![warn(clippy::items_after_statements)] +#![allow(clippy::uninlined_format_args)] fn ok() { fn foo() { diff --git a/tests/ui/item_after_statement.stderr b/tests/ui/item_after_statement.stderr index ab4a6374c73ca..2523c53ac53a1 100644 --- a/tests/ui/item_after_statement.stderr +++ b/tests/ui/item_after_statement.stderr @@ -1,5 +1,5 @@ error: adding items after statements is confusing, since items exist from the start of the scope - --> $DIR/item_after_statement.rs:12:5 + --> $DIR/item_after_statement.rs:13:5 | LL | / fn foo() { LL | | println!("foo"); @@ -9,7 +9,7 @@ LL | | } = note: `-D clippy::items-after-statements` implied by `-D warnings` error: adding items after statements is confusing, since items exist from the start of the scope - --> $DIR/item_after_statement.rs:19:5 + --> $DIR/item_after_statement.rs:20:5 | LL | / fn foo() { LL | | println!("foo"); @@ -17,7 +17,7 @@ LL | | } | |_____^ error: adding items after statements is confusing, since items exist from the start of the scope - --> $DIR/item_after_statement.rs:32:13 + --> $DIR/item_after_statement.rs:33:13 | LL | / fn say_something() { LL | | println!("something"); diff --git a/tests/ui/manual_assert.edition2018.fixed b/tests/ui/manual_assert.edition2018.fixed index 84f6855f3387b..26e3b8f63e700 100644 --- a/tests/ui/manual_assert.edition2018.fixed +++ b/tests/ui/manual_assert.edition2018.fixed @@ -4,7 +4,8 @@ // run-rustfix #![warn(clippy::manual_assert)] -#![allow(dead_code, unused_doc_comments, clippy::nonminimal_bool)] +#![allow(dead_code, unused_doc_comments)] +#![allow(clippy::nonminimal_bool, clippy::uninlined_format_args)] macro_rules! one { () => { diff --git a/tests/ui/manual_assert.edition2018.stderr b/tests/ui/manual_assert.edition2018.stderr index dbd21be2da9e1..7718588fdf6f4 100644 --- a/tests/ui/manual_assert.edition2018.stderr +++ b/tests/ui/manual_assert.edition2018.stderr @@ -1,5 +1,5 @@ error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:30:5 + --> $DIR/manual_assert.rs:31:5 | LL | / if !a.is_empty() { LL | | panic!("qaqaq{:?}", a); @@ -13,7 +13,7 @@ LL | assert!(a.is_empty(), "qaqaq{:?}", a); | error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:33:5 + --> $DIR/manual_assert.rs:34:5 | LL | / if !a.is_empty() { LL | | panic!("qwqwq"); @@ -26,7 +26,7 @@ LL | assert!(a.is_empty(), "qwqwq"); | error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:50:5 + --> $DIR/manual_assert.rs:51:5 | LL | / if b.is_empty() { LL | | panic!("panic1"); @@ -39,7 +39,7 @@ LL | assert!(!b.is_empty(), "panic1"); | error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:53:5 + --> $DIR/manual_assert.rs:54:5 | LL | / if b.is_empty() && a.is_empty() { LL | | panic!("panic2"); @@ -52,7 +52,7 @@ LL | assert!(!(b.is_empty() && a.is_empty()), "panic2"); | error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:56:5 + --> $DIR/manual_assert.rs:57:5 | LL | / if a.is_empty() && !b.is_empty() { LL | | panic!("panic3"); @@ -65,7 +65,7 @@ LL | assert!(!(a.is_empty() && !b.is_empty()), "panic3"); | error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:59:5 + --> $DIR/manual_assert.rs:60:5 | LL | / if b.is_empty() || a.is_empty() { LL | | panic!("panic4"); @@ -78,7 +78,7 @@ LL | assert!(!(b.is_empty() || a.is_empty()), "panic4"); | error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:62:5 + --> $DIR/manual_assert.rs:63:5 | LL | / if a.is_empty() || !b.is_empty() { LL | | panic!("panic5"); @@ -91,7 +91,7 @@ LL | assert!(!(a.is_empty() || !b.is_empty()), "panic5"); | error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:65:5 + --> $DIR/manual_assert.rs:66:5 | LL | / if a.is_empty() { LL | | panic!("with expansion {}", one!()) @@ -104,7 +104,7 @@ LL | assert!(!a.is_empty(), "with expansion {}", one!()); | error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:72:5 + --> $DIR/manual_assert.rs:73:5 | LL | / if a > 2 { LL | | // comment diff --git a/tests/ui/manual_assert.edition2021.fixed b/tests/ui/manual_assert.edition2021.fixed index 84f6855f3387b..26e3b8f63e700 100644 --- a/tests/ui/manual_assert.edition2021.fixed +++ b/tests/ui/manual_assert.edition2021.fixed @@ -4,7 +4,8 @@ // run-rustfix #![warn(clippy::manual_assert)] -#![allow(dead_code, unused_doc_comments, clippy::nonminimal_bool)] +#![allow(dead_code, unused_doc_comments)] +#![allow(clippy::nonminimal_bool, clippy::uninlined_format_args)] macro_rules! one { () => { diff --git a/tests/ui/manual_assert.edition2021.stderr b/tests/ui/manual_assert.edition2021.stderr index dbd21be2da9e1..7718588fdf6f4 100644 --- a/tests/ui/manual_assert.edition2021.stderr +++ b/tests/ui/manual_assert.edition2021.stderr @@ -1,5 +1,5 @@ error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:30:5 + --> $DIR/manual_assert.rs:31:5 | LL | / if !a.is_empty() { LL | | panic!("qaqaq{:?}", a); @@ -13,7 +13,7 @@ LL | assert!(a.is_empty(), "qaqaq{:?}", a); | error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:33:5 + --> $DIR/manual_assert.rs:34:5 | LL | / if !a.is_empty() { LL | | panic!("qwqwq"); @@ -26,7 +26,7 @@ LL | assert!(a.is_empty(), "qwqwq"); | error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:50:5 + --> $DIR/manual_assert.rs:51:5 | LL | / if b.is_empty() { LL | | panic!("panic1"); @@ -39,7 +39,7 @@ LL | assert!(!b.is_empty(), "panic1"); | error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:53:5 + --> $DIR/manual_assert.rs:54:5 | LL | / if b.is_empty() && a.is_empty() { LL | | panic!("panic2"); @@ -52,7 +52,7 @@ LL | assert!(!(b.is_empty() && a.is_empty()), "panic2"); | error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:56:5 + --> $DIR/manual_assert.rs:57:5 | LL | / if a.is_empty() && !b.is_empty() { LL | | panic!("panic3"); @@ -65,7 +65,7 @@ LL | assert!(!(a.is_empty() && !b.is_empty()), "panic3"); | error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:59:5 + --> $DIR/manual_assert.rs:60:5 | LL | / if b.is_empty() || a.is_empty() { LL | | panic!("panic4"); @@ -78,7 +78,7 @@ LL | assert!(!(b.is_empty() || a.is_empty()), "panic4"); | error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:62:5 + --> $DIR/manual_assert.rs:63:5 | LL | / if a.is_empty() || !b.is_empty() { LL | | panic!("panic5"); @@ -91,7 +91,7 @@ LL | assert!(!(a.is_empty() || !b.is_empty()), "panic5"); | error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:65:5 + --> $DIR/manual_assert.rs:66:5 | LL | / if a.is_empty() { LL | | panic!("with expansion {}", one!()) @@ -104,7 +104,7 @@ LL | assert!(!a.is_empty(), "with expansion {}", one!()); | error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:72:5 + --> $DIR/manual_assert.rs:73:5 | LL | / if a > 2 { LL | | // comment diff --git a/tests/ui/manual_assert.rs b/tests/ui/manual_assert.rs index 14abf94965af0..8c37753071dfb 100644 --- a/tests/ui/manual_assert.rs +++ b/tests/ui/manual_assert.rs @@ -4,7 +4,8 @@ // run-rustfix #![warn(clippy::manual_assert)] -#![allow(dead_code, unused_doc_comments, clippy::nonminimal_bool)] +#![allow(dead_code, unused_doc_comments)] +#![allow(clippy::nonminimal_bool, clippy::uninlined_format_args)] macro_rules! one { () => { diff --git a/tests/ui/manual_find_fixable.fixed b/tests/ui/manual_find_fixable.fixed index 36d1644c22bda..2bce6e624c90d 100644 --- a/tests/ui/manual_find_fixable.fixed +++ b/tests/ui/manual_find_fixable.fixed @@ -1,7 +1,7 @@ // run-rustfix - -#![allow(unused, clippy::needless_return)] #![warn(clippy::manual_find)] +#![allow(unused)] +#![allow(clippy::needless_return, clippy::uninlined_format_args)] use std::collections::HashMap; diff --git a/tests/ui/manual_find_fixable.rs b/tests/ui/manual_find_fixable.rs index ed277ddaa722d..f5c6de37a257f 100644 --- a/tests/ui/manual_find_fixable.rs +++ b/tests/ui/manual_find_fixable.rs @@ -1,7 +1,7 @@ // run-rustfix - -#![allow(unused, clippy::needless_return)] #![warn(clippy::manual_find)] +#![allow(unused)] +#![allow(clippy::needless_return, clippy::uninlined_format_args)] use std::collections::HashMap; diff --git a/tests/ui/manual_flatten.rs b/tests/ui/manual_flatten.rs index d922593bc6f93..96cd87c0e19a7 100644 --- a/tests/ui/manual_flatten.rs +++ b/tests/ui/manual_flatten.rs @@ -1,5 +1,5 @@ #![warn(clippy::manual_flatten)] -#![allow(clippy::useless_vec)] +#![allow(clippy::useless_vec, clippy::uninlined_format_args)] fn main() { // Test for loop over implicitly adjusted `Iterator` with `if let` expression diff --git a/tests/ui/map_unwrap_or.rs b/tests/ui/map_unwrap_or.rs index 87e16f5d09bd7..5429fb4e454e3 100644 --- a/tests/ui/map_unwrap_or.rs +++ b/tests/ui/map_unwrap_or.rs @@ -1,6 +1,6 @@ // aux-build:option_helpers.rs - #![warn(clippy::map_unwrap_or)] +#![allow(clippy::uninlined_format_args)] #[macro_use] extern crate option_helpers; diff --git a/tests/ui/match_ref_pats.fixed b/tests/ui/match_ref_pats.fixed index 1b6c2d9241218..cf37fc6dc90a1 100644 --- a/tests/ui/match_ref_pats.fixed +++ b/tests/ui/match_ref_pats.fixed @@ -1,6 +1,7 @@ // run-rustfix #![warn(clippy::match_ref_pats)] -#![allow(dead_code, unused_variables, clippy::equatable_if_let, clippy::enum_variant_names)] +#![allow(dead_code, unused_variables)] +#![allow(clippy::enum_variant_names, clippy::equatable_if_let, clippy::uninlined_format_args)] fn ref_pats() { { diff --git a/tests/ui/match_ref_pats.rs b/tests/ui/match_ref_pats.rs index 68dfac4e2e978..3220b97d1b511 100644 --- a/tests/ui/match_ref_pats.rs +++ b/tests/ui/match_ref_pats.rs @@ -1,6 +1,7 @@ // run-rustfix #![warn(clippy::match_ref_pats)] -#![allow(dead_code, unused_variables, clippy::equatable_if_let, clippy::enum_variant_names)] +#![allow(dead_code, unused_variables)] +#![allow(clippy::enum_variant_names, clippy::equatable_if_let, clippy::uninlined_format_args)] fn ref_pats() { { diff --git a/tests/ui/match_ref_pats.stderr b/tests/ui/match_ref_pats.stderr index 353f7399d9c27..7d9646c842ee8 100644 --- a/tests/ui/match_ref_pats.stderr +++ b/tests/ui/match_ref_pats.stderr @@ -1,5 +1,5 @@ error: you don't need to add `&` to all patterns - --> $DIR/match_ref_pats.rs:8:9 + --> $DIR/match_ref_pats.rs:9:9 | LL | / match v { LL | | &Some(v) => println!("{:?}", v), @@ -16,7 +16,7 @@ LL ~ None => println!("none"), | error: you don't need to add `&` to both the expression and the patterns - --> $DIR/match_ref_pats.rs:25:5 + --> $DIR/match_ref_pats.rs:26:5 | LL | / match &w { LL | | &Some(v) => println!("{:?}", v), @@ -32,7 +32,7 @@ LL ~ None => println!("none"), | error: redundant pattern matching, consider using `is_none()` - --> $DIR/match_ref_pats.rs:37:12 + --> $DIR/match_ref_pats.rs:38:12 | LL | if let &None = a { | -------^^^^^---- help: try this: `if a.is_none()` @@ -40,13 +40,13 @@ LL | if let &None = a { = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` error: redundant pattern matching, consider using `is_none()` - --> $DIR/match_ref_pats.rs:42:12 + --> $DIR/match_ref_pats.rs:43:12 | LL | if let &None = &b { | -------^^^^^----- help: try this: `if b.is_none()` error: you don't need to add `&` to all patterns - --> $DIR/match_ref_pats.rs:102:9 + --> $DIR/match_ref_pats.rs:103:9 | LL | / match foobar_variant!(0) { LL | | &FooBar::Foo => println!("Foo"), diff --git a/tests/ui/match_result_ok.fixed b/tests/ui/match_result_ok.fixed index d4760a97567ea..8b91b9854a040 100644 --- a/tests/ui/match_result_ok.fixed +++ b/tests/ui/match_result_ok.fixed @@ -1,8 +1,7 @@ // run-rustfix - #![warn(clippy::match_result_ok)] -#![allow(clippy::boxed_local)] #![allow(dead_code)] +#![allow(clippy::boxed_local, clippy::uninlined_format_args)] // Checking `if` cases diff --git a/tests/ui/match_result_ok.rs b/tests/ui/match_result_ok.rs index 0b818723d9897..bc2c4b50e2729 100644 --- a/tests/ui/match_result_ok.rs +++ b/tests/ui/match_result_ok.rs @@ -1,8 +1,7 @@ // run-rustfix - #![warn(clippy::match_result_ok)] -#![allow(clippy::boxed_local)] #![allow(dead_code)] +#![allow(clippy::boxed_local, clippy::uninlined_format_args)] // Checking `if` cases diff --git a/tests/ui/match_result_ok.stderr b/tests/ui/match_result_ok.stderr index cc3bc8c76ff3a..98a95705ca59a 100644 --- a/tests/ui/match_result_ok.stderr +++ b/tests/ui/match_result_ok.stderr @@ -1,5 +1,5 @@ error: matching on `Some` with `ok()` is redundant - --> $DIR/match_result_ok.rs:10:5 + --> $DIR/match_result_ok.rs:9:5 | LL | if let Some(y) = x.parse().ok() { y } else { 0 } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -11,7 +11,7 @@ LL | if let Ok(y) = x.parse() { y } else { 0 } | ~~~~~~~~~~~~~~~~~~~~~~~~ error: matching on `Some` with `ok()` is redundant - --> $DIR/match_result_ok.rs:20:9 + --> $DIR/match_result_ok.rs:19:9 | LL | if let Some(y) = x . parse() . ok () { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -22,7 +22,7 @@ LL | if let Ok(y) = x . parse() { | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: matching on `Some` with `ok()` is redundant - --> $DIR/match_result_ok.rs:46:5 + --> $DIR/match_result_ok.rs:45:5 | LL | while let Some(a) = wat.next().ok() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/match_same_arms2.rs b/tests/ui/match_same_arms2.rs index 61793e80c98d4..82b2c433d99e2 100644 --- a/tests/ui/match_same_arms2.rs +++ b/tests/ui/match_same_arms2.rs @@ -1,5 +1,9 @@ #![warn(clippy::match_same_arms)] -#![allow(clippy::disallowed_names, clippy::diverging_sub_expression)] +#![allow( + clippy::disallowed_names, + clippy::diverging_sub_expression, + clippy::uninlined_format_args +)] fn bar(_: T) {} fn foo() -> bool { diff --git a/tests/ui/match_same_arms2.stderr b/tests/ui/match_same_arms2.stderr index 14a672ba2fec1..9d73e57178825 100644 --- a/tests/ui/match_same_arms2.stderr +++ b/tests/ui/match_same_arms2.stderr @@ -1,5 +1,5 @@ error: this match arm has an identical body to the `_` wildcard arm - --> $DIR/match_same_arms2.rs:11:9 + --> $DIR/match_same_arms2.rs:15:9 | LL | / 42 => { LL | | foo(); @@ -13,7 +13,7 @@ LL | | }, = note: `-D clippy::match-same-arms` implied by `-D warnings` = help: or try changing either arm body note: `_` wildcard arm here - --> $DIR/match_same_arms2.rs:20:9 + --> $DIR/match_same_arms2.rs:24:9 | LL | / _ => { LL | | //~ ERROR match arms have same body @@ -25,7 +25,7 @@ LL | | }, | |_________^ error: this match arm has an identical body to another arm - --> $DIR/match_same_arms2.rs:34:9 + --> $DIR/match_same_arms2.rs:38:9 | LL | 51 => foo(), //~ ERROR match arms have same body | --^^^^^^^^^ @@ -34,13 +34,13 @@ LL | 51 => foo(), //~ ERROR match arms have same body | = help: or try changing either arm body note: other arm here - --> $DIR/match_same_arms2.rs:33:9 + --> $DIR/match_same_arms2.rs:37:9 | LL | 42 => foo(), | ^^^^^^^^^^^ error: this match arm has an identical body to another arm - --> $DIR/match_same_arms2.rs:40:9 + --> $DIR/match_same_arms2.rs:44:9 | LL | None => 24, //~ ERROR match arms have same body | ----^^^^^^ @@ -49,13 +49,13 @@ LL | None => 24, //~ ERROR match arms have same body | = help: or try changing either arm body note: other arm here - --> $DIR/match_same_arms2.rs:39:9 + --> $DIR/match_same_arms2.rs:43:9 | LL | Some(_) => 24, | ^^^^^^^^^^^^^ error: this match arm has an identical body to another arm - --> $DIR/match_same_arms2.rs:62:9 + --> $DIR/match_same_arms2.rs:66:9 | LL | (None, Some(a)) => bar(a), //~ ERROR match arms have same body | ---------------^^^^^^^^^^ @@ -64,13 +64,13 @@ LL | (None, Some(a)) => bar(a), //~ ERROR match arms have same body | = help: or try changing either arm body note: other arm here - --> $DIR/match_same_arms2.rs:61:9 + --> $DIR/match_same_arms2.rs:65:9 | LL | (Some(a), None) => bar(a), | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: this match arm has an identical body to another arm - --> $DIR/match_same_arms2.rs:67:9 + --> $DIR/match_same_arms2.rs:71:9 | LL | (Some(a), ..) => bar(a), | -------------^^^^^^^^^^ @@ -79,13 +79,13 @@ LL | (Some(a), ..) => bar(a), | = help: or try changing either arm body note: other arm here - --> $DIR/match_same_arms2.rs:68:9 + --> $DIR/match_same_arms2.rs:72:9 | LL | (.., Some(a)) => bar(a), //~ ERROR match arms have same body | ^^^^^^^^^^^^^^^^^^^^^^^ error: this match arm has an identical body to another arm - --> $DIR/match_same_arms2.rs:101:9 + --> $DIR/match_same_arms2.rs:105:9 | LL | (Ok(x), Some(_)) => println!("ok {}", x), | ----------------^^^^^^^^^^^^^^^^^^^^^^^^ @@ -94,13 +94,13 @@ LL | (Ok(x), Some(_)) => println!("ok {}", x), | = help: or try changing either arm body note: other arm here - --> $DIR/match_same_arms2.rs:102:9 + --> $DIR/match_same_arms2.rs:106:9 | LL | (Ok(_), Some(x)) => println!("ok {}", x), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this match arm has an identical body to another arm - --> $DIR/match_same_arms2.rs:117:9 + --> $DIR/match_same_arms2.rs:121:9 | LL | Ok(_) => println!("ok"), | -----^^^^^^^^^^^^^^^^^^ @@ -109,13 +109,13 @@ LL | Ok(_) => println!("ok"), | = help: or try changing either arm body note: other arm here - --> $DIR/match_same_arms2.rs:116:9 + --> $DIR/match_same_arms2.rs:120:9 | LL | Ok(3) => println!("ok"), | ^^^^^^^^^^^^^^^^^^^^^^^ error: this match arm has an identical body to another arm - --> $DIR/match_same_arms2.rs:144:9 + --> $DIR/match_same_arms2.rs:148:9 | LL | 1 => { | ^ help: try merging the arm patterns: `1 | 0` @@ -127,7 +127,7 @@ LL | | }, | = help: or try changing either arm body note: other arm here - --> $DIR/match_same_arms2.rs:141:9 + --> $DIR/match_same_arms2.rs:145:9 | LL | / 0 => { LL | | empty!(0); @@ -135,7 +135,7 @@ LL | | }, | |_________^ error: match expression looks like `matches!` macro - --> $DIR/match_same_arms2.rs:162:16 + --> $DIR/match_same_arms2.rs:166:16 | LL | let _ans = match x { | ________________^ @@ -148,7 +148,7 @@ LL | | }; = note: `-D clippy::match-like-matches-macro` implied by `-D warnings` error: this match arm has an identical body to another arm - --> $DIR/match_same_arms2.rs:194:9 + --> $DIR/match_same_arms2.rs:198:9 | LL | Foo::X(0) => 1, | ---------^^^^^ @@ -157,13 +157,13 @@ LL | Foo::X(0) => 1, | = help: or try changing either arm body note: other arm here - --> $DIR/match_same_arms2.rs:196:9 + --> $DIR/match_same_arms2.rs:200:9 | LL | Foo::Z(_) => 1, | ^^^^^^^^^^^^^^ error: this match arm has an identical body to another arm - --> $DIR/match_same_arms2.rs:204:9 + --> $DIR/match_same_arms2.rs:208:9 | LL | Foo::Z(_) => 1, | ---------^^^^^ @@ -172,13 +172,13 @@ LL | Foo::Z(_) => 1, | = help: or try changing either arm body note: other arm here - --> $DIR/match_same_arms2.rs:202:9 + --> $DIR/match_same_arms2.rs:206:9 | LL | Foo::X(0) => 1, | ^^^^^^^^^^^^^^ error: this match arm has an identical body to another arm - --> $DIR/match_same_arms2.rs:227:9 + --> $DIR/match_same_arms2.rs:231:9 | LL | Some(Bar { y: 0, x: 5, .. }) => 1, | ----------------------------^^^^^ @@ -187,7 +187,7 @@ LL | Some(Bar { y: 0, x: 5, .. }) => 1, | = help: or try changing either arm body note: other arm here - --> $DIR/match_same_arms2.rs:224:9 + --> $DIR/match_same_arms2.rs:228:9 | LL | Some(Bar { x: 0, y: 5, .. }) => 1, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/match_single_binding.fixed b/tests/ui/match_single_binding.fixed index de46e6cff55ba..951f552eb32b6 100644 --- a/tests/ui/match_single_binding.fixed +++ b/tests/ui/match_single_binding.fixed @@ -1,7 +1,7 @@ // run-rustfix - #![warn(clippy::match_single_binding)] -#![allow(unused_variables, clippy::toplevel_ref_arg)] +#![allow(unused_variables)] +#![allow(clippy::toplevel_ref_arg, clippy::uninlined_format_args)] struct Point { x: i32, diff --git a/tests/ui/match_single_binding.rs b/tests/ui/match_single_binding.rs index eea64fcb292b8..19c0fee8fd688 100644 --- a/tests/ui/match_single_binding.rs +++ b/tests/ui/match_single_binding.rs @@ -1,7 +1,7 @@ // run-rustfix - #![warn(clippy::match_single_binding)] -#![allow(unused_variables, clippy::toplevel_ref_arg)] +#![allow(unused_variables)] +#![allow(clippy::toplevel_ref_arg, clippy::uninlined_format_args)] struct Point { x: i32, diff --git a/tests/ui/match_single_binding2.fixed b/tests/ui/match_single_binding2.fixed index a91fcc2125d41..6a7db67e311a5 100644 --- a/tests/ui/match_single_binding2.fixed +++ b/tests/ui/match_single_binding2.fixed @@ -1,7 +1,7 @@ // run-rustfix - #![warn(clippy::match_single_binding)] #![allow(unused_variables)] +#![allow(clippy::uninlined_format_args)] fn main() { // Lint (additional curly braces needed, see #6572) diff --git a/tests/ui/match_single_binding2.rs b/tests/ui/match_single_binding2.rs index 476386ebabe20..5a4bb8441fffc 100644 --- a/tests/ui/match_single_binding2.rs +++ b/tests/ui/match_single_binding2.rs @@ -1,7 +1,7 @@ // run-rustfix - #![warn(clippy::match_single_binding)] #![allow(unused_variables)] +#![allow(clippy::uninlined_format_args)] fn main() { // Lint (additional curly braces needed, see #6572) diff --git a/tests/ui/mut_mut.rs b/tests/ui/mut_mut.rs index be854d9418332..ac8fd9d8fb093 100644 --- a/tests/ui/mut_mut.rs +++ b/tests/ui/mut_mut.rs @@ -1,7 +1,7 @@ // aux-build:macro_rules.rs - -#![allow(unused, clippy::no_effect, clippy::unnecessary_operation)] #![warn(clippy::mut_mut)] +#![allow(unused)] +#![allow(clippy::no_effect, clippy::uninlined_format_args, clippy::unnecessary_operation)] #[macro_use] extern crate macro_rules; diff --git a/tests/ui/needless_borrow.fixed b/tests/ui/needless_borrow.fixed index 6914f9183c7cc..aa2687159ef47 100644 --- a/tests/ui/needless_borrow.fixed +++ b/tests/ui/needless_borrow.fixed @@ -1,9 +1,9 @@ // run-rustfix - #![feature(custom_inner_attributes, lint_reasons)] #[warn(clippy::all, clippy::needless_borrow)] -#[allow(unused_variables, clippy::unnecessary_mut_passed)] +#[allow(unused_variables)] +#[allow(clippy::uninlined_format_args, clippy::unnecessary_mut_passed)] fn main() { let a = 5; let ref_a = &a; diff --git a/tests/ui/needless_borrow.rs b/tests/ui/needless_borrow.rs index e2a609fa5d275..d41251e8f6aac 100644 --- a/tests/ui/needless_borrow.rs +++ b/tests/ui/needless_borrow.rs @@ -1,9 +1,9 @@ // run-rustfix - #![feature(custom_inner_attributes, lint_reasons)] #[warn(clippy::all, clippy::needless_borrow)] -#[allow(unused_variables, clippy::unnecessary_mut_passed)] +#[allow(unused_variables)] +#[allow(clippy::uninlined_format_args, clippy::unnecessary_mut_passed)] fn main() { let a = 5; let ref_a = &a; diff --git a/tests/ui/needless_collect_indirect.rs b/tests/ui/needless_collect_indirect.rs index 12a9ace1ee688..6d213b46c20cb 100644 --- a/tests/ui/needless_collect_indirect.rs +++ b/tests/ui/needless_collect_indirect.rs @@ -1,3 +1,5 @@ +#![allow(clippy::uninlined_format_args)] + use std::collections::{BinaryHeap, HashMap, HashSet, LinkedList, VecDeque}; fn main() { diff --git a/tests/ui/needless_collect_indirect.stderr b/tests/ui/needless_collect_indirect.stderr index 9f0880cc6069d..99e1b91d8fea2 100644 --- a/tests/ui/needless_collect_indirect.stderr +++ b/tests/ui/needless_collect_indirect.stderr @@ -1,5 +1,5 @@ error: avoid using `collect()` when not needed - --> $DIR/needless_collect_indirect.rs:5:39 + --> $DIR/needless_collect_indirect.rs:7:39 | LL | let indirect_iter = sample.iter().collect::>(); | ^^^^^^^ @@ -14,7 +14,7 @@ LL ~ sample.iter().map(|x| (x, x + 1)).collect::>(); | error: avoid using `collect()` when not needed - --> $DIR/needless_collect_indirect.rs:7:38 + --> $DIR/needless_collect_indirect.rs:9:38 | LL | let indirect_len = sample.iter().collect::>(); | ^^^^^^^ @@ -28,7 +28,7 @@ LL ~ sample.iter().count(); | error: avoid using `collect()` when not needed - --> $DIR/needless_collect_indirect.rs:9:40 + --> $DIR/needless_collect_indirect.rs:11:40 | LL | let indirect_empty = sample.iter().collect::>(); | ^^^^^^^ @@ -42,7 +42,7 @@ LL ~ sample.iter().next().is_none(); | error: avoid using `collect()` when not needed - --> $DIR/needless_collect_indirect.rs:11:43 + --> $DIR/needless_collect_indirect.rs:13:43 | LL | let indirect_contains = sample.iter().collect::>(); | ^^^^^^^ @@ -56,7 +56,7 @@ LL ~ sample.iter().any(|x| x == &5); | error: avoid using `collect()` when not needed - --> $DIR/needless_collect_indirect.rs:23:48 + --> $DIR/needless_collect_indirect.rs:25:48 | LL | let non_copy_contains = sample.into_iter().collect::>(); | ^^^^^^^ @@ -70,7 +70,7 @@ LL ~ sample.into_iter().any(|x| x == a); | error: avoid using `collect()` when not needed - --> $DIR/needless_collect_indirect.rs:52:51 + --> $DIR/needless_collect_indirect.rs:54:51 | LL | let buffer: Vec<&str> = string.split('/').collect(); | ^^^^^^^ @@ -84,7 +84,7 @@ LL ~ string.split('/').count() | error: avoid using `collect()` when not needed - --> $DIR/needless_collect_indirect.rs:57:55 + --> $DIR/needless_collect_indirect.rs:59:55 | LL | let indirect_len: VecDeque<_> = sample.iter().collect(); | ^^^^^^^ @@ -98,7 +98,7 @@ LL ~ sample.iter().count() | error: avoid using `collect()` when not needed - --> $DIR/needless_collect_indirect.rs:62:57 + --> $DIR/needless_collect_indirect.rs:64:57 | LL | let indirect_len: LinkedList<_> = sample.iter().collect(); | ^^^^^^^ @@ -112,7 +112,7 @@ LL ~ sample.iter().count() | error: avoid using `collect()` when not needed - --> $DIR/needless_collect_indirect.rs:67:57 + --> $DIR/needless_collect_indirect.rs:69:57 | LL | let indirect_len: BinaryHeap<_> = sample.iter().collect(); | ^^^^^^^ @@ -126,7 +126,7 @@ LL ~ sample.iter().count() | error: avoid using `collect()` when not needed - --> $DIR/needless_collect_indirect.rs:127:59 + --> $DIR/needless_collect_indirect.rs:129:59 | LL | let y: Vec = vec.iter().map(|k| k * k).collect(); | ^^^^^^^ @@ -143,7 +143,7 @@ LL ~ vec.iter().map(|k| k * k).any(|x| x == i); | error: avoid using `collect()` when not needed - --> $DIR/needless_collect_indirect.rs:152:59 + --> $DIR/needless_collect_indirect.rs:154:59 | LL | let y: Vec = vec.iter().map(|k| k * k).collect(); | ^^^^^^^ @@ -160,7 +160,7 @@ LL ~ vec.iter().map(|k| k * k).any(|x| x == n); | error: avoid using `collect()` when not needed - --> $DIR/needless_collect_indirect.rs:181:63 + --> $DIR/needless_collect_indirect.rs:183:63 | LL | let y: Vec = vec.iter().map(|k| k * k).collect(); | ^^^^^^^ @@ -177,7 +177,7 @@ LL ~ vec.iter().map(|k| k * k).any(|x| x == n); | error: avoid using `collect()` when not needed - --> $DIR/needless_collect_indirect.rs:217:59 + --> $DIR/needless_collect_indirect.rs:219:59 | LL | let y: Vec = vec.iter().map(|k| k * k).collect(); | ^^^^^^^ @@ -195,7 +195,7 @@ LL ~ vec.iter().map(|k| k * k).any(|x| x == n); | error: avoid using `collect()` when not needed - --> $DIR/needless_collect_indirect.rs:242:26 + --> $DIR/needless_collect_indirect.rs:244:26 | LL | let w = v.iter().collect::>(); | ^^^^^^^ @@ -211,7 +211,7 @@ LL ~ for _ in 0..v.iter().count() { | error: avoid using `collect()` when not needed - --> $DIR/needless_collect_indirect.rs:264:30 + --> $DIR/needless_collect_indirect.rs:266:30 | LL | let mut w = v.iter().collect::>(); | ^^^^^^^ @@ -227,7 +227,7 @@ LL ~ while 1 == v.iter().count() { | error: avoid using `collect()` when not needed - --> $DIR/needless_collect_indirect.rs:286:30 + --> $DIR/needless_collect_indirect.rs:288:30 | LL | let mut w = v.iter().collect::>(); | ^^^^^^^ diff --git a/tests/ui/needless_continue.rs b/tests/ui/needless_continue.rs index f105d3d659ac7..c891c9de3aeca 100644 --- a/tests/ui/needless_continue.rs +++ b/tests/ui/needless_continue.rs @@ -1,4 +1,5 @@ #![warn(clippy::needless_continue)] +#![allow(clippy::uninlined_format_args)] macro_rules! zero { ($x:expr) => { diff --git a/tests/ui/needless_continue.stderr b/tests/ui/needless_continue.stderr index b8657c74caa69..44ca3cb97f105 100644 --- a/tests/ui/needless_continue.stderr +++ b/tests/ui/needless_continue.stderr @@ -1,5 +1,5 @@ error: this `else` block is redundant - --> $DIR/needless_continue.rs:29:16 + --> $DIR/needless_continue.rs:30:16 | LL | } else { | ________________^ @@ -35,7 +35,7 @@ LL | | } } error: there is no need for an explicit `else` block for this `if` expression - --> $DIR/needless_continue.rs:44:9 + --> $DIR/needless_continue.rs:45:9 | LL | / if (zero!(i % 2) || nonzero!(i % 5)) && i % 3 != 0 { LL | | continue; @@ -55,7 +55,7 @@ LL | | } } error: this `continue` expression is redundant - --> $DIR/needless_continue.rs:57:9 + --> $DIR/needless_continue.rs:58:9 | LL | continue; // should lint here | ^^^^^^^^^ @@ -63,7 +63,7 @@ LL | continue; // should lint here = help: consider dropping the `continue` expression error: this `continue` expression is redundant - --> $DIR/needless_continue.rs:64:9 + --> $DIR/needless_continue.rs:65:9 | LL | continue; // should lint here | ^^^^^^^^^ @@ -71,7 +71,7 @@ LL | continue; // should lint here = help: consider dropping the `continue` expression error: this `continue` expression is redundant - --> $DIR/needless_continue.rs:71:9 + --> $DIR/needless_continue.rs:72:9 | LL | continue // should lint here | ^^^^^^^^ @@ -79,7 +79,7 @@ LL | continue // should lint here = help: consider dropping the `continue` expression error: this `continue` expression is redundant - --> $DIR/needless_continue.rs:79:9 + --> $DIR/needless_continue.rs:80:9 | LL | continue // should lint here | ^^^^^^^^ @@ -87,7 +87,7 @@ LL | continue // should lint here = help: consider dropping the `continue` expression error: this `else` block is redundant - --> $DIR/needless_continue.rs:129:24 + --> $DIR/needless_continue.rs:130:24 | LL | } else { | ________________________^ @@ -110,7 +110,7 @@ LL | | } } error: there is no need for an explicit `else` block for this `if` expression - --> $DIR/needless_continue.rs:135:17 + --> $DIR/needless_continue.rs:136:17 | LL | / if condition() { LL | | continue; // should lint here diff --git a/tests/ui/needless_for_each_fixable.fixed b/tests/ui/needless_for_each_fixable.fixed index c1685f7b6d7ad..09e671b88e1aa 100644 --- a/tests/ui/needless_for_each_fixable.fixed +++ b/tests/ui/needless_for_each_fixable.fixed @@ -1,10 +1,11 @@ // run-rustfix #![warn(clippy::needless_for_each)] +#![allow(unused)] #![allow( - unused, - clippy::needless_return, + clippy::let_unit_value, clippy::match_single_binding, - clippy::let_unit_value + clippy::needless_return, + clippy::uninlined_format_args )] use std::collections::HashMap; diff --git a/tests/ui/needless_for_each_fixable.rs b/tests/ui/needless_for_each_fixable.rs index ad17b0956fa93..abb4045b9197d 100644 --- a/tests/ui/needless_for_each_fixable.rs +++ b/tests/ui/needless_for_each_fixable.rs @@ -1,10 +1,11 @@ // run-rustfix #![warn(clippy::needless_for_each)] +#![allow(unused)] #![allow( - unused, - clippy::needless_return, + clippy::let_unit_value, clippy::match_single_binding, - clippy::let_unit_value + clippy::needless_return, + clippy::uninlined_format_args )] use std::collections::HashMap; diff --git a/tests/ui/needless_for_each_fixable.stderr b/tests/ui/needless_for_each_fixable.stderr index 08e995851d7a5..aebb762cc2283 100644 --- a/tests/ui/needless_for_each_fixable.stderr +++ b/tests/ui/needless_for_each_fixable.stderr @@ -1,5 +1,5 @@ error: needless use of `for_each` - --> $DIR/needless_for_each_fixable.rs:15:5 + --> $DIR/needless_for_each_fixable.rs:16:5 | LL | / v.iter().for_each(|elem| { LL | | acc += elem; @@ -15,7 +15,7 @@ LL + } | error: needless use of `for_each` - --> $DIR/needless_for_each_fixable.rs:18:5 + --> $DIR/needless_for_each_fixable.rs:19:5 | LL | / v.into_iter().for_each(|elem| { LL | | acc += elem; @@ -30,7 +30,7 @@ LL + } | error: needless use of `for_each` - --> $DIR/needless_for_each_fixable.rs:22:5 + --> $DIR/needless_for_each_fixable.rs:23:5 | LL | / [1, 2, 3].iter().for_each(|elem| { LL | | acc += elem; @@ -45,7 +45,7 @@ LL + } | error: needless use of `for_each` - --> $DIR/needless_for_each_fixable.rs:27:5 + --> $DIR/needless_for_each_fixable.rs:28:5 | LL | / hash_map.iter().for_each(|(k, v)| { LL | | acc += k + v; @@ -60,7 +60,7 @@ LL + } | error: needless use of `for_each` - --> $DIR/needless_for_each_fixable.rs:30:5 + --> $DIR/needless_for_each_fixable.rs:31:5 | LL | / hash_map.iter_mut().for_each(|(k, v)| { LL | | acc += *k + *v; @@ -75,7 +75,7 @@ LL + } | error: needless use of `for_each` - --> $DIR/needless_for_each_fixable.rs:33:5 + --> $DIR/needless_for_each_fixable.rs:34:5 | LL | / hash_map.keys().for_each(|k| { LL | | acc += k; @@ -90,7 +90,7 @@ LL + } | error: needless use of `for_each` - --> $DIR/needless_for_each_fixable.rs:36:5 + --> $DIR/needless_for_each_fixable.rs:37:5 | LL | / hash_map.values().for_each(|v| { LL | | acc += v; @@ -105,7 +105,7 @@ LL + } | error: needless use of `for_each` - --> $DIR/needless_for_each_fixable.rs:43:5 + --> $DIR/needless_for_each_fixable.rs:44:5 | LL | / my_vec().iter().for_each(|elem| { LL | | acc += elem; diff --git a/tests/ui/needless_for_each_unfixable.rs b/tests/ui/needless_for_each_unfixable.rs index d765d7dab65c9..282c72881d510 100644 --- a/tests/ui/needless_for_each_unfixable.rs +++ b/tests/ui/needless_for_each_unfixable.rs @@ -1,5 +1,5 @@ #![warn(clippy::needless_for_each)] -#![allow(clippy::needless_return)] +#![allow(clippy::needless_return, clippy::uninlined_format_args)] fn main() { let v: Vec = Vec::new(); diff --git a/tests/ui/needless_late_init.fixed b/tests/ui/needless_late_init.fixed index fee8e3030b808..17f2227ba91c4 100644 --- a/tests/ui/needless_late_init.fixed +++ b/tests/ui/needless_late_init.fixed @@ -1,12 +1,13 @@ // run-rustfix #![feature(let_chains)] +#![allow(unused)] #![allow( - unused, clippy::assign_op_pattern, clippy::blocks_in_if_conditions, clippy::let_and_return, clippy::let_unit_value, - clippy::nonminimal_bool + clippy::nonminimal_bool, + clippy::uninlined_format_args )] use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; diff --git a/tests/ui/needless_late_init.rs b/tests/ui/needless_late_init.rs index 402d9f9ef7f81..d84457a298753 100644 --- a/tests/ui/needless_late_init.rs +++ b/tests/ui/needless_late_init.rs @@ -1,12 +1,13 @@ // run-rustfix #![feature(let_chains)] +#![allow(unused)] #![allow( - unused, clippy::assign_op_pattern, clippy::blocks_in_if_conditions, clippy::let_and_return, clippy::let_unit_value, - clippy::nonminimal_bool + clippy::nonminimal_bool, + clippy::uninlined_format_args )] use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; diff --git a/tests/ui/needless_late_init.stderr b/tests/ui/needless_late_init.stderr index 313cdbbeba183..0a256fb4a131c 100644 --- a/tests/ui/needless_late_init.stderr +++ b/tests/ui/needless_late_init.stderr @@ -1,5 +1,5 @@ error: unneeded late initialization - --> $DIR/needless_late_init.rs:23:5 + --> $DIR/needless_late_init.rs:24:5 | LL | let a; | ^^^^^^ created here @@ -13,7 +13,7 @@ LL | let a = "zero"; | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:26:5 + --> $DIR/needless_late_init.rs:27:5 | LL | let b; | ^^^^^^ created here @@ -27,7 +27,7 @@ LL | let b = 1; | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:27:5 + --> $DIR/needless_late_init.rs:28:5 | LL | let c; | ^^^^^^ created here @@ -41,7 +41,7 @@ LL | let c = 2; | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:31:5 + --> $DIR/needless_late_init.rs:32:5 | LL | let d: usize; | ^^^^^^^^^^^^^ created here @@ -54,7 +54,7 @@ LL | let d: usize = 1; | ~~~~~~~~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:34:5 + --> $DIR/needless_late_init.rs:35:5 | LL | let e; | ^^^^^^ created here @@ -67,7 +67,7 @@ LL | let e = format!("{}", d); | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:39:5 + --> $DIR/needless_late_init.rs:40:5 | LL | let a; | ^^^^^^ @@ -88,7 +88,7 @@ LL | }; | + error: unneeded late initialization - --> $DIR/needless_late_init.rs:48:5 + --> $DIR/needless_late_init.rs:49:5 | LL | let b; | ^^^^^^ @@ -109,7 +109,7 @@ LL | }; | + error: unneeded late initialization - --> $DIR/needless_late_init.rs:55:5 + --> $DIR/needless_late_init.rs:56:5 | LL | let d; | ^^^^^^ @@ -130,7 +130,7 @@ LL | }; | + error: unneeded late initialization - --> $DIR/needless_late_init.rs:63:5 + --> $DIR/needless_late_init.rs:64:5 | LL | let e; | ^^^^^^ @@ -151,7 +151,7 @@ LL | }; | + error: unneeded late initialization - --> $DIR/needless_late_init.rs:70:5 + --> $DIR/needless_late_init.rs:71:5 | LL | let f; | ^^^^^^ @@ -167,7 +167,7 @@ LL + 1 => "three", | error: unneeded late initialization - --> $DIR/needless_late_init.rs:76:5 + --> $DIR/needless_late_init.rs:77:5 | LL | let g: usize; | ^^^^^^^^^^^^^ @@ -187,7 +187,7 @@ LL | }; | + error: unneeded late initialization - --> $DIR/needless_late_init.rs:84:5 + --> $DIR/needless_late_init.rs:85:5 | LL | let x; | ^^^^^^ created here @@ -201,7 +201,7 @@ LL | let x = 1; | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:88:5 + --> $DIR/needless_late_init.rs:89:5 | LL | let x; | ^^^^^^ created here @@ -215,7 +215,7 @@ LL | let x = SignificantDrop; | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:92:5 + --> $DIR/needless_late_init.rs:93:5 | LL | let x; | ^^^^^^ created here @@ -229,7 +229,7 @@ LL | let x = SignificantDrop; | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:111:5 + --> $DIR/needless_late_init.rs:112:5 | LL | let a; | ^^^^^^ @@ -250,7 +250,7 @@ LL | }; | + error: unneeded late initialization - --> $DIR/needless_late_init.rs:128:5 + --> $DIR/needless_late_init.rs:129:5 | LL | let a; | ^^^^^^ diff --git a/tests/ui/needless_pass_by_value.rs b/tests/ui/needless_pass_by_value.rs index 5a35b100afe07..d79ad86b1948c 100644 --- a/tests/ui/needless_pass_by_value.rs +++ b/tests/ui/needless_pass_by_value.rs @@ -1,10 +1,11 @@ #![warn(clippy::needless_pass_by_value)] +#![allow(dead_code)] #![allow( - dead_code, - clippy::single_match, - clippy::redundant_pattern_matching, clippy::option_option, - clippy::redundant_clone + clippy::redundant_clone, + clippy::redundant_pattern_matching, + clippy::single_match, + clippy::uninlined_format_args )] use std::borrow::Borrow; diff --git a/tests/ui/needless_pass_by_value.stderr b/tests/ui/needless_pass_by_value.stderr index 38f33c53f128b..0e660a77dc0cc 100644 --- a/tests/ui/needless_pass_by_value.stderr +++ b/tests/ui/needless_pass_by_value.stderr @@ -1,5 +1,5 @@ error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:17:23 + --> $DIR/needless_pass_by_value.rs:18:23 | LL | fn foo(v: Vec, w: Vec, mut x: Vec, y: Vec) -> Vec { | ^^^^^^ help: consider changing the type to: `&[T]` @@ -7,55 +7,55 @@ LL | fn foo(v: Vec, w: Vec, mut x: Vec, y: Vec) -> Vec $DIR/needless_pass_by_value.rs:31:11 + --> $DIR/needless_pass_by_value.rs:32:11 | LL | fn bar(x: String, y: Wrapper) { | ^^^^^^ help: consider changing the type to: `&str` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:31:22 + --> $DIR/needless_pass_by_value.rs:32:22 | LL | fn bar(x: String, y: Wrapper) { | ^^^^^^^ help: consider taking a reference instead: `&Wrapper` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:37:71 + --> $DIR/needless_pass_by_value.rs:38:71 | LL | fn test_borrow_trait, U: AsRef, V>(t: T, u: U, v: V) { | ^ help: consider taking a reference instead: `&V` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:49:18 + --> $DIR/needless_pass_by_value.rs:50:18 | LL | fn test_match(x: Option>, y: Option>) { | ^^^^^^^^^^^^^^^^^^^^^^ help: consider taking a reference instead: `&Option>` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:62:24 + --> $DIR/needless_pass_by_value.rs:63:24 | LL | fn test_destructure(x: Wrapper, y: Wrapper, z: Wrapper) { | ^^^^^^^ help: consider taking a reference instead: `&Wrapper` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:62:36 + --> $DIR/needless_pass_by_value.rs:63:36 | LL | fn test_destructure(x: Wrapper, y: Wrapper, z: Wrapper) { | ^^^^^^^ help: consider taking a reference instead: `&Wrapper` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:78:49 + --> $DIR/needless_pass_by_value.rs:79:49 | LL | fn test_blanket_ref(_foo: T, _serializable: S) {} | ^ help: consider taking a reference instead: `&T` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:80:18 + --> $DIR/needless_pass_by_value.rs:81:18 | LL | fn issue_2114(s: String, t: String, u: Vec, v: Vec) { | ^^^^^^ help: consider taking a reference instead: `&String` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:80:29 + --> $DIR/needless_pass_by_value.rs:81:29 | LL | fn issue_2114(s: String, t: String, u: Vec, v: Vec) { | ^^^^^^ @@ -70,13 +70,13 @@ LL | let _ = t.to_string(); | ~~~~~~~~~~~~~ error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:80:40 + --> $DIR/needless_pass_by_value.rs:81:40 | LL | fn issue_2114(s: String, t: String, u: Vec, v: Vec) { | ^^^^^^^^ help: consider taking a reference instead: `&Vec` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:80:53 + --> $DIR/needless_pass_by_value.rs:81:53 | LL | fn issue_2114(s: String, t: String, u: Vec, v: Vec) { | ^^^^^^^^ @@ -91,85 +91,85 @@ LL | let _ = v.to_owned(); | ~~~~~~~~~~~~ error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:93:12 + --> $DIR/needless_pass_by_value.rs:94:12 | LL | s: String, | ^^^^^^ help: consider changing the type to: `&str` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:94:12 + --> $DIR/needless_pass_by_value.rs:95:12 | LL | t: String, | ^^^^^^ help: consider taking a reference instead: `&String` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:103:23 + --> $DIR/needless_pass_by_value.rs:104:23 | LL | fn baz(&self, _u: U, _s: Self) {} | ^ help: consider taking a reference instead: `&U` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:103:30 + --> $DIR/needless_pass_by_value.rs:104:30 | LL | fn baz(&self, _u: U, _s: Self) {} | ^^^^ help: consider taking a reference instead: `&Self` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:125:24 + --> $DIR/needless_pass_by_value.rs:126:24 | LL | fn bar_copy(x: u32, y: CopyWrapper) { | ^^^^^^^^^^^ help: consider taking a reference instead: `&CopyWrapper` | help: consider marking this type as `Copy` - --> $DIR/needless_pass_by_value.rs:123:1 + --> $DIR/needless_pass_by_value.rs:124:1 | LL | struct CopyWrapper(u32); | ^^^^^^^^^^^^^^^^^^ error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:131:29 + --> $DIR/needless_pass_by_value.rs:132:29 | LL | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) { | ^^^^^^^^^^^ help: consider taking a reference instead: `&CopyWrapper` | help: consider marking this type as `Copy` - --> $DIR/needless_pass_by_value.rs:123:1 + --> $DIR/needless_pass_by_value.rs:124:1 | LL | struct CopyWrapper(u32); | ^^^^^^^^^^^^^^^^^^ error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:131:45 + --> $DIR/needless_pass_by_value.rs:132:45 | LL | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) { | ^^^^^^^^^^^ help: consider taking a reference instead: `&CopyWrapper` | help: consider marking this type as `Copy` - --> $DIR/needless_pass_by_value.rs:123:1 + --> $DIR/needless_pass_by_value.rs:124:1 | LL | struct CopyWrapper(u32); | ^^^^^^^^^^^^^^^^^^ error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:131:61 + --> $DIR/needless_pass_by_value.rs:132:61 | LL | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) { | ^^^^^^^^^^^ help: consider taking a reference instead: `&CopyWrapper` | help: consider marking this type as `Copy` - --> $DIR/needless_pass_by_value.rs:123:1 + --> $DIR/needless_pass_by_value.rs:124:1 | LL | struct CopyWrapper(u32); | ^^^^^^^^^^^^^^^^^^ error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:143:40 + --> $DIR/needless_pass_by_value.rs:144:40 | LL | fn some_fun<'b, S: Bar<'b, ()>>(_item: S) {} | ^ help: consider taking a reference instead: `&S` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:148:20 + --> $DIR/needless_pass_by_value.rs:149:20 | LL | fn more_fun(_item: impl Club<'static, i32>) {} | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider taking a reference instead: `&impl Club<'static, i32>` diff --git a/tests/ui/needless_range_loop.rs b/tests/ui/needless_range_loop.rs index 3fce34367ae50..921801138a9b6 100644 --- a/tests/ui/needless_range_loop.rs +++ b/tests/ui/needless_range_loop.rs @@ -1,4 +1,5 @@ #![warn(clippy::needless_range_loop)] +#![allow(clippy::uninlined_format_args)] static STATIC: [usize; 4] = [0, 1, 8, 16]; const CONST: [usize; 4] = [0, 1, 8, 16]; diff --git a/tests/ui/needless_range_loop.stderr b/tests/ui/needless_range_loop.stderr index a86cc69dfc5db..b31544ec334a6 100644 --- a/tests/ui/needless_range_loop.stderr +++ b/tests/ui/needless_range_loop.stderr @@ -1,5 +1,5 @@ error: the loop variable `i` is only used to index `vec` - --> $DIR/needless_range_loop.rs:10:14 + --> $DIR/needless_range_loop.rs:11:14 | LL | for i in 0..vec.len() { | ^^^^^^^^^^^^ @@ -11,7 +11,7 @@ LL | for in &vec { | ~~~~~~ ~~~~ error: the loop variable `i` is only used to index `vec` - --> $DIR/needless_range_loop.rs:19:14 + --> $DIR/needless_range_loop.rs:20:14 | LL | for i in 0..vec.len() { | ^^^^^^^^^^^^ @@ -22,7 +22,7 @@ LL | for in &vec { | ~~~~~~ ~~~~ error: the loop variable `j` is only used to index `STATIC` - --> $DIR/needless_range_loop.rs:24:14 + --> $DIR/needless_range_loop.rs:25:14 | LL | for j in 0..4 { | ^^^^ @@ -33,7 +33,7 @@ LL | for in &STATIC { | ~~~~~~ ~~~~~~~ error: the loop variable `j` is only used to index `CONST` - --> $DIR/needless_range_loop.rs:28:14 + --> $DIR/needless_range_loop.rs:29:14 | LL | for j in 0..4 { | ^^^^ @@ -44,7 +44,7 @@ LL | for in &CONST { | ~~~~~~ ~~~~~~ error: the loop variable `i` is used to index `vec` - --> $DIR/needless_range_loop.rs:32:14 + --> $DIR/needless_range_loop.rs:33:14 | LL | for i in 0..vec.len() { | ^^^^^^^^^^^^ @@ -55,7 +55,7 @@ LL | for (i, ) in vec.iter().enumerate() { | ~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~ error: the loop variable `i` is only used to index `vec2` - --> $DIR/needless_range_loop.rs:40:14 + --> $DIR/needless_range_loop.rs:41:14 | LL | for i in 0..vec.len() { | ^^^^^^^^^^^^ @@ -66,7 +66,7 @@ LL | for in vec2.iter().take(vec.len()) { | ~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: the loop variable `i` is only used to index `vec` - --> $DIR/needless_range_loop.rs:44:14 + --> $DIR/needless_range_loop.rs:45:14 | LL | for i in 5..vec.len() { | ^^^^^^^^^^^^ @@ -77,7 +77,7 @@ LL | for in vec.iter().skip(5) { | ~~~~~~ ~~~~~~~~~~~~~~~~~~ error: the loop variable `i` is only used to index `vec` - --> $DIR/needless_range_loop.rs:48:14 + --> $DIR/needless_range_loop.rs:49:14 | LL | for i in 0..MAX_LEN { | ^^^^^^^^^^ @@ -88,7 +88,7 @@ LL | for in vec.iter().take(MAX_LEN) { | ~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~ error: the loop variable `i` is only used to index `vec` - --> $DIR/needless_range_loop.rs:52:14 + --> $DIR/needless_range_loop.rs:53:14 | LL | for i in 0..=MAX_LEN { | ^^^^^^^^^^^ @@ -99,7 +99,7 @@ LL | for in vec.iter().take(MAX_LEN + 1) { | ~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: the loop variable `i` is only used to index `vec` - --> $DIR/needless_range_loop.rs:56:14 + --> $DIR/needless_range_loop.rs:57:14 | LL | for i in 5..10 { | ^^^^^ @@ -110,7 +110,7 @@ LL | for in vec.iter().take(10).skip(5) { | ~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: the loop variable `i` is only used to index `vec` - --> $DIR/needless_range_loop.rs:60:14 + --> $DIR/needless_range_loop.rs:61:14 | LL | for i in 5..=10 { | ^^^^^^ @@ -121,7 +121,7 @@ LL | for in vec.iter().take(10 + 1).skip(5) { | ~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: the loop variable `i` is used to index `vec` - --> $DIR/needless_range_loop.rs:64:14 + --> $DIR/needless_range_loop.rs:65:14 | LL | for i in 5..vec.len() { | ^^^^^^^^^^^^ @@ -132,7 +132,7 @@ LL | for (i, ) in vec.iter().enumerate().skip(5) { | ~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: the loop variable `i` is used to index `vec` - --> $DIR/needless_range_loop.rs:68:14 + --> $DIR/needless_range_loop.rs:69:14 | LL | for i in 5..10 { | ^^^^^ @@ -143,7 +143,7 @@ LL | for (i, ) in vec.iter().enumerate().take(10).skip(5) { | ~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: the loop variable `i` is used to index `vec` - --> $DIR/needless_range_loop.rs:73:14 + --> $DIR/needless_range_loop.rs:74:14 | LL | for i in 0..vec.len() { | ^^^^^^^^^^^^ diff --git a/tests/ui/no_effect.rs b/tests/ui/no_effect.rs index fdefb11ae17a5..f08eb092e6b21 100644 --- a/tests/ui/no_effect.rs +++ b/tests/ui/no_effect.rs @@ -1,9 +1,7 @@ #![feature(box_syntax, fn_traits, unboxed_closures)] #![warn(clippy::no_effect_underscore_binding)] -#![allow(dead_code)] -#![allow(path_statements)] -#![allow(clippy::deref_addrof)] -#![allow(clippy::redundant_field_names)] +#![allow(dead_code, path_statements)] +#![allow(clippy::deref_addrof, clippy::redundant_field_names, clippy::uninlined_format_args)] struct Unit; struct Tuple(i32); diff --git a/tests/ui/no_effect.stderr b/tests/ui/no_effect.stderr index 328d2555ceb8e..6a1e636f9a61b 100644 --- a/tests/ui/no_effect.stderr +++ b/tests/ui/no_effect.stderr @@ -1,5 +1,5 @@ error: statement with no effect - --> $DIR/no_effect.rs:94:5 + --> $DIR/no_effect.rs:92:5 | LL | 0; | ^^ @@ -7,157 +7,157 @@ LL | 0; = note: `-D clippy::no-effect` implied by `-D warnings` error: statement with no effect - --> $DIR/no_effect.rs:95:5 + --> $DIR/no_effect.rs:93:5 | LL | s2; | ^^^ error: statement with no effect - --> $DIR/no_effect.rs:96:5 + --> $DIR/no_effect.rs:94:5 | LL | Unit; | ^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:97:5 + --> $DIR/no_effect.rs:95:5 | LL | Tuple(0); | ^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:98:5 + --> $DIR/no_effect.rs:96:5 | LL | Struct { field: 0 }; | ^^^^^^^^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:99:5 + --> $DIR/no_effect.rs:97:5 | LL | Struct { ..s }; | ^^^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:100:5 + --> $DIR/no_effect.rs:98:5 | LL | Union { a: 0 }; | ^^^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:101:5 + --> $DIR/no_effect.rs:99:5 | LL | Enum::Tuple(0); | ^^^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:102:5 + --> $DIR/no_effect.rs:100:5 | LL | Enum::Struct { field: 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:103:5 + --> $DIR/no_effect.rs:101:5 | LL | 5 + 6; | ^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:104:5 + --> $DIR/no_effect.rs:102:5 | LL | *&42; | ^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:105:5 + --> $DIR/no_effect.rs:103:5 | LL | &6; | ^^^ error: statement with no effect - --> $DIR/no_effect.rs:106:5 + --> $DIR/no_effect.rs:104:5 | LL | (5, 6, 7); | ^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:107:5 + --> $DIR/no_effect.rs:105:5 | LL | box 42; | ^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:108:5 + --> $DIR/no_effect.rs:106:5 | LL | ..; | ^^^ error: statement with no effect - --> $DIR/no_effect.rs:109:5 + --> $DIR/no_effect.rs:107:5 | LL | 5..; | ^^^^ error: statement with no effect - --> $DIR/no_effect.rs:110:5 + --> $DIR/no_effect.rs:108:5 | LL | ..5; | ^^^^ error: statement with no effect - --> $DIR/no_effect.rs:111:5 + --> $DIR/no_effect.rs:109:5 | LL | 5..6; | ^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:112:5 + --> $DIR/no_effect.rs:110:5 | LL | 5..=6; | ^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:113:5 + --> $DIR/no_effect.rs:111:5 | LL | [42, 55]; | ^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:114:5 + --> $DIR/no_effect.rs:112:5 | LL | [42, 55][1]; | ^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:115:5 + --> $DIR/no_effect.rs:113:5 | LL | (42, 55).1; | ^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:116:5 + --> $DIR/no_effect.rs:114:5 | LL | [42; 55]; | ^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:117:5 + --> $DIR/no_effect.rs:115:5 | LL | [42; 55][13]; | ^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:119:5 + --> $DIR/no_effect.rs:117:5 | LL | || x += 5; | ^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:121:5 + --> $DIR/no_effect.rs:119:5 | LL | FooString { s: s }; | ^^^^^^^^^^^^^^^^^^^ error: binding to `_` prefixed variable with no side-effect - --> $DIR/no_effect.rs:122:5 + --> $DIR/no_effect.rs:120:5 | LL | let _unused = 1; | ^^^^^^^^^^^^^^^^ @@ -165,19 +165,19 @@ LL | let _unused = 1; = note: `-D clippy::no-effect-underscore-binding` implied by `-D warnings` error: binding to `_` prefixed variable with no side-effect - --> $DIR/no_effect.rs:123:5 + --> $DIR/no_effect.rs:121:5 | LL | let _penguin = || println!("Some helpful closure"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: binding to `_` prefixed variable with no side-effect - --> $DIR/no_effect.rs:124:5 + --> $DIR/no_effect.rs:122:5 | LL | let _duck = Struct { field: 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: binding to `_` prefixed variable with no side-effect - --> $DIR/no_effect.rs:125:5 + --> $DIR/no_effect.rs:123:5 | LL | let _cat = [2, 4, 6, 8][2]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/option_map_unit_fn_fixable.fixed b/tests/ui/option_map_unit_fn_fixable.fixed index 1290bd8efebd2..00264dcceaa8d 100644 --- a/tests/ui/option_map_unit_fn_fixable.fixed +++ b/tests/ui/option_map_unit_fn_fixable.fixed @@ -1,8 +1,7 @@ // run-rustfix - #![warn(clippy::option_map_unit_fn)] #![allow(unused)] -#![allow(clippy::unnecessary_wraps)] +#![allow(clippy::uninlined_format_args, clippy::unnecessary_wraps)] fn do_nothing(_: T) {} diff --git a/tests/ui/option_map_unit_fn_fixable.rs b/tests/ui/option_map_unit_fn_fixable.rs index f3e5b62c65b7f..f3363ebce54e2 100644 --- a/tests/ui/option_map_unit_fn_fixable.rs +++ b/tests/ui/option_map_unit_fn_fixable.rs @@ -1,8 +1,7 @@ // run-rustfix - #![warn(clippy::option_map_unit_fn)] #![allow(unused)] -#![allow(clippy::unnecessary_wraps)] +#![allow(clippy::uninlined_format_args, clippy::unnecessary_wraps)] fn do_nothing(_: T) {} diff --git a/tests/ui/option_map_unit_fn_fixable.stderr b/tests/ui/option_map_unit_fn_fixable.stderr index ab2a294a060f0..0305387b9f8ae 100644 --- a/tests/ui/option_map_unit_fn_fixable.stderr +++ b/tests/ui/option_map_unit_fn_fixable.stderr @@ -1,5 +1,5 @@ error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:39:5 + --> $DIR/option_map_unit_fn_fixable.rs:38:5 | LL | x.field.map(do_nothing); | ^^^^^^^^^^^^^^^^^^^^^^^- @@ -9,7 +9,7 @@ LL | x.field.map(do_nothing); = note: `-D clippy::option-map-unit-fn` implied by `-D warnings` error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:41:5 + --> $DIR/option_map_unit_fn_fixable.rs:40:5 | LL | x.field.map(do_nothing); | ^^^^^^^^^^^^^^^^^^^^^^^- @@ -17,7 +17,7 @@ LL | x.field.map(do_nothing); | help: try this: `if let Some(x_field) = x.field { do_nothing(x_field) }` error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:43:5 + --> $DIR/option_map_unit_fn_fixable.rs:42:5 | LL | x.field.map(diverge); | ^^^^^^^^^^^^^^^^^^^^- @@ -25,7 +25,7 @@ LL | x.field.map(diverge); | help: try this: `if let Some(x_field) = x.field { diverge(x_field) }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:49:5 + --> $DIR/option_map_unit_fn_fixable.rs:48:5 | LL | x.field.map(|value| x.do_option_nothing(value + captured)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -33,7 +33,7 @@ LL | x.field.map(|value| x.do_option_nothing(value + captured)); | help: try this: `if let Some(value) = x.field { x.do_option_nothing(value + captured) }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:51:5 + --> $DIR/option_map_unit_fn_fixable.rs:50:5 | LL | x.field.map(|value| { x.do_option_plus_one(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -41,7 +41,7 @@ LL | x.field.map(|value| { x.do_option_plus_one(value + captured); }); | help: try this: `if let Some(value) = x.field { x.do_option_plus_one(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:54:5 + --> $DIR/option_map_unit_fn_fixable.rs:53:5 | LL | x.field.map(|value| do_nothing(value + captured)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -49,7 +49,7 @@ LL | x.field.map(|value| do_nothing(value + captured)); | help: try this: `if let Some(value) = x.field { do_nothing(value + captured) }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:56:5 + --> $DIR/option_map_unit_fn_fixable.rs:55:5 | LL | x.field.map(|value| { do_nothing(value + captured) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -57,7 +57,7 @@ LL | x.field.map(|value| { do_nothing(value + captured) }); | help: try this: `if let Some(value) = x.field { do_nothing(value + captured) }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:58:5 + --> $DIR/option_map_unit_fn_fixable.rs:57:5 | LL | x.field.map(|value| { do_nothing(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -65,7 +65,7 @@ LL | x.field.map(|value| { do_nothing(value + captured); }); | help: try this: `if let Some(value) = x.field { do_nothing(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:60:5 + --> $DIR/option_map_unit_fn_fixable.rs:59:5 | LL | x.field.map(|value| { { do_nothing(value + captured); } }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -73,7 +73,7 @@ LL | x.field.map(|value| { { do_nothing(value + captured); } }); | help: try this: `if let Some(value) = x.field { do_nothing(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:63:5 + --> $DIR/option_map_unit_fn_fixable.rs:62:5 | LL | x.field.map(|value| diverge(value + captured)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -81,7 +81,7 @@ LL | x.field.map(|value| diverge(value + captured)); | help: try this: `if let Some(value) = x.field { diverge(value + captured) }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:65:5 + --> $DIR/option_map_unit_fn_fixable.rs:64:5 | LL | x.field.map(|value| { diverge(value + captured) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -89,7 +89,7 @@ LL | x.field.map(|value| { diverge(value + captured) }); | help: try this: `if let Some(value) = x.field { diverge(value + captured) }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:67:5 + --> $DIR/option_map_unit_fn_fixable.rs:66:5 | LL | x.field.map(|value| { diverge(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -97,7 +97,7 @@ LL | x.field.map(|value| { diverge(value + captured); }); | help: try this: `if let Some(value) = x.field { diverge(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:69:5 + --> $DIR/option_map_unit_fn_fixable.rs:68:5 | LL | x.field.map(|value| { { diverge(value + captured); } }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -105,7 +105,7 @@ LL | x.field.map(|value| { { diverge(value + captured); } }); | help: try this: `if let Some(value) = x.field { diverge(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:74:5 + --> $DIR/option_map_unit_fn_fixable.rs:73:5 | LL | x.field.map(|value| { let y = plus_one(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -113,7 +113,7 @@ LL | x.field.map(|value| { let y = plus_one(value + captured); }); | help: try this: `if let Some(value) = x.field { let y = plus_one(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:76:5 + --> $DIR/option_map_unit_fn_fixable.rs:75:5 | LL | x.field.map(|value| { plus_one(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -121,7 +121,7 @@ LL | x.field.map(|value| { plus_one(value + captured); }); | help: try this: `if let Some(value) = x.field { plus_one(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:78:5 + --> $DIR/option_map_unit_fn_fixable.rs:77:5 | LL | x.field.map(|value| { { plus_one(value + captured); } }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -129,7 +129,7 @@ LL | x.field.map(|value| { { plus_one(value + captured); } }); | help: try this: `if let Some(value) = x.field { plus_one(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:81:5 + --> $DIR/option_map_unit_fn_fixable.rs:80:5 | LL | x.field.map(|ref value| { do_nothing(value + captured) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -137,7 +137,7 @@ LL | x.field.map(|ref value| { do_nothing(value + captured) }); | help: try this: `if let Some(ref value) = x.field { do_nothing(value + captured) }` error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:83:5 + --> $DIR/option_map_unit_fn_fixable.rs:82:5 | LL | option().map(do_nothing); | ^^^^^^^^^^^^^^^^^^^^^^^^- @@ -145,7 +145,7 @@ LL | option().map(do_nothing); | help: try this: `if let Some(a) = option() { do_nothing(a) }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:85:5 + --> $DIR/option_map_unit_fn_fixable.rs:84:5 | LL | option().map(|value| println!("{:?}", value)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- diff --git a/tests/ui/or_fun_call.fixed b/tests/ui/or_fun_call.fixed index 5991188ab6372..896430780ea80 100644 --- a/tests/ui/or_fun_call.fixed +++ b/tests/ui/or_fun_call.fixed @@ -1,8 +1,7 @@ // run-rustfix - #![warn(clippy::or_fun_call)] #![allow(dead_code)] -#![allow(clippy::unnecessary_wraps, clippy::borrow_as_ptr)] +#![allow(clippy::borrow_as_ptr, clippy::uninlined_format_args, clippy::unnecessary_wraps)] use std::collections::BTreeMap; use std::collections::HashMap; diff --git a/tests/ui/or_fun_call.rs b/tests/ui/or_fun_call.rs index c353b41e4495d..2473163d4fd2f 100644 --- a/tests/ui/or_fun_call.rs +++ b/tests/ui/or_fun_call.rs @@ -1,8 +1,7 @@ // run-rustfix - #![warn(clippy::or_fun_call)] #![allow(dead_code)] -#![allow(clippy::unnecessary_wraps, clippy::borrow_as_ptr)] +#![allow(clippy::borrow_as_ptr, clippy::uninlined_format_args, clippy::unnecessary_wraps)] use std::collections::BTreeMap; use std::collections::HashMap; diff --git a/tests/ui/or_fun_call.stderr b/tests/ui/or_fun_call.stderr index e3dab4cb14778..113ba150c6192 100644 --- a/tests/ui/or_fun_call.stderr +++ b/tests/ui/or_fun_call.stderr @@ -1,5 +1,5 @@ error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:49:22 + --> $DIR/or_fun_call.rs:48:22 | LL | with_constructor.unwrap_or(make()); | ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(make)` @@ -7,151 +7,151 @@ LL | with_constructor.unwrap_or(make()); = note: `-D clippy::or-fun-call` implied by `-D warnings` error: use of `unwrap_or` followed by a call to `new` - --> $DIR/or_fun_call.rs:52:14 + --> $DIR/or_fun_call.rs:51:14 | LL | with_new.unwrap_or(Vec::new()); | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:55:21 + --> $DIR/or_fun_call.rs:54:21 | LL | with_const_args.unwrap_or(Vec::with_capacity(12)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| Vec::with_capacity(12))` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:58:14 + --> $DIR/or_fun_call.rs:57:14 | LL | with_err.unwrap_or(make()); | ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| make())` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:61:19 + --> $DIR/or_fun_call.rs:60:19 | LL | with_err_args.unwrap_or(Vec::with_capacity(12)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| Vec::with_capacity(12))` error: use of `unwrap_or` followed by a call to `default` - --> $DIR/or_fun_call.rs:64:24 + --> $DIR/or_fun_call.rs:63:24 | LL | with_default_trait.unwrap_or(Default::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` error: use of `unwrap_or` followed by a call to `default` - --> $DIR/or_fun_call.rs:67:23 + --> $DIR/or_fun_call.rs:66:23 | LL | with_default_type.unwrap_or(u64::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:70:18 + --> $DIR/or_fun_call.rs:69:18 | LL | self_default.unwrap_or(::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(::default)` error: use of `unwrap_or` followed by a call to `default` - --> $DIR/or_fun_call.rs:73:18 + --> $DIR/or_fun_call.rs:72:18 | LL | real_default.unwrap_or(::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` error: use of `unwrap_or` followed by a call to `new` - --> $DIR/or_fun_call.rs:76:14 + --> $DIR/or_fun_call.rs:75:14 | LL | with_vec.unwrap_or(vec![]); | ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:79:21 + --> $DIR/or_fun_call.rs:78:21 | LL | without_default.unwrap_or(Foo::new()); | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(Foo::new)` error: use of `or_insert` followed by a call to `new` - --> $DIR/or_fun_call.rs:82:19 + --> $DIR/or_fun_call.rs:81:19 | LL | map.entry(42).or_insert(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_default()` error: use of `or_insert` followed by a call to `new` - --> $DIR/or_fun_call.rs:85:23 + --> $DIR/or_fun_call.rs:84:23 | LL | map_vec.entry(42).or_insert(vec![]); | ^^^^^^^^^^^^^^^^^ help: try this: `or_default()` error: use of `or_insert` followed by a call to `new` - --> $DIR/or_fun_call.rs:88:21 + --> $DIR/or_fun_call.rs:87:21 | LL | btree.entry(42).or_insert(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_default()` error: use of `or_insert` followed by a call to `new` - --> $DIR/or_fun_call.rs:91:25 + --> $DIR/or_fun_call.rs:90:25 | LL | btree_vec.entry(42).or_insert(vec![]); | ^^^^^^^^^^^^^^^^^ help: try this: `or_default()` error: use of `unwrap_or` followed by a call to `new` - --> $DIR/or_fun_call.rs:94:21 + --> $DIR/or_fun_call.rs:93:21 | LL | let _ = stringy.unwrap_or(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:102:21 + --> $DIR/or_fun_call.rs:101:21 | LL | let _ = Some(1).unwrap_or(map[&1]); | ^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| map[&1])` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:104:21 + --> $DIR/or_fun_call.rs:103:21 | LL | let _ = Some(1).unwrap_or(map[&1]); | ^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| map[&1])` error: use of `or` followed by a function call - --> $DIR/or_fun_call.rs:128:35 + --> $DIR/or_fun_call.rs:127:35 | LL | let _ = Some("a".to_string()).or(Some("b".to_string())); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some("b".to_string()))` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:167:14 + --> $DIR/or_fun_call.rs:166:14 | LL | None.unwrap_or(ptr_to_ref(s)); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| ptr_to_ref(s))` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:173:14 + --> $DIR/or_fun_call.rs:172:14 | LL | None.unwrap_or(unsafe { ptr_to_ref(s) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:175:14 + --> $DIR/or_fun_call.rs:174:14 | LL | None.unwrap_or( unsafe { ptr_to_ref(s) } ); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })` error: use of `unwrap_or` followed by a call to `new` - --> $DIR/or_fun_call.rs:189:14 + --> $DIR/or_fun_call.rs:188:14 | LL | .unwrap_or(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` error: use of `unwrap_or` followed by a call to `new` - --> $DIR/or_fun_call.rs:202:14 + --> $DIR/or_fun_call.rs:201:14 | LL | .unwrap_or(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` error: use of `unwrap_or` followed by a call to `new` - --> $DIR/or_fun_call.rs:214:14 + --> $DIR/or_fun_call.rs:213:14 | LL | .unwrap_or(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` error: use of `unwrap_or` followed by a call to `new` - --> $DIR/or_fun_call.rs:225:10 + --> $DIR/or_fun_call.rs:224:10 | LL | .unwrap_or(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` diff --git a/tests/ui/panic_in_result_fn_assertions.rs b/tests/ui/panic_in_result_fn_assertions.rs index ffdf8288adc70..08ab4d8681edd 100644 --- a/tests/ui/panic_in_result_fn_assertions.rs +++ b/tests/ui/panic_in_result_fn_assertions.rs @@ -1,5 +1,5 @@ #![warn(clippy::panic_in_result_fn)] -#![allow(clippy::unnecessary_wraps)] +#![allow(clippy::uninlined_format_args, clippy::unnecessary_wraps)] struct A; diff --git a/tests/ui/panic_in_result_fn_debug_assertions.rs b/tests/ui/panic_in_result_fn_debug_assertions.rs index c4fcd7e70944c..df89d8c50246a 100644 --- a/tests/ui/panic_in_result_fn_debug_assertions.rs +++ b/tests/ui/panic_in_result_fn_debug_assertions.rs @@ -1,5 +1,5 @@ #![warn(clippy::panic_in_result_fn)] -#![allow(clippy::unnecessary_wraps)] +#![allow(clippy::uninlined_format_args, clippy::unnecessary_wraps)] // debug_assert should never trigger the `panic_in_result_fn` lint diff --git a/tests/ui/patterns.fixed b/tests/ui/patterns.fixed index f22388154499a..cd69014326ebb 100644 --- a/tests/ui/patterns.fixed +++ b/tests/ui/patterns.fixed @@ -1,6 +1,7 @@ // run-rustfix -#![allow(unused)] #![warn(clippy::all)] +#![allow(unused)] +#![allow(clippy::uninlined_format_args)] fn main() { let v = Some(true); diff --git a/tests/ui/patterns.rs b/tests/ui/patterns.rs index 5848ecd38d98d..9128da420c0d3 100644 --- a/tests/ui/patterns.rs +++ b/tests/ui/patterns.rs @@ -1,6 +1,7 @@ // run-rustfix -#![allow(unused)] #![warn(clippy::all)] +#![allow(unused)] +#![allow(clippy::uninlined_format_args)] fn main() { let v = Some(true); diff --git a/tests/ui/patterns.stderr b/tests/ui/patterns.stderr index af067580688b5..2c46b4eb593e3 100644 --- a/tests/ui/patterns.stderr +++ b/tests/ui/patterns.stderr @@ -1,5 +1,5 @@ error: the `y @ _` pattern can be written as just `y` - --> $DIR/patterns.rs:10:9 + --> $DIR/patterns.rs:11:9 | LL | y @ _ => (), | ^^^^^ help: try: `y` @@ -7,13 +7,13 @@ LL | y @ _ => (), = note: `-D clippy::redundant-pattern` implied by `-D warnings` error: the `x @ _` pattern can be written as just `x` - --> $DIR/patterns.rs:25:9 + --> $DIR/patterns.rs:26:9 | LL | ref mut x @ _ => { | ^^^^^^^^^^^^^ help: try: `ref mut x` error: the `x @ _` pattern can be written as just `x` - --> $DIR/patterns.rs:33:9 + --> $DIR/patterns.rs:34:9 | LL | ref x @ _ => println!("vec: {:?}", x), | ^^^^^^^^^ help: try: `ref x` diff --git a/tests/ui/print_literal.rs b/tests/ui/print_literal.rs index 3f6639c14585a..86f908f66b8f3 100644 --- a/tests/ui/print_literal.rs +++ b/tests/ui/print_literal.rs @@ -1,4 +1,5 @@ #![warn(clippy::print_literal)] +#![allow(clippy::uninlined_format_args)] fn main() { // these should be fine diff --git a/tests/ui/print_literal.stderr b/tests/ui/print_literal.stderr index 23e6dbc3e341f..6404dacdafa56 100644 --- a/tests/ui/print_literal.stderr +++ b/tests/ui/print_literal.stderr @@ -1,5 +1,5 @@ error: literal with an empty format string - --> $DIR/print_literal.rs:26:24 + --> $DIR/print_literal.rs:27:24 | LL | print!("Hello {}", "world"); | ^^^^^^^ @@ -12,7 +12,7 @@ LL + print!("Hello world"); | error: literal with an empty format string - --> $DIR/print_literal.rs:27:36 + --> $DIR/print_literal.rs:28:36 | LL | println!("Hello {} {}", world, "world"); | ^^^^^^^ @@ -24,7 +24,7 @@ LL + println!("Hello {} world", world); | error: literal with an empty format string - --> $DIR/print_literal.rs:28:26 + --> $DIR/print_literal.rs:29:26 | LL | println!("Hello {}", "world"); | ^^^^^^^ @@ -36,7 +36,7 @@ LL + println!("Hello world"); | error: literal with an empty format string - --> $DIR/print_literal.rs:29:26 + --> $DIR/print_literal.rs:30:26 | LL | println!("{} {:.4}", "a literal", 5); | ^^^^^^^^^^^ @@ -48,7 +48,7 @@ LL + println!("a literal {:.4}", 5); | error: literal with an empty format string - --> $DIR/print_literal.rs:34:25 + --> $DIR/print_literal.rs:35:25 | LL | println!("{0} {1}", "hello", "world"); | ^^^^^^^ @@ -60,7 +60,7 @@ LL + println!("hello {1}", "world"); | error: literal with an empty format string - --> $DIR/print_literal.rs:34:34 + --> $DIR/print_literal.rs:35:34 | LL | println!("{0} {1}", "hello", "world"); | ^^^^^^^ @@ -72,7 +72,7 @@ LL + println!("{0} world", "hello"); | error: literal with an empty format string - --> $DIR/print_literal.rs:35:34 + --> $DIR/print_literal.rs:36:34 | LL | println!("{1} {0}", "hello", "world"); | ^^^^^^^ @@ -84,7 +84,7 @@ LL + println!("world {0}", "hello"); | error: literal with an empty format string - --> $DIR/print_literal.rs:35:25 + --> $DIR/print_literal.rs:36:25 | LL | println!("{1} {0}", "hello", "world"); | ^^^^^^^ @@ -96,7 +96,7 @@ LL + println!("{1} hello", "world"); | error: literal with an empty format string - --> $DIR/print_literal.rs:38:35 + --> $DIR/print_literal.rs:39:35 | LL | println!("{foo} {bar}", foo = "hello", bar = "world"); | ^^^^^^^ @@ -108,7 +108,7 @@ LL + println!("hello {bar}", bar = "world"); | error: literal with an empty format string - --> $DIR/print_literal.rs:38:50 + --> $DIR/print_literal.rs:39:50 | LL | println!("{foo} {bar}", foo = "hello", bar = "world"); | ^^^^^^^ @@ -120,7 +120,7 @@ LL + println!("{foo} world", foo = "hello"); | error: literal with an empty format string - --> $DIR/print_literal.rs:39:50 + --> $DIR/print_literal.rs:40:50 | LL | println!("{bar} {foo}", foo = "hello", bar = "world"); | ^^^^^^^ @@ -132,7 +132,7 @@ LL + println!("world {foo}", foo = "hello"); | error: literal with an empty format string - --> $DIR/print_literal.rs:39:35 + --> $DIR/print_literal.rs:40:35 | LL | println!("{bar} {foo}", foo = "hello", bar = "world"); | ^^^^^^^ diff --git a/tests/ui/recursive_format_impl.rs b/tests/ui/recursive_format_impl.rs index cb6ba36b14c80..b92490b4c5234 100644 --- a/tests/ui/recursive_format_impl.rs +++ b/tests/ui/recursive_format_impl.rs @@ -1,9 +1,10 @@ #![warn(clippy::recursive_format_impl)] #![allow( + clippy::borrow_deref_ref, + clippy::deref_addrof, clippy::inherent_to_string_shadow_display, clippy::to_string_in_format_args, - clippy::deref_addrof, - clippy::borrow_deref_ref + clippy::uninlined_format_args )] use std::fmt; diff --git a/tests/ui/recursive_format_impl.stderr b/tests/ui/recursive_format_impl.stderr index 84ce69df56696..8a58b9a3b178b 100644 --- a/tests/ui/recursive_format_impl.stderr +++ b/tests/ui/recursive_format_impl.stderr @@ -1,5 +1,5 @@ error: using `self.to_string` in `fmt::Display` implementation will cause infinite recursion - --> $DIR/recursive_format_impl.rs:30:25 + --> $DIR/recursive_format_impl.rs:31:25 | LL | write!(f, "{}", self.to_string()) | ^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | write!(f, "{}", self.to_string()) = note: `-D clippy::recursive-format-impl` implied by `-D warnings` error: using `self` as `Display` in `impl Display` will cause infinite recursion - --> $DIR/recursive_format_impl.rs:74:9 + --> $DIR/recursive_format_impl.rs:75:9 | LL | write!(f, "{}", self) | ^^^^^^^^^^^^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | write!(f, "{}", self) = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info) error: using `self` as `Display` in `impl Display` will cause infinite recursion - --> $DIR/recursive_format_impl.rs:83:9 + --> $DIR/recursive_format_impl.rs:84:9 | LL | write!(f, "{}", &self) | ^^^^^^^^^^^^^^^^^^^^^^ @@ -23,7 +23,7 @@ LL | write!(f, "{}", &self) = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info) error: using `self` as `Debug` in `impl Debug` will cause infinite recursion - --> $DIR/recursive_format_impl.rs:89:9 + --> $DIR/recursive_format_impl.rs:90:9 | LL | write!(f, "{:?}", &self) | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -31,7 +31,7 @@ LL | write!(f, "{:?}", &self) = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info) error: using `self` as `Display` in `impl Display` will cause infinite recursion - --> $DIR/recursive_format_impl.rs:98:9 + --> $DIR/recursive_format_impl.rs:99:9 | LL | write!(f, "{}", &&&self) | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -39,7 +39,7 @@ LL | write!(f, "{}", &&&self) = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info) error: using `self` as `Display` in `impl Display` will cause infinite recursion - --> $DIR/recursive_format_impl.rs:172:9 + --> $DIR/recursive_format_impl.rs:173:9 | LL | write!(f, "{}", &*self) | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -47,7 +47,7 @@ LL | write!(f, "{}", &*self) = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info) error: using `self` as `Debug` in `impl Debug` will cause infinite recursion - --> $DIR/recursive_format_impl.rs:178:9 + --> $DIR/recursive_format_impl.rs:179:9 | LL | write!(f, "{:?}", &*self) | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -55,7 +55,7 @@ LL | write!(f, "{:?}", &*self) = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info) error: using `self` as `Display` in `impl Display` will cause infinite recursion - --> $DIR/recursive_format_impl.rs:194:9 + --> $DIR/recursive_format_impl.rs:195:9 | LL | write!(f, "{}", *self) | ^^^^^^^^^^^^^^^^^^^^^^ @@ -63,7 +63,7 @@ LL | write!(f, "{}", *self) = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info) error: using `self` as `Display` in `impl Display` will cause infinite recursion - --> $DIR/recursive_format_impl.rs:210:9 + --> $DIR/recursive_format_impl.rs:211:9 | LL | write!(f, "{}", **&&*self) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -71,7 +71,7 @@ LL | write!(f, "{}", **&&*self) = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info) error: using `self` as `Display` in `impl Display` will cause infinite recursion - --> $DIR/recursive_format_impl.rs:226:9 + --> $DIR/recursive_format_impl.rs:227:9 | LL | write!(f, "{}", &&**&&*self) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/redundant_clone.fixed b/tests/ui/redundant_clone.fixed index da52c0acf93b0..00b427450935d 100644 --- a/tests/ui/redundant_clone.fixed +++ b/tests/ui/redundant_clone.fixed @@ -1,8 +1,8 @@ // run-rustfix // rustfix-only-machine-applicable - #![feature(lint_reasons)] -#![allow(clippy::implicit_clone, clippy::drop_non_drop)] +#![allow(clippy::drop_non_drop, clippy::implicit_clone, clippy::uninlined_format_args)] + use std::ffi::OsString; use std::path::Path; diff --git a/tests/ui/redundant_clone.rs b/tests/ui/redundant_clone.rs index 5867d019dbb7d..f899127db8d04 100644 --- a/tests/ui/redundant_clone.rs +++ b/tests/ui/redundant_clone.rs @@ -1,8 +1,8 @@ // run-rustfix // rustfix-only-machine-applicable - #![feature(lint_reasons)] -#![allow(clippy::implicit_clone, clippy::drop_non_drop)] +#![allow(clippy::drop_non_drop, clippy::implicit_clone, clippy::uninlined_format_args)] + use std::ffi::OsString; use std::path::Path; diff --git a/tests/ui/redundant_pattern_matching_ipaddr.fixed b/tests/ui/redundant_pattern_matching_ipaddr.fixed index acc8de5f41ee8..21bae909555ca 100644 --- a/tests/ui/redundant_pattern_matching_ipaddr.fixed +++ b/tests/ui/redundant_pattern_matching_ipaddr.fixed @@ -1,8 +1,11 @@ // run-rustfix - -#![warn(clippy::all)] -#![warn(clippy::redundant_pattern_matching)] -#![allow(unused_must_use, clippy::needless_bool, clippy::match_like_matches_macro)] +#![warn(clippy::all, clippy::redundant_pattern_matching)] +#![allow(unused_must_use)] +#![allow( + clippy::match_like_matches_macro, + clippy::needless_bool, + clippy::uninlined_format_args +)] use std::net::{ IpAddr::{self, V4, V6}, diff --git a/tests/ui/redundant_pattern_matching_ipaddr.rs b/tests/ui/redundant_pattern_matching_ipaddr.rs index 678d91ce93acd..4dd9171677ec2 100644 --- a/tests/ui/redundant_pattern_matching_ipaddr.rs +++ b/tests/ui/redundant_pattern_matching_ipaddr.rs @@ -1,8 +1,11 @@ // run-rustfix - -#![warn(clippy::all)] -#![warn(clippy::redundant_pattern_matching)] -#![allow(unused_must_use, clippy::needless_bool, clippy::match_like_matches_macro)] +#![warn(clippy::all, clippy::redundant_pattern_matching)] +#![allow(unused_must_use)] +#![allow( + clippy::match_like_matches_macro, + clippy::needless_bool, + clippy::uninlined_format_args +)] use std::net::{ IpAddr::{self, V4, V6}, diff --git a/tests/ui/redundant_pattern_matching_ipaddr.stderr b/tests/ui/redundant_pattern_matching_ipaddr.stderr index caf458cd862e0..536b589de54c0 100644 --- a/tests/ui/redundant_pattern_matching_ipaddr.stderr +++ b/tests/ui/redundant_pattern_matching_ipaddr.stderr @@ -1,5 +1,5 @@ error: redundant pattern matching, consider using `is_ipv4()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:14:12 + --> $DIR/redundant_pattern_matching_ipaddr.rs:17:12 | LL | if let V4(_) = &ipaddr {} | -------^^^^^---------- help: try this: `if ipaddr.is_ipv4()` @@ -7,31 +7,31 @@ LL | if let V4(_) = &ipaddr {} = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` error: redundant pattern matching, consider using `is_ipv4()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:16:12 + --> $DIR/redundant_pattern_matching_ipaddr.rs:19:12 | LL | if let V4(_) = V4(Ipv4Addr::LOCALHOST) {} | -------^^^^^-------------------------- help: try this: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:18:12 + --> $DIR/redundant_pattern_matching_ipaddr.rs:21:12 | LL | if let V6(_) = V6(Ipv6Addr::LOCALHOST) {} | -------^^^^^-------------------------- help: try this: `if V6(Ipv6Addr::LOCALHOST).is_ipv6()` error: redundant pattern matching, consider using `is_ipv4()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:20:15 + --> $DIR/redundant_pattern_matching_ipaddr.rs:23:15 | LL | while let V4(_) = V4(Ipv4Addr::LOCALHOST) {} | ----------^^^^^-------------------------- help: try this: `while V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:22:15 + --> $DIR/redundant_pattern_matching_ipaddr.rs:25:15 | LL | while let V6(_) = V6(Ipv6Addr::LOCALHOST) {} | ----------^^^^^-------------------------- help: try this: `while V6(Ipv6Addr::LOCALHOST).is_ipv6()` error: redundant pattern matching, consider using `is_ipv4()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:32:5 + --> $DIR/redundant_pattern_matching_ipaddr.rs:35:5 | LL | / match V4(Ipv4Addr::LOCALHOST) { LL | | V4(_) => true, @@ -40,7 +40,7 @@ LL | | }; | |_____^ help: try this: `V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:37:5 + --> $DIR/redundant_pattern_matching_ipaddr.rs:40:5 | LL | / match V4(Ipv4Addr::LOCALHOST) { LL | | V4(_) => false, @@ -49,7 +49,7 @@ LL | | }; | |_____^ help: try this: `V4(Ipv4Addr::LOCALHOST).is_ipv6()` error: redundant pattern matching, consider using `is_ipv6()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:42:5 + --> $DIR/redundant_pattern_matching_ipaddr.rs:45:5 | LL | / match V6(Ipv6Addr::LOCALHOST) { LL | | V4(_) => false, @@ -58,7 +58,7 @@ LL | | }; | |_____^ help: try this: `V6(Ipv6Addr::LOCALHOST).is_ipv6()` error: redundant pattern matching, consider using `is_ipv4()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:47:5 + --> $DIR/redundant_pattern_matching_ipaddr.rs:50:5 | LL | / match V6(Ipv6Addr::LOCALHOST) { LL | | V4(_) => true, @@ -67,49 +67,49 @@ LL | | }; | |_____^ help: try this: `V6(Ipv6Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv4()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:52:20 + --> $DIR/redundant_pattern_matching_ipaddr.rs:55:20 | LL | let _ = if let V4(_) = V4(Ipv4Addr::LOCALHOST) { | -------^^^^^-------------------------- help: try this: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv4()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:60:20 + --> $DIR/redundant_pattern_matching_ipaddr.rs:63:20 | LL | let _ = if let V4(_) = gen_ipaddr() { | -------^^^^^--------------- help: try this: `if gen_ipaddr().is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:62:19 + --> $DIR/redundant_pattern_matching_ipaddr.rs:65:19 | LL | } else if let V6(_) = gen_ipaddr() { | -------^^^^^--------------- help: try this: `if gen_ipaddr().is_ipv6()` error: redundant pattern matching, consider using `is_ipv4()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:74:12 + --> $DIR/redundant_pattern_matching_ipaddr.rs:77:12 | LL | if let V4(_) = V4(Ipv4Addr::LOCALHOST) {} | -------^^^^^-------------------------- help: try this: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:76:12 + --> $DIR/redundant_pattern_matching_ipaddr.rs:79:12 | LL | if let V6(_) = V6(Ipv6Addr::LOCALHOST) {} | -------^^^^^-------------------------- help: try this: `if V6(Ipv6Addr::LOCALHOST).is_ipv6()` error: redundant pattern matching, consider using `is_ipv4()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:78:15 + --> $DIR/redundant_pattern_matching_ipaddr.rs:81:15 | LL | while let V4(_) = V4(Ipv4Addr::LOCALHOST) {} | ----------^^^^^-------------------------- help: try this: `while V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:80:15 + --> $DIR/redundant_pattern_matching_ipaddr.rs:83:15 | LL | while let V6(_) = V6(Ipv6Addr::LOCALHOST) {} | ----------^^^^^-------------------------- help: try this: `while V6(Ipv6Addr::LOCALHOST).is_ipv6()` error: redundant pattern matching, consider using `is_ipv4()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:82:5 + --> $DIR/redundant_pattern_matching_ipaddr.rs:85:5 | LL | / match V4(Ipv4Addr::LOCALHOST) { LL | | V4(_) => true, @@ -118,7 +118,7 @@ LL | | }; | |_____^ help: try this: `V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:87:5 + --> $DIR/redundant_pattern_matching_ipaddr.rs:90:5 | LL | / match V6(Ipv6Addr::LOCALHOST) { LL | | V4(_) => false, diff --git a/tests/ui/redundant_pattern_matching_result.fixed b/tests/ui/redundant_pattern_matching_result.fixed index 83c783385efec..b88c5d0bec82e 100644 --- a/tests/ui/redundant_pattern_matching_result.fixed +++ b/tests/ui/redundant_pattern_matching_result.fixed @@ -1,14 +1,13 @@ // run-rustfix - #![warn(clippy::all)] #![warn(clippy::redundant_pattern_matching)] +#![allow(deprecated, unused_must_use)] #![allow( - unused_must_use, - clippy::needless_bool, + clippy::if_same_then_else, clippy::match_like_matches_macro, - clippy::unnecessary_wraps, - deprecated, - clippy::if_same_then_else + clippy::needless_bool, + clippy::uninlined_format_args, + clippy::unnecessary_wraps )] fn main() { diff --git a/tests/ui/redundant_pattern_matching_result.rs b/tests/ui/redundant_pattern_matching_result.rs index e06d4485ae4f2..5949cb2271c62 100644 --- a/tests/ui/redundant_pattern_matching_result.rs +++ b/tests/ui/redundant_pattern_matching_result.rs @@ -1,14 +1,13 @@ // run-rustfix - #![warn(clippy::all)] #![warn(clippy::redundant_pattern_matching)] +#![allow(deprecated, unused_must_use)] #![allow( - unused_must_use, - clippy::needless_bool, + clippy::if_same_then_else, clippy::match_like_matches_macro, - clippy::unnecessary_wraps, - deprecated, - clippy::if_same_then_else + clippy::needless_bool, + clippy::uninlined_format_args, + clippy::unnecessary_wraps )] fn main() { diff --git a/tests/ui/redundant_pattern_matching_result.stderr b/tests/ui/redundant_pattern_matching_result.stderr index d674d061e4dd7..e6afe9eb78eaa 100644 --- a/tests/ui/redundant_pattern_matching_result.stderr +++ b/tests/ui/redundant_pattern_matching_result.stderr @@ -1,5 +1,5 @@ error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching_result.rs:16:12 + --> $DIR/redundant_pattern_matching_result.rs:15:12 | LL | if let Ok(_) = &result {} | -------^^^^^---------- help: try this: `if result.is_ok()` @@ -7,31 +7,31 @@ LL | if let Ok(_) = &result {} = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching_result.rs:18:12 + --> $DIR/redundant_pattern_matching_result.rs:17:12 | LL | if let Ok(_) = Ok::(42) {} | -------^^^^^--------------------- help: try this: `if Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching_result.rs:20:12 + --> $DIR/redundant_pattern_matching_result.rs:19:12 | LL | if let Err(_) = Err::(42) {} | -------^^^^^^---------------------- help: try this: `if Err::(42).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching_result.rs:22:15 + --> $DIR/redundant_pattern_matching_result.rs:21:15 | LL | while let Ok(_) = Ok::(10) {} | ----------^^^^^--------------------- help: try this: `while Ok::(10).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching_result.rs:24:15 + --> $DIR/redundant_pattern_matching_result.rs:23:15 | LL | while let Err(_) = Ok::(10) {} | ----------^^^^^^--------------------- help: try this: `while Ok::(10).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching_result.rs:34:5 + --> $DIR/redundant_pattern_matching_result.rs:33:5 | LL | / match Ok::(42) { LL | | Ok(_) => true, @@ -40,7 +40,7 @@ LL | | }; | |_____^ help: try this: `Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching_result.rs:39:5 + --> $DIR/redundant_pattern_matching_result.rs:38:5 | LL | / match Ok::(42) { LL | | Ok(_) => false, @@ -49,7 +49,7 @@ LL | | }; | |_____^ help: try this: `Ok::(42).is_err()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching_result.rs:44:5 + --> $DIR/redundant_pattern_matching_result.rs:43:5 | LL | / match Err::(42) { LL | | Ok(_) => false, @@ -58,7 +58,7 @@ LL | | }; | |_____^ help: try this: `Err::(42).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching_result.rs:49:5 + --> $DIR/redundant_pattern_matching_result.rs:48:5 | LL | / match Err::(42) { LL | | Ok(_) => true, @@ -67,73 +67,73 @@ LL | | }; | |_____^ help: try this: `Err::(42).is_ok()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching_result.rs:54:20 + --> $DIR/redundant_pattern_matching_result.rs:53:20 | LL | let _ = if let Ok(_) = Ok::(4) { true } else { false }; | -------^^^^^--------------------- help: try this: `if Ok::(4).is_ok()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching_result.rs:60:20 + --> $DIR/redundant_pattern_matching_result.rs:59:20 | LL | let _ = if let Ok(_) = gen_res() { | -------^^^^^------------ help: try this: `if gen_res().is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching_result.rs:62:19 + --> $DIR/redundant_pattern_matching_result.rs:61:19 | LL | } else if let Err(_) = gen_res() { | -------^^^^^^------------ help: try this: `if gen_res().is_err()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_result.rs:85:19 + --> $DIR/redundant_pattern_matching_result.rs:84:19 | LL | while let Some(_) = r#try!(result_opt()) {} | ----------^^^^^^^----------------------- help: try this: `while (r#try!(result_opt())).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_result.rs:86:16 + --> $DIR/redundant_pattern_matching_result.rs:85:16 | LL | if let Some(_) = r#try!(result_opt()) {} | -------^^^^^^^----------------------- help: try this: `if (r#try!(result_opt())).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_result.rs:92:12 + --> $DIR/redundant_pattern_matching_result.rs:91:12 | LL | if let Some(_) = m!() {} | -------^^^^^^^------- help: try this: `if m!().is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_result.rs:93:15 + --> $DIR/redundant_pattern_matching_result.rs:92:15 | LL | while let Some(_) = m!() {} | ----------^^^^^^^------- help: try this: `while m!().is_some()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching_result.rs:111:12 + --> $DIR/redundant_pattern_matching_result.rs:110:12 | LL | if let Ok(_) = Ok::(42) {} | -------^^^^^--------------------- help: try this: `if Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching_result.rs:113:12 + --> $DIR/redundant_pattern_matching_result.rs:112:12 | LL | if let Err(_) = Err::(42) {} | -------^^^^^^---------------------- help: try this: `if Err::(42).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching_result.rs:115:15 + --> $DIR/redundant_pattern_matching_result.rs:114:15 | LL | while let Ok(_) = Ok::(10) {} | ----------^^^^^--------------------- help: try this: `while Ok::(10).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching_result.rs:117:15 + --> $DIR/redundant_pattern_matching_result.rs:116:15 | LL | while let Err(_) = Ok::(10) {} | ----------^^^^^^--------------------- help: try this: `while Ok::(10).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching_result.rs:119:5 + --> $DIR/redundant_pattern_matching_result.rs:118:5 | LL | / match Ok::(42) { LL | | Ok(_) => true, @@ -142,7 +142,7 @@ LL | | }; | |_____^ help: try this: `Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching_result.rs:124:5 + --> $DIR/redundant_pattern_matching_result.rs:123:5 | LL | / match Err::(42) { LL | | Ok(_) => false, diff --git a/tests/ui/result_map_unit_fn_fixable.fixed b/tests/ui/result_map_unit_fn_fixable.fixed index 14c331f67e739..d8b56237e9832 100644 --- a/tests/ui/result_map_unit_fn_fixable.fixed +++ b/tests/ui/result_map_unit_fn_fixable.fixed @@ -1,7 +1,7 @@ // run-rustfix - #![warn(clippy::result_map_unit_fn)] #![allow(unused)] +#![allow(clippy::uninlined_format_args)] fn do_nothing(_: T) {} diff --git a/tests/ui/result_map_unit_fn_fixable.rs b/tests/ui/result_map_unit_fn_fixable.rs index 8b0fca9ece1a3..44f50d21109cd 100644 --- a/tests/ui/result_map_unit_fn_fixable.rs +++ b/tests/ui/result_map_unit_fn_fixable.rs @@ -1,7 +1,7 @@ // run-rustfix - #![warn(clippy::result_map_unit_fn)] #![allow(unused)] +#![allow(clippy::uninlined_format_args)] fn do_nothing(_: T) {} diff --git a/tests/ui/reversed_empty_ranges_fixable.fixed b/tests/ui/reversed_empty_ranges_fixable.fixed index 79e482eec3037..c67edb36c67ad 100644 --- a/tests/ui/reversed_empty_ranges_fixable.fixed +++ b/tests/ui/reversed_empty_ranges_fixable.fixed @@ -1,5 +1,6 @@ // run-rustfix #![warn(clippy::reversed_empty_ranges)] +#![allow(clippy::uninlined_format_args)] const ANSWER: i32 = 42; diff --git a/tests/ui/reversed_empty_ranges_fixable.rs b/tests/ui/reversed_empty_ranges_fixable.rs index b2e8bf33771ac..0a4fef5bfe87b 100644 --- a/tests/ui/reversed_empty_ranges_fixable.rs +++ b/tests/ui/reversed_empty_ranges_fixable.rs @@ -1,5 +1,6 @@ // run-rustfix #![warn(clippy::reversed_empty_ranges)] +#![allow(clippy::uninlined_format_args)] const ANSWER: i32 = 42; diff --git a/tests/ui/reversed_empty_ranges_fixable.stderr b/tests/ui/reversed_empty_ranges_fixable.stderr index 2d1bfe62c9236..c2495ea95f975 100644 --- a/tests/ui/reversed_empty_ranges_fixable.stderr +++ b/tests/ui/reversed_empty_ranges_fixable.stderr @@ -1,5 +1,5 @@ error: this range is empty so it will yield no values - --> $DIR/reversed_empty_ranges_fixable.rs:9:5 + --> $DIR/reversed_empty_ranges_fixable.rs:10:5 | LL | (42..=21).for_each(|x| println!("{}", x)); | ^^^^^^^^^ @@ -11,7 +11,7 @@ LL | (21..=42).rev().for_each(|x| println!("{}", x)); | ~~~~~~~~~~~~~~~ error: this range is empty so it will yield no values - --> $DIR/reversed_empty_ranges_fixable.rs:10:13 + --> $DIR/reversed_empty_ranges_fixable.rs:11:13 | LL | let _ = (ANSWER..21).filter(|x| x % 2 == 0).take(10).collect::>(); | ^^^^^^^^^^^^ @@ -22,7 +22,7 @@ LL | let _ = (21..ANSWER).rev().filter(|x| x % 2 == 0).take(10).collect:: $DIR/reversed_empty_ranges_fixable.rs:12:14 + --> $DIR/reversed_empty_ranges_fixable.rs:13:14 | LL | for _ in -21..=-42 {} | ^^^^^^^^^ @@ -33,7 +33,7 @@ LL | for _ in (-42..=-21).rev() {} | ~~~~~~~~~~~~~~~~~ error: this range is empty so it will yield no values - --> $DIR/reversed_empty_ranges_fixable.rs:13:14 + --> $DIR/reversed_empty_ranges_fixable.rs:14:14 | LL | for _ in 42u32..21u32 {} | ^^^^^^^^^^^^ diff --git a/tests/ui/reversed_empty_ranges_loops_fixable.fixed b/tests/ui/reversed_empty_ranges_loops_fixable.fixed index f1503ed6d12f9..78401e463d50d 100644 --- a/tests/ui/reversed_empty_ranges_loops_fixable.fixed +++ b/tests/ui/reversed_empty_ranges_loops_fixable.fixed @@ -1,5 +1,6 @@ // run-rustfix #![warn(clippy::reversed_empty_ranges)] +#![allow(clippy::uninlined_format_args)] fn main() { const MAX_LEN: usize = 42; diff --git a/tests/ui/reversed_empty_ranges_loops_fixable.rs b/tests/ui/reversed_empty_ranges_loops_fixable.rs index a733788dc22c1..f9e0f7fcd6dbf 100644 --- a/tests/ui/reversed_empty_ranges_loops_fixable.rs +++ b/tests/ui/reversed_empty_ranges_loops_fixable.rs @@ -1,5 +1,6 @@ // run-rustfix #![warn(clippy::reversed_empty_ranges)] +#![allow(clippy::uninlined_format_args)] fn main() { const MAX_LEN: usize = 42; diff --git a/tests/ui/reversed_empty_ranges_loops_fixable.stderr b/tests/ui/reversed_empty_ranges_loops_fixable.stderr index a135da488ffd3..dfc52e64c7515 100644 --- a/tests/ui/reversed_empty_ranges_loops_fixable.stderr +++ b/tests/ui/reversed_empty_ranges_loops_fixable.stderr @@ -1,5 +1,5 @@ error: this range is empty so it will yield no values - --> $DIR/reversed_empty_ranges_loops_fixable.rs:7:14 + --> $DIR/reversed_empty_ranges_loops_fixable.rs:8:14 | LL | for i in 10..0 { | ^^^^^ @@ -11,7 +11,7 @@ LL | for i in (0..10).rev() { | ~~~~~~~~~~~~~ error: this range is empty so it will yield no values - --> $DIR/reversed_empty_ranges_loops_fixable.rs:11:14 + --> $DIR/reversed_empty_ranges_loops_fixable.rs:12:14 | LL | for i in 10..=0 { | ^^^^^^ @@ -22,7 +22,7 @@ LL | for i in (0..=10).rev() { | ~~~~~~~~~~~~~~ error: this range is empty so it will yield no values - --> $DIR/reversed_empty_ranges_loops_fixable.rs:15:14 + --> $DIR/reversed_empty_ranges_loops_fixable.rs:16:14 | LL | for i in MAX_LEN..0 { | ^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | for i in (0..MAX_LEN).rev() { | ~~~~~~~~~~~~~~~~~~ error: this range is empty so it will yield no values - --> $DIR/reversed_empty_ranges_loops_fixable.rs:34:14 + --> $DIR/reversed_empty_ranges_loops_fixable.rs:35:14 | LL | for i in (10..0).map(|x| x * 2) { | ^^^^^^^ @@ -44,7 +44,7 @@ LL | for i in (0..10).rev().map(|x| x * 2) { | ~~~~~~~~~~~~~ error: this range is empty so it will yield no values - --> $DIR/reversed_empty_ranges_loops_fixable.rs:39:14 + --> $DIR/reversed_empty_ranges_loops_fixable.rs:40:14 | LL | for i in 10..5 + 4 { | ^^^^^^^^^ @@ -55,7 +55,7 @@ LL | for i in (5 + 4..10).rev() { | ~~~~~~~~~~~~~~~~~ error: this range is empty so it will yield no values - --> $DIR/reversed_empty_ranges_loops_fixable.rs:43:14 + --> $DIR/reversed_empty_ranges_loops_fixable.rs:44:14 | LL | for i in (5 + 2)..(3 - 1) { | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/reversed_empty_ranges_loops_unfixable.rs b/tests/ui/reversed_empty_ranges_loops_unfixable.rs index c4c572244168b..50264ef68cc06 100644 --- a/tests/ui/reversed_empty_ranges_loops_unfixable.rs +++ b/tests/ui/reversed_empty_ranges_loops_unfixable.rs @@ -1,4 +1,5 @@ #![warn(clippy::reversed_empty_ranges)] +#![allow(clippy::uninlined_format_args)] fn main() { for i in 5..5 { diff --git a/tests/ui/reversed_empty_ranges_loops_unfixable.stderr b/tests/ui/reversed_empty_ranges_loops_unfixable.stderr index 30095d20cfd41..4490ff35f5a69 100644 --- a/tests/ui/reversed_empty_ranges_loops_unfixable.stderr +++ b/tests/ui/reversed_empty_ranges_loops_unfixable.stderr @@ -1,5 +1,5 @@ error: this range is empty so it will yield no values - --> $DIR/reversed_empty_ranges_loops_unfixable.rs:4:14 + --> $DIR/reversed_empty_ranges_loops_unfixable.rs:5:14 | LL | for i in 5..5 { | ^^^^ @@ -7,7 +7,7 @@ LL | for i in 5..5 { = note: `-D clippy::reversed-empty-ranges` implied by `-D warnings` error: this range is empty so it will yield no values - --> $DIR/reversed_empty_ranges_loops_unfixable.rs:8:14 + --> $DIR/reversed_empty_ranges_loops_unfixable.rs:9:14 | LL | for i in (5 + 2)..(8 - 1) { | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/same_functions_in_if_condition.rs b/tests/ui/same_functions_in_if_condition.rs index a48829caac019..e6198a1bc9a07 100644 --- a/tests/ui/same_functions_in_if_condition.rs +++ b/tests/ui/same_functions_in_if_condition.rs @@ -1,8 +1,14 @@ #![feature(adt_const_params)] -#![allow(incomplete_features)] #![warn(clippy::same_functions_in_if_condition)] -#![allow(clippy::ifs_same_cond)] // This warning is different from `ifs_same_cond`. -#![allow(clippy::if_same_then_else, clippy::comparison_chain)] // all empty blocks +// ifs_same_cond warning is different from `ifs_same_cond`. +// clippy::if_same_then_else, clippy::comparison_chain -- all empty blocks +#![allow(incomplete_features)] +#![allow( + clippy::comparison_chain, + clippy::if_same_then_else, + clippy::ifs_same_cond, + clippy::uninlined_format_args +)] fn function() -> bool { true diff --git a/tests/ui/same_functions_in_if_condition.stderr b/tests/ui/same_functions_in_if_condition.stderr index cd438b830401d..cab044ba3ef43 100644 --- a/tests/ui/same_functions_in_if_condition.stderr +++ b/tests/ui/same_functions_in_if_condition.stderr @@ -1,72 +1,72 @@ error: this `if` has the same function call as a previous `if` - --> $DIR/same_functions_in_if_condition.rs:31:15 + --> $DIR/same_functions_in_if_condition.rs:37:15 | LL | } else if function() { | ^^^^^^^^^^ | = note: `-D clippy::same-functions-in-if-condition` implied by `-D warnings` note: same as this - --> $DIR/same_functions_in_if_condition.rs:30:8 + --> $DIR/same_functions_in_if_condition.rs:36:8 | LL | if function() { | ^^^^^^^^^^ error: this `if` has the same function call as a previous `if` - --> $DIR/same_functions_in_if_condition.rs:36:15 + --> $DIR/same_functions_in_if_condition.rs:42:15 | LL | } else if fn_arg(a) { | ^^^^^^^^^ | note: same as this - --> $DIR/same_functions_in_if_condition.rs:35:8 + --> $DIR/same_functions_in_if_condition.rs:41:8 | LL | if fn_arg(a) { | ^^^^^^^^^ error: this `if` has the same function call as a previous `if` - --> $DIR/same_functions_in_if_condition.rs:41:15 + --> $DIR/same_functions_in_if_condition.rs:47:15 | LL | } else if obj.method() { | ^^^^^^^^^^^^ | note: same as this - --> $DIR/same_functions_in_if_condition.rs:40:8 + --> $DIR/same_functions_in_if_condition.rs:46:8 | LL | if obj.method() { | ^^^^^^^^^^^^ error: this `if` has the same function call as a previous `if` - --> $DIR/same_functions_in_if_condition.rs:46:15 + --> $DIR/same_functions_in_if_condition.rs:52:15 | LL | } else if obj.method_arg(a) { | ^^^^^^^^^^^^^^^^^ | note: same as this - --> $DIR/same_functions_in_if_condition.rs:45:8 + --> $DIR/same_functions_in_if_condition.rs:51:8 | LL | if obj.method_arg(a) { | ^^^^^^^^^^^^^^^^^ error: this `if` has the same function call as a previous `if` - --> $DIR/same_functions_in_if_condition.rs:53:15 + --> $DIR/same_functions_in_if_condition.rs:59:15 | LL | } else if v.pop().is_none() { | ^^^^^^^^^^^^^^^^^ | note: same as this - --> $DIR/same_functions_in_if_condition.rs:51:8 + --> $DIR/same_functions_in_if_condition.rs:57:8 | LL | if v.pop().is_none() { | ^^^^^^^^^^^^^^^^^ error: this `if` has the same function call as a previous `if` - --> $DIR/same_functions_in_if_condition.rs:58:15 + --> $DIR/same_functions_in_if_condition.rs:64:15 | LL | } else if v.len() == 42 { | ^^^^^^^^^^^^^ | note: same as this - --> $DIR/same_functions_in_if_condition.rs:56:8 + --> $DIR/same_functions_in_if_condition.rs:62:8 | LL | if v.len() == 42 { | ^^^^^^^^^^^^^ diff --git a/tests/ui/semicolon_if_nothing_returned.rs b/tests/ui/semicolon_if_nothing_returned.rs index c4dfbd9210e0d..4ab7dbab59cf0 100644 --- a/tests/ui/semicolon_if_nothing_returned.rs +++ b/tests/ui/semicolon_if_nothing_returned.rs @@ -1,5 +1,5 @@ #![warn(clippy::semicolon_if_nothing_returned)] -#![allow(clippy::redundant_closure)] +#![allow(clippy::redundant_closure, clippy::uninlined_format_args)] fn get_unit() {} diff --git a/tests/ui/significant_drop_in_scrutinee.rs b/tests/ui/significant_drop_in_scrutinee.rs index 84ecf1ea53ed7..c65df9ece38c4 100644 --- a/tests/ui/significant_drop_in_scrutinee.rs +++ b/tests/ui/significant_drop_in_scrutinee.rs @@ -1,11 +1,8 @@ // FIXME: Ideally these suggestions would be fixed via rustfix. Blocked by rust-lang/rust#53934 // // run-rustfix - #![warn(clippy::significant_drop_in_scrutinee)] -#![allow(clippy::single_match)] -#![allow(clippy::match_single_binding)] -#![allow(unused_assignments)] -#![allow(dead_code)] +#![allow(dead_code, unused_assignments)] +#![allow(clippy::match_single_binding, clippy::single_match, clippy::uninlined_format_args)] use std::num::ParseIntError; use std::ops::Deref; diff --git a/tests/ui/significant_drop_in_scrutinee.stderr b/tests/ui/significant_drop_in_scrutinee.stderr index 88ea6bce25b6b..179ac72564a05 100644 --- a/tests/ui/significant_drop_in_scrutinee.stderr +++ b/tests/ui/significant_drop_in_scrutinee.stderr @@ -1,5 +1,5 @@ error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:59:11 + --> $DIR/significant_drop_in_scrutinee.rs:56:11 | LL | match mutex.lock().unwrap().foo() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -19,7 +19,7 @@ LL ~ match value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:145:11 + --> $DIR/significant_drop_in_scrutinee.rs:142:11 | LL | match s.lock_m().get_the_value() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -38,7 +38,7 @@ LL ~ match value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:166:11 + --> $DIR/significant_drop_in_scrutinee.rs:163:11 | LL | match s.lock_m_m().get_the_value() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -57,7 +57,7 @@ LL ~ match value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:214:11 + --> $DIR/significant_drop_in_scrutinee.rs:211:11 | LL | match counter.temp_increment().len() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL ~ match value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:237:16 + --> $DIR/significant_drop_in_scrutinee.rs:234:16 | LL | match (mutex1.lock().unwrap().s.len(), true) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -92,7 +92,7 @@ LL ~ match (value, true) { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:246:22 + --> $DIR/significant_drop_in_scrutinee.rs:243:22 | LL | match (true, mutex1.lock().unwrap().s.len(), true) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -111,7 +111,7 @@ LL ~ match (true, value, true) { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:256:16 + --> $DIR/significant_drop_in_scrutinee.rs:253:16 | LL | match (mutex1.lock().unwrap().s.len(), true, mutex2.lock().unwrap().s.len()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -132,7 +132,7 @@ LL ~ match (value, true, mutex2.lock().unwrap().s.len()) { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:256:54 + --> $DIR/significant_drop_in_scrutinee.rs:253:54 | LL | match (mutex1.lock().unwrap().s.len(), true, mutex2.lock().unwrap().s.len()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -153,7 +153,7 @@ LL ~ match (mutex1.lock().unwrap().s.len(), true, value) { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:267:15 + --> $DIR/significant_drop_in_scrutinee.rs:264:15 | LL | match mutex3.lock().unwrap().s.as_str() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -169,7 +169,7 @@ LL | }; = note: this might lead to deadlocks or other unexpected behavior error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:277:22 + --> $DIR/significant_drop_in_scrutinee.rs:274:22 | LL | match (true, mutex3.lock().unwrap().s.as_str()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -185,7 +185,7 @@ LL | }; = note: this might lead to deadlocks or other unexpected behavior error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:296:11 + --> $DIR/significant_drop_in_scrutinee.rs:293:11 | LL | match mutex.lock().unwrap().s.len() > 1 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -204,7 +204,7 @@ LL ~ match value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:303:11 + --> $DIR/significant_drop_in_scrutinee.rs:300:11 | LL | match 1 < mutex.lock().unwrap().s.len() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -223,7 +223,7 @@ LL ~ match value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:321:11 + --> $DIR/significant_drop_in_scrutinee.rs:318:11 | LL | match mutex1.lock().unwrap().s.len() < mutex2.lock().unwrap().s.len() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -244,7 +244,7 @@ LL ~ match value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:332:11 + --> $DIR/significant_drop_in_scrutinee.rs:329:11 | LL | match mutex1.lock().unwrap().s.len() >= mutex2.lock().unwrap().s.len() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -265,7 +265,7 @@ LL ~ match value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:367:11 + --> $DIR/significant_drop_in_scrutinee.rs:364:11 | LL | match get_mutex_guard().s.len() > 1 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -284,7 +284,7 @@ LL ~ match value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:384:11 + --> $DIR/significant_drop_in_scrutinee.rs:381:11 | LL | match match i { | ___________^ @@ -316,7 +316,7 @@ LL ~ match value | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:410:11 + --> $DIR/significant_drop_in_scrutinee.rs:407:11 | LL | match if i > 1 { | ___________^ @@ -349,7 +349,7 @@ LL ~ match value | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:464:11 + --> $DIR/significant_drop_in_scrutinee.rs:461:11 | LL | match s.lock().deref().deref() { | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -367,7 +367,7 @@ LL ~ match value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:492:11 + --> $DIR/significant_drop_in_scrutinee.rs:489:11 | LL | match s.lock().deref().deref() { | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -380,7 +380,7 @@ LL | }; = note: this might lead to deadlocks or other unexpected behavior error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:511:11 + --> $DIR/significant_drop_in_scrutinee.rs:508:11 | LL | match mutex.lock().unwrap().i = i { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -399,7 +399,7 @@ LL ~ match () { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:517:11 + --> $DIR/significant_drop_in_scrutinee.rs:514:11 | LL | match i = mutex.lock().unwrap().i { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -418,7 +418,7 @@ LL ~ match () { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:523:11 + --> $DIR/significant_drop_in_scrutinee.rs:520:11 | LL | match mutex.lock().unwrap().i += 1 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -437,7 +437,7 @@ LL ~ match () { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:529:11 + --> $DIR/significant_drop_in_scrutinee.rs:526:11 | LL | match i += mutex.lock().unwrap().i { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -456,7 +456,7 @@ LL ~ match () { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:592:11 + --> $DIR/significant_drop_in_scrutinee.rs:589:11 | LL | match rwlock.read().unwrap().to_number() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -467,7 +467,7 @@ LL | }; = note: this might lead to deadlocks or other unexpected behavior error: temporary with significant `Drop` in `for` loop condition will live until the end of the `for` expression - --> $DIR/significant_drop_in_scrutinee.rs:602:14 + --> $DIR/significant_drop_in_scrutinee.rs:599:14 | LL | for s in rwlock.read().unwrap().iter() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -478,7 +478,7 @@ LL | } = note: this might lead to deadlocks or other unexpected behavior error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:617:11 + --> $DIR/significant_drop_in_scrutinee.rs:614:11 | LL | match mutex.lock().unwrap().foo() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/single_match.rs b/tests/ui/single_match.rs index dd148edf5292d..d0c9b7b5663e7 100644 --- a/tests/ui/single_match.rs +++ b/tests/ui/single_match.rs @@ -1,4 +1,5 @@ #![warn(clippy::single_match)] +#![allow(clippy::uninlined_format_args)] fn dummy() {} diff --git a/tests/ui/single_match.stderr b/tests/ui/single_match.stderr index 4d2b9ec5f903a..7cecc1b739506 100644 --- a/tests/ui/single_match.stderr +++ b/tests/ui/single_match.stderr @@ -1,5 +1,5 @@ error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> $DIR/single_match.rs:8:5 + --> $DIR/single_match.rs:9:5 | LL | / match x { LL | | Some(y) => { @@ -18,7 +18,7 @@ LL ~ }; | error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> $DIR/single_match.rs:16:5 + --> $DIR/single_match.rs:17:5 | LL | / match x { LL | | // Note the missing block braces. @@ -30,7 +30,7 @@ LL | | } | |_____^ help: try this: `if let Some(y) = x { println!("{:?}", y) }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> $DIR/single_match.rs:25:5 + --> $DIR/single_match.rs:26:5 | LL | / match z { LL | | (2..=3, 7..=9) => dummy(), @@ -39,7 +39,7 @@ LL | | }; | |_____^ help: try this: `if let (2..=3, 7..=9) = z { dummy() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> $DIR/single_match.rs:54:5 + --> $DIR/single_match.rs:55:5 | LL | / match x { LL | | Some(y) => dummy(), @@ -48,7 +48,7 @@ LL | | }; | |_____^ help: try this: `if let Some(y) = x { dummy() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> $DIR/single_match.rs:59:5 + --> $DIR/single_match.rs:60:5 | LL | / match y { LL | | Ok(y) => dummy(), @@ -57,7 +57,7 @@ LL | | }; | |_____^ help: try this: `if let Ok(y) = y { dummy() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> $DIR/single_match.rs:66:5 + --> $DIR/single_match.rs:67:5 | LL | / match c { LL | | Cow::Borrowed(..) => dummy(), @@ -66,7 +66,7 @@ LL | | }; | |_____^ help: try this: `if let Cow::Borrowed(..) = c { dummy() }` error: you seem to be trying to use `match` for an equality check. Consider using `if` - --> $DIR/single_match.rs:87:5 + --> $DIR/single_match.rs:88:5 | LL | / match x { LL | | "test" => println!(), @@ -75,7 +75,7 @@ LL | | } | |_____^ help: try this: `if x == "test" { println!() }` error: you seem to be trying to use `match` for an equality check. Consider using `if` - --> $DIR/single_match.rs:100:5 + --> $DIR/single_match.rs:101:5 | LL | / match x { LL | | Foo::A => println!(), @@ -84,7 +84,7 @@ LL | | } | |_____^ help: try this: `if x == Foo::A { println!() }` error: you seem to be trying to use `match` for an equality check. Consider using `if` - --> $DIR/single_match.rs:106:5 + --> $DIR/single_match.rs:107:5 | LL | / match x { LL | | FOO_C => println!(), @@ -93,7 +93,7 @@ LL | | } | |_____^ help: try this: `if x == FOO_C { println!() }` error: you seem to be trying to use `match` for an equality check. Consider using `if` - --> $DIR/single_match.rs:111:5 + --> $DIR/single_match.rs:112:5 | LL | / match &&x { LL | | Foo::A => println!(), @@ -102,7 +102,7 @@ LL | | } | |_____^ help: try this: `if x == Foo::A { println!() }` error: you seem to be trying to use `match` for an equality check. Consider using `if` - --> $DIR/single_match.rs:117:5 + --> $DIR/single_match.rs:118:5 | LL | / match &x { LL | | Foo::A => println!(), @@ -111,7 +111,7 @@ LL | | } | |_____^ help: try this: `if x == &Foo::A { println!() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> $DIR/single_match.rs:134:5 + --> $DIR/single_match.rs:135:5 | LL | / match x { LL | | Bar::A => println!(), @@ -120,7 +120,7 @@ LL | | } | |_____^ help: try this: `if let Bar::A = x { println!() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> $DIR/single_match.rs:142:5 + --> $DIR/single_match.rs:143:5 | LL | / match x { LL | | None => println!(), @@ -129,7 +129,7 @@ LL | | }; | |_____^ help: try this: `if let None = x { println!() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> $DIR/single_match.rs:164:5 + --> $DIR/single_match.rs:165:5 | LL | / match x { LL | | (Some(_), _) => {}, @@ -138,7 +138,7 @@ LL | | } | |_____^ help: try this: `if let (Some(_), _) = x {}` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> $DIR/single_match.rs:170:5 + --> $DIR/single_match.rs:171:5 | LL | / match x { LL | | (Some(E::V), _) => todo!(), @@ -147,7 +147,7 @@ LL | | } | |_____^ help: try this: `if let (Some(E::V), _) = x { todo!() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> $DIR/single_match.rs:176:5 + --> $DIR/single_match.rs:177:5 | LL | / match (Some(42), Some(E::V), Some(42)) { LL | | (.., Some(E::V), _) => {}, diff --git a/tests/ui/single_match_else.rs b/tests/ui/single_match_else.rs index 70d6febb71f9d..5d03f77e9326e 100644 --- a/tests/ui/single_match_else.rs +++ b/tests/ui/single_match_else.rs @@ -1,8 +1,6 @@ // aux-build: proc_macro_with_span.rs - #![warn(clippy::single_match_else)] -#![allow(clippy::needless_return)] -#![allow(clippy::no_effect)] +#![allow(clippy::needless_return, clippy::no_effect, clippy::uninlined_format_args)] extern crate proc_macro_with_span; use proc_macro_with_span::with_span; diff --git a/tests/ui/single_match_else.stderr b/tests/ui/single_match_else.stderr index 38fd9c6a6782a..62876a55dc616 100644 --- a/tests/ui/single_match_else.stderr +++ b/tests/ui/single_match_else.stderr @@ -1,5 +1,5 @@ error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> $DIR/single_match_else.rs:19:13 + --> $DIR/single_match_else.rs:17:13 | LL | let _ = match ExprNode::Butterflies { | _____________^ @@ -21,7 +21,7 @@ LL ~ }; | error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> $DIR/single_match_else.rs:84:5 + --> $DIR/single_match_else.rs:82:5 | LL | / match Some(1) { LL | | Some(a) => println!("${:?}", a), @@ -41,7 +41,7 @@ LL + } | error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> $DIR/single_match_else.rs:93:5 + --> $DIR/single_match_else.rs:91:5 | LL | / match Some(1) { LL | | Some(a) => println!("${:?}", a), @@ -61,7 +61,7 @@ LL + } | error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> $DIR/single_match_else.rs:103:5 + --> $DIR/single_match_else.rs:101:5 | LL | / match Result::::Ok(1) { LL | | Ok(a) => println!("${:?}", a), @@ -81,7 +81,7 @@ LL + } | error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> $DIR/single_match_else.rs:112:5 + --> $DIR/single_match_else.rs:110:5 | LL | / match Cow::from("moo") { LL | | Cow::Owned(a) => println!("${:?}", a), diff --git a/tests/ui/toplevel_ref_arg.fixed b/tests/ui/toplevel_ref_arg.fixed index b129d95c5602f..09fb66ca37e04 100644 --- a/tests/ui/toplevel_ref_arg.fixed +++ b/tests/ui/toplevel_ref_arg.fixed @@ -1,7 +1,7 @@ // run-rustfix // aux-build:macro_rules.rs - #![warn(clippy::toplevel_ref_arg)] +#![allow(clippy::uninlined_format_args)] #[macro_use] extern crate macro_rules; diff --git a/tests/ui/toplevel_ref_arg.rs b/tests/ui/toplevel_ref_arg.rs index 73eb4ff7306f7..9d1f2f810983a 100644 --- a/tests/ui/toplevel_ref_arg.rs +++ b/tests/ui/toplevel_ref_arg.rs @@ -1,7 +1,7 @@ // run-rustfix // aux-build:macro_rules.rs - #![warn(clippy::toplevel_ref_arg)] +#![allow(clippy::uninlined_format_args)] #[macro_use] extern crate macro_rules; diff --git a/tests/ui/trivially_copy_pass_by_ref.rs b/tests/ui/trivially_copy_pass_by_ref.rs index c0c64ebcabfbb..af4f3b18443bd 100644 --- a/tests/ui/trivially_copy_pass_by_ref.rs +++ b/tests/ui/trivially_copy_pass_by_ref.rs @@ -1,8 +1,11 @@ // normalize-stderr-test "\(\d+ byte\)" -> "(N byte)" // normalize-stderr-test "\(limit: \d+ byte\)" -> "(limit: N byte)" - #![deny(clippy::trivially_copy_pass_by_ref)] -#![allow(clippy::disallowed_names, clippy::redundant_field_names)] +#![allow( + clippy::disallowed_names, + clippy::redundant_field_names, + clippy::uninlined_format_args +)] #[derive(Copy, Clone)] struct Foo(u32); diff --git a/tests/ui/trivially_copy_pass_by_ref.stderr b/tests/ui/trivially_copy_pass_by_ref.stderr index 66ecb3d8e77ac..6a8eca9655343 100644 --- a/tests/ui/trivially_copy_pass_by_ref.stderr +++ b/tests/ui/trivially_copy_pass_by_ref.stderr @@ -1,113 +1,113 @@ error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:47:11 + --> $DIR/trivially_copy_pass_by_ref.rs:50:11 | LL | fn bad(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `u32` | note: the lint level is defined here - --> $DIR/trivially_copy_pass_by_ref.rs:4:9 + --> $DIR/trivially_copy_pass_by_ref.rs:3:9 | LL | #![deny(clippy::trivially_copy_pass_by_ref)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:47:20 + --> $DIR/trivially_copy_pass_by_ref.rs:50:20 | LL | fn bad(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Foo` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:47:29 + --> $DIR/trivially_copy_pass_by_ref.rs:50:29 | LL | fn bad(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Baz` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:54:12 + --> $DIR/trivially_copy_pass_by_ref.rs:57:12 | LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {} | ^^^^^ help: consider passing by value instead: `self` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:54:22 + --> $DIR/trivially_copy_pass_by_ref.rs:57:22 | LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `u32` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:54:31 + --> $DIR/trivially_copy_pass_by_ref.rs:57:31 | LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Foo` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:54:40 + --> $DIR/trivially_copy_pass_by_ref.rs:57:40 | LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Baz` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:56:16 + --> $DIR/trivially_copy_pass_by_ref.rs:59:16 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `u32` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:56:25 + --> $DIR/trivially_copy_pass_by_ref.rs:59:25 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Foo` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:56:34 + --> $DIR/trivially_copy_pass_by_ref.rs:59:34 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Baz` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:58:35 + --> $DIR/trivially_copy_pass_by_ref.rs:61:35 | LL | fn bad_issue7518(self, other: &Self) {} | ^^^^^ help: consider passing by value instead: `Self` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:70:16 + --> $DIR/trivially_copy_pass_by_ref.rs:73:16 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `u32` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:70:25 + --> $DIR/trivially_copy_pass_by_ref.rs:73:25 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Foo` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:70:34 + --> $DIR/trivially_copy_pass_by_ref.rs:73:34 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Baz` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:74:34 + --> $DIR/trivially_copy_pass_by_ref.rs:77:34 | LL | fn trait_method(&self, _foo: &Foo); | ^^^^ help: consider passing by value instead: `Foo` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:106:21 + --> $DIR/trivially_copy_pass_by_ref.rs:109:21 | LL | fn foo_never(x: &i32) { | ^^^^ help: consider passing by value instead: `i32` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:111:15 + --> $DIR/trivially_copy_pass_by_ref.rs:114:15 | LL | fn foo(x: &i32) { | ^^^^ help: consider passing by value instead: `i32` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:138:37 + --> $DIR/trivially_copy_pass_by_ref.rs:141:37 | LL | fn _unrelated_lifetimes<'a, 'b>(_x: &'a u32, y: &'b u32) -> &'b u32 { | ^^^^^^^ help: consider passing by value instead: `u32` diff --git a/tests/ui/uninlined_format_args.fixed b/tests/ui/uninlined_format_args.fixed index bade0ed8ad641..931916819ce2e 100644 --- a/tests/ui/uninlined_format_args.fixed +++ b/tests/ui/uninlined_format_args.fixed @@ -1,12 +1,8 @@ // run-rustfix - -#![allow(clippy::eq_op)] -#![allow(clippy::format_in_format_args)] -#![allow(clippy::print_literal)] -#![allow(named_arguments_used_positionally)] -#![allow(unused_variables, unused_imports, unused_macros)] -#![warn(clippy::uninlined_format_args)] #![feature(custom_inner_attributes)] +#![warn(clippy::uninlined_format_args)] +#![allow(named_arguments_used_positionally, unused_imports, unused_macros, unused_variables)] +#![allow(clippy::eq_op, clippy::format_in_format_args, clippy::print_literal)] macro_rules! no_param_str { () => { diff --git a/tests/ui/uninlined_format_args.rs b/tests/ui/uninlined_format_args.rs index ac958f9e5b607..0a9086775143b 100644 --- a/tests/ui/uninlined_format_args.rs +++ b/tests/ui/uninlined_format_args.rs @@ -1,12 +1,8 @@ // run-rustfix - -#![allow(clippy::eq_op)] -#![allow(clippy::format_in_format_args)] -#![allow(clippy::print_literal)] -#![allow(named_arguments_used_positionally)] -#![allow(unused_variables, unused_imports, unused_macros)] -#![warn(clippy::uninlined_format_args)] #![feature(custom_inner_attributes)] +#![warn(clippy::uninlined_format_args)] +#![allow(named_arguments_used_positionally, unused_imports, unused_macros, unused_variables)] +#![allow(clippy::eq_op, clippy::format_in_format_args, clippy::print_literal)] macro_rules! no_param_str { () => { diff --git a/tests/ui/uninlined_format_args.stderr b/tests/ui/uninlined_format_args.stderr index 7e652d0354f24..6c8f3f4334807 100644 --- a/tests/ui/uninlined_format_args.stderr +++ b/tests/ui/uninlined_format_args.stderr @@ -1,5 +1,5 @@ error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:47:5 + --> $DIR/uninlined_format_args.rs:43:5 | LL | println!("val='{}'", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -12,7 +12,7 @@ LL + println!("val='{local_i32}'"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:48:5 + --> $DIR/uninlined_format_args.rs:44:5 | LL | println!("val='{ }'", local_i32); // 3 spaces | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL + println!("val='{local_i32}'"); // 3 spaces | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:49:5 + --> $DIR/uninlined_format_args.rs:45:5 | LL | println!("val='{ }'", local_i32); // tab | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -36,7 +36,7 @@ LL + println!("val='{local_i32}'"); // tab | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:50:5 + --> $DIR/uninlined_format_args.rs:46:5 | LL | println!("val='{ }'", local_i32); // space+tab | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -48,7 +48,7 @@ LL + println!("val='{local_i32}'"); // space+tab | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:51:5 + --> $DIR/uninlined_format_args.rs:47:5 | LL | println!("val='{ }'", local_i32); // tab+space | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -60,7 +60,7 @@ LL + println!("val='{local_i32}'"); // tab+space | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:52:5 + --> $DIR/uninlined_format_args.rs:48:5 | LL | / println!( LL | | "val='{ @@ -76,7 +76,7 @@ LL + "val='{local_i32}'" | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:57:5 + --> $DIR/uninlined_format_args.rs:53:5 | LL | println!("{}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -88,7 +88,7 @@ LL + println!("{local_i32}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:58:5 + --> $DIR/uninlined_format_args.rs:54:5 | LL | println!("{}", fn_arg); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -100,7 +100,7 @@ LL + println!("{fn_arg}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:59:5 + --> $DIR/uninlined_format_args.rs:55:5 | LL | println!("{:?}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -112,7 +112,7 @@ LL + println!("{local_i32:?}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:60:5 + --> $DIR/uninlined_format_args.rs:56:5 | LL | println!("{:#?}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -124,7 +124,7 @@ LL + println!("{local_i32:#?}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:61:5 + --> $DIR/uninlined_format_args.rs:57:5 | LL | println!("{:4}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -136,7 +136,7 @@ LL + println!("{local_i32:4}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:62:5 + --> $DIR/uninlined_format_args.rs:58:5 | LL | println!("{:04}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -148,7 +148,7 @@ LL + println!("{local_i32:04}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:63:5 + --> $DIR/uninlined_format_args.rs:59:5 | LL | println!("{:<3}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -160,7 +160,7 @@ LL + println!("{local_i32:<3}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:64:5 + --> $DIR/uninlined_format_args.rs:60:5 | LL | println!("{:#010x}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -172,7 +172,7 @@ LL + println!("{local_i32:#010x}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:65:5 + --> $DIR/uninlined_format_args.rs:61:5 | LL | println!("{:.1}", local_f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -184,7 +184,7 @@ LL + println!("{local_f64:.1}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:66:5 + --> $DIR/uninlined_format_args.rs:62:5 | LL | println!("Hello {} is {:.*}", "x", local_i32, local_f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -196,7 +196,7 @@ LL + println!("Hello {} is {local_f64:.local_i32$}", "x"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:67:5 + --> $DIR/uninlined_format_args.rs:63:5 | LL | println!("Hello {} is {:.*}", local_i32, 5, local_f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -208,7 +208,7 @@ LL + println!("Hello {local_i32} is {local_f64:.*}", 5); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:68:5 + --> $DIR/uninlined_format_args.rs:64:5 | LL | println!("Hello {} is {2:.*}", local_i32, 5, local_f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -220,7 +220,7 @@ LL + println!("Hello {local_i32} is {local_f64:.*}", 5); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:69:5 + --> $DIR/uninlined_format_args.rs:65:5 | LL | println!("{} {}", local_i32, local_f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -232,7 +232,7 @@ LL + println!("{local_i32} {local_f64}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:70:5 + --> $DIR/uninlined_format_args.rs:66:5 | LL | println!("{}, {}", local_i32, local_opt.unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -244,7 +244,7 @@ LL + println!("{local_i32}, {}", local_opt.unwrap()); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:71:5 + --> $DIR/uninlined_format_args.rs:67:5 | LL | println!("{}", val); | ^^^^^^^^^^^^^^^^^^^ @@ -256,7 +256,7 @@ LL + println!("{val}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:72:5 + --> $DIR/uninlined_format_args.rs:68:5 | LL | println!("{}", v = val); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -268,7 +268,7 @@ LL + println!("{val}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:74:5 + --> $DIR/uninlined_format_args.rs:70:5 | LL | println!("val='{/t }'", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -280,7 +280,7 @@ LL + println!("val='{local_i32}'"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:75:5 + --> $DIR/uninlined_format_args.rs:71:5 | LL | println!("val='{/n }'", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -292,7 +292,7 @@ LL + println!("val='{local_i32}'"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:76:5 + --> $DIR/uninlined_format_args.rs:72:5 | LL | println!("val='{local_i32}'", local_i32 = local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -304,7 +304,7 @@ LL + println!("val='{local_i32}'"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:77:5 + --> $DIR/uninlined_format_args.rs:73:5 | LL | println!("val='{local_i32}'", local_i32 = fn_arg); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -316,7 +316,7 @@ LL + println!("val='{fn_arg}'"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:78:5 + --> $DIR/uninlined_format_args.rs:74:5 | LL | println!("{0}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -328,7 +328,7 @@ LL + println!("{local_i32}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:79:5 + --> $DIR/uninlined_format_args.rs:75:5 | LL | println!("{0:?}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -340,7 +340,7 @@ LL + println!("{local_i32:?}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:80:5 + --> $DIR/uninlined_format_args.rs:76:5 | LL | println!("{0:#?}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -352,7 +352,7 @@ LL + println!("{local_i32:#?}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:81:5 + --> $DIR/uninlined_format_args.rs:77:5 | LL | println!("{0:04}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -364,7 +364,7 @@ LL + println!("{local_i32:04}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:82:5 + --> $DIR/uninlined_format_args.rs:78:5 | LL | println!("{0:<3}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -376,7 +376,7 @@ LL + println!("{local_i32:<3}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:83:5 + --> $DIR/uninlined_format_args.rs:79:5 | LL | println!("{0:#010x}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -388,7 +388,7 @@ LL + println!("{local_i32:#010x}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:84:5 + --> $DIR/uninlined_format_args.rs:80:5 | LL | println!("{0:.1}", local_f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -400,7 +400,7 @@ LL + println!("{local_f64:.1}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:85:5 + --> $DIR/uninlined_format_args.rs:81:5 | LL | println!("{0} {0}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -412,7 +412,7 @@ LL + println!("{local_i32} {local_i32}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:86:5 + --> $DIR/uninlined_format_args.rs:82:5 | LL | println!("{1} {} {0} {}", local_i32, local_f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -424,7 +424,7 @@ LL + println!("{local_f64} {local_i32} {local_i32} {local_f64}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:87:5 + --> $DIR/uninlined_format_args.rs:83:5 | LL | println!("{0} {1}", local_i32, local_f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -436,7 +436,7 @@ LL + println!("{local_i32} {local_f64}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:88:5 + --> $DIR/uninlined_format_args.rs:84:5 | LL | println!("{1} {0}", local_i32, local_f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -448,7 +448,7 @@ LL + println!("{local_f64} {local_i32}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:89:5 + --> $DIR/uninlined_format_args.rs:85:5 | LL | println!("{1} {0} {1} {0}", local_i32, local_f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -460,7 +460,7 @@ LL + println!("{local_f64} {local_i32} {local_f64} {local_i32}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:91:5 + --> $DIR/uninlined_format_args.rs:87:5 | LL | println!("{v}", v = local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -472,7 +472,7 @@ LL + println!("{local_i32}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:92:5 + --> $DIR/uninlined_format_args.rs:88:5 | LL | println!("{local_i32:0$}", width); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -484,7 +484,7 @@ LL + println!("{local_i32:width$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:93:5 + --> $DIR/uninlined_format_args.rs:89:5 | LL | println!("{local_i32:w$}", w = width); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -496,7 +496,7 @@ LL + println!("{local_i32:width$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:94:5 + --> $DIR/uninlined_format_args.rs:90:5 | LL | println!("{local_i32:.0$}", prec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -508,7 +508,7 @@ LL + println!("{local_i32:.prec$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:95:5 + --> $DIR/uninlined_format_args.rs:91:5 | LL | println!("{local_i32:.p$}", p = prec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -520,7 +520,7 @@ LL + println!("{local_i32:.prec$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:96:5 + --> $DIR/uninlined_format_args.rs:92:5 | LL | println!("{:0$}", v = val); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -532,7 +532,7 @@ LL + println!("{val:val$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:97:5 + --> $DIR/uninlined_format_args.rs:93:5 | LL | println!("{0:0$}", v = val); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -544,7 +544,7 @@ LL + println!("{val:val$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:98:5 + --> $DIR/uninlined_format_args.rs:94:5 | LL | println!("{:0$.0$}", v = val); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -556,7 +556,7 @@ LL + println!("{val:val$.val$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:99:5 + --> $DIR/uninlined_format_args.rs:95:5 | LL | println!("{0:0$.0$}", v = val); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -568,7 +568,7 @@ LL + println!("{val:val$.val$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:100:5 + --> $DIR/uninlined_format_args.rs:96:5 | LL | println!("{0:0$.v$}", v = val); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -580,7 +580,7 @@ LL + println!("{val:val$.val$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:101:5 + --> $DIR/uninlined_format_args.rs:97:5 | LL | println!("{0:v$.0$}", v = val); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -592,7 +592,7 @@ LL + println!("{val:val$.val$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:102:5 + --> $DIR/uninlined_format_args.rs:98:5 | LL | println!("{v:0$.0$}", v = val); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -604,7 +604,7 @@ LL + println!("{val:val$.val$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:103:5 + --> $DIR/uninlined_format_args.rs:99:5 | LL | println!("{v:v$.0$}", v = val); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -616,7 +616,7 @@ LL + println!("{val:val$.val$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:104:5 + --> $DIR/uninlined_format_args.rs:100:5 | LL | println!("{v:0$.v$}", v = val); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -628,7 +628,7 @@ LL + println!("{val:val$.val$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:105:5 + --> $DIR/uninlined_format_args.rs:101:5 | LL | println!("{v:v$.v$}", v = val); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -640,7 +640,7 @@ LL + println!("{val:val$.val$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:106:5 + --> $DIR/uninlined_format_args.rs:102:5 | LL | println!("{:0$}", width); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -652,7 +652,7 @@ LL + println!("{width:width$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:107:5 + --> $DIR/uninlined_format_args.rs:103:5 | LL | println!("{:1$}", local_i32, width); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -664,7 +664,7 @@ LL + println!("{local_i32:width$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:108:5 + --> $DIR/uninlined_format_args.rs:104:5 | LL | println!("{:w$}", w = width); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -676,7 +676,7 @@ LL + println!("{width:width$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:109:5 + --> $DIR/uninlined_format_args.rs:105:5 | LL | println!("{:w$}", local_i32, w = width); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -688,7 +688,7 @@ LL + println!("{local_i32:width$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:110:5 + --> $DIR/uninlined_format_args.rs:106:5 | LL | println!("{:.0$}", prec); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -700,7 +700,7 @@ LL + println!("{prec:.prec$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:111:5 + --> $DIR/uninlined_format_args.rs:107:5 | LL | println!("{:.1$}", local_i32, prec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -712,7 +712,7 @@ LL + println!("{local_i32:.prec$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:112:5 + --> $DIR/uninlined_format_args.rs:108:5 | LL | println!("{:.p$}", p = prec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -724,7 +724,7 @@ LL + println!("{prec:.prec$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:113:5 + --> $DIR/uninlined_format_args.rs:109:5 | LL | println!("{:.p$}", local_i32, p = prec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -736,7 +736,7 @@ LL + println!("{local_i32:.prec$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:114:5 + --> $DIR/uninlined_format_args.rs:110:5 | LL | println!("{:0$.1$}", width, prec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -748,7 +748,7 @@ LL + println!("{width:width$.prec$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:115:5 + --> $DIR/uninlined_format_args.rs:111:5 | LL | println!("{:0$.w$}", width, w = prec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -760,7 +760,7 @@ LL + println!("{width:width$.prec$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:116:5 + --> $DIR/uninlined_format_args.rs:112:5 | LL | println!("{:1$.2$}", local_f64, width, prec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -772,7 +772,7 @@ LL + println!("{local_f64:width$.prec$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:117:5 + --> $DIR/uninlined_format_args.rs:113:5 | LL | println!("{:1$.2$} {0} {1} {2}", local_f64, width, prec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -784,7 +784,7 @@ LL + println!("{local_f64:width$.prec$} {local_f64} {width} {prec}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:118:5 + --> $DIR/uninlined_format_args.rs:114:5 | LL | / println!( LL | | "{0:1$.2$} {0:2$.1$} {1:0$.2$} {1:2$.0$} {2:0$.1$} {2:1$.0$}", @@ -803,7 +803,7 @@ LL ~ "{0:1$.2$} {0:2$.1$} {1:0$.2$} {1:2$.0$} {2:0$.1$} {2:1$.0$}", | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:129:5 + --> $DIR/uninlined_format_args.rs:125:5 | LL | println!("Width = {}, value with width = {:0$}", local_i32, local_f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -815,7 +815,7 @@ LL + println!("Width = {local_i32}, value with width = {local_f64:local_i32$ | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:130:5 + --> $DIR/uninlined_format_args.rs:126:5 | LL | println!("{:w$.p$}", local_i32, w = width, p = prec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -827,7 +827,7 @@ LL + println!("{local_i32:width$.prec$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:131:5 + --> $DIR/uninlined_format_args.rs:127:5 | LL | println!("{:w$.p$}", w = width, p = prec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -839,7 +839,7 @@ LL + println!("{width:width$.prec$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:132:20 + --> $DIR/uninlined_format_args.rs:128:20 | LL | println!("{}", format!("{}", local_i32)); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -851,7 +851,7 @@ LL + println!("{}", format!("{local_i32}")); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:170:5 + --> $DIR/uninlined_format_args.rs:166:5 | LL | println!("expand='{}'", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/unit_arg.rs b/tests/ui/unit_arg.rs index 7bf3adc07ac56..07e70873a8132 100644 --- a/tests/ui/unit_arg.rs +++ b/tests/ui/unit_arg.rs @@ -1,17 +1,16 @@ // aux-build: proc_macro_with_span.rs - #![warn(clippy::unit_arg)] +#![allow(unused_must_use, unused_variables)] #![allow( + clippy::let_unit_value, + clippy::needless_question_mark, + clippy::never_loop, clippy::no_effect, - unused_must_use, - unused_variables, - clippy::unused_unit, - clippy::unnecessary_wraps, clippy::or_fun_call, - clippy::needless_question_mark, clippy::self_named_constructors, - clippy::let_unit_value, - clippy::never_loop + clippy::uninlined_format_args, + clippy::unnecessary_wraps, + clippy::unused_unit )] extern crate proc_macro_with_span; diff --git a/tests/ui/unit_arg.stderr b/tests/ui/unit_arg.stderr index 1de9d44bb0d6e..74d4d2f4052f7 100644 --- a/tests/ui/unit_arg.stderr +++ b/tests/ui/unit_arg.stderr @@ -1,5 +1,5 @@ error: passing a unit value to a function - --> $DIR/unit_arg.rs:63:5 + --> $DIR/unit_arg.rs:62:5 | LL | / foo({ LL | | 1; @@ -20,7 +20,7 @@ LL ~ foo(()); | error: passing a unit value to a function - --> $DIR/unit_arg.rs:66:5 + --> $DIR/unit_arg.rs:65:5 | LL | foo(foo(1)); | ^^^^^^^^^^^ @@ -32,7 +32,7 @@ LL ~ foo(()); | error: passing a unit value to a function - --> $DIR/unit_arg.rs:67:5 + --> $DIR/unit_arg.rs:66:5 | LL | / foo({ LL | | foo(1); @@ -54,7 +54,7 @@ LL ~ foo(()); | error: passing a unit value to a function - --> $DIR/unit_arg.rs:72:5 + --> $DIR/unit_arg.rs:71:5 | LL | / b.bar({ LL | | 1; @@ -74,7 +74,7 @@ LL ~ b.bar(()); | error: passing unit values to a function - --> $DIR/unit_arg.rs:75:5 + --> $DIR/unit_arg.rs:74:5 | LL | taking_multiple_units(foo(0), foo(1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -87,7 +87,7 @@ LL ~ taking_multiple_units((), ()); | error: passing unit values to a function - --> $DIR/unit_arg.rs:76:5 + --> $DIR/unit_arg.rs:75:5 | LL | / taking_multiple_units(foo(0), { LL | | foo(1); @@ -110,7 +110,7 @@ LL ~ taking_multiple_units((), ()); | error: passing unit values to a function - --> $DIR/unit_arg.rs:80:5 + --> $DIR/unit_arg.rs:79:5 | LL | / taking_multiple_units( LL | | { @@ -146,7 +146,7 @@ LL ~ ); | error: passing a unit value to a function - --> $DIR/unit_arg.rs:91:13 + --> $DIR/unit_arg.rs:90:13 | LL | None.or(Some(foo(2))); | ^^^^^^^^^^^^ @@ -160,7 +160,7 @@ LL ~ }); | error: passing a unit value to a function - --> $DIR/unit_arg.rs:94:5 + --> $DIR/unit_arg.rs:93:5 | LL | foo(foo(())); | ^^^^^^^^^^^^ @@ -172,7 +172,7 @@ LL ~ foo(()); | error: passing a unit value to a function - --> $DIR/unit_arg.rs:131:5 + --> $DIR/unit_arg.rs:130:5 | LL | Some(foo(1)) | ^^^^^^^^^^^^ diff --git a/tests/ui/unit_arg_empty_blocks.fixed b/tests/ui/unit_arg_empty_blocks.fixed index 9400e93cac839..5787471a32caa 100644 --- a/tests/ui/unit_arg_empty_blocks.fixed +++ b/tests/ui/unit_arg_empty_blocks.fixed @@ -1,6 +1,7 @@ // run-rustfix #![warn(clippy::unit_arg)] -#![allow(clippy::no_effect, unused_must_use, unused_variables)] +#![allow(unused_must_use, unused_variables)] +#![allow(clippy::no_effect, clippy::uninlined_format_args)] use std::fmt::Debug; diff --git a/tests/ui/unit_arg_empty_blocks.rs b/tests/ui/unit_arg_empty_blocks.rs index 5f52b6c5315fd..6a42c2ccf42b3 100644 --- a/tests/ui/unit_arg_empty_blocks.rs +++ b/tests/ui/unit_arg_empty_blocks.rs @@ -1,6 +1,7 @@ // run-rustfix #![warn(clippy::unit_arg)] -#![allow(clippy::no_effect, unused_must_use, unused_variables)] +#![allow(unused_must_use, unused_variables)] +#![allow(clippy::no_effect, clippy::uninlined_format_args)] use std::fmt::Debug; diff --git a/tests/ui/unit_arg_empty_blocks.stderr b/tests/ui/unit_arg_empty_blocks.stderr index d35e931697d21..c697dfb1efa26 100644 --- a/tests/ui/unit_arg_empty_blocks.stderr +++ b/tests/ui/unit_arg_empty_blocks.stderr @@ -1,5 +1,5 @@ error: passing a unit value to a function - --> $DIR/unit_arg_empty_blocks.rs:16:5 + --> $DIR/unit_arg_empty_blocks.rs:17:5 | LL | foo({}); | ^^^^--^ @@ -9,7 +9,7 @@ LL | foo({}); = note: `-D clippy::unit-arg` implied by `-D warnings` error: passing a unit value to a function - --> $DIR/unit_arg_empty_blocks.rs:17:5 + --> $DIR/unit_arg_empty_blocks.rs:18:5 | LL | foo3({}, 2, 2); | ^^^^^--^^^^^^^ @@ -17,7 +17,7 @@ LL | foo3({}, 2, 2); | help: use a unit literal instead: `()` error: passing unit values to a function - --> $DIR/unit_arg_empty_blocks.rs:18:5 + --> $DIR/unit_arg_empty_blocks.rs:19:5 | LL | taking_two_units({}, foo(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -29,7 +29,7 @@ LL ~ taking_two_units((), ()); | error: passing unit values to a function - --> $DIR/unit_arg_empty_blocks.rs:19:5 + --> $DIR/unit_arg_empty_blocks.rs:20:5 | LL | taking_three_units({}, foo(0), foo(1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/unnecessary_clone.rs b/tests/ui/unnecessary_clone.rs index 6770a7fac90fd..8b1629b19a769 100644 --- a/tests/ui/unnecessary_clone.rs +++ b/tests/ui/unnecessary_clone.rs @@ -1,7 +1,7 @@ // does not test any rustfixable lints - #![warn(clippy::clone_on_ref_ptr)] -#![allow(unused, clippy::redundant_clone, clippy::unnecessary_wraps)] +#![allow(unused)] +#![allow(clippy::redundant_clone, clippy::uninlined_format_args, clippy::unnecessary_wraps)] use std::cell::RefCell; use std::rc::{self, Rc}; diff --git a/tests/ui/unnecessary_join.fixed b/tests/ui/unnecessary_join.fixed index 7e12c6ae4be98..3479539602575 100644 --- a/tests/ui/unnecessary_join.fixed +++ b/tests/ui/unnecessary_join.fixed @@ -1,6 +1,6 @@ // run-rustfix - #![warn(clippy::unnecessary_join)] +#![allow(clippy::uninlined_format_args)] fn main() { // should be linted diff --git a/tests/ui/unnecessary_join.rs b/tests/ui/unnecessary_join.rs index 0a21656a7558e..344918cd2a2ec 100644 --- a/tests/ui/unnecessary_join.rs +++ b/tests/ui/unnecessary_join.rs @@ -1,6 +1,6 @@ // run-rustfix - #![warn(clippy::unnecessary_join)] +#![allow(clippy::uninlined_format_args)] fn main() { // should be linted diff --git a/tests/ui/used_underscore_binding.rs b/tests/ui/used_underscore_binding.rs index 322083511ac18..8c29e15b14592 100644 --- a/tests/ui/used_underscore_binding.rs +++ b/tests/ui/used_underscore_binding.rs @@ -1,9 +1,8 @@ // aux-build:proc_macro_derive.rs - #![feature(rustc_private)] #![warn(clippy::all)] -#![allow(clippy::disallowed_names, clippy::eq_op)] #![warn(clippy::used_underscore_binding)] +#![allow(clippy::disallowed_names, clippy::eq_op, clippy::uninlined_format_args)] #[macro_use] extern crate proc_macro_derive; diff --git a/tests/ui/used_underscore_binding.stderr b/tests/ui/used_underscore_binding.stderr index 61a9161d212da..875fafe438a13 100644 --- a/tests/ui/used_underscore_binding.stderr +++ b/tests/ui/used_underscore_binding.stderr @@ -1,5 +1,5 @@ error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used - --> $DIR/used_underscore_binding.rs:25:5 + --> $DIR/used_underscore_binding.rs:24:5 | LL | _foo + 1 | ^^^^ @@ -7,31 +7,31 @@ LL | _foo + 1 = note: `-D clippy::used-underscore-binding` implied by `-D warnings` error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used - --> $DIR/used_underscore_binding.rs:30:20 + --> $DIR/used_underscore_binding.rs:29:20 | LL | println!("{}", _foo); | ^^^^ error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used - --> $DIR/used_underscore_binding.rs:31:16 + --> $DIR/used_underscore_binding.rs:30:16 | LL | assert_eq!(_foo, _foo); | ^^^^ error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used - --> $DIR/used_underscore_binding.rs:31:22 + --> $DIR/used_underscore_binding.rs:30:22 | LL | assert_eq!(_foo, _foo); | ^^^^ error: used binding `_underscore_field` which is prefixed with an underscore. A leading underscore signals that a binding will not be used - --> $DIR/used_underscore_binding.rs:44:5 + --> $DIR/used_underscore_binding.rs:43:5 | LL | s._underscore_field += 1; | ^^^^^^^^^^^^^^^^^^^ error: used binding `_i` which is prefixed with an underscore. A leading underscore signals that a binding will not be used - --> $DIR/used_underscore_binding.rs:105:16 + --> $DIR/used_underscore_binding.rs:104:16 | LL | uses_i(_i); | ^^ diff --git a/tests/ui/useless_asref.fixed b/tests/ui/useless_asref.fixed index 90cb8945e77ff..38e4b9201e6de 100644 --- a/tests/ui/useless_asref.fixed +++ b/tests/ui/useless_asref.fixed @@ -1,7 +1,6 @@ // run-rustfix - #![deny(clippy::useless_asref)] -#![allow(clippy::explicit_auto_deref)] +#![allow(clippy::explicit_auto_deref, clippy::uninlined_format_args)] use std::fmt::Debug; diff --git a/tests/ui/useless_asref.rs b/tests/ui/useless_asref.rs index cb9f8ae5909a5..f1e83f9d396cd 100644 --- a/tests/ui/useless_asref.rs +++ b/tests/ui/useless_asref.rs @@ -1,7 +1,6 @@ // run-rustfix - #![deny(clippy::useless_asref)] -#![allow(clippy::explicit_auto_deref)] +#![allow(clippy::explicit_auto_deref, clippy::uninlined_format_args)] use std::fmt::Debug; diff --git a/tests/ui/useless_asref.stderr b/tests/ui/useless_asref.stderr index b21c67bb3645f..67ce8b64e0e3d 100644 --- a/tests/ui/useless_asref.stderr +++ b/tests/ui/useless_asref.stderr @@ -1,71 +1,71 @@ error: this call to `as_ref` does nothing - --> $DIR/useless_asref.rs:44:18 + --> $DIR/useless_asref.rs:43:18 | LL | foo_rstr(rstr.as_ref()); | ^^^^^^^^^^^^^ help: try this: `rstr` | note: the lint level is defined here - --> $DIR/useless_asref.rs:3:9 + --> $DIR/useless_asref.rs:2:9 | LL | #![deny(clippy::useless_asref)] | ^^^^^^^^^^^^^^^^^^^^^ error: this call to `as_ref` does nothing - --> $DIR/useless_asref.rs:46:20 + --> $DIR/useless_asref.rs:45:20 | LL | foo_rslice(rslice.as_ref()); | ^^^^^^^^^^^^^^^ help: try this: `rslice` error: this call to `as_mut` does nothing - --> $DIR/useless_asref.rs:50:21 + --> $DIR/useless_asref.rs:49:21 | LL | foo_mrslice(mrslice.as_mut()); | ^^^^^^^^^^^^^^^^ help: try this: `mrslice` error: this call to `as_ref` does nothing - --> $DIR/useless_asref.rs:52:20 + --> $DIR/useless_asref.rs:51:20 | LL | foo_rslice(mrslice.as_ref()); | ^^^^^^^^^^^^^^^^ help: try this: `mrslice` error: this call to `as_ref` does nothing - --> $DIR/useless_asref.rs:59:20 + --> $DIR/useless_asref.rs:58:20 | LL | foo_rslice(rrrrrslice.as_ref()); | ^^^^^^^^^^^^^^^^^^^ help: try this: `rrrrrslice` error: this call to `as_ref` does nothing - --> $DIR/useless_asref.rs:61:18 + --> $DIR/useless_asref.rs:60:18 | LL | foo_rstr(rrrrrstr.as_ref()); | ^^^^^^^^^^^^^^^^^ help: try this: `rrrrrstr` error: this call to `as_mut` does nothing - --> $DIR/useless_asref.rs:66:21 + --> $DIR/useless_asref.rs:65:21 | LL | foo_mrslice(mrrrrrslice.as_mut()); | ^^^^^^^^^^^^^^^^^^^^ help: try this: `mrrrrrslice` error: this call to `as_ref` does nothing - --> $DIR/useless_asref.rs:68:20 + --> $DIR/useless_asref.rs:67:20 | LL | foo_rslice(mrrrrrslice.as_ref()); | ^^^^^^^^^^^^^^^^^^^^ help: try this: `mrrrrrslice` error: this call to `as_ref` does nothing - --> $DIR/useless_asref.rs:72:16 + --> $DIR/useless_asref.rs:71:16 | LL | foo_rrrrmr((&&&&MoreRef).as_ref()); | ^^^^^^^^^^^^^^^^^^^^^^ help: try this: `(&&&&MoreRef)` error: this call to `as_mut` does nothing - --> $DIR/useless_asref.rs:122:13 + --> $DIR/useless_asref.rs:121:13 | LL | foo_mrt(mrt.as_mut()); | ^^^^^^^^^^^^ help: try this: `mrt` error: this call to `as_ref` does nothing - --> $DIR/useless_asref.rs:124:12 + --> $DIR/useless_asref.rs:123:12 | LL | foo_rt(mrt.as_ref()); | ^^^^^^^^^^^^ help: try this: `mrt` diff --git a/tests/ui/vec.fixed b/tests/ui/vec.fixed index 318f9c2dceb64..2518d80491500 100644 --- a/tests/ui/vec.fixed +++ b/tests/ui/vec.fixed @@ -1,6 +1,6 @@ // run-rustfix -#![allow(clippy::nonstandard_macro_braces)] #![warn(clippy::useless_vec)] +#![allow(clippy::nonstandard_macro_braces, clippy::uninlined_format_args)] #[derive(Debug)] struct NonCopy; diff --git a/tests/ui/vec.rs b/tests/ui/vec.rs index d7673ce3e6437..e1492e2f3aef0 100644 --- a/tests/ui/vec.rs +++ b/tests/ui/vec.rs @@ -1,6 +1,6 @@ // run-rustfix -#![allow(clippy::nonstandard_macro_braces)] #![warn(clippy::useless_vec)] +#![allow(clippy::nonstandard_macro_braces, clippy::uninlined_format_args)] #[derive(Debug)] struct NonCopy; diff --git a/tests/ui/while_let_loop.rs b/tests/ui/while_let_loop.rs index c42e2a79a9bf9..5b8075731cb79 100644 --- a/tests/ui/while_let_loop.rs +++ b/tests/ui/while_let_loop.rs @@ -1,4 +1,5 @@ #![warn(clippy::while_let_loop)] +#![allow(clippy::uninlined_format_args)] fn main() { let y = Some(true); diff --git a/tests/ui/while_let_loop.stderr b/tests/ui/while_let_loop.stderr index 13dd0ee224c10..04808c0b3adaf 100644 --- a/tests/ui/while_let_loop.stderr +++ b/tests/ui/while_let_loop.stderr @@ -1,5 +1,5 @@ error: this loop could be written as a `while let` loop - --> $DIR/while_let_loop.rs:5:5 + --> $DIR/while_let_loop.rs:6:5 | LL | / loop { LL | | if let Some(_x) = y { @@ -13,7 +13,7 @@ LL | | } = note: `-D clippy::while-let-loop` implied by `-D warnings` error: this loop could be written as a `while let` loop - --> $DIR/while_let_loop.rs:22:5 + --> $DIR/while_let_loop.rs:23:5 | LL | / loop { LL | | match y { @@ -24,7 +24,7 @@ LL | | } | |_____^ help: try: `while let Some(_x) = y { .. }` error: this loop could be written as a `while let` loop - --> $DIR/while_let_loop.rs:29:5 + --> $DIR/while_let_loop.rs:30:5 | LL | / loop { LL | | let x = match y { @@ -36,7 +36,7 @@ LL | | } | |_____^ help: try: `while let Some(x) = y { .. }` error: this loop could be written as a `while let` loop - --> $DIR/while_let_loop.rs:38:5 + --> $DIR/while_let_loop.rs:39:5 | LL | / loop { LL | | let x = match y { @@ -48,7 +48,7 @@ LL | | } | |_____^ help: try: `while let Some(x) = y { .. }` error: this loop could be written as a `while let` loop - --> $DIR/while_let_loop.rs:68:5 + --> $DIR/while_let_loop.rs:69:5 | LL | / loop { LL | | let (e, l) = match "".split_whitespace().next() { diff --git a/tests/ui/while_let_on_iterator.fixed b/tests/ui/while_let_on_iterator.fixed index c57c46736342b..5afa0a89f82c8 100644 --- a/tests/ui/while_let_on_iterator.fixed +++ b/tests/ui/while_let_on_iterator.fixed @@ -1,14 +1,12 @@ // run-rustfix - #![warn(clippy::while_let_on_iterator)] +#![allow(dead_code, unreachable_code, unused_mut)] #![allow( - clippy::never_loop, - unreachable_code, - unused_mut, - dead_code, clippy::equatable_if_let, clippy::manual_find, - clippy::redundant_closure_call + clippy::never_loop, + clippy::redundant_closure_call, + clippy::uninlined_format_args )] fn base() { diff --git a/tests/ui/while_let_on_iterator.rs b/tests/ui/while_let_on_iterator.rs index 8b9a2dbcce3a7..3de586c9d8fd4 100644 --- a/tests/ui/while_let_on_iterator.rs +++ b/tests/ui/while_let_on_iterator.rs @@ -1,14 +1,12 @@ // run-rustfix - #![warn(clippy::while_let_on_iterator)] +#![allow(dead_code, unreachable_code, unused_mut)] #![allow( - clippy::never_loop, - unreachable_code, - unused_mut, - dead_code, clippy::equatable_if_let, clippy::manual_find, - clippy::redundant_closure_call + clippy::never_loop, + clippy::redundant_closure_call, + clippy::uninlined_format_args )] fn base() { diff --git a/tests/ui/while_let_on_iterator.stderr b/tests/ui/while_let_on_iterator.stderr index 3236765e1db0f..4d98666190d67 100644 --- a/tests/ui/while_let_on_iterator.stderr +++ b/tests/ui/while_let_on_iterator.stderr @@ -1,5 +1,5 @@ error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:16:5 + --> $DIR/while_let_on_iterator.rs:14:5 | LL | while let Option::Some(x) = iter.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in iter` @@ -7,151 +7,151 @@ LL | while let Option::Some(x) = iter.next() { = note: `-D clippy::while-let-on-iterator` implied by `-D warnings` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:21:5 + --> $DIR/while_let_on_iterator.rs:19:5 | LL | while let Some(x) = iter.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in iter` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:26:5 + --> $DIR/while_let_on_iterator.rs:24:5 | LL | while let Some(_) = iter.next() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in iter` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:102:9 + --> $DIR/while_let_on_iterator.rs:100:9 | LL | while let Some([..]) = it.next() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for [..] in it` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:109:9 + --> $DIR/while_let_on_iterator.rs:107:9 | LL | while let Some([_x]) = it.next() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for [_x] in it` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:122:9 + --> $DIR/while_let_on_iterator.rs:120:9 | LL | while let Some(x @ [_]) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x @ [_] in it` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:142:9 + --> $DIR/while_let_on_iterator.rs:140:9 | LL | while let Some(_) = y.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in y` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:199:9 + --> $DIR/while_let_on_iterator.rs:197:9 | LL | while let Some(m) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:210:5 + --> $DIR/while_let_on_iterator.rs:208:5 | LL | while let Some(n) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for n in it` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:212:9 + --> $DIR/while_let_on_iterator.rs:210:9 | LL | while let Some(m) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:221:9 + --> $DIR/while_let_on_iterator.rs:219:9 | LL | while let Some(m) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:230:9 + --> $DIR/while_let_on_iterator.rs:228:9 | LL | while let Some(m) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:247:9 + --> $DIR/while_let_on_iterator.rs:245:9 | LL | while let Some(m) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:262:13 + --> $DIR/while_let_on_iterator.rs:260:13 | LL | while let Some(i) = self.0.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for i in self.0.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:294:13 + --> $DIR/while_let_on_iterator.rs:292:13 | LL | while let Some(i) = self.0.0.0.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for i in self.0.0.0.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:323:5 + --> $DIR/while_let_on_iterator.rs:321:5 | LL | while let Some(n) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for n in it.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:335:9 + --> $DIR/while_let_on_iterator.rs:333:9 | LL | while let Some(x) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:349:5 + --> $DIR/while_let_on_iterator.rs:347:5 | LL | while let Some(x) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:360:5 + --> $DIR/while_let_on_iterator.rs:358:5 | LL | while let Some(x) = it.0.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.0.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:395:5 + --> $DIR/while_let_on_iterator.rs:393:5 | LL | while let Some(x) = s.x.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in s.x.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:402:5 + --> $DIR/while_let_on_iterator.rs:400:5 | LL | while let Some(x) = x[0].next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in x[0].by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:410:9 + --> $DIR/while_let_on_iterator.rs:408:9 | LL | while let Some(x) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:420:9 + --> $DIR/while_let_on_iterator.rs:418:9 | LL | while let Some(x) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:430:9 + --> $DIR/while_let_on_iterator.rs:428:9 | LL | while let Some(x) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:440:9 + --> $DIR/while_let_on_iterator.rs:438:9 | LL | while let Some(x) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:450:5 + --> $DIR/while_let_on_iterator.rs:448:5 | LL | while let Some(..) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in it` diff --git a/tests/ui/wildcard_enum_match_arm.fixed b/tests/ui/wildcard_enum_match_arm.fixed index 3ee4ab48ac84b..23607497841e4 100644 --- a/tests/ui/wildcard_enum_match_arm.fixed +++ b/tests/ui/wildcard_enum_match_arm.fixed @@ -1,15 +1,13 @@ // run-rustfix // aux-build:non-exhaustive-enum.rs - #![deny(clippy::wildcard_enum_match_arm)] +#![allow(dead_code, unreachable_code, unused_variables)] #![allow( - unreachable_code, - unused_variables, - dead_code, + clippy::diverging_sub_expression, clippy::single_match, - clippy::wildcard_in_or_patterns, + clippy::uninlined_format_args, clippy::unnested_or_patterns, - clippy::diverging_sub_expression + clippy::wildcard_in_or_patterns )] extern crate non_exhaustive_enum; diff --git a/tests/ui/wildcard_enum_match_arm.rs b/tests/ui/wildcard_enum_match_arm.rs index 4688655045330..decd86165f3a4 100644 --- a/tests/ui/wildcard_enum_match_arm.rs +++ b/tests/ui/wildcard_enum_match_arm.rs @@ -1,15 +1,13 @@ // run-rustfix // aux-build:non-exhaustive-enum.rs - #![deny(clippy::wildcard_enum_match_arm)] +#![allow(dead_code, unreachable_code, unused_variables)] #![allow( - unreachable_code, - unused_variables, - dead_code, + clippy::diverging_sub_expression, clippy::single_match, - clippy::wildcard_in_or_patterns, + clippy::uninlined_format_args, clippy::unnested_or_patterns, - clippy::diverging_sub_expression + clippy::wildcard_in_or_patterns )] extern crate non_exhaustive_enum; diff --git a/tests/ui/wildcard_enum_match_arm.stderr b/tests/ui/wildcard_enum_match_arm.stderr index d63f209035315..efecc9576cc7b 100644 --- a/tests/ui/wildcard_enum_match_arm.stderr +++ b/tests/ui/wildcard_enum_match_arm.stderr @@ -1,41 +1,41 @@ error: wildcard match will also match any future added variants - --> $DIR/wildcard_enum_match_arm.rs:42:9 + --> $DIR/wildcard_enum_match_arm.rs:40:9 | LL | _ => eprintln!("Not red"), | ^ help: try this: `Color::Green | Color::Blue | Color::Rgb(..) | Color::Cyan` | note: the lint level is defined here - --> $DIR/wildcard_enum_match_arm.rs:4:9 + --> $DIR/wildcard_enum_match_arm.rs:3:9 | LL | #![deny(clippy::wildcard_enum_match_arm)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: wildcard match will also match any future added variants - --> $DIR/wildcard_enum_match_arm.rs:46:9 + --> $DIR/wildcard_enum_match_arm.rs:44:9 | LL | _not_red => eprintln!("Not red"), | ^^^^^^^^ help: try this: `_not_red @ Color::Green | _not_red @ Color::Blue | _not_red @ Color::Rgb(..) | _not_red @ Color::Cyan` error: wildcard match will also match any future added variants - --> $DIR/wildcard_enum_match_arm.rs:50:9 + --> $DIR/wildcard_enum_match_arm.rs:48:9 | LL | not_red => format!("{:?}", not_red), | ^^^^^^^ help: try this: `not_red @ Color::Green | not_red @ Color::Blue | not_red @ Color::Rgb(..) | not_red @ Color::Cyan` error: wildcard match will also match any future added variants - --> $DIR/wildcard_enum_match_arm.rs:66:9 + --> $DIR/wildcard_enum_match_arm.rs:64:9 | LL | _ => "No red", | ^ help: try this: `Color::Red | Color::Green | Color::Blue | Color::Rgb(..) | Color::Cyan` error: wildcard matches known variants and will also match future added variants - --> $DIR/wildcard_enum_match_arm.rs:83:9 + --> $DIR/wildcard_enum_match_arm.rs:81:9 | LL | _ => {}, | ^ help: try this: `ErrorKind::PermissionDenied | _` error: wildcard matches known variants and will also match future added variants - --> $DIR/wildcard_enum_match_arm.rs:101:13 + --> $DIR/wildcard_enum_match_arm.rs:99:13 | LL | _ => (), | ^ help: try this: `Enum::B | _` diff --git a/tests/ui/write_literal.rs b/tests/ui/write_literal.rs index 5892818aa9a61..218385ea12966 100644 --- a/tests/ui/write_literal.rs +++ b/tests/ui/write_literal.rs @@ -1,5 +1,5 @@ -#![allow(unused_must_use)] #![warn(clippy::write_literal)] +#![allow(clippy::uninlined_format_args, unused_must_use)] use std::io::Write; From 649d443646e8ca6efad73643dcc11b488ae60a79 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Thu, 28 Apr 2022 13:29:44 -0400 Subject: [PATCH 098/114] Replace `expr_visitor` with `for_each_expr` --- clippy_lints/src/implicit_return.rs | 12 +- clippy_lints/src/methods/str_splitn.rs | 20 ++- clippy_lints/src/needless_late_init.rs | 34 +++-- clippy_lints/src/panic_in_result_fn.rs | 19 +-- clippy_lints/src/read_zero_byte_vec.rs | 40 +++--- clippy_utils/src/lib.rs | 19 ++- clippy_utils/src/macros.rs | 79 +++++------- clippy_utils/src/ptr.rs | 37 +++--- clippy_utils/src/usage.rs | 49 +++----- clippy_utils/src/visitors.rs | 164 +++++++++++-------------- 10 files changed, 206 insertions(+), 267 deletions(-) diff --git a/clippy_lints/src/implicit_return.rs b/clippy_lints/src/implicit_return.rs index cfc988da2335d..946d04eff6f98 100644 --- a/clippy_lints/src/implicit_return.rs +++ b/clippy_lints/src/implicit_return.rs @@ -2,10 +2,11 @@ use clippy_utils::{ diagnostics::span_lint_hir_and_then, get_async_fn_body, is_async_fn, source::{snippet_with_applicability, snippet_with_context, walk_span_to_context}, - visitors::expr_visitor_no_bodies, + visitors::for_each_expr, }; +use core::ops::ControlFlow; use rustc_errors::Applicability; -use rustc_hir::intravisit::{FnKind, Visitor}; +use rustc_hir::intravisit::FnKind; use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, FnRetTy, HirId}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; @@ -152,7 +153,7 @@ fn lint_implicit_returns( ExprKind::Loop(block, ..) => { let mut add_return = false; - expr_visitor_no_bodies(|e| { + let _: Option = for_each_expr(block, |e| { if let ExprKind::Break(dest, sub_expr) = e.kind { if dest.target_id.ok() == Some(expr.hir_id) { if call_site_span.is_none() && e.span.ctxt() == ctxt { @@ -167,9 +168,8 @@ fn lint_implicit_returns( } } } - true - }) - .visit_block(block); + ControlFlow::Continue(()) + }); if add_return { #[expect(clippy::option_if_let_else)] if let Some(span) = call_site_span { diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs index 9ca4d65550d3e..ae3594bd36c3a 100644 --- a/clippy_lints/src/methods/str_splitn.rs +++ b/clippy_lints/src/methods/str_splitn.rs @@ -2,11 +2,11 @@ use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::snippet_with_context; use clippy_utils::usage::local_used_after_expr; -use clippy_utils::visitors::expr_visitor; +use clippy_utils::visitors::{for_each_expr_with_closures, Descend}; use clippy_utils::{is_diag_item_method, match_def_path, meets_msrv, msrvs, path_to_local_id, paths}; +use core::ops::ControlFlow; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::intravisit::Visitor; use rustc_hir::{ BindingAnnotation, Expr, ExprKind, HirId, LangItem, Local, MatchSource, Node, Pat, PatKind, QPath, Stmt, StmtKind, }; @@ -211,7 +211,7 @@ fn indirect_usage<'tcx>( binding: HirId, ctxt: SyntaxContext, ) -> Option> { - if let StmtKind::Local(Local { + if let StmtKind::Local(&Local { pat: Pat { kind: PatKind::Binding(BindingAnnotation::NONE, _, ident, None), .. @@ -222,14 +222,12 @@ fn indirect_usage<'tcx>( }) = stmt.kind { let mut path_to_binding = None; - expr_visitor(cx, |expr| { - if path_to_local_id(expr, binding) { - path_to_binding = Some(expr); + let _: Option = for_each_expr_with_closures(cx, init_expr, |e| { + if path_to_local_id(e, binding) { + path_to_binding = Some(e); } - - path_to_binding.is_none() - }) - .visit_expr(init_expr); + ControlFlow::Continue(Descend::from(path_to_binding.is_none())) + }); let mut parents = cx.tcx.hir().parent_iter(path_to_binding?.hir_id); let iter_usage = parse_iter_usage(cx, ctxt, &mut parents)?; @@ -250,7 +248,7 @@ fn indirect_usage<'tcx>( .. } = iter_usage { - if parent_id == *local_hir_id { + if parent_id == local_hir_id { return Some(IndirectUsage { name: ident.name, span: stmt.span, diff --git a/clippy_lints/src/needless_late_init.rs b/clippy_lints/src/needless_late_init.rs index cbad53f4450b2..9d26e5900866c 100644 --- a/clippy_lints/src/needless_late_init.rs +++ b/clippy_lints/src/needless_late_init.rs @@ -2,9 +2,9 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::path_to_local; use clippy_utils::source::snippet_opt; use clippy_utils::ty::needs_ordered_drop; -use clippy_utils::visitors::{expr_visitor, expr_visitor_no_bodies, is_local_used}; +use clippy_utils::visitors::{for_each_expr, for_each_expr_with_closures, is_local_used}; +use core::ops::ControlFlow; use rustc_errors::{Applicability, MultiSpan}; -use rustc_hir::intravisit::Visitor; use rustc_hir::{ BindingAnnotation, Block, Expr, ExprKind, HirId, Local, LocalSource, MatchSource, Node, Pat, PatKind, Stmt, StmtKind, @@ -64,31 +64,25 @@ declare_clippy_lint! { declare_lint_pass!(NeedlessLateInit => [NEEDLESS_LATE_INIT]); fn contains_assign_expr<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) -> bool { - let mut seen = false; - expr_visitor(cx, |expr| { - if let ExprKind::Assign(..) = expr.kind { - seen = true; + for_each_expr_with_closures(cx, stmt, |e| { + if matches!(e.kind, ExprKind::Assign(..)) { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(()) } - - !seen }) - .visit_stmt(stmt); - - seen + .is_some() } fn contains_let(cond: &Expr<'_>) -> bool { - let mut seen = false; - expr_visitor_no_bodies(|expr| { - if let ExprKind::Let(_) = expr.kind { - seen = true; + for_each_expr(cond, |e| { + if matches!(e.kind, ExprKind::Let(_)) { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(()) } - - !seen }) - .visit_expr(cond); - - seen + .is_some() } fn stmt_needs_ordered_drop(cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool { diff --git a/clippy_lints/src/panic_in_result_fn.rs b/clippy_lints/src/panic_in_result_fn.rs index 4aa0d9227abad..efec12489a9ba 100644 --- a/clippy_lints/src/panic_in_result_fn.rs +++ b/clippy_lints/src/panic_in_result_fn.rs @@ -2,9 +2,10 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::root_macro_call_first_node; use clippy_utils::return_ty; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::visitors::expr_visitor_no_bodies; +use clippy_utils::visitors::{for_each_expr, Descend}; +use core::ops::ControlFlow; use rustc_hir as hir; -use rustc_hir::intravisit::{FnKind, Visitor}; +use rustc_hir::intravisit::FnKind; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{sym, Span}; @@ -58,18 +59,20 @@ impl<'tcx> LateLintPass<'tcx> for PanicInResultFn { fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, body: &'tcx hir::Body<'tcx>) { let mut panics = Vec::new(); - expr_visitor_no_bodies(|expr| { - let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return true }; + let _: Option = for_each_expr(body.value, |e| { + let Some(macro_call) = root_macro_call_first_node(cx, e) else { + return ControlFlow::Continue(Descend::Yes); + }; if matches!( cx.tcx.item_name(macro_call.def_id).as_str(), "unimplemented" | "unreachable" | "panic" | "todo" | "assert" | "assert_eq" | "assert_ne" ) { panics.push(macro_call.span); - return false; + ControlFlow::Continue(Descend::No) + } else { + ControlFlow::Continue(Descend::Yes) } - true - }) - .visit_expr(body.value); + }); if !panics.is_empty() { span_lint_and_then( cx, diff --git a/clippy_lints/src/read_zero_byte_vec.rs b/clippy_lints/src/read_zero_byte_vec.rs index ae80b6f126916..fa107858863a4 100644 --- a/clippy_lints/src/read_zero_byte_vec.rs +++ b/clippy_lints/src/read_zero_byte_vec.rs @@ -2,9 +2,10 @@ use clippy_utils::{ diagnostics::{span_lint, span_lint_and_sugg}, higher::{get_vec_init_kind, VecInitKind}, source::snippet, - visitors::expr_visitor_no_bodies, + visitors::for_each_expr, }; -use hir::{intravisit::Visitor, ExprKind, Local, PatKind, PathSegment, QPath, StmtKind}; +use core::ops::ControlFlow; +use hir::{Expr, ExprKind, Local, PatKind, PathSegment, QPath, StmtKind}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; @@ -58,10 +59,8 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec { && let PatKind::Binding(_, _, ident, _) = pat.kind && let Some(vec_init_kind) = get_vec_init_kind(cx, init) { - // finds use of `_.read(&mut v)` - let mut read_found = false; - let mut visitor = expr_visitor_no_bodies(|expr| { - if let ExprKind::MethodCall(path, _self, [arg], _) = expr.kind + let visitor = |expr: &Expr<'_>| { + if let ExprKind::MethodCall(path, _, [arg], _) = expr.kind && let PathSegment { ident: read_or_read_exact, .. } = *path && matches!(read_or_read_exact.as_str(), "read" | "read_exact") && let ExprKind::AddrOf(_, hir::Mutability::Mut, inner) = arg.kind @@ -69,27 +68,22 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec { && let [inner_seg] = inner_path.segments && ident.name == inner_seg.ident.name { - read_found = true; + ControlFlow::Break(()) + } else { + ControlFlow::Continue(()) } - !read_found - }); + }; - let next_stmt_span; - if idx == block.stmts.len() - 1 { + let (read_found, next_stmt_span) = + if let Some(next_stmt) = block.stmts.get(idx + 1) { + // case { .. stmt; stmt; .. } + (for_each_expr(next_stmt, visitor).is_some(), next_stmt.span) + } else if let Some(e) = block.expr { // case { .. stmt; expr } - if let Some(e) = block.expr { - visitor.visit_expr(e); - next_stmt_span = e.span; - } else { - return; - } + (for_each_expr(e, visitor).is_some(), e.span) } else { - // case { .. stmt; stmt; .. } - let next_stmt = &block.stmts[idx + 1]; - visitor.visit_stmt(next_stmt); - next_stmt_span = next_stmt.span; - } - drop(visitor); + return + }; if read_found && !next_stmt_span.from_expansion() { let applicability = Applicability::MaybeIncorrect; diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 8f67fa109fc70..3caa6380e0989 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -3,6 +3,7 @@ #![feature(control_flow_enum)] #![feature(let_chains)] #![feature(lint_reasons)] +#![feature(never_type)] #![feature(once_cell)] #![feature(rustc_private)] #![recursion_limit = "512"] @@ -65,6 +66,7 @@ pub use self::hir_utils::{ both, count_eq, eq_expr_value, hash_expr, hash_stmt, over, HirEqInterExpr, SpanlessEq, SpanlessHash, }; +use core::ops::ControlFlow; use std::collections::hash_map::Entry; use std::hash::BuildHasherDefault; use std::sync::OnceLock; @@ -113,7 +115,7 @@ use rustc_target::abi::Integer; use crate::consts::{constant, Constant}; use crate::ty::{can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type, ty_is_fn_once_param}; -use crate::visitors::expr_visitor_no_bodies; +use crate::visitors::for_each_expr; pub fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option) -> Option { if let Ok(version) = RustcVersion::parse(msrv) { @@ -1193,17 +1195,14 @@ pub fn contains_name(name: Symbol, expr: &Expr<'_>) -> bool { /// Returns `true` if `expr` contains a return expression pub fn contains_return(expr: &hir::Expr<'_>) -> bool { - let mut found = false; - expr_visitor_no_bodies(|expr| { - if !found { - if let hir::ExprKind::Ret(..) = &expr.kind { - found = true; - } + for_each_expr(expr, |e| { + if matches!(e.kind, hir::ExprKind::Ret(..)) { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(()) } - !found }) - .visit_expr(expr); - found + .is_some() } /// Extends the span to the beginning of the spans line, incl. whitespaces. diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs index 079c8f50f12a2..c0b87cd175ecc 100644 --- a/clippy_utils/src/macros.rs +++ b/clippy_utils/src/macros.rs @@ -2,7 +2,7 @@ use crate::is_path_diagnostic_item; use crate::source::snippet_opt; -use crate::visitors::expr_visitor_no_bodies; +use crate::visitors::{for_each_expr, Descend}; use arrayvec::ArrayVec; use itertools::{izip, Either, Itertools}; @@ -270,20 +270,19 @@ fn find_assert_args_inner<'a, const N: usize>( }; let mut args = ArrayVec::new(); let mut panic_expn = None; - expr_visitor_no_bodies(|e| { + let _: Option = for_each_expr(expr, |e| { if args.is_full() { if panic_expn.is_none() && e.span.ctxt() != expr.span.ctxt() { panic_expn = PanicExpn::parse(cx, e); } - panic_expn.is_none() + ControlFlow::Continue(Descend::from(panic_expn.is_none())) } else if is_assert_arg(cx, e, expn) { args.push(e); - false + ControlFlow::Continue(Descend::No) } else { - true + ControlFlow::Continue(Descend::Yes) } - }) - .visit_expr(expr); + }); let args = args.into_inner().ok()?; // if no `panic!(..)` is found, use `PanicExpn::Empty` // to indicate that the default assertion message is used @@ -297,22 +296,19 @@ fn find_assert_within_debug_assert<'a>( expn: ExpnId, assert_name: Symbol, ) -> Option<(&'a Expr<'a>, ExpnId)> { - let mut found = None; - expr_visitor_no_bodies(|e| { - if found.is_some() || !e.span.from_expansion() { - return false; + for_each_expr(expr, |e| { + if !e.span.from_expansion() { + return ControlFlow::Continue(Descend::No); } let e_expn = e.span.ctxt().outer_expn(); if e_expn == expn { - return true; - } - if e_expn.expn_data().macro_def_id.map(|id| cx.tcx.item_name(id)) == Some(assert_name) { - found = Some((e, e_expn)); + ControlFlow::Continue(Descend::Yes) + } else if e_expn.expn_data().macro_def_id.map(|id| cx.tcx.item_name(id)) == Some(assert_name) { + ControlFlow::Break((e, e_expn)) + } else { + ControlFlow::Continue(Descend::No) } - false }) - .visit_expr(expr); - found } fn is_assert_arg(cx: &LateContext<'_>, expr: &Expr<'_>, assert_expn: ExpnId) -> bool { @@ -396,16 +392,14 @@ impl FormatString { }); let mut parts = Vec::new(); - expr_visitor_no_bodies(|expr| { - if let ExprKind::Lit(lit) = &expr.kind { - if let LitKind::Str(symbol, _) = lit.node { - parts.push(symbol); - } + let _: Option = for_each_expr(pieces, |expr| { + if let ExprKind::Lit(lit) = &expr.kind + && let LitKind::Str(symbol, _) = lit.node + { + parts.push(symbol); } - - true - }) - .visit_expr(pieces); + ControlFlow::Continue(()) + }); Some(Self { span, @@ -431,7 +425,7 @@ impl<'tcx> FormatArgsValues<'tcx> { fn new(args: &'tcx Expr<'tcx>, format_string_span: SpanData) -> Self { let mut pos_to_value_index = Vec::new(); let mut value_args = Vec::new(); - expr_visitor_no_bodies(|expr| { + let _: Option = for_each_expr(args, |expr| { if expr.span.ctxt() == args.span.ctxt() { // ArgumentV1::new_() // ArgumentV1::from_usize() @@ -453,16 +447,13 @@ impl<'tcx> FormatArgsValues<'tcx> { pos_to_value_index.push(val_idx); } - - true + ControlFlow::Continue(Descend::Yes) } else { // assume that any expr with a differing span is a value value_args.push(expr); - - false + ControlFlow::Continue(Descend::No) } - }) - .visit_expr(args); + }); Self { value_args, @@ -866,22 +857,18 @@ impl<'tcx> FormatArgsExpn<'tcx> { } pub fn find_nested(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, expn_id: ExpnId) -> Option { - let mut format_args = None; - expr_visitor_no_bodies(|e| { - if format_args.is_some() { - return false; - } + for_each_expr(expr, |e| { let e_ctxt = e.span.ctxt(); if e_ctxt == expr.span.ctxt() { - return true; - } - if e_ctxt.outer_expn().is_descendant_of(expn_id) { - format_args = FormatArgsExpn::parse(cx, e); + ControlFlow::Continue(Descend::Yes) + } else if e_ctxt.outer_expn().is_descendant_of(expn_id) + && let Some(args) = FormatArgsExpn::parse(cx, e) + { + ControlFlow::Break(args) + } else { + ControlFlow::Continue(Descend::No) } - false }) - .visit_expr(expr); - format_args } /// Source callsite span of all inputs diff --git a/clippy_utils/src/ptr.rs b/clippy_utils/src/ptr.rs index 0226f74906b51..88837d8a143ed 100644 --- a/clippy_utils/src/ptr.rs +++ b/clippy_utils/src/ptr.rs @@ -1,7 +1,7 @@ use crate::source::snippet; -use crate::visitors::expr_visitor_no_bodies; +use crate::visitors::{for_each_expr, Descend}; use crate::{path_to_local_id, strip_pat_refs}; -use rustc_hir::intravisit::Visitor; +use core::ops::ControlFlow; use rustc_hir::{Body, BodyId, ExprKind, HirId, PatKind}; use rustc_lint::LateContext; use rustc_span::Span; @@ -30,28 +30,23 @@ fn extract_clone_suggestions<'tcx>( replace: &[(&'static str, &'static str)], body: &'tcx Body<'_>, ) -> Option)>> { - let mut abort = false; let mut spans = Vec::new(); - expr_visitor_no_bodies(|expr| { - if abort { - return false; - } - if let ExprKind::MethodCall(seg, recv, [], _) = expr.kind { - if path_to_local_id(recv, id) { - if seg.ident.name.as_str() == "capacity" { - abort = true; - return false; - } - for &(fn_name, suffix) in replace { - if seg.ident.name.as_str() == fn_name { - spans.push((expr.span, snippet(cx, recv.span, "_") + suffix)); - return false; - } + for_each_expr(body, |e| { + if let ExprKind::MethodCall(seg, recv, [], _) = e.kind + && path_to_local_id(recv, id) + { + if seg.ident.as_str() == "capacity" { + return ControlFlow::Break(()); + } + for &(fn_name, suffix) in replace { + if seg.ident.as_str() == fn_name { + spans.push((e.span, snippet(cx, recv.span, "_") + suffix)); + return ControlFlow::Continue(Descend::No); } } } - !abort + ControlFlow::Continue(Descend::Yes) }) - .visit_body(body); - if abort { None } else { Some(spans) } + .is_none() + .then_some(spans) } diff --git a/clippy_utils/src/usage.rs b/clippy_utils/src/usage.rs index 3221b82aed419..b5ec3fef3e0b4 100644 --- a/clippy_utils/src/usage.rs +++ b/clippy_utils/src/usage.rs @@ -1,5 +1,6 @@ use crate as utils; -use crate::visitors::{expr_visitor, expr_visitor_no_bodies}; +use crate::visitors::{for_each_expr, for_each_expr_with_closures, Descend}; +use core::ops::ControlFlow; use rustc_hir as hir; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::HirIdSet; @@ -148,28 +149,17 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for BindingUsageFinder<'a, 'tcx> { } pub fn contains_return_break_continue_macro(expression: &Expr<'_>) -> bool { - let mut seen_return_break_continue = false; - expr_visitor_no_bodies(|ex| { - if seen_return_break_continue { - return false; - } - match &ex.kind { - ExprKind::Ret(..) | ExprKind::Break(..) | ExprKind::Continue(..) => { - seen_return_break_continue = true; - }, + for_each_expr(expression, |e| { + match e.kind { + ExprKind::Ret(..) | ExprKind::Break(..) | ExprKind::Continue(..) => ControlFlow::Break(()), // Something special could be done here to handle while or for loop // desugaring, as this will detect a break if there's a while loop // or a for loop inside the expression. - _ => { - if ex.span.from_expansion() { - seen_return_break_continue = true; - } - }, + _ if e.span.from_expansion() => ControlFlow::Break(()), + _ => ControlFlow::Continue(()), } - !seen_return_break_continue }) - .visit_expr(expression); - seen_return_break_continue + .is_some() } pub fn local_used_after_expr(cx: &LateContext<'_>, local_id: HirId, after: &Expr<'_>) -> bool { @@ -200,23 +190,16 @@ pub fn local_used_after_expr(cx: &LateContext<'_>, local_id: HirId, after: &Expr return true; } - let mut used_after_expr = false; let mut past_expr = false; - expr_visitor(cx, |expr| { - if used_after_expr { - return false; - } - - if expr.hir_id == after.hir_id { + for_each_expr_with_closures(cx, block, |e| { + if e.hir_id == after.hir_id { past_expr = true; - return false; - } - - if past_expr && utils::path_to_local_id(expr, local_id) { - used_after_expr = true; + ControlFlow::Continue(Descend::No) + } else if past_expr && utils::path_to_local_id(e, local_id) { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(Descend::Yes) } - !used_after_expr }) - .visit_block(block); - used_after_expr + .is_some() } diff --git a/clippy_utils/src/visitors.rs b/clippy_utils/src/visitors.rs index 232d571902b6c..d4294f18fd501 100644 --- a/clippy_utils/src/visitors.rs +++ b/clippy_utils/src/visitors.rs @@ -5,14 +5,13 @@ use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::intravisit::{self, walk_block, walk_expr, Visitor}; use rustc_hir::{ - Arm, Block, BlockCheckMode, Body, BodyId, Expr, ExprKind, HirId, ItemId, ItemKind, Let, Pat, QPath, Stmt, UnOp, - UnsafeSource, Unsafety, + AnonConst, Arm, Block, BlockCheckMode, Body, BodyId, Expr, ExprKind, HirId, ItemId, ItemKind, Let, Pat, QPath, + Stmt, UnOp, UnsafeSource, Unsafety, }; use rustc_lint::LateContext; -use rustc_middle::hir::map::Map; use rustc_middle::hir::nested_filter; use rustc_middle::ty::adjustment::Adjust; -use rustc_middle::ty::{self, Ty, TypeckResults}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeckResults}; use rustc_span::Span; mod internal { @@ -48,6 +47,26 @@ impl Continue for Descend { } } +/// A type which can be visited. +pub trait Visitable<'tcx> { + /// Calls the corresponding `visit_*` function on the visitor. + fn visit>(self, visitor: &mut V); +} +macro_rules! visitable_ref { + ($t:ident, $f:ident) => { + impl<'tcx> Visitable<'tcx> for &'tcx $t<'tcx> { + fn visit>(self, visitor: &mut V) { + visitor.$f(self); + } + } + }; +} +visitable_ref!(Arm, visit_arm); +visitable_ref!(Block, visit_block); +visitable_ref!(Body, visit_body); +visitable_ref!(Expr, visit_expr); +visitable_ref!(Stmt, visit_stmt); + /// Calls the given function once for each expression contained. This does not enter any bodies or /// nested items. pub fn for_each_expr<'tcx, B, C: Continue>( @@ -82,57 +101,63 @@ pub fn for_each_expr<'tcx, B, C: Continue>( v.res } -/// Convenience method for creating a `Visitor` with just `visit_expr` overridden and nested -/// bodies (i.e. closures) are visited. -/// If the callback returns `true`, the expr just provided to the callback is walked. -#[must_use] -pub fn expr_visitor<'tcx>(cx: &LateContext<'tcx>, f: impl FnMut(&'tcx Expr<'tcx>) -> bool) -> impl Visitor<'tcx> { - struct V<'tcx, F> { - hir: Map<'tcx>, +/// Calls the given function once for each expression contained. This will enter bodies, but not +/// nested items. +pub fn for_each_expr_with_closures<'tcx, B, C: Continue>( + cx: &LateContext<'tcx>, + node: impl Visitable<'tcx>, + f: impl FnMut(&'tcx Expr<'tcx>) -> ControlFlow, +) -> Option { + struct V<'tcx, B, F> { + tcx: TyCtxt<'tcx>, f: F, + res: Option, } - impl<'tcx, F: FnMut(&'tcx Expr<'tcx>) -> bool> Visitor<'tcx> for V<'tcx, F> { + impl<'tcx, B, C: Continue, F: FnMut(&'tcx Expr<'tcx>) -> ControlFlow> Visitor<'tcx> for V<'tcx, B, F> { type NestedFilter = nested_filter::OnlyBodies; fn nested_visit_map(&mut self) -> Self::Map { - self.hir + self.tcx.hir() } - fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { - if (self.f)(expr) { - walk_expr(self, expr); + fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) { + if self.res.is_some() { + return; } - } - } - V { hir: cx.tcx.hir(), f } -} - -/// Convenience method for creating a `Visitor` with just `visit_expr` overridden and nested -/// bodies (i.e. closures) are not visited. -/// If the callback returns `true`, the expr just provided to the callback is walked. -#[must_use] -pub fn expr_visitor_no_bodies<'tcx>(f: impl FnMut(&'tcx Expr<'tcx>) -> bool) -> impl Visitor<'tcx> { - struct V(F); - impl<'tcx, F: FnMut(&'tcx Expr<'tcx>) -> bool> Visitor<'tcx> for V { - fn visit_expr(&mut self, e: &'tcx Expr<'_>) { - if (self.0)(e) { - walk_expr(self, e); + match (self.f)(e) { + ControlFlow::Continue(c) if c.descend() => walk_expr(self, e), + ControlFlow::Break(b) => self.res = Some(b), + ControlFlow::Continue(_) => (), } } + + // Only walk closures + fn visit_anon_const(&mut self, _: &'tcx AnonConst) {} + // Avoid unnecessary `walk_*` calls. + fn visit_ty(&mut self, _: &'tcx hir::Ty<'tcx>) {} + fn visit_pat(&mut self, _: &'tcx Pat<'tcx>) {} + fn visit_qpath(&mut self, _: &'tcx QPath<'tcx>, _: HirId, _: Span) {} + // Avoid monomorphising all `visit_*` functions. + fn visit_nested_item(&mut self, _: ItemId) {} } - V(f) + let mut v = V { + tcx: cx.tcx, + f, + res: None, + }; + node.visit(&mut v); + v.res } /// returns `true` if expr contains match expr desugared from try fn contains_try(expr: &hir::Expr<'_>) -> bool { - let mut found = false; - expr_visitor_no_bodies(|e| { - if !found { - found = matches!(e.kind, hir::ExprKind::Match(_, _, hir::MatchSource::TryDesugar)); + for_each_expr(expr, |e| { + if matches!(e.kind, hir::ExprKind::Match(_, _, hir::MatchSource::TryDesugar)) { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(()) } - !found }) - .visit_expr(expr); - found + .is_some() } pub fn find_all_ret_expressions<'hir, F>(_cx: &LateContext<'_>, expr: &'hir hir::Expr<'hir>, callback: F) -> bool @@ -228,68 +253,29 @@ where } } -/// A type which can be visited. -pub trait Visitable<'tcx> { - /// Calls the corresponding `visit_*` function on the visitor. - fn visit>(self, visitor: &mut V); -} -macro_rules! visitable_ref { - ($t:ident, $f:ident) => { - impl<'tcx> Visitable<'tcx> for &'tcx $t<'tcx> { - fn visit>(self, visitor: &mut V) { - visitor.$f(self); - } - } - }; -} -visitable_ref!(Arm, visit_arm); -visitable_ref!(Block, visit_block); -visitable_ref!(Body, visit_body); -visitable_ref!(Expr, visit_expr); -visitable_ref!(Stmt, visit_stmt); - -// impl<'tcx, I: IntoIterator> Visitable<'tcx> for I -// where -// I::Item: Visitable<'tcx>, -// { -// fn visit>(self, visitor: &mut V) { -// for x in self { -// x.visit(visitor); -// } -// } -// } - /// Checks if the given resolved path is used in the given body. pub fn is_res_used(cx: &LateContext<'_>, res: Res, body: BodyId) -> bool { - let mut found = false; - expr_visitor(cx, |e| { - if found { - return false; - } - + for_each_expr_with_closures(cx, cx.tcx.hir().body(body).value, |e| { if let ExprKind::Path(p) = &e.kind { if cx.qpath_res(p, e.hir_id) == res { - found = true; + return ControlFlow::Break(()); } } - !found + ControlFlow::Continue(()) }) - .visit_expr(cx.tcx.hir().body(body).value); - found + .is_some() } /// Checks if the given local is used. pub fn is_local_used<'tcx>(cx: &LateContext<'tcx>, visitable: impl Visitable<'tcx>, id: HirId) -> bool { - let mut is_used = false; - let mut visitor = expr_visitor(cx, |expr| { - if !is_used { - is_used = path_to_local_id(expr, id); + for_each_expr_with_closures(cx, visitable, |e| { + if path_to_local_id(e, id) { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(()) } - !is_used - }); - visitable.visit(&mut visitor); - drop(visitor); - is_used + }) + .is_some() } /// Checks if the given expression is a constant. From 38236a713512d0a70d1f03e995201d9bac63c882 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Fri, 29 Apr 2022 00:09:55 -0400 Subject: [PATCH 099/114] Use `for_each_expr` in place of some visitors --- clippy_lints/src/blocks_in_if_conditions.rs | 68 ++++++-------- clippy_lints/src/cognitive_complexity.rs | 63 ++++++------- clippy_lints/src/functions/must_use.rs | 77 +++++++--------- .../src/functions/not_unsafe_ptr_arg_deref.rs | 91 +++++++------------ .../src/methods/unnecessary_filter_map.rs | 51 +++-------- .../src/operators/assign_op_pattern.rs | 39 +++----- clippy_lints/src/returns.rs | 39 +++----- clippy_lints/src/suspicious_trait_impl.rs | 33 +++---- clippy_lints/src/unwrap_in_result.rs | 72 ++++++--------- 9 files changed, 205 insertions(+), 328 deletions(-) diff --git a/clippy_lints/src/blocks_in_if_conditions.rs b/clippy_lints/src/blocks_in_if_conditions.rs index 4df4d6ddf4167..569bf27c3e716 100644 --- a/clippy_lints/src/blocks_in_if_conditions.rs +++ b/clippy_lints/src/blocks_in_if_conditions.rs @@ -3,10 +3,11 @@ use clippy_utils::get_parent_expr; use clippy_utils::higher; use clippy_utils::source::snippet_block_with_applicability; use clippy_utils::ty::implements_trait; +use clippy_utils::visitors::{for_each_expr, Descend}; +use core::ops::ControlFlow; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::intravisit::{walk_expr, Visitor}; -use rustc_hir::{BlockCheckMode, Closure, Expr, ExprKind}; +use rustc_hir::{BlockCheckMode, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -44,39 +45,6 @@ declare_clippy_lint! { declare_lint_pass!(BlocksInIfConditions => [BLOCKS_IN_IF_CONDITIONS]); -struct ExVisitor<'a, 'tcx> { - found_block: Option<&'tcx Expr<'tcx>>, - cx: &'a LateContext<'tcx>, -} - -impl<'a, 'tcx> Visitor<'tcx> for ExVisitor<'a, 'tcx> { - fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { - if let ExprKind::Closure(&Closure { body, .. }) = expr.kind { - // do not lint if the closure is called using an iterator (see #1141) - if_chain! { - if let Some(parent) = get_parent_expr(self.cx, expr); - if let ExprKind::MethodCall(_, self_arg, ..) = &parent.kind; - let caller = self.cx.typeck_results().expr_ty(self_arg); - if let Some(iter_id) = self.cx.tcx.get_diagnostic_item(sym::Iterator); - if implements_trait(self.cx, caller, iter_id, &[]); - then { - return; - } - } - - let body = self.cx.tcx.hir().body(body); - let ex = &body.value; - if let ExprKind::Block(block, _) = ex.kind { - if !body.value.span.from_expansion() && !block.stmts.is_empty() { - self.found_block = Some(ex); - return; - } - } - } - walk_expr(self, expr); - } -} - const BRACED_EXPR_MESSAGE: &str = "omit braces around single expression condition"; const COMPLEX_BLOCK_MESSAGE: &str = "in an `if` condition, avoid complex blocks or closures with blocks; \ instead, move the block or closure higher and bind it with a `let`"; @@ -144,11 +112,31 @@ impl<'tcx> LateLintPass<'tcx> for BlocksInIfConditions { } } } else { - let mut visitor = ExVisitor { found_block: None, cx }; - walk_expr(&mut visitor, cond); - if let Some(block) = visitor.found_block { - span_lint(cx, BLOCKS_IN_IF_CONDITIONS, block.span, COMPLEX_BLOCK_MESSAGE); - } + let _: Option = for_each_expr(cond, |e| { + if let ExprKind::Closure(closure) = e.kind { + // do not lint if the closure is called using an iterator (see #1141) + if_chain! { + if let Some(parent) = get_parent_expr(cx, e); + if let ExprKind::MethodCall(_, self_arg, _, _) = &parent.kind; + let caller = cx.typeck_results().expr_ty(self_arg); + if let Some(iter_id) = cx.tcx.get_diagnostic_item(sym::Iterator); + if implements_trait(cx, caller, iter_id, &[]); + then { + return ControlFlow::Continue(Descend::No); + } + } + + let body = cx.tcx.hir().body(closure.body); + let ex = &body.value; + if let ExprKind::Block(block, _) = ex.kind { + if !body.value.span.from_expansion() && !block.stmts.is_empty() { + span_lint(cx, BLOCKS_IN_IF_CONDITIONS, ex.span, COMPLEX_BLOCK_MESSAGE); + return ControlFlow::Continue(Descend::No); + } + } + } + ControlFlow::Continue(Descend::Yes) + }); } } } diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs index fed04ae7f3d59..77af3b53d6333 100644 --- a/clippy_lints/src/cognitive_complexity.rs +++ b/clippy_lints/src/cognitive_complexity.rs @@ -3,10 +3,12 @@ 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 core::ops::ControlFlow; use rustc_ast::ast::Attribute; -use rustc_hir::intravisit::{walk_expr, FnKind, Visitor}; -use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirId}; +use rustc_hir::intravisit::FnKind; +use rustc_hir::{Body, ExprKind, FnDecl, HirId}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; @@ -61,11 +63,27 @@ impl CognitiveComplexity { return; } - let expr = &body.value; + let expr = body.value; + + let mut cc = 1u64; + let mut returns = 0u64; + let _: Option = for_each_expr(expr, |e| { + match e.kind { + ExprKind::If(_, _, _) => { + cc += 1; + }, + ExprKind::Match(_, arms, _) => { + if arms.len() > 1 { + cc += 1; + } + cc += arms.iter().filter(|arm| arm.guard.is_some()).count() as u64; + }, + ExprKind::Ret(_) => returns += 1, + _ => {}, + } + ControlFlow::Continue(()) + }); - let mut helper = CcHelper { cc: 1, returns: 0 }; - helper.visit_expr(expr); - let CcHelper { cc, returns } = helper; let ret_ty = cx.typeck_results().node_type(expr.hir_id); let ret_adjust = if is_type_diagnostic_item(cx, ret_ty, sym::Result) { returns @@ -74,13 +92,12 @@ impl CognitiveComplexity { (returns / 2) }; - let mut rust_cc = cc; // prevent degenerate cases where unreachable code contains `return` statements - if rust_cc >= ret_adjust { - rust_cc -= ret_adjust; + if cc >= ret_adjust { + cc -= ret_adjust; } - if rust_cc > self.limit.limit() { + if cc > self.limit.limit() { let fn_span = match kind { FnKind::ItemFn(ident, _, _) | FnKind::Method(ident, _) => ident.span, FnKind::Closure => { @@ -107,7 +124,7 @@ impl CognitiveComplexity { COGNITIVE_COMPLEXITY, fn_span, &format!( - "the function has a cognitive complexity of ({rust_cc}/{})", + "the function has a cognitive complexity of ({cc}/{})", self.limit.limit() ), None, @@ -140,27 +157,3 @@ impl<'tcx> LateLintPass<'tcx> for CognitiveComplexity { self.limit.pop_attrs(cx.sess(), attrs, "cognitive_complexity"); } } - -struct CcHelper { - cc: u64, - returns: u64, -} - -impl<'tcx> Visitor<'tcx> for CcHelper { - fn visit_expr(&mut self, e: &'tcx Expr<'_>) { - walk_expr(self, e); - match e.kind { - ExprKind::If(_, _, _) => { - self.cc += 1; - }, - ExprKind::Match(_, arms, _) => { - if arms.len() > 1 { - self.cc += 1; - } - self.cc += arms.iter().filter(|arm| arm.guard.is_some()).count() as u64; - }, - ExprKind::Ret(_) => self.returns += 1, - _ => {}, - } - } -} diff --git a/clippy_lints/src/functions/must_use.rs b/clippy_lints/src/functions/must_use.rs index 977c8ee594f4c..d263804f32cf4 100644 --- a/clippy_lints/src/functions/must_use.rs +++ b/clippy_lints/src/functions/must_use.rs @@ -1,7 +1,7 @@ use rustc_ast::ast::Attribute; use rustc_errors::Applicability; use rustc_hir::def_id::{DefIdSet, LocalDefId}; -use rustc_hir::{self as hir, def::Res, intravisit, QPath}; +use rustc_hir::{self as hir, def::Res, QPath}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::{ lint::in_external_macro, @@ -13,8 +13,11 @@ use clippy_utils::attrs::is_proc_macro; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; use clippy_utils::source::snippet_opt; use clippy_utils::ty::is_must_use_ty; +use clippy_utils::visitors::for_each_expr; use clippy_utils::{match_def_path, return_ty, trait_ref_of_method}; +use core::ops::ControlFlow; + use super::{DOUBLE_MUST_USE, MUST_USE_CANDIDATE, MUST_USE_UNIT}; pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { @@ -200,79 +203,65 @@ fn is_mutable_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Span, tys: &m } } -struct StaticMutVisitor<'a, 'tcx> { - cx: &'a LateContext<'tcx>, - mutates_static: bool, +fn is_mutated_static(e: &hir::Expr<'_>) -> bool { + use hir::ExprKind::{Field, Index, Path}; + + match e.kind { + Path(QPath::Resolved(_, path)) => !matches!(path.res, Res::Local(_)), + Path(_) => true, + Field(inner, _) | Index(inner, _) => is_mutated_static(inner), + _ => false, + } } -impl<'a, 'tcx> intravisit::Visitor<'tcx> for StaticMutVisitor<'a, 'tcx> { - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) { +fn mutates_static<'tcx>(cx: &LateContext<'tcx>, body: &'tcx hir::Body<'_>) -> bool { + for_each_expr(body.value, |e| { use hir::ExprKind::{AddrOf, Assign, AssignOp, Call, MethodCall}; - if self.mutates_static { - return; - } - match expr.kind { + match e.kind { Call(_, args) => { let mut tys = DefIdSet::default(); for arg in args { - if self.cx.tcx.has_typeck_results(arg.hir_id.owner.to_def_id()) + if cx.tcx.has_typeck_results(arg.hir_id.owner.to_def_id()) && is_mutable_ty( - self.cx, - self.cx.tcx.typeck(arg.hir_id.owner.def_id).expr_ty(arg), + cx, + cx.tcx.typeck(arg.hir_id.owner.def_id).expr_ty(arg), arg.span, &mut tys, ) && is_mutated_static(arg) { - self.mutates_static = true; - return; + return ControlFlow::Break(()); } tys.clear(); } + ControlFlow::Continue(()) }, MethodCall(_, receiver, args, _) => { let mut tys = DefIdSet::default(); for arg in std::iter::once(receiver).chain(args.iter()) { - if self.cx.tcx.has_typeck_results(arg.hir_id.owner.to_def_id()) + if cx.tcx.has_typeck_results(arg.hir_id.owner.to_def_id()) && is_mutable_ty( - self.cx, - self.cx.tcx.typeck(arg.hir_id.owner.def_id).expr_ty(arg), + cx, + cx.tcx.typeck(arg.hir_id.owner.def_id).expr_ty(arg), arg.span, &mut tys, ) && is_mutated_static(arg) { - self.mutates_static = true; - return; + return ControlFlow::Break(()); } tys.clear(); } + ControlFlow::Continue(()) }, - Assign(target, ..) | AssignOp(_, target, _) | AddrOf(_, hir::Mutability::Mut, target) => { - self.mutates_static |= is_mutated_static(target); + Assign(target, ..) | AssignOp(_, target, _) | AddrOf(_, hir::Mutability::Mut, target) + if is_mutated_static(target) => + { + ControlFlow::Break(()) }, - _ => {}, + _ => ControlFlow::Continue(()), } - } -} - -fn is_mutated_static(e: &hir::Expr<'_>) -> bool { - use hir::ExprKind::{Field, Index, Path}; - - match e.kind { - Path(QPath::Resolved(_, path)) => !matches!(path.res, Res::Local(_)), - Path(_) => true, - Field(inner, _) | Index(inner, _) => is_mutated_static(inner), - _ => false, - } -} - -fn mutates_static<'tcx>(cx: &LateContext<'tcx>, body: &'tcx hir::Body<'_>) -> bool { - let mut v = StaticMutVisitor { - cx, - mutates_static: false, - }; - intravisit::walk_expr(&mut v, body.value); - v.mutates_static + }) + .is_some() } diff --git a/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs b/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs index 0b50431fbaaba..b7595d101e0fa 100644 --- a/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs +++ b/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs @@ -5,8 +5,11 @@ use rustc_span::def_id::LocalDefId; use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::type_is_unsafe_function; +use clippy_utils::visitors::for_each_expr_with_closures; use clippy_utils::{iter_input_pats, path_to_local}; +use core::ops::ControlFlow; + use super::NOT_UNSAFE_PTR_ARG_DEREF; pub(super) fn check_fn<'tcx>( @@ -39,21 +42,34 @@ fn check_raw_ptr<'tcx>( body: &'tcx hir::Body<'tcx>, def_id: LocalDefId, ) { - let expr = &body.value; if unsafety == hir::Unsafety::Normal && cx.access_levels.is_exported(def_id) { let raw_ptrs = iter_input_pats(decl, body) .filter_map(|arg| raw_ptr_arg(cx, arg)) .collect::(); if !raw_ptrs.is_empty() { - let typeck_results = cx.tcx.typeck_body(body.id()); - let mut v = DerefVisitor { - cx, - ptrs: raw_ptrs, - typeck_results, - }; - - intravisit::walk_expr(&mut v, expr); + let typeck = cx.tcx.typeck_body(body.id()); + let _: Option = for_each_expr_with_closures(cx, body.value, |e| { + match e.kind { + hir::ExprKind::Call(f, args) if type_is_unsafe_function(cx, typeck.expr_ty(f)) => { + for arg in args { + check_arg(cx, &raw_ptrs, arg); + } + }, + hir::ExprKind::MethodCall(_, recv, args, _) => { + let def_id = typeck.type_dependent_def_id(e.hir_id).unwrap(); + if cx.tcx.fn_sig(def_id).skip_binder().unsafety == hir::Unsafety::Unsafe { + check_arg(cx, &raw_ptrs, recv); + for arg in args { + check_arg(cx, &raw_ptrs, arg); + } + } + }, + hir::ExprKind::Unary(hir::UnOp::Deref, ptr) => check_arg(cx, &raw_ptrs, ptr), + _ => (), + } + ControlFlow::Continue(()) + }); } } } @@ -70,54 +86,13 @@ fn raw_ptr_arg(cx: &LateContext<'_>, arg: &hir::Param<'_>) -> Option } } -struct DerefVisitor<'a, 'tcx> { - cx: &'a LateContext<'tcx>, - ptrs: HirIdSet, - typeck_results: &'a ty::TypeckResults<'tcx>, -} - -impl<'a, 'tcx> intravisit::Visitor<'tcx> for DerefVisitor<'a, 'tcx> { - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) { - match expr.kind { - hir::ExprKind::Call(f, args) => { - let ty = self.typeck_results.expr_ty(f); - - if type_is_unsafe_function(self.cx, ty) { - for arg in args { - self.check_arg(arg); - } - } - }, - hir::ExprKind::MethodCall(_, receiver, args, _) => { - let def_id = self.typeck_results.type_dependent_def_id(expr.hir_id).unwrap(); - let base_type = self.cx.tcx.type_of(def_id); - - if type_is_unsafe_function(self.cx, base_type) { - self.check_arg(receiver); - for arg in args { - self.check_arg(arg); - } - } - }, - hir::ExprKind::Unary(hir::UnOp::Deref, ptr) => self.check_arg(ptr), - _ => (), - } - - intravisit::walk_expr(self, expr); - } -} - -impl<'a, 'tcx> DerefVisitor<'a, 'tcx> { - fn check_arg(&self, ptr: &hir::Expr<'_>) { - if let Some(id) = path_to_local(ptr) { - if self.ptrs.contains(&id) { - span_lint( - self.cx, - NOT_UNSAFE_PTR_ARG_DEREF, - ptr.span, - "this public function might dereference a raw pointer but is not marked `unsafe`", - ); - } - } +fn check_arg(cx: &LateContext<'_>, raw_ptrs: &HirIdSet, arg: &hir::Expr<'_>) { + if path_to_local(arg).map_or(false, |id| raw_ptrs.contains(&id)) { + span_lint( + cx, + NOT_UNSAFE_PTR_ARG_DEREF, + arg.span, + "this public function might dereference a raw pointer but is not marked `unsafe`", + ); } } diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs index 50434a5658ac5..1cef6226ad4ff 100644 --- a/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -2,9 +2,10 @@ use super::utils::clone_or_copy_needed; use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::is_copy; use clippy_utils::usage::mutated_variables; +use clippy_utils::visitors::{for_each_expr, Descend}; use clippy_utils::{is_res_lang_ctor, is_trait_method, path_res, path_to_local_id}; +use core::ops::ControlFlow; use rustc_hir as hir; -use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_lint::LateContext; use rustc_middle::ty; @@ -13,7 +14,7 @@ use rustc_span::sym; use super::UNNECESSARY_FILTER_MAP; use super::UNNECESSARY_FIND_MAP; -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>, name: &str) { +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, arg: &'tcx hir::Expr<'tcx>, name: &str) { if !is_trait_method(cx, expr, sym::Iterator) { return; } @@ -26,10 +27,16 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr< let (mut found_mapping, mut found_filtering) = check_expression(cx, arg_id, body.value); - let mut return_visitor = ReturnVisitor::new(cx, arg_id); - return_visitor.visit_expr(body.value); - found_mapping |= return_visitor.found_mapping; - found_filtering |= return_visitor.found_filtering; + let _: Option = for_each_expr(body.value, |e| { + if let hir::ExprKind::Ret(Some(e)) = &e.kind { + let (found_mapping_res, found_filtering_res) = check_expression(cx, arg_id, e); + found_mapping |= found_mapping_res; + found_filtering |= found_filtering_res; + ControlFlow::Continue(Descend::No) + } else { + ControlFlow::Continue(Descend::Yes) + } + }); let in_ty = cx.typeck_results().node_type(body.params[0].hir_id); let sugg = if !found_filtering { @@ -97,35 +104,3 @@ fn check_expression<'tcx>(cx: &LateContext<'tcx>, arg_id: hir::HirId, expr: &'tc _ => (true, true), } } - -struct ReturnVisitor<'a, 'tcx> { - cx: &'a LateContext<'tcx>, - arg_id: hir::HirId, - // Found a non-None return that isn't Some(input) - found_mapping: bool, - // Found a return that isn't Some - found_filtering: bool, -} - -impl<'a, 'tcx> ReturnVisitor<'a, 'tcx> { - fn new(cx: &'a LateContext<'tcx>, arg_id: hir::HirId) -> ReturnVisitor<'a, 'tcx> { - ReturnVisitor { - cx, - arg_id, - found_mapping: false, - found_filtering: false, - } - } -} - -impl<'a, 'tcx> Visitor<'tcx> for ReturnVisitor<'a, 'tcx> { - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) { - if let hir::ExprKind::Ret(Some(expr)) = &expr.kind { - let (found_mapping, found_filtering) = check_expression(self.cx, self.arg_id, expr); - self.found_mapping |= found_mapping; - self.found_filtering |= found_filtering; - } else { - walk_expr(self, expr); - } - } -} diff --git a/clippy_lints/src/operators/assign_op_pattern.rs b/clippy_lints/src/operators/assign_op_pattern.rs index 2d5d5d143ffaf..26bca7c306a84 100644 --- a/clippy_lints/src/operators/assign_op_pattern.rs +++ b/clippy_lints/src/operators/assign_op_pattern.rs @@ -2,11 +2,12 @@ use clippy_utils::binop_traits; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_opt; use clippy_utils::ty::implements_trait; +use clippy_utils::visitors::for_each_expr; use clippy_utils::{eq_expr_value, trait_ref_of_method}; +use core::ops::ControlFlow; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir_analysis::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; use rustc_lint::LateContext; use rustc_middle::mir::FakeReadCause; @@ -65,15 +66,19 @@ pub(super) fn check<'tcx>( } }; - let mut visitor = ExprVisitor { - assignee, - counter: 0, - cx, - }; - - walk_expr(&mut visitor, e); + let mut found = false; + let found_multiple = for_each_expr(e, |e| { + if eq_expr_value(cx, assignee, e) { + if found { + return ControlFlow::Break(()); + } + found = true; + } + ControlFlow::Continue(()) + }) + .is_some(); - if visitor.counter == 1 { + if found && !found_multiple { // a = a op b if eq_expr_value(cx, assignee, l) { lint(assignee, r); @@ -98,22 +103,6 @@ pub(super) fn check<'tcx>( } } -struct ExprVisitor<'a, 'tcx> { - assignee: &'a hir::Expr<'a>, - counter: u8, - cx: &'a LateContext<'tcx>, -} - -impl<'a, 'tcx> Visitor<'tcx> for ExprVisitor<'a, 'tcx> { - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) { - if eq_expr_value(self.cx, self.assignee, expr) { - self.counter += 1; - } - - walk_expr(self, expr); - } -} - fn imm_borrows_in_expr(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> hir::HirIdSet { struct S(hir::HirIdSet); impl Delegate<'_> for S { diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index f758f4cff8ba1..2b2a41d160117 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -1,9 +1,11 @@ use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::source::{snippet_opt, snippet_with_context}; +use clippy_utils::visitors::{for_each_expr, Descend}; use clippy_utils::{fn_def_id, path_to_local_id}; +use core::ops::ControlFlow; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::intravisit::{walk_expr, FnKind, Visitor}; +use rustc_hir::intravisit::FnKind; use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, HirId, MatchSource, PatKind, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; @@ -270,33 +272,20 @@ fn emit_return_lint( } fn last_statement_borrows<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { - let mut visitor = BorrowVisitor { cx, borrows: false }; - walk_expr(&mut visitor, expr); - visitor.borrows -} - -struct BorrowVisitor<'a, 'tcx> { - cx: &'a LateContext<'tcx>, - borrows: bool, -} - -impl<'tcx> Visitor<'tcx> for BorrowVisitor<'_, 'tcx> { - fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { - if self.borrows || expr.span.from_expansion() { - return; - } - - if let Some(def_id) = fn_def_id(self.cx, expr) { - self.borrows = self - .cx + for_each_expr(expr, |e| { + if let Some(def_id) = fn_def_id(cx, e) + && cx .tcx .fn_sig(def_id) - .output() .skip_binder() + .output() .walk() - .any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_))); + .any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_))) + { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(Descend::from(!expr.span.from_expansion())) } - - walk_expr(self, expr); - } + }) + .is_some() } diff --git a/clippy_lints/src/suspicious_trait_impl.rs b/clippy_lints/src/suspicious_trait_impl.rs index d47ed459387ef..b57b484bdc897 100644 --- a/clippy_lints/src/suspicious_trait_impl.rs +++ b/clippy_lints/src/suspicious_trait_impl.rs @@ -1,8 +1,9 @@ use clippy_utils::diagnostics::span_lint; +use clippy_utils::visitors::for_each_expr; use clippy_utils::{binop_traits, trait_ref_of_method, BINOP_TRAITS, OP_ASSIGN_TRAITS}; +use core::ops::ControlFlow; use if_chain::if_chain; use rustc_hir as hir; -use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -92,25 +93,17 @@ impl<'tcx> LateLintPass<'tcx> for SuspiciousImpl { } fn count_binops(expr: &hir::Expr<'_>) -> u32 { - let mut visitor = BinaryExprVisitor::default(); - visitor.visit_expr(expr); - visitor.nb_binops -} - -#[derive(Default)] -struct BinaryExprVisitor { - nb_binops: u32, -} - -impl<'tcx> Visitor<'tcx> for BinaryExprVisitor { - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) { - match expr.kind { + let mut count = 0u32; + let _: Option = for_each_expr(expr, |e| { + if matches!( + e.kind, hir::ExprKind::Binary(..) - | hir::ExprKind::Unary(hir::UnOp::Not | hir::UnOp::Neg, _) - | hir::ExprKind::AssignOp(..) => self.nb_binops += 1, - _ => {}, + | hir::ExprKind::Unary(hir::UnOp::Not | hir::UnOp::Neg, _) + | hir::ExprKind::AssignOp(..) + ) { + count += 1; } - - walk_expr(self, expr); - } + ControlFlow::Continue(()) + }); + count } diff --git a/clippy_lints/src/unwrap_in_result.rs b/clippy_lints/src/unwrap_in_result.rs index baa53ba664f69..a69719b127b2f 100644 --- a/clippy_lints/src/unwrap_in_result.rs +++ b/clippy_lints/src/unwrap_in_result.rs @@ -1,12 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::visitors::for_each_expr; use clippy_utils::{method_chain_args, return_ty}; +use core::ops::ControlFlow; use if_chain::if_chain; use rustc_hir as hir; -use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{Expr, ImplItemKind}; +use rustc_hir::ImplItemKind; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{sym, Span}; @@ -73,51 +73,37 @@ impl<'tcx> LateLintPass<'tcx> for UnwrapInResult { } } -struct FindExpectUnwrap<'a, 'tcx> { - lcx: &'a LateContext<'tcx>, - typeck_results: &'tcx ty::TypeckResults<'tcx>, - result: Vec, -} - -impl<'a, 'tcx> Visitor<'tcx> for FindExpectUnwrap<'a, 'tcx> { - fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { - // check for `expect` - if let Some(arglists) = method_chain_args(expr, &["expect"]) { - let receiver_ty = self.typeck_results.expr_ty(arglists[0].0).peel_refs(); - if is_type_diagnostic_item(self.lcx, receiver_ty, sym::Option) - || is_type_diagnostic_item(self.lcx, receiver_ty, sym::Result) - { - self.result.push(expr.span); +fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_item: &'tcx hir::ImplItem<'_>) { + if let ImplItemKind::Fn(_, body_id) = impl_item.kind { + let body = cx.tcx.hir().body(body_id); + let typeck = cx.tcx.typeck(impl_item.def_id.def_id); + let mut result = Vec::new(); + let _: Option = for_each_expr(body.value, |e| { + // check for `expect` + if let Some(arglists) = method_chain_args(e, &["expect"]) { + let receiver_ty = typeck.expr_ty(arglists[0].0).peel_refs(); + if is_type_diagnostic_item(cx, receiver_ty, sym::Option) + || is_type_diagnostic_item(cx, receiver_ty, sym::Result) + { + result.push(e.span); + } } - } - // check for `unwrap` - if let Some(arglists) = method_chain_args(expr, &["unwrap"]) { - let receiver_ty = self.typeck_results.expr_ty(arglists[0].0).peel_refs(); - if is_type_diagnostic_item(self.lcx, receiver_ty, sym::Option) - || is_type_diagnostic_item(self.lcx, receiver_ty, sym::Result) - { - self.result.push(expr.span); + // check for `unwrap` + if let Some(arglists) = method_chain_args(e, &["unwrap"]) { + let receiver_ty = typeck.expr_ty(arglists[0].0).peel_refs(); + if is_type_diagnostic_item(cx, receiver_ty, sym::Option) + || is_type_diagnostic_item(cx, receiver_ty, sym::Result) + { + result.push(e.span); + } } - } - // and check sub-expressions - intravisit::walk_expr(self, expr); - } -} - -fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_item: &'tcx hir::ImplItem<'_>) { - if let ImplItemKind::Fn(_, body_id) = impl_item.kind { - let body = cx.tcx.hir().body(body_id); - let mut fpu = FindExpectUnwrap { - lcx: cx, - typeck_results: cx.tcx.typeck(impl_item.def_id.def_id), - result: Vec::new(), - }; - fpu.visit_expr(body.value); + ControlFlow::Continue(()) + }); // if we've found one, lint - if !fpu.result.is_empty() { + if !result.is_empty() { span_lint_and_then( cx, UNWRAP_IN_RESULT, @@ -125,7 +111,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_item: &'tc "used unwrap or expect in a function that returns result or option", move |diag| { diag.help("unwrap and expect should not be used in a function that returns result or option"); - diag.span_note(fpu.result, "potential non-recoverable error(s)"); + diag.span_note(result, "potential non-recoverable error(s)"); }, ); } From 26bb36636ca9d71958055e05053946d22fcfbdbb Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 2 Oct 2022 17:11:10 -0400 Subject: [PATCH 100/114] Workaround rustc bug --- clippy_utils/src/macros.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs index c0b87cd175ecc..dda21b903901f 100644 --- a/clippy_utils/src/macros.rs +++ b/clippy_utils/src/macros.rs @@ -861,10 +861,12 @@ impl<'tcx> FormatArgsExpn<'tcx> { let e_ctxt = e.span.ctxt(); if e_ctxt == expr.span.ctxt() { ControlFlow::Continue(Descend::Yes) - } else if e_ctxt.outer_expn().is_descendant_of(expn_id) - && let Some(args) = FormatArgsExpn::parse(cx, e) - { - ControlFlow::Break(args) + } else if e_ctxt.outer_expn().is_descendant_of(expn_id) { + if let Some(args) = FormatArgsExpn::parse(cx, e) { + ControlFlow::Break(args) + } else { + ControlFlow::Continue(Descend::No) + } } else { ControlFlow::Continue(Descend::No) } From bf18768219549a502d33d6821e691aeb0abfe69f Mon Sep 17 00:00:00 2001 From: TennyZhuang Date: Mon, 3 Oct 2022 10:11:57 +0800 Subject: [PATCH 101/114] let upper_case_acronyms check the enum name Signed-off-by: TennyZhuang --- clippy_lints/src/upper_case_acronyms.rs | 1 + tests/ui/upper_case_acronyms.rs | 9 +++++++++ tests/ui/upper_case_acronyms.stderr | 14 +++++++++++++- 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/upper_case_acronyms.rs b/clippy_lints/src/upper_case_acronyms.rs index 2ab58f06d6b8d..654ea306793bd 100644 --- a/clippy_lints/src/upper_case_acronyms.rs +++ b/clippy_lints/src/upper_case_acronyms.rs @@ -114,6 +114,7 @@ impl LateLintPass<'_> for UpperCaseAcronyms { check_ident(cx, &it.ident, self.upper_case_acronyms_aggressive); }, ItemKind::Enum(ref enumdef, _) => { + check_ident(cx, &it.ident, self.upper_case_acronyms_aggressive); // check enum variants separately because again we only want to lint on private enums and // the fn check_variant does not know about the vis of the enum of its variants enumdef diff --git a/tests/ui/upper_case_acronyms.rs b/tests/ui/upper_case_acronyms.rs index 48bb9e54b122b..9b7c2f28e1cfc 100644 --- a/tests/ui/upper_case_acronyms.rs +++ b/tests/ui/upper_case_acronyms.rs @@ -38,4 +38,13 @@ enum ParseErrorPrivate { Parse(T, String), } +// do lint here +struct JSON; + +// do lint here +enum YAML { + Num(u32), + Str(String), +} + fn main() {} diff --git a/tests/ui/upper_case_acronyms.stderr b/tests/ui/upper_case_acronyms.stderr index 250b196a99eb2..74082ec16dd45 100644 --- a/tests/ui/upper_case_acronyms.stderr +++ b/tests/ui/upper_case_acronyms.stderr @@ -54,5 +54,17 @@ error: name `WASD` contains a capitalized acronym LL | WASD(u8), | ^^^^ help: consider making the acronym lowercase, except the initial letter: `Wasd` -error: aborting due to 9 previous errors +error: name `JSON` contains a capitalized acronym + --> $DIR/upper_case_acronyms.rs:42:8 + | +LL | struct JSON; + | ^^^^ help: consider making the acronym lowercase, except the initial letter: `Json` + +error: name `YAML` contains a capitalized acronym + --> $DIR/upper_case_acronyms.rs:45:6 + | +LL | enum YAML { + | ^^^^ help: consider making the acronym lowercase, except the initial letter: `Yaml` + +error: aborting due to 11 previous errors From 7747032b774de25cb9e1cf672a9244f17eb234cb Mon Sep 17 00:00:00 2001 From: Elliot Bobrow Date: Sun, 2 Oct 2022 21:00:51 -0700 Subject: [PATCH 102/114] `suboptimal_flops` lint for multiply and subtract --- clippy_lints/src/floating_point_arithmetic.rs | 48 ++++++++++++++----- tests/ui/floating_point_mul_add.fixed | 2 + tests/ui/floating_point_mul_add.rs | 2 + tests/ui/floating_point_mul_add.stderr | 30 ++++++++---- tests/ui/floating_point_powi.fixed | 2 + tests/ui/floating_point_powi.rs | 2 + tests/ui/floating_point_powi.stderr | 20 ++++++-- 7 files changed, 81 insertions(+), 25 deletions(-) diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index e71afec12a77c..0ed301964758e 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -311,7 +311,8 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: if let ExprKind::Binary( Spanned { - node: BinOpKind::Add, .. + node: op @ (BinOpKind::Add | BinOpKind::Sub), + .. }, lhs, rhs, @@ -319,6 +320,16 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: { let other_addend = if lhs.hir_id == expr.hir_id { rhs } else { lhs }; + // Negate expr if original code has subtraction and expr is on the right side + let maybe_neg_sugg = |expr, hir_id| { + let sugg = Sugg::hir(cx, expr, ".."); + if matches!(op, BinOpKind::Sub) && hir_id == rhs.hir_id { + format!("-{sugg}") + } else { + sugg.to_string() + } + }; + span_lint_and_sugg( cx, SUBOPTIMAL_FLOPS, @@ -328,8 +339,8 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: format!( "{}.mul_add({}, {})", Sugg::hir(cx, receiver, "..").maybe_par(), - Sugg::hir(cx, receiver, ".."), - Sugg::hir(cx, other_addend, ".."), + maybe_neg_sugg(receiver, expr.hir_id), + maybe_neg_sugg(other_addend, other_addend.hir_id), ), Applicability::MachineApplicable, ); @@ -443,7 +454,8 @@ fn is_float_mul_expr<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(&' fn check_mul_add(cx: &LateContext<'_>, expr: &Expr<'_>) { if let ExprKind::Binary( Spanned { - node: BinOpKind::Add, .. + node: op @ (BinOpKind::Add | BinOpKind::Sub), + .. }, lhs, rhs, @@ -457,10 +469,27 @@ fn check_mul_add(cx: &LateContext<'_>, expr: &Expr<'_>) { } } + let maybe_neg_sugg = |expr| { + let sugg = Sugg::hir(cx, expr, ".."); + if let BinOpKind::Sub = op { + format!("-{sugg}") + } else { + sugg.to_string() + } + }; + let (recv, arg1, arg2) = if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, lhs) { - (inner_lhs, inner_rhs, rhs) + ( + inner_lhs, + Sugg::hir(cx, inner_rhs, "..").to_string(), + maybe_neg_sugg(rhs), + ) } else if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, rhs) { - (inner_lhs, inner_rhs, lhs) + ( + inner_lhs, + maybe_neg_sugg(inner_rhs), + Sugg::hir(cx, lhs, "..").to_string(), + ) } else { return; }; @@ -471,12 +500,7 @@ fn check_mul_add(cx: &LateContext<'_>, expr: &Expr<'_>) { expr.span, "multiply and add expressions can be calculated more efficiently and accurately", "consider using", - format!( - "{}.mul_add({}, {})", - prepare_receiver_sugg(cx, recv), - Sugg::hir(cx, arg1, ".."), - Sugg::hir(cx, arg2, ".."), - ), + format!("{}.mul_add({arg1}, {arg2})", prepare_receiver_sugg(cx, recv)), Applicability::MachineApplicable, ); } diff --git a/tests/ui/floating_point_mul_add.fixed b/tests/ui/floating_point_mul_add.fixed index 169ec02f82be6..d3e536ba3500d 100644 --- a/tests/ui/floating_point_mul_add.fixed +++ b/tests/ui/floating_point_mul_add.fixed @@ -19,7 +19,9 @@ fn main() { let d: f64 = 0.0001; let _ = a.mul_add(b, c); + let _ = a.mul_add(b, -c); let _ = a.mul_add(b, c); + let _ = a.mul_add(-b, c); let _ = 2.0f64.mul_add(4.0, a); let _ = 2.0f64.mul_add(4., a); diff --git a/tests/ui/floating_point_mul_add.rs b/tests/ui/floating_point_mul_add.rs index 5338d4fc2b749..5d4a9e35cfc22 100644 --- a/tests/ui/floating_point_mul_add.rs +++ b/tests/ui/floating_point_mul_add.rs @@ -19,7 +19,9 @@ fn main() { let d: f64 = 0.0001; let _ = a * b + c; + let _ = a * b - c; let _ = c + a * b; + let _ = c - a * b; let _ = a + 2.0 * 4.0; let _ = a + 2. * 4.; diff --git a/tests/ui/floating_point_mul_add.stderr b/tests/ui/floating_point_mul_add.stderr index e637bbf90caa2..a79ae94e8d431 100644 --- a/tests/ui/floating_point_mul_add.stderr +++ b/tests/ui/floating_point_mul_add.stderr @@ -9,56 +9,68 @@ LL | let _ = a * b + c; error: multiply and add expressions can be calculated more efficiently and accurately --> $DIR/floating_point_mul_add.rs:22:13 | +LL | let _ = a * b - c; + | ^^^^^^^^^ help: consider using: `a.mul_add(b, -c)` + +error: multiply and add expressions can be calculated more efficiently and accurately + --> $DIR/floating_point_mul_add.rs:23:13 + | LL | let _ = c + a * b; | ^^^^^^^^^ help: consider using: `a.mul_add(b, c)` error: multiply and add expressions can be calculated more efficiently and accurately - --> $DIR/floating_point_mul_add.rs:23:13 + --> $DIR/floating_point_mul_add.rs:24:13 + | +LL | let _ = c - a * b; + | ^^^^^^^^^ help: consider using: `a.mul_add(-b, c)` + +error: multiply and add expressions can be calculated more efficiently and accurately + --> $DIR/floating_point_mul_add.rs:25:13 | LL | let _ = a + 2.0 * 4.0; | ^^^^^^^^^^^^^ help: consider using: `2.0f64.mul_add(4.0, a)` error: multiply and add expressions can be calculated more efficiently and accurately - --> $DIR/floating_point_mul_add.rs:24:13 + --> $DIR/floating_point_mul_add.rs:26:13 | LL | let _ = a + 2. * 4.; | ^^^^^^^^^^^ help: consider using: `2.0f64.mul_add(4., a)` error: multiply and add expressions can be calculated more efficiently and accurately - --> $DIR/floating_point_mul_add.rs:26:13 + --> $DIR/floating_point_mul_add.rs:28:13 | LL | let _ = (a * b) + c; | ^^^^^^^^^^^ help: consider using: `a.mul_add(b, c)` error: multiply and add expressions can be calculated more efficiently and accurately - --> $DIR/floating_point_mul_add.rs:27:13 + --> $DIR/floating_point_mul_add.rs:29:13 | LL | let _ = c + (a * b); | ^^^^^^^^^^^ help: consider using: `a.mul_add(b, c)` error: multiply and add expressions can be calculated more efficiently and accurately - --> $DIR/floating_point_mul_add.rs:28:13 + --> $DIR/floating_point_mul_add.rs:30:13 | LL | let _ = a * b * c + d; | ^^^^^^^^^^^^^ help: consider using: `(a * b).mul_add(c, d)` error: multiply and add expressions can be calculated more efficiently and accurately - --> $DIR/floating_point_mul_add.rs:30:13 + --> $DIR/floating_point_mul_add.rs:32:13 | LL | let _ = a.mul_add(b, c) * a.mul_add(b, c) + a.mul_add(b, c) + c; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `a.mul_add(b, c).mul_add(a.mul_add(b, c), a.mul_add(b, c))` error: multiply and add expressions can be calculated more efficiently and accurately - --> $DIR/floating_point_mul_add.rs:31:13 + --> $DIR/floating_point_mul_add.rs:33:13 | LL | let _ = 1234.567_f64 * 45.67834_f64 + 0.0004_f64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1234.567_f64.mul_add(45.67834_f64, 0.0004_f64)` error: multiply and add expressions can be calculated more efficiently and accurately - --> $DIR/floating_point_mul_add.rs:33:13 + --> $DIR/floating_point_mul_add.rs:35:13 | LL | let _ = (a * a + b).sqrt(); | ^^^^^^^^^^^ help: consider using: `a.mul_add(a, b)` -error: aborting due to 10 previous errors +error: aborting due to 12 previous errors diff --git a/tests/ui/floating_point_powi.fixed b/tests/ui/floating_point_powi.fixed index 5758db7c6c82d..cc3370388885c 100644 --- a/tests/ui/floating_point_powi.fixed +++ b/tests/ui/floating_point_powi.fixed @@ -7,7 +7,9 @@ fn main() { let y = 4f32; let _ = x.mul_add(x, y); + let _ = x.mul_add(x, -y); let _ = y.mul_add(y, x); + let _ = y.mul_add(-y, x); let _ = (y as f32).mul_add(y as f32, x); let _ = x.mul_add(x, y).sqrt(); let _ = y.mul_add(y, x).sqrt(); diff --git a/tests/ui/floating_point_powi.rs b/tests/ui/floating_point_powi.rs index 5926bf1b00042..5950902178cb7 100644 --- a/tests/ui/floating_point_powi.rs +++ b/tests/ui/floating_point_powi.rs @@ -7,7 +7,9 @@ fn main() { let y = 4f32; let _ = x.powi(2) + y; + let _ = x.powi(2) - y; let _ = x + y.powi(2); + let _ = x - y.powi(2); let _ = x + (y as f32).powi(2); let _ = (x.powi(2) + y).sqrt(); let _ = (x + y.powi(2)).sqrt(); diff --git a/tests/ui/floating_point_powi.stderr b/tests/ui/floating_point_powi.stderr index a3c74544212b2..643b70739cdc5 100644 --- a/tests/ui/floating_point_powi.stderr +++ b/tests/ui/floating_point_powi.stderr @@ -9,26 +9,38 @@ LL | let _ = x.powi(2) + y; error: multiply and add expressions can be calculated more efficiently and accurately --> $DIR/floating_point_powi.rs:10:13 | +LL | let _ = x.powi(2) - y; + | ^^^^^^^^^^^^^ help: consider using: `x.mul_add(x, -y)` + +error: multiply and add expressions can be calculated more efficiently and accurately + --> $DIR/floating_point_powi.rs:11:13 + | LL | let _ = x + y.powi(2); | ^^^^^^^^^^^^^ help: consider using: `y.mul_add(y, x)` error: multiply and add expressions can be calculated more efficiently and accurately - --> $DIR/floating_point_powi.rs:11:13 + --> $DIR/floating_point_powi.rs:12:13 + | +LL | let _ = x - y.powi(2); + | ^^^^^^^^^^^^^ help: consider using: `y.mul_add(-y, x)` + +error: multiply and add expressions can be calculated more efficiently and accurately + --> $DIR/floating_point_powi.rs:13:13 | LL | let _ = x + (y as f32).powi(2); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(y as f32).mul_add(y as f32, x)` error: multiply and add expressions can be calculated more efficiently and accurately - --> $DIR/floating_point_powi.rs:12:13 + --> $DIR/floating_point_powi.rs:14:13 | LL | let _ = (x.powi(2) + y).sqrt(); | ^^^^^^^^^^^^^^^ help: consider using: `x.mul_add(x, y)` error: multiply and add expressions can be calculated more efficiently and accurately - --> $DIR/floating_point_powi.rs:13:13 + --> $DIR/floating_point_powi.rs:15:13 | LL | let _ = (x + y.powi(2)).sqrt(); | ^^^^^^^^^^^^^^^ help: consider using: `y.mul_add(y, x)` -error: aborting due to 5 previous errors +error: aborting due to 7 previous errors From f1c831ad176b853d074563acda9c58566233e123 Mon Sep 17 00:00:00 2001 From: royrustdev Date: Wed, 28 Sep 2022 19:47:13 +0530 Subject: [PATCH 103/114] add `implicit_saturating_add` lint --- CHANGELOG.md | 1 + clippy_lints/src/implicit_saturating_add.rs | 114 +++++++++++ clippy_lints/src/lib.register_all.rs | 1 + clippy_lints/src/lib.register_lints.rs | 1 + clippy_lints/src/lib.register_style.rs | 1 + clippy_lints/src/lib.rs | 2 + src/docs.rs | 1 + src/docs/implicit_saturating_add.txt | 20 ++ tests/ui/implicit_saturating_add.fixed | 106 +++++++++++ tests/ui/implicit_saturating_add.rs | 154 +++++++++++++++ tests/ui/implicit_saturating_add.stderr | 197 ++++++++++++++++++++ 11 files changed, 598 insertions(+) create mode 100644 clippy_lints/src/implicit_saturating_add.rs create mode 100644 src/docs/implicit_saturating_add.txt create mode 100644 tests/ui/implicit_saturating_add.fixed create mode 100644 tests/ui/implicit_saturating_add.rs create mode 100644 tests/ui/implicit_saturating_add.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f12a67359624..bfeb009727b5b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3917,6 +3917,7 @@ Released 2018-09-13 [`implicit_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_clone [`implicit_hasher`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_hasher [`implicit_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_return +[`implicit_saturating_add`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_saturating_add [`implicit_saturating_sub`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_saturating_sub [`imprecise_flops`]: https://rust-lang.github.io/rust-clippy/master/index.html#imprecise_flops [`inconsistent_digit_grouping`]: https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_digit_grouping diff --git a/clippy_lints/src/implicit_saturating_add.rs b/clippy_lints/src/implicit_saturating_add.rs new file mode 100644 index 0000000000000..bf1351829c6a5 --- /dev/null +++ b/clippy_lints/src/implicit_saturating_add.rs @@ -0,0 +1,114 @@ +use clippy_utils::consts::{constant, Constant}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::get_parent_expr; +use clippy_utils::source::snippet_with_applicability; +use if_chain::if_chain; +use rustc_ast::ast::{LitIntType, LitKind}; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Block, Expr, ExprKind, Stmt, StmtKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::{Int, IntTy, Ty, Uint, UintTy}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// ### What it does + /// Checks for implicit saturating addition. + /// + /// ### Why is this bad? + /// The built-in function is more readable and may be faster. + /// + /// ### Example + /// ```rust + ///let mut u:u32 = 7000; + /// + /// if u != u32::MAX { + /// u += 1; + /// } + /// ``` + /// Use instead: + /// ```rust + ///let mut u:u32 = 7000; + /// + /// u = u.saturating_add(1); + /// ``` + #[clippy::version = "1.65.0"] + pub IMPLICIT_SATURATING_ADD, + style, + "Perform saturating addition instead of implicitly checking max bound of data type" +} +declare_lint_pass!(ImplicitSaturatingAdd => [IMPLICIT_SATURATING_ADD]); + +impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingAdd { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { + if_chain! { + if let ExprKind::If(cond, then, None) = expr.kind; + if let ExprKind::DropTemps(expr1) = cond.kind; + if let Some((c, op_node, l)) = get_const(cx, expr1); + if let BinOpKind::Ne | BinOpKind::Lt = op_node; + if let ExprKind::Block(block, None) = then.kind; + if let Block { + stmts: + [Stmt + { kind: StmtKind::Expr(ex) | StmtKind::Semi(ex), .. }], + expr: None, ..} | + Block { stmts: [], expr: Some(ex), ..} = block; + if let ExprKind::AssignOp(op1, target, value) = ex.kind; + let ty = cx.typeck_results().expr_ty(target); + if Some(c) == get_int_max(ty); + if clippy_utils::SpanlessEq::new(cx).eq_expr(l, target); + if BinOpKind::Add == op1.node; + if let ExprKind::Lit(ref lit) = value.kind; + if let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node; + if block.expr.is_none(); + then { + let mut app = Applicability::MachineApplicable; + let code = snippet_with_applicability(cx, target.span, "_", &mut app); + let sugg = if let Some(parent) = get_parent_expr(cx, expr) && let ExprKind::If(_cond, _then, Some(else_)) = parent.kind && else_.hir_id == expr.hir_id {format!("{{{code} = {code}.saturating_add(1); }}")} else {format!("{code} = {code}.saturating_add(1);")}; + span_lint_and_sugg(cx, IMPLICIT_SATURATING_ADD, expr.span, "manual saturating add detected", "use instead", sugg, app); + } + } + } +} + +fn get_int_max(ty: Ty<'_>) -> Option { + match ty.peel_refs().kind() { + Int(IntTy::I8) => i8::max_value().try_into().ok(), + Int(IntTy::I16) => i16::max_value().try_into().ok(), + Int(IntTy::I32) => i32::max_value().try_into().ok(), + Int(IntTy::I64) => i64::max_value().try_into().ok(), + Int(IntTy::I128) => i128::max_value().try_into().ok(), + Int(IntTy::Isize) => isize::max_value().try_into().ok(), + Uint(UintTy::U8) => u8::max_value().try_into().ok(), + Uint(UintTy::U16) => u16::max_value().try_into().ok(), + Uint(UintTy::U32) => u32::max_value().try_into().ok(), + Uint(UintTy::U64) => u64::max_value().try_into().ok(), + Uint(UintTy::U128) => Some(u128::max_value()), + Uint(UintTy::Usize) => usize::max_value().try_into().ok(), + _ => None, + } +} + +fn get_const<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<(u128, BinOpKind, &'tcx Expr<'tcx>)> { + if let ExprKind::Binary(op, l, r) = expr.kind { + let tr = cx.typeck_results(); + if let Some((Constant::Int(c), _)) = constant(cx, tr, r) { + return Some((c, op.node, l)); + }; + if let Some((Constant::Int(c), _)) = constant(cx, tr, l) { + return Some((c, invert_op(op.node)?, r)); + } + } + None +} + +fn invert_op(op: BinOpKind) -> Option { + use rustc_hir::BinOpKind::{Ge, Gt, Le, Lt, Ne}; + match op { + Lt => Some(Gt), + Le => Some(Ge), + Ne => Some(Ne), + Ge => Some(Le), + Gt => Some(Lt), + _ => None, + } +} diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index 9ad2a88eb26ca..642d7070fb6ba 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -85,6 +85,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ 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(indexing_slicing::OUT_OF_BOUNDS_INDEXING), LintId::of(infinite_iter::INFINITE_ITER), LintId::of(inherent_to_string::INHERENT_TO_STRING), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 307ec40f40b3b..08eb6c2b39bc4 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -184,6 +184,7 @@ store.register_lints(&[ 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, diff --git a/clippy_lints/src/lib.register_style.rs b/clippy_lints/src/lib.register_style.rs index ab7c4034b0e6a..6d5483bc70102 100644 --- a/clippy_lints/src/lib.register_style.rs +++ b/clippy_lints/src/lib.register_style.rs @@ -29,6 +29,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ 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(inherent_to_string::INHERENT_TO_STRING), LintId::of(init_numbered_fields::INIT_NUMBERED_FIELDS), LintId::of(len_zero::COMPARISON_TO_EMPTY), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 3b78e492baa48..e5d26ac22a745 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -238,6 +238,7 @@ mod if_not_else; mod if_then_some_else_none; mod implicit_hasher; mod implicit_return; +mod implicit_saturating_add; mod implicit_saturating_sub; mod inconsistent_struct_constructor; mod index_refutable_slice; @@ -904,6 +905,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(|| Box::new(multi_assignments::MultiAssignments)); store.register_late_pass(|_| Box::new(bool_to_int_with_if::BoolToIntWithIf)); store.register_late_pass(|_| Box::new(box_default::BoxDefault)); + store.register_late_pass(|_| Box::new(implicit_saturating_add::ImplicitSaturatingAdd)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/src/docs.rs b/src/docs.rs index 39540e4b04892..1b727e1a10049 100644 --- a/src/docs.rs +++ b/src/docs.rs @@ -191,6 +191,7 @@ docs! { "implicit_clone", "implicit_hasher", "implicit_return", + "implicit_saturating_add", "implicit_saturating_sub", "imprecise_flops", "inconsistent_digit_grouping", diff --git a/src/docs/implicit_saturating_add.txt b/src/docs/implicit_saturating_add.txt new file mode 100644 index 0000000000000..5883a5363e2b6 --- /dev/null +++ b/src/docs/implicit_saturating_add.txt @@ -0,0 +1,20 @@ +### What it does +Checks for implicit saturating addition. + +### Why is this bad? +The built-in function is more readable and may be faster. + +### Example +``` +let mut u:u32 = 7000; + +if u != u32::MAX { + u += 1; +} +``` +Use instead: +``` +let mut u:u32 = 7000; + +u = u.saturating_add(1); +``` \ No newline at end of file diff --git a/tests/ui/implicit_saturating_add.fixed b/tests/ui/implicit_saturating_add.fixed new file mode 100644 index 0000000000000..7d363d59a6f09 --- /dev/null +++ b/tests/ui/implicit_saturating_add.fixed @@ -0,0 +1,106 @@ +// run-rustfix + +#![allow(unused)] +#![warn(clippy::implicit_saturating_add)] + +fn main() { + let mut u_8: u8 = 255; + let mut u_16: u16 = 500; + let mut u_32: u32 = 7000; + let mut u_64: u64 = 7000; + let mut i_8: i8 = 30; + let mut i_16: i16 = 500; + let mut i_32: i32 = 7000; + let mut i_64: i64 = 7000; + + if i_8 < 42 { + i_8 += 1; + } + if i_8 != 42 { + i_8 += 1; + } + + u_8 = u_8.saturating_add(1); + + u_8 = u_8.saturating_add(1); + + if u_8 < 15 { + u_8 += 1; + } + + u_16 = u_16.saturating_add(1); + + u_16 = u_16.saturating_add(1); + + u_16 = u_16.saturating_add(1); + + u_32 = u_32.saturating_add(1); + + u_32 = u_32.saturating_add(1); + + u_32 = u_32.saturating_add(1); + + u_64 = u_64.saturating_add(1); + + u_64 = u_64.saturating_add(1); + + u_64 = u_64.saturating_add(1); + + i_8 = i_8.saturating_add(1); + + i_8 = i_8.saturating_add(1); + + i_8 = i_8.saturating_add(1); + + i_16 = i_16.saturating_add(1); + + i_16 = i_16.saturating_add(1); + + i_16 = i_16.saturating_add(1); + + i_32 = i_32.saturating_add(1); + + i_32 = i_32.saturating_add(1); + + i_32 = i_32.saturating_add(1); + + i_64 = i_64.saturating_add(1); + + i_64 = i_64.saturating_add(1); + + i_64 = i_64.saturating_add(1); + + if i_64 < 42 { + i_64 += 1; + } + + if 42 > i_64 { + i_64 += 1; + } + + let a = 12; + let mut b = 8; + + if a < u8::MAX { + b += 1; + } + + if u8::MAX > a { + b += 1; + } + + if u_32 < u32::MAX { + u_32 += 1; + } else { + println!("don't lint this"); + } + + if u_32 < u32::MAX { + println!("don't lint this"); + u_32 += 1; + } + + if u_32 < 42 { + println!("brace yourself!"); + } else {u_32 = u_32.saturating_add(1); } +} diff --git a/tests/ui/implicit_saturating_add.rs b/tests/ui/implicit_saturating_add.rs new file mode 100644 index 0000000000000..31a5916277fa7 --- /dev/null +++ b/tests/ui/implicit_saturating_add.rs @@ -0,0 +1,154 @@ +// run-rustfix + +#![allow(unused)] +#![warn(clippy::implicit_saturating_add)] + +fn main() { + let mut u_8: u8 = 255; + let mut u_16: u16 = 500; + let mut u_32: u32 = 7000; + let mut u_64: u64 = 7000; + let mut i_8: i8 = 30; + let mut i_16: i16 = 500; + let mut i_32: i32 = 7000; + let mut i_64: i64 = 7000; + + if i_8 < 42 { + i_8 += 1; + } + if i_8 != 42 { + i_8 += 1; + } + + if u_8 != u8::MAX { + u_8 += 1; + } + + if u_8 < u8::MAX { + u_8 += 1; + } + + if u_8 < 15 { + u_8 += 1; + } + + if u_16 != u16::MAX { + u_16 += 1; + } + + if u_16 < u16::MAX { + u_16 += 1; + } + + if u16::MAX > u_16 { + u_16 += 1; + } + + if u_32 != u32::MAX { + u_32 += 1; + } + + if u_32 < u32::MAX { + u_32 += 1; + } + + if u32::MAX > u_32 { + u_32 += 1; + } + + if u_64 != u64::MAX { + u_64 += 1; + } + + if u_64 < u64::MAX { + u_64 += 1; + } + + if u64::MAX > u_64 { + u_64 += 1; + } + + if i_8 != i8::MAX { + i_8 += 1; + } + + if i_8 < i8::MAX { + i_8 += 1; + } + + if i8::MAX > i_8 { + i_8 += 1; + } + + if i_16 != i16::MAX { + i_16 += 1; + } + + if i_16 < i16::MAX { + i_16 += 1; + } + + if i16::MAX > i_16 { + i_16 += 1; + } + + if i_32 != i32::MAX { + i_32 += 1; + } + + if i_32 < i32::MAX { + i_32 += 1; + } + + if i32::MAX > i_32 { + i_32 += 1; + } + + if i_64 != i64::MAX { + i_64 += 1; + } + + if i_64 < i64::MAX { + i_64 += 1; + } + + if i64::MAX > i_64 { + i_64 += 1; + } + + if i_64 < 42 { + i_64 += 1; + } + + if 42 > i_64 { + i_64 += 1; + } + + let a = 12; + let mut b = 8; + + if a < u8::MAX { + b += 1; + } + + if u8::MAX > a { + b += 1; + } + + if u_32 < u32::MAX { + u_32 += 1; + } else { + println!("don't lint this"); + } + + if u_32 < u32::MAX { + println!("don't lint this"); + u_32 += 1; + } + + if u_32 < 42 { + println!("brace yourself!"); + } else if u_32 < u32::MAX { + u_32 += 1; + } +} diff --git a/tests/ui/implicit_saturating_add.stderr b/tests/ui/implicit_saturating_add.stderr new file mode 100644 index 0000000000000..42ae1b488853d --- /dev/null +++ b/tests/ui/implicit_saturating_add.stderr @@ -0,0 +1,197 @@ +error: manual saturating add detected + --> $DIR/implicit_saturating_add.rs:23:5 + | +LL | / if u_8 != u8::MAX { +LL | | u_8 += 1; +LL | | } + | |_____^ help: use instead: `u_8 = u_8.saturating_add(1);` + | + = note: `-D clippy::implicit-saturating-add` implied by `-D warnings` + +error: manual saturating add detected + --> $DIR/implicit_saturating_add.rs:27:5 + | +LL | / if u_8 < u8::MAX { +LL | | u_8 += 1; +LL | | } + | |_____^ help: use instead: `u_8 = u_8.saturating_add(1);` + +error: manual saturating add detected + --> $DIR/implicit_saturating_add.rs:35:5 + | +LL | / if u_16 != u16::MAX { +LL | | u_16 += 1; +LL | | } + | |_____^ help: use instead: `u_16 = u_16.saturating_add(1);` + +error: manual saturating add detected + --> $DIR/implicit_saturating_add.rs:39:5 + | +LL | / if u_16 < u16::MAX { +LL | | u_16 += 1; +LL | | } + | |_____^ help: use instead: `u_16 = u_16.saturating_add(1);` + +error: manual saturating add detected + --> $DIR/implicit_saturating_add.rs:43:5 + | +LL | / if u16::MAX > u_16 { +LL | | u_16 += 1; +LL | | } + | |_____^ help: use instead: `u_16 = u_16.saturating_add(1);` + +error: manual saturating add detected + --> $DIR/implicit_saturating_add.rs:47:5 + | +LL | / if u_32 != u32::MAX { +LL | | u_32 += 1; +LL | | } + | |_____^ help: use instead: `u_32 = u_32.saturating_add(1);` + +error: manual saturating add detected + --> $DIR/implicit_saturating_add.rs:51:5 + | +LL | / if u_32 < u32::MAX { +LL | | u_32 += 1; +LL | | } + | |_____^ help: use instead: `u_32 = u_32.saturating_add(1);` + +error: manual saturating add detected + --> $DIR/implicit_saturating_add.rs:55:5 + | +LL | / if u32::MAX > u_32 { +LL | | u_32 += 1; +LL | | } + | |_____^ help: use instead: `u_32 = u_32.saturating_add(1);` + +error: manual saturating add detected + --> $DIR/implicit_saturating_add.rs:59:5 + | +LL | / if u_64 != u64::MAX { +LL | | u_64 += 1; +LL | | } + | |_____^ help: use instead: `u_64 = u_64.saturating_add(1);` + +error: manual saturating add detected + --> $DIR/implicit_saturating_add.rs:63:5 + | +LL | / if u_64 < u64::MAX { +LL | | u_64 += 1; +LL | | } + | |_____^ help: use instead: `u_64 = u_64.saturating_add(1);` + +error: manual saturating add detected + --> $DIR/implicit_saturating_add.rs:67:5 + | +LL | / if u64::MAX > u_64 { +LL | | u_64 += 1; +LL | | } + | |_____^ help: use instead: `u_64 = u_64.saturating_add(1);` + +error: manual saturating add detected + --> $DIR/implicit_saturating_add.rs:71:5 + | +LL | / if i_8 != i8::MAX { +LL | | i_8 += 1; +LL | | } + | |_____^ help: use instead: `i_8 = i_8.saturating_add(1);` + +error: manual saturating add detected + --> $DIR/implicit_saturating_add.rs:75:5 + | +LL | / if i_8 < i8::MAX { +LL | | i_8 += 1; +LL | | } + | |_____^ help: use instead: `i_8 = i_8.saturating_add(1);` + +error: manual saturating add detected + --> $DIR/implicit_saturating_add.rs:79:5 + | +LL | / if i8::MAX > i_8 { +LL | | i_8 += 1; +LL | | } + | |_____^ help: use instead: `i_8 = i_8.saturating_add(1);` + +error: manual saturating add detected + --> $DIR/implicit_saturating_add.rs:83:5 + | +LL | / if i_16 != i16::MAX { +LL | | i_16 += 1; +LL | | } + | |_____^ help: use instead: `i_16 = i_16.saturating_add(1);` + +error: manual saturating add detected + --> $DIR/implicit_saturating_add.rs:87:5 + | +LL | / if i_16 < i16::MAX { +LL | | i_16 += 1; +LL | | } + | |_____^ help: use instead: `i_16 = i_16.saturating_add(1);` + +error: manual saturating add detected + --> $DIR/implicit_saturating_add.rs:91:5 + | +LL | / if i16::MAX > i_16 { +LL | | i_16 += 1; +LL | | } + | |_____^ help: use instead: `i_16 = i_16.saturating_add(1);` + +error: manual saturating add detected + --> $DIR/implicit_saturating_add.rs:95:5 + | +LL | / if i_32 != i32::MAX { +LL | | i_32 += 1; +LL | | } + | |_____^ help: use instead: `i_32 = i_32.saturating_add(1);` + +error: manual saturating add detected + --> $DIR/implicit_saturating_add.rs:99:5 + | +LL | / if i_32 < i32::MAX { +LL | | i_32 += 1; +LL | | } + | |_____^ help: use instead: `i_32 = i_32.saturating_add(1);` + +error: manual saturating add detected + --> $DIR/implicit_saturating_add.rs:103:5 + | +LL | / if i32::MAX > i_32 { +LL | | i_32 += 1; +LL | | } + | |_____^ help: use instead: `i_32 = i_32.saturating_add(1);` + +error: manual saturating add detected + --> $DIR/implicit_saturating_add.rs:107:5 + | +LL | / if i_64 != i64::MAX { +LL | | i_64 += 1; +LL | | } + | |_____^ help: use instead: `i_64 = i_64.saturating_add(1);` + +error: manual saturating add detected + --> $DIR/implicit_saturating_add.rs:111:5 + | +LL | / if i_64 < i64::MAX { +LL | | i_64 += 1; +LL | | } + | |_____^ help: use instead: `i_64 = i_64.saturating_add(1);` + +error: manual saturating add detected + --> $DIR/implicit_saturating_add.rs:115:5 + | +LL | / if i64::MAX > i_64 { +LL | | i_64 += 1; +LL | | } + | |_____^ help: use instead: `i_64 = i_64.saturating_add(1);` + +error: manual saturating add detected + --> $DIR/implicit_saturating_add.rs:151:12 + | +LL | } else if u_32 < u32::MAX { + | ____________^ +LL | | u_32 += 1; +LL | | } + | |_____^ help: use instead: `{u_32 = u_32.saturating_add(1); }` + +error: aborting due to 24 previous errors + From 99363fef657f399eca30b49df5f7b68d8b8a0ee8 Mon Sep 17 00:00:00 2001 From: Caio Date: Mon, 3 Oct 2022 18:36:12 -0300 Subject: [PATCH 104/114] Address comments --- .../src/operators/arithmetic_side_effects.rs | 24 +++++++++---------- tests/ui/arithmetic_side_effects.stderr | 24 ++++++++++++++++--- 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/clippy_lints/src/operators/arithmetic_side_effects.rs b/clippy_lints/src/operators/arithmetic_side_effects.rs index d871b72db8f42..fc2a828bfc038 100644 --- a/clippy_lints/src/operators/arithmetic_side_effects.rs +++ b/clippy_lints/src/operators/arithmetic_side_effects.rs @@ -9,6 +9,7 @@ use rustc_ast as ast; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::Ty; use rustc_session::impl_lint_pass; use rustc_span::source_map::{Span, Spanned}; @@ -67,20 +68,14 @@ impl ArithmeticSideEffects { } /// Checks if the given `expr` has any of the inner `allowed` elements. - fn is_allowed_ty(&self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { - self.allowed.contains( - cx.typeck_results() - .expr_ty(expr) - .to_string() - .split('<') - .next() - .unwrap_or_default(), - ) + fn is_allowed_ty(&self, ty: Ty<'_>) -> bool { + self.allowed + .contains(ty.to_string().split('<').next().unwrap_or_default()) } // For example, 8i32 or &i64::MAX. - fn is_integral<'expr, 'tcx>(cx: &LateContext<'tcx>, expr: &'expr hir::Expr<'tcx>) -> bool { - cx.typeck_results().expr_ty(expr).peel_refs().is_integral() + fn is_integral(ty: Ty<'_>) -> bool { + ty.peel_refs().is_integral() } // Common entry-point to avoid code duplication. @@ -129,10 +124,13 @@ impl ArithmeticSideEffects { ) { return; }; - if self.is_allowed_ty(cx, lhs) && self.is_allowed_ty(cx, rhs) { + let lhs_ty = cx.typeck_results().expr_ty(lhs); + let rhs_ty = cx.typeck_results().expr_ty(rhs); + let lhs_and_rhs_have_the_same_ty = lhs_ty == rhs_ty; + if lhs_and_rhs_have_the_same_ty && self.is_allowed_ty(lhs_ty) && self.is_allowed_ty(rhs_ty) { return; } - let has_valid_op = if Self::is_integral(cx, lhs) && Self::is_integral(cx, rhs) { + 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, None) => false, (None, Some(local_expr)) => Self::has_valid_op(op, local_expr), diff --git a/tests/ui/arithmetic_side_effects.stderr b/tests/ui/arithmetic_side_effects.stderr index 7870c942e7dfc..8cabd05c2f98a 100644 --- a/tests/ui/arithmetic_side_effects.stderr +++ b/tests/ui/arithmetic_side_effects.stderr @@ -1,10 +1,28 @@ +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:78:13 + | +LL | let _ = String::new() + ""; + | ^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::arithmetic-side-effects` implied by `-D warnings` + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:86:27 + | +LL | let inferred_string = string + ""; + | ^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:90:13 + | +LL | let _ = inferred_string + ""; + | ^^^^^^^^^^^^^^^^^^^^ + error: arithmetic operation that can potentially result in unexpected side-effects --> $DIR/arithmetic_side_effects.rs:162:5 | LL | _n += 1; | ^^^^^^^ - | - = note: `-D clippy::arithmetic-side-effects` implied by `-D warnings` error: arithmetic operation that can potentially result in unexpected side-effects --> $DIR/arithmetic_side_effects.rs:163:5 @@ -312,5 +330,5 @@ error: arithmetic operation that can potentially result in unexpected side-effec LL | _n = -&_n; | ^^^^ -error: aborting due to 52 previous errors +error: aborting due to 55 previous errors From 2a6a98f95be4d630bac368b0bbd622749e999eb3 Mon Sep 17 00:00:00 2001 From: Caio Date: Mon, 3 Oct 2022 19:49:03 -0300 Subject: [PATCH 105/114] [arithmetic-side-effects] Do not ignore literal references --- .../src/operators/arithmetic_side_effects.rs | 45 ++++--- tests/ui/arithmetic_side_effects.rs | 4 +- tests/ui/arithmetic_side_effects.stderr | 124 ++++++++++-------- 3 files changed, 103 insertions(+), 70 deletions(-) diff --git a/clippy_lints/src/operators/arithmetic_side_effects.rs b/clippy_lints/src/operators/arithmetic_side_effects.rs index 9ba9cc1c517f8..54cbcd35587bd 100644 --- a/clippy_lints/src/operators/arithmetic_side_effects.rs +++ b/clippy_lints/src/operators/arithmetic_side_effects.rs @@ -1,8 +1,3 @@ -#![allow( - // False positive - clippy::match_same_arms -)] - use super::ARITHMETIC_SIDE_EFFECTS; use clippy_utils::{consts::constant_simple, diagnostics::span_lint}; use rustc_ast as ast; @@ -14,12 +9,12 @@ use rustc_session::impl_lint_pass; use rustc_span::source_map::{Span, Spanned}; const HARD_CODED_ALLOWED: &[&str] = &[ + "&str", "f32", "f64", "std::num::Saturating", "std::num::Wrapping", "std::string::String", - "&str", ]; #[derive(Debug)] @@ -79,16 +74,13 @@ impl ArithmeticSideEffects { self.expr_span = Some(expr.span); } - /// * If `expr` is a literal integer like `1` or `i32::MAX`, returns itself. - /// * Is `expr` is a literal integer reference like `&199`, returns the literal integer without - /// references. - /// * If `expr` is anything else, returns `None`. - fn literal_integer<'expr, 'tcx>(expr: &'expr hir::Expr<'tcx>) -> Option<&'expr hir::Expr<'tcx>> { + /// If `expr` does not match any variant of [LiteralIntegerTy], returns `None`. + fn literal_integer<'expr, 'tcx>(expr: &'expr hir::Expr<'tcx>) -> Option> { if matches!(expr.kind, hir::ExprKind::Lit(_)) { - return Some(expr); + return Some(LiteralIntegerTy::Value(expr)); } if let hir::ExprKind::AddrOf(.., inn) = expr.kind && let hir::ExprKind::Lit(_) = inn.kind { - return Some(inn) + return Some(LiteralIntegerTy::Ref(inn)); } None } @@ -127,9 +119,10 @@ impl ArithmeticSideEffects { 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, None) => false, - (None, Some(local_expr)) => Self::has_valid_op(op, local_expr), - (Some(local_expr), None) => Self::has_valid_op(op, local_expr), - (Some(_), Some(_)) => true, + (None, Some(lit_int_ty)) => Self::has_valid_op(op, lit_int_ty.into()), + (Some(lit_int_ty), None) => Self::has_valid_op(op, lit_int_ty.into()), + (Some(LiteralIntegerTy::Value(_)), Some(LiteralIntegerTy::Value(_))) => true, + (Some(_), Some(_)) => false, } } else { false @@ -186,3 +179,23 @@ impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects { } } } + +/// Tells if an expression is a integer passed 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> for &'expr hir::Expr<'tcx> { + fn from(from: LiteralIntegerTy<'expr, 'tcx>) -> Self { + match from { + LiteralIntegerTy::Ref(elem) => elem, + LiteralIntegerTy::Value(elem) => elem, + } + } +} diff --git a/tests/ui/arithmetic_side_effects.rs b/tests/ui/arithmetic_side_effects.rs index c9c0f8be65336..b25e68f13061b 100644 --- a/tests/ui/arithmetic_side_effects.rs +++ b/tests/ui/arithmetic_side_effects.rs @@ -148,7 +148,6 @@ pub fn non_overflowing_ops_or_ops_already_handled_by_the_compiler_should_not_tri _n = 1 * _n; _n = &1 * _n; _n = 23 + 85; - _n = &23 + &85; // Unary _n = -1; @@ -187,6 +186,9 @@ pub fn runtime_ops() { _n = _n * &2; _n = 2 * _n; _n = &2 * _n; + _n = 23 + &85; + _n = &23 + 85; + _n = &23 + &85; // Custom let _ = Custom + 0; diff --git a/tests/ui/arithmetic_side_effects.stderr b/tests/ui/arithmetic_side_effects.stderr index 8cabd05c2f98a..0f06e22bae96b 100644 --- a/tests/ui/arithmetic_side_effects.stderr +++ b/tests/ui/arithmetic_side_effects.stderr @@ -19,316 +19,334 @@ LL | let _ = inferred_string + ""; | ^^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:162:5 + --> $DIR/arithmetic_side_effects.rs:161:5 | LL | _n += 1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:163:5 + --> $DIR/arithmetic_side_effects.rs:162:5 | LL | _n += &1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:164:5 + --> $DIR/arithmetic_side_effects.rs:163:5 | LL | _n -= 1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:165:5 + --> $DIR/arithmetic_side_effects.rs:164:5 | LL | _n -= &1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:166:5 + --> $DIR/arithmetic_side_effects.rs:165:5 | LL | _n /= 0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:167:5 + --> $DIR/arithmetic_side_effects.rs:166:5 | LL | _n /= &0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:168:5 + --> $DIR/arithmetic_side_effects.rs:167:5 | LL | _n %= 0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:169:5 + --> $DIR/arithmetic_side_effects.rs:168:5 | LL | _n %= &0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:170:5 + --> $DIR/arithmetic_side_effects.rs:169:5 | LL | _n *= 2; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:171:5 + --> $DIR/arithmetic_side_effects.rs:170:5 | LL | _n *= &2; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:174:10 + --> $DIR/arithmetic_side_effects.rs:173:10 | LL | _n = _n + 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:175:10 + --> $DIR/arithmetic_side_effects.rs:174:10 | LL | _n = _n + &1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:176:10 + --> $DIR/arithmetic_side_effects.rs:175:10 | LL | _n = 1 + _n; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:177:10 + --> $DIR/arithmetic_side_effects.rs:176:10 | LL | _n = &1 + _n; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:178:10 + --> $DIR/arithmetic_side_effects.rs:177:10 | LL | _n = _n - 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:179:10 + --> $DIR/arithmetic_side_effects.rs:178:10 | LL | _n = _n - &1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:180:10 + --> $DIR/arithmetic_side_effects.rs:179:10 | LL | _n = 1 - _n; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:181:10 + --> $DIR/arithmetic_side_effects.rs:180:10 | LL | _n = &1 - _n; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:182:10 + --> $DIR/arithmetic_side_effects.rs:181:10 | LL | _n = _n / 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:183:10 + --> $DIR/arithmetic_side_effects.rs:182:10 | LL | _n = _n / &0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:184:10 + --> $DIR/arithmetic_side_effects.rs:183:10 | LL | _n = _n % 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:185:10 + --> $DIR/arithmetic_side_effects.rs:184:10 | LL | _n = _n % &0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:186:10 + --> $DIR/arithmetic_side_effects.rs:185:10 | LL | _n = _n * 2; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:187:10 + --> $DIR/arithmetic_side_effects.rs:186:10 | LL | _n = _n * &2; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:188:10 + --> $DIR/arithmetic_side_effects.rs:187:10 | LL | _n = 2 * _n; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:189:10 + --> $DIR/arithmetic_side_effects.rs:188:10 | LL | _n = &2 * _n; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:192:13 + --> $DIR/arithmetic_side_effects.rs:189:10 + | +LL | _n = 23 + &85; + | ^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:190:10 + | +LL | _n = &23 + 85; + | ^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:191:10 + | +LL | _n = &23 + &85; + | ^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:194:13 | LL | let _ = Custom + 0; | ^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:193:13 + --> $DIR/arithmetic_side_effects.rs:195:13 | LL | let _ = Custom + 1; | ^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:194:13 + --> $DIR/arithmetic_side_effects.rs:196:13 | LL | let _ = Custom + 2; | ^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:195:13 + --> $DIR/arithmetic_side_effects.rs:197:13 | LL | let _ = Custom + 0.0; | ^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:196:13 + --> $DIR/arithmetic_side_effects.rs:198:13 | LL | let _ = Custom + 1.0; | ^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:197:13 + --> $DIR/arithmetic_side_effects.rs:199:13 | LL | let _ = Custom + 2.0; | ^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:198:13 + --> $DIR/arithmetic_side_effects.rs:200:13 | LL | let _ = Custom - 0; | ^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:199:13 + --> $DIR/arithmetic_side_effects.rs:201:13 | LL | let _ = Custom - 1; | ^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:200:13 + --> $DIR/arithmetic_side_effects.rs:202:13 | LL | let _ = Custom - 2; | ^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:201:13 + --> $DIR/arithmetic_side_effects.rs:203:13 | LL | let _ = Custom - 0.0; | ^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:202:13 + --> $DIR/arithmetic_side_effects.rs:204:13 | LL | let _ = Custom - 1.0; | ^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:203:13 + --> $DIR/arithmetic_side_effects.rs:205:13 | LL | let _ = Custom - 2.0; | ^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:204:13 + --> $DIR/arithmetic_side_effects.rs:206:13 | LL | let _ = Custom / 0; | ^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:205:13 + --> $DIR/arithmetic_side_effects.rs:207:13 | LL | let _ = Custom / 1; | ^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:206:13 + --> $DIR/arithmetic_side_effects.rs:208:13 | LL | let _ = Custom / 2; | ^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:207:13 + --> $DIR/arithmetic_side_effects.rs:209:13 | LL | let _ = Custom / 0.0; | ^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:208:13 + --> $DIR/arithmetic_side_effects.rs:210:13 | LL | let _ = Custom / 1.0; | ^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:209:13 + --> $DIR/arithmetic_side_effects.rs:211:13 | LL | let _ = Custom / 2.0; | ^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:210:13 + --> $DIR/arithmetic_side_effects.rs:212:13 | LL | let _ = Custom * 0; | ^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:211:13 + --> $DIR/arithmetic_side_effects.rs:213:13 | LL | let _ = Custom * 1; | ^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:212:13 + --> $DIR/arithmetic_side_effects.rs:214:13 | LL | let _ = Custom * 2; | ^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:213:13 + --> $DIR/arithmetic_side_effects.rs:215:13 | LL | let _ = Custom * 0.0; | ^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:214:13 + --> $DIR/arithmetic_side_effects.rs:216:13 | LL | let _ = Custom * 1.0; | ^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:215:13 + --> $DIR/arithmetic_side_effects.rs:217:13 | LL | let _ = Custom * 2.0; | ^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:218:10 + --> $DIR/arithmetic_side_effects.rs:220:10 | LL | _n = -_n; | ^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:219:10 + --> $DIR/arithmetic_side_effects.rs:221:10 | LL | _n = -&_n; | ^^^^ -error: aborting due to 55 previous errors +error: aborting due to 58 previous errors From a44914fcd32eb3c0c3ff65f10b8b062e0b11b6f5 Mon Sep 17 00:00:00 2001 From: Caio Date: Mon, 3 Oct 2022 20:10:00 -0300 Subject: [PATCH 106/114] Dogfood --- .../src/operators/arithmetic_side_effects.rs | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/clippy_lints/src/operators/arithmetic_side_effects.rs b/clippy_lints/src/operators/arithmetic_side_effects.rs index 54cbcd35587bd..8827daaa3ee7c 100644 --- a/clippy_lints/src/operators/arithmetic_side_effects.rs +++ b/clippy_lints/src/operators/arithmetic_side_effects.rs @@ -45,10 +45,10 @@ impl ArithmeticSideEffects { let ast::LitKind::Int(value, _) = lit.node { match (&op.node, value) { - (hir::BinOpKind::Add | hir::BinOpKind::Sub, 0) | - (hir::BinOpKind::Mul, 0 | 1) => true, (hir::BinOpKind::Div | hir::BinOpKind::Rem, 0) => false, - (hir::BinOpKind::Div | hir::BinOpKind::Rem, _) => true, + (hir::BinOpKind::Add | hir::BinOpKind::Sub, 0) + | (hir::BinOpKind::Div | hir::BinOpKind::Rem, _) + | (hir::BinOpKind::Mul, 0 | 1) => true, _ => false, } } else { @@ -74,7 +74,7 @@ impl ArithmeticSideEffects { self.expr_span = Some(expr.span); } - /// If `expr` does not match any variant of [LiteralIntegerTy], returns `None`. + /// If `expr` does not match any variant of `LiteralIntegerTy`, returns `None`. fn literal_integer<'expr, 'tcx>(expr: &'expr hir::Expr<'tcx>) -> Option> { if matches!(expr.kind, hir::ExprKind::Lit(_)) { return Some(LiteralIntegerTy::Value(expr)); @@ -118,11 +118,9 @@ impl ArithmeticSideEffects { } 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, None) => false, - (None, Some(lit_int_ty)) => Self::has_valid_op(op, lit_int_ty.into()), - (Some(lit_int_ty), None) => Self::has_valid_op(op, lit_int_ty.into()), + (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, - (Some(_), Some(_)) => false, + (None, None) | (Some(_), Some(_)) => false, } } else { false @@ -180,9 +178,9 @@ impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects { } } -/// Tells if an expression is a integer passed by value or by reference. +/// 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 +/// If `LiteralIntegerTy::Ref`, then the contained value will be `hir::ExprKind::Lit` rather /// than `hirExprKind::Addr`. enum LiteralIntegerTy<'expr, 'tcx> { /// For example, `&199` @@ -194,8 +192,7 @@ enum LiteralIntegerTy<'expr, 'tcx> { impl<'expr, 'tcx> From> for &'expr hir::Expr<'tcx> { fn from(from: LiteralIntegerTy<'expr, 'tcx>) -> Self { match from { - LiteralIntegerTy::Ref(elem) => elem, - LiteralIntegerTy::Value(elem) => elem, + LiteralIntegerTy::Ref(elem) | LiteralIntegerTy::Value(elem) => elem, } } } From da16cc1da9814710e637ff242b71768a4d3724b7 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 4 Oct 2022 09:43:34 +0000 Subject: [PATCH 107/114] It's not about types or consts, but the lack of regions --- clippy_lints/src/dereference.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index e54d71fc8e417..f0d5ed6f594bd 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -1238,7 +1238,7 @@ fn ty_auto_deref_stability<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, precedenc ty::Adt(..) if ty.has_placeholders() || ty.has_opaque_types() => { Position::ReborrowStable(precedence).into() }, - ty::Adt(_, substs) if substs.has_param_types_or_consts() => { + ty::Adt(_, substs) if substs.has_non_region_param() => { TyPosition::new_deref_stable_for_result(precedence, ty) }, ty::Bool From 14f9f2b69d5306936296ce7a2e0db7809fd6a113 Mon Sep 17 00:00:00 2001 From: Andy-Python-Programmer Date: Wed, 5 Oct 2022 18:59:01 +1100 Subject: [PATCH 108/114] lint::unsafe_removed_from_name: fix false positive result when allowed * Allowing `unsafe_removed_from_name` on imports produces a false positive on `useless_attribute`. Fixes: #9197 Signed-off-by: Andy-Python-Programmer --- clippy_lints/src/attrs.rs | 3 ++- tests/ui/unsafe_removed_from_name.rs | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 5f45c69d7f98d..0bd1f8b784e8f 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -357,7 +357,8 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { "wildcard_imports" | "enum_glob_use" | "redundant_pub_crate" - | "macro_use_imports", + | "macro_use_imports" + | "unsafe_removed_from_name", ) }) { diff --git a/tests/ui/unsafe_removed_from_name.rs b/tests/ui/unsafe_removed_from_name.rs index cde4e96d668c2..d29888ac62f6b 100644 --- a/tests/ui/unsafe_removed_from_name.rs +++ b/tests/ui/unsafe_removed_from_name.rs @@ -24,4 +24,7 @@ use mod_with_some_unsafe_things::Unsafe as LieAboutModSafety; use mod_with_some_unsafe_things::Safe as IPromiseItsSafeThisTime; use mod_with_some_unsafe_things::Unsafe as SuperUnsafeModThing; +#[allow(clippy::unsafe_removed_from_name)] +use mod_with_some_unsafe_things::Unsafe as SuperSafeThing; + fn main() {} From 86c86c37429e95aee45846262bb50239a69be546 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Wed, 5 Oct 2022 13:44:01 +0000 Subject: [PATCH 109/114] Add `disallowed_macros` lint --- CHANGELOG.md | 1 + clippy_lints/src/await_holding_invalid.rs | 34 ++-- clippy_lints/src/disallowed_macros.rs | 151 ++++++++++++++++++ clippy_lints/src/disallowed_methods.rs | 15 +- clippy_lints/src/disallowed_types.rs | 20 +-- clippy_lints/src/lib.register_all.rs | 1 + clippy_lints/src/lib.register_lints.rs | 1 + clippy_lints/src/lib.register_style.rs | 1 + clippy_lints/src/lib.rs | 3 + .../src/missing_enforced_import_rename.rs | 3 +- clippy_lints/src/utils/conf.rs | 30 ++-- clippy_lints/src/utils/internal_lints.rs | 10 +- clippy_utils/src/lib.rs | 105 +++++++----- src/docs.rs | 1 + src/docs/disallowed_macros.txt | 36 +++++ .../disallowed_macros/auxiliary/macros.rs | 32 ++++ tests/ui-toml/disallowed_macros/clippy.toml | 11 ++ .../disallowed_macros/disallowed_macros.rs | 39 +++++ .../disallowed_macros.stderr | 84 ++++++++++ .../toml_disallowed_methods/clippy.toml | 1 + .../conf_disallowed_methods.rs | 6 + .../conf_disallowed_methods.stderr | 24 +-- .../toml_unknown_key/conf_unknown_key.stderr | 1 + 23 files changed, 500 insertions(+), 110 deletions(-) create mode 100644 clippy_lints/src/disallowed_macros.rs create mode 100644 src/docs/disallowed_macros.txt create mode 100644 tests/ui-toml/disallowed_macros/auxiliary/macros.rs create mode 100644 tests/ui-toml/disallowed_macros/clippy.toml create mode 100644 tests/ui-toml/disallowed_macros/disallowed_macros.rs create mode 100644 tests/ui-toml/disallowed_macros/disallowed_macros.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index bfeb009727b5b..42615179f7053 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3820,6 +3820,7 @@ Released 2018-09-13 [`derive_hash_xor_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_hash_xor_eq [`derive_ord_xor_partial_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_ord_xor_partial_ord [`derive_partial_eq_without_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_partial_eq_without_eq +[`disallowed_macros`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_macros [`disallowed_method`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_method [`disallowed_methods`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_methods [`disallowed_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_names diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs index 24a3588ecf16f..34717811866d8 100644 --- a/clippy_lints/src/await_holding_invalid.rs +++ b/clippy_lints/src/await_holding_invalid.rs @@ -1,14 +1,15 @@ 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::{def::Res, AsyncGeneratorKind, Body, BodyId, GeneratorKind}; +use rustc_hir::{AsyncGeneratorKind, Body, BodyId, GeneratorKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::GeneratorInteriorTypeCause; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{sym, Span}; -use crate::utils::conf::DisallowedType; +use crate::utils::conf::DisallowedPath; declare_clippy_lint! { /// ### What it does @@ -171,12 +172,12 @@ impl_lint_pass!(AwaitHolding => [AWAIT_HOLDING_LOCK, AWAIT_HOLDING_REFCELL_REF, #[derive(Debug)] pub struct AwaitHolding { - conf_invalid_types: Vec, - def_ids: FxHashMap, + conf_invalid_types: Vec, + def_ids: FxHashMap, } impl AwaitHolding { - pub(crate) fn new(conf_invalid_types: Vec) -> Self { + pub(crate) fn new(conf_invalid_types: Vec) -> Self { Self { conf_invalid_types, def_ids: FxHashMap::default(), @@ -187,11 +188,8 @@ impl AwaitHolding { impl LateLintPass<'_> for AwaitHolding { fn check_crate(&mut self, cx: &LateContext<'_>) { for conf in &self.conf_invalid_types { - let path = match conf { - DisallowedType::Simple(path) | DisallowedType::WithReason { path, .. } => path, - }; - let segs: Vec<_> = path.split("::").collect(); - if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &segs) { + let segs: Vec<_> = conf.path().split("::").collect(); + if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &segs, Some(Namespace::TypeNS)) { self.def_ids.insert(id, conf.clone()); } } @@ -256,20 +254,18 @@ impl AwaitHolding { } } -fn emit_invalid_type(cx: &LateContext<'_>, span: Span, disallowed: &DisallowedType) { - let (type_name, reason) = match disallowed { - DisallowedType::Simple(path) => (path, &None), - DisallowedType::WithReason { path, reason } => (path, reason), - }; - +fn emit_invalid_type(cx: &LateContext<'_>, span: Span, disallowed: &DisallowedPath) { span_lint_and_then( cx, AWAIT_HOLDING_INVALID_TYPE, span, - &format!("`{type_name}` may not be held across an `await` point per `clippy.toml`",), + &format!( + "`{}` may not be held across an `await` point per `clippy.toml`", + disallowed.path() + ), |diag| { - if let Some(reason) = reason { - diag.note(reason.clone()); + if let Some(reason) = disallowed.reason() { + diag.note(reason); } }, ); diff --git a/clippy_lints/src/disallowed_macros.rs b/clippy_lints/src/disallowed_macros.rs new file mode 100644 index 0000000000000..5ab7144e29098 --- /dev/null +++ b/clippy_lints/src/disallowed_macros.rs @@ -0,0 +1,151 @@ +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}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::{ExpnId, Span}; + +use crate::utils::conf; + +declare_clippy_lint! { + /// ### What it does + /// Denies the configured macros in clippy.toml + /// + /// Note: Even though this lint is warn-by-default, it will only trigger if + /// macros are defined in the clippy.toml file. + /// + /// ### Why is this bad? + /// Some macros are undesirable in certain contexts, and it's beneficial to + /// lint for them as needed. + /// + /// ### Example + /// An example clippy.toml configuration: + /// ```toml + /// # clippy.toml + /// disallowed-macros = [ + /// # Can use a string as the path of the disallowed macro. + /// "std::print", + /// # Can also use an inline table with a `path` key. + /// { path = "std::println" }, + /// # When using an inline table, can add a `reason` for why the macro + /// # is disallowed. + /// { path = "serde::Serialize", reason = "no serializing" }, + /// ] + /// ``` + /// ``` + /// use serde::Serialize; + /// + /// // Example code where clippy issues a warning + /// println!("warns"); + /// + /// // The diagnostic will contain the message "no serializing" + /// #[derive(Serialize)] + /// struct Data { + /// name: String, + /// value: usize, + /// } + /// ``` + #[clippy::version = "1.65.0"] + pub DISALLOWED_MACROS, + style, + "use of a disallowed macro" +} + +pub struct DisallowedMacros { + conf_disallowed: Vec, + disallowed: DefIdMap, + seen: FxHashSet, +} + +impl DisallowedMacros { + pub fn new(conf_disallowed: Vec) -> Self { + Self { + conf_disallowed, + disallowed: DefIdMap::default(), + seen: FxHashSet::default(), + } + } + + fn check(&mut self, cx: &LateContext<'_>, span: Span) { + if self.conf_disallowed.is_empty() { + return; + } + + for mac in macro_backtrace(span) { + if !self.seen.insert(mac.expn) { + return; + } + + if let Some(&index) = self.disallowed.get(&mac.def_id) { + let conf = &self.conf_disallowed[index]; + + span_lint_and_then( + cx, + DISALLOWED_MACROS, + mac.span, + &format!("use of a disallowed macro `{}`", conf.path()), + |diag| { + if let Some(reason) = conf.reason() { + diag.note(&format!("{reason} (from clippy.toml)")); + } + }, + ); + } + } + } +} + +impl_lint_pass!(DisallowedMacros => [DISALLOWED_MACROS]); + +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)) { + self.disallowed.insert(id, index); + } + } + } + + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + self.check(cx, expr.span); + } + + fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &Stmt<'_>) { + self.check(cx, stmt.span); + } + + fn check_ty(&mut self, cx: &LateContext<'_>, ty: &Ty<'_>) { + self.check(cx, ty.span); + } + + fn check_pat(&mut self, cx: &LateContext<'_>, pat: &Pat<'_>) { + self.check(cx, pat.span); + } + + fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { + self.check(cx, item.span); + self.check(cx, item.vis_span); + } + + fn check_foreign_item(&mut self, cx: &LateContext<'_>, item: &ForeignItem<'_>) { + self.check(cx, item.span); + self.check(cx, item.vis_span); + } + + fn check_impl_item(&mut self, cx: &LateContext<'_>, item: &ImplItem<'_>) { + self.check(cx, item.span); + self.check(cx, item.vis_span); + } + + fn check_trait_item(&mut self, cx: &LateContext<'_>, item: &TraitItem<'_>) { + self.check(cx, item.span); + } + + fn check_path(&mut self, cx: &LateContext<'_>, path: &Path<'_>, _: HirId) { + self.check(cx, path.span); + } +} diff --git a/clippy_lints/src/disallowed_methods.rs b/clippy_lints/src/disallowed_methods.rs index b02f87c07db73..1a381f92c0314 100644 --- a/clippy_lints/src/disallowed_methods.rs +++ b/clippy_lints/src/disallowed_methods.rs @@ -1,7 +1,9 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::{fn_def_id, get_parent_expr, path_def_id}; -use rustc_hir::{def::Res, def_id::DefIdMap, Expr, ExprKind}; +use rustc_hir::def::{Namespace, Res}; +use rustc_hir::def_id::DefIdMap; +use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; @@ -58,12 +60,12 @@ declare_clippy_lint! { #[derive(Clone, Debug)] pub struct DisallowedMethods { - conf_disallowed: Vec, + conf_disallowed: Vec, disallowed: DefIdMap, } impl DisallowedMethods { - pub fn new(conf_disallowed: Vec) -> Self { + pub fn new(conf_disallowed: Vec) -> Self { Self { conf_disallowed, disallowed: DefIdMap::default(), @@ -77,7 +79,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) { + if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &segs, Some(Namespace::ValueNS)) { self.disallowed.insert(id, index); } } @@ -102,10 +104,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 conf::DisallowedMethod::WithReason { - reason: Some(reason), .. - } = conf - { + if let Some(reason) = conf.reason() { diag.note(&format!("{reason} (from clippy.toml)")); } }); diff --git a/clippy_lints/src/disallowed_types.rs b/clippy_lints/src/disallowed_types.rs index debcd75ae75b6..c7131fc164d3e 100644 --- a/clippy_lints/src/disallowed_types.rs +++ b/clippy_lints/src/disallowed_types.rs @@ -1,7 +1,9 @@ use clippy_utils::diagnostics::span_lint_and_then; use rustc_data_structures::fx::FxHashMap; -use rustc_hir::{def::Res, def_id::DefId, Item, ItemKind, PolyTraitRef, PrimTy, Ty, TyKind, UseKind}; +use rustc_hir::def::{Namespace, Res}; +use rustc_hir::def_id::DefId; +use rustc_hir::{Item, ItemKind, PolyTraitRef, PrimTy, Ty, TyKind, UseKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::Span; @@ -50,13 +52,13 @@ declare_clippy_lint! { } #[derive(Clone, Debug)] pub struct DisallowedTypes { - conf_disallowed: Vec, + conf_disallowed: Vec, def_ids: FxHashMap>, prim_tys: FxHashMap>, } impl DisallowedTypes { - pub fn new(conf_disallowed: Vec) -> Self { + pub fn new(conf_disallowed: Vec) -> Self { Self { conf_disallowed, def_ids: FxHashMap::default(), @@ -86,15 +88,9 @@ 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 { - let (path, reason) = match conf { - conf::DisallowedType::Simple(path) => (path, None), - conf::DisallowedType::WithReason { path, reason } => ( - path, - reason.as_ref().map(|reason| format!("{reason} (from clippy.toml)")), - ), - }; - let segs: Vec<_> = path.split("::").collect(); - match clippy_utils::def_path_res(cx, &segs) { + 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); }, diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index 642d7070fb6ba..5d26e4b336012 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -45,6 +45,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ 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), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 08eb6c2b39bc4..05d927dbea794 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -114,6 +114,7 @@ store.register_lints(&[ 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, diff --git a/clippy_lints/src/lib.register_style.rs b/clippy_lints/src/lib.register_style.rs index 6d5483bc70102..8e1390167dc81 100644 --- a/clippy_lints/src/lib.register_style.rs +++ b/clippy_lints/src/lib.register_style.rs @@ -15,6 +15,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ 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), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index e5d26ac22a745..2dcefd78763b7 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -199,6 +199,7 @@ mod default_union_representation; mod dereference; mod derivable_impls; mod derive; +mod disallowed_macros; mod disallowed_methods; mod disallowed_names; mod disallowed_script_idents; @@ -820,6 +821,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(unwrap_in_result::UnwrapInResult)); store.register_late_pass(|_| Box::new(semicolon_if_nothing_returned::SemicolonIfNothingReturned)); store.register_late_pass(|_| Box::new(async_yields_async::AsyncYieldsAsync)); + let disallowed_macros = conf.disallowed_macros.clone(); + store.register_late_pass(move |_| Box::new(disallowed_macros::DisallowedMacros::new(disallowed_macros.clone()))); let disallowed_methods = conf.disallowed_methods.clone(); store.register_late_pass(move |_| Box::new(disallowed_methods::DisallowedMethods::new(disallowed_methods.clone()))); store.register_early_pass(|| Box::new(asm_syntax::InlineAsmX86AttSyntax)); diff --git a/clippy_lints/src/missing_enforced_import_rename.rs b/clippy_lints/src/missing_enforced_import_rename.rs index 697e6fd24dd11..872679f25ab5a 100644 --- a/clippy_lints/src/missing_enforced_import_rename.rs +++ b/clippy_lints/src/missing_enforced_import_rename.rs @@ -58,7 +58,8 @@ impl_lint_pass!(ImportRename => [MISSING_ENFORCED_IMPORT_RENAMES]); impl LateLintPass<'_> for ImportRename { fn check_crate(&mut self, cx: &LateContext<'_>) { for Rename { path, rename } in &self.conf_renames { - if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &path.split("::").collect::>()) { + let segs = path.split("::").collect::>(); + if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &segs, None) { self.renames.insert(id, Symbol::intern(rename)); } } diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 2b336e87ef76e..668123e4d6e39 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -39,28 +39,28 @@ pub struct Rename { pub rename: String, } -/// A single disallowed method, used by the `DISALLOWED_METHODS` lint. #[derive(Clone, Debug, Deserialize)] #[serde(untagged)] -pub enum DisallowedMethod { +pub enum DisallowedPath { Simple(String), WithReason { path: String, reason: Option }, } -impl DisallowedMethod { +impl DisallowedPath { pub fn path(&self) -> &str { let (Self::Simple(path) | Self::WithReason { path, .. }) = self; path } -} -/// A single disallowed type, used by the `DISALLOWED_TYPES` lint. -#[derive(Clone, Debug, Deserialize)] -#[serde(untagged)] -pub enum DisallowedType { - Simple(String), - WithReason { path: String, reason: Option }, + pub fn reason(&self) -> Option<&str> { + match self { + Self::WithReason { + reason: Some(reason), .. + } => Some(reason), + _ => None, + } + } } /// Conf with parse errors @@ -315,14 +315,18 @@ define_Conf! { /// /// Whether to allow certain wildcard imports (prelude, super in tests). (warn_on_all_wildcard_imports: bool = false), + /// Lint: DISALLOWED_MACROS. + /// + /// The list of disallowed macros, written as fully qualified paths. + (disallowed_macros: Vec = Vec::new()), /// Lint: DISALLOWED_METHODS. /// /// The list of disallowed methods, written as fully qualified paths. - (disallowed_methods: Vec = Vec::new()), + (disallowed_methods: Vec = Vec::new()), /// Lint: DISALLOWED_TYPES. /// /// The list of disallowed types, written as fully qualified paths. - (disallowed_types: Vec = Vec::new()), + (disallowed_types: Vec = Vec::new()), /// Lint: UNREADABLE_LITERAL. /// /// Should the fraction of a decimal be linted to include separators. @@ -362,7 +366,7 @@ define_Conf! { /// For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements. (max_suggested_slice_pattern_length: u64 = 3), /// Lint: AWAIT_HOLDING_INVALID_TYPE - (await_holding_invalid_types: Vec = Vec::new()), + (await_holding_invalid_types: Vec = Vec::new()), /// Lint: LARGE_INCLUDE_FILE. /// /// The maximum size of a file included via `include_bytes!()` or `include_str!()`, in bytes diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index 6309a04c73d5d..85bcbc7ad2369 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -15,7 +15,7 @@ use rustc_ast::visit::FnKind; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::def::{DefKind, Res}; +use rustc_hir::def::{DefKind, Namespace, Res}; use rustc_hir::def_id::DefId; use rustc_hir::hir_id::CRATE_HIR_ID; use rustc_hir::intravisit::Visitor; @@ -920,7 +920,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryDefPath { // Extract the path to the matched type if let Some(segments) = path_to_matched_type(cx, item_arg); let segments: Vec<&str> = segments.iter().map(|sym| &**sym).collect(); - if let Some(def_id) = def_path_res(cx, &segments[..]).opt_def_id(); + if let Some(def_id) = def_path_res(cx, &segments[..], None).opt_def_id(); then { // def_path_res will match field names before anything else, but for this we want to match // inherent functions first. @@ -952,7 +952,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryDefPath { Item::DiagnosticItem(*item_name), ) } else if let Some(lang_item) = cx.tcx.lang_items().items().iter().position(|id| *id == Some(def_id)) { - let lang_items = def_path_res(cx, &["rustc_hir", "lang_items", "LangItem"]).def_id(); + let lang_items = def_path_res(cx, &["rustc_hir", "lang_items", "LangItem"], Some(Namespace::TypeNS)).def_id(); let item_name = cx.tcx.adt_def(lang_items).variants().iter().nth(lang_item).unwrap().name; ( "use of a def path to a `LangItem`", @@ -1115,7 +1115,7 @@ fn read_mir_alloc_def_path<'tcx>(cx: &LateContext<'tcx>, alloc: &'tcx Allocation // This is not a complete resolver for paths. It works on all the paths currently used in the paths // module. That's all it does and all it needs to do. pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool { - if def_path_res(cx, path) != Res::Err { + if def_path_res(cx, path, None) != Res::Err { return true; } @@ -1206,7 +1206,7 @@ impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol { } for &module in &[&paths::KW_MODULE, &paths::SYM_MODULE] { - if let Some(def_id) = def_path_res(cx, module).opt_def_id() { + if let Some(def_id) = def_path_res(cx, module, None).opt_def_id() { for item in cx.tcx.module_children(def_id).iter() { if_chain! { if let Res::Def(DefKind::Const, item_def_id) = item.res; diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 3caa6380e0989..3919851932923 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -78,7 +78,7 @@ use rustc_ast::Attribute; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::unhash::UnhashMap; use rustc_hir as hir; -use rustc_hir::def::{DefKind, Res}; +use rustc_hir::def::{DefKind, Namespace, Res}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId}; use rustc_hir::hir_id::{HirIdMap, HirIdSet}; use rustc_hir::intravisit::{walk_expr, FnKind, Visitor}; @@ -522,15 +522,49 @@ pub fn path_def_id<'tcx>(cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx> path_res(cx, maybe_path).opt_def_id() } -/// Resolves a def path like `std::vec::Vec`. +fn find_primitive<'tcx>(tcx: TyCtxt<'tcx>, name: &str) -> impl Iterator + 'tcx { + let single = |ty| tcx.incoherent_impls(ty).iter().copied(); + let empty = || [].iter().copied(); + match name { + "bool" => single(BoolSimplifiedType), + "char" => single(CharSimplifiedType), + "str" => single(StrSimplifiedType), + "array" => single(ArraySimplifiedType), + "slice" => single(SliceSimplifiedType), + // FIXME: rustdoc documents these two using just `pointer`. + // + // Maybe this is something we should do here too. + "const_ptr" => single(PtrSimplifiedType(Mutability::Not)), + "mut_ptr" => single(PtrSimplifiedType(Mutability::Mut)), + "isize" => single(IntSimplifiedType(IntTy::Isize)), + "i8" => single(IntSimplifiedType(IntTy::I8)), + "i16" => single(IntSimplifiedType(IntTy::I16)), + "i32" => single(IntSimplifiedType(IntTy::I32)), + "i64" => single(IntSimplifiedType(IntTy::I64)), + "i128" => single(IntSimplifiedType(IntTy::I128)), + "usize" => single(UintSimplifiedType(UintTy::Usize)), + "u8" => single(UintSimplifiedType(UintTy::U8)), + "u16" => single(UintSimplifiedType(UintTy::U16)), + "u32" => single(UintSimplifiedType(UintTy::U32)), + "u64" => single(UintSimplifiedType(UintTy::U64)), + "u128" => single(UintSimplifiedType(UintTy::U128)), + "f32" => single(FloatSimplifiedType(FloatTy::F32)), + "f64" => single(FloatSimplifiedType(FloatTy::F64)), + _ => empty(), + } +} + +/// Resolves a def path like `std::vec::Vec`. `namespace_hint` can be supplied to disambiguate +/// between `std::vec` the module and `std::vec` the macro +/// /// This function is expensive and should be used sparingly. -pub fn def_path_res(cx: &LateContext<'_>, path: &[&str]) -> Res { - fn item_child_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: &str) -> Option { +pub fn def_path_res(cx: &LateContext<'_>, path: &[&str], namespace_hint: Option) -> Res { + fn item_child_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: &str, matches_ns: impl Fn(Res) -> bool) -> Option { match tcx.def_kind(def_id) { DefKind::Mod | DefKind::Enum | DefKind::Trait => tcx .module_children(def_id) .iter() - .find(|item| item.ident.name.as_str() == name) + .find(|item| item.ident.name.as_str() == name && matches_ns(item.res.expect_non_local())) .map(|child| child.res.expect_non_local()), DefKind::Impl => tcx .associated_item_def_ids(def_id) @@ -548,37 +582,7 @@ pub fn def_path_res(cx: &LateContext<'_>, path: &[&str]) -> Res { _ => None, } } - fn find_primitive<'tcx>(tcx: TyCtxt<'tcx>, name: &str) -> impl Iterator + 'tcx { - let single = |ty| tcx.incoherent_impls(ty).iter().copied(); - let empty = || [].iter().copied(); - match name { - "bool" => single(BoolSimplifiedType), - "char" => single(CharSimplifiedType), - "str" => single(StrSimplifiedType), - "array" => single(ArraySimplifiedType), - "slice" => single(SliceSimplifiedType), - // FIXME: rustdoc documents these two using just `pointer`. - // - // Maybe this is something we should do here too. - "const_ptr" => single(PtrSimplifiedType(Mutability::Not)), - "mut_ptr" => single(PtrSimplifiedType(Mutability::Mut)), - "isize" => single(IntSimplifiedType(IntTy::Isize)), - "i8" => single(IntSimplifiedType(IntTy::I8)), - "i16" => single(IntSimplifiedType(IntTy::I16)), - "i32" => single(IntSimplifiedType(IntTy::I32)), - "i64" => single(IntSimplifiedType(IntTy::I64)), - "i128" => single(IntSimplifiedType(IntTy::I128)), - "usize" => single(UintSimplifiedType(UintTy::Usize)), - "u8" => single(UintSimplifiedType(UintTy::U8)), - "u16" => single(UintSimplifiedType(UintTy::U16)), - "u32" => single(UintSimplifiedType(UintTy::U32)), - "u64" => single(UintSimplifiedType(UintTy::U64)), - "u128" => single(UintSimplifiedType(UintTy::U128)), - "f32" => single(FloatSimplifiedType(FloatTy::F32)), - "f64" => single(FloatSimplifiedType(FloatTy::F64)), - _ => empty(), - } - } + fn find_crate(tcx: TyCtxt<'_>, name: &str) -> Option { tcx.crates(()) .iter() @@ -587,32 +591,45 @@ pub fn def_path_res(cx: &LateContext<'_>, path: &[&str]) -> Res { .map(CrateNum::as_def_id) } - let (base, first, path) = match *path { - [base, first, ref path @ ..] => (base, first, path), + let (base, path) = match *path { [primitive] => { return PrimTy::from_name(Symbol::intern(primitive)).map_or(Res::Err, Res::PrimTy); }, + [base, ref path @ ..] => (base, path), _ => return Res::Err, }; let tcx = cx.tcx; let starts = find_primitive(tcx, base) .chain(find_crate(tcx, base)) - .filter_map(|id| item_child_by_name(tcx, id, first)); + .map(|id| Res::Def(tcx.def_kind(id), id)); for first in starts { let last = path .iter() .copied() + .enumerate() // for each segment, find the child item - .try_fold(first, |res, segment| { + .try_fold(first, |res, (idx, segment)| { + let matches_ns = |res: Res| { + // If at the last segment in the path, respect the namespace hint + if idx == path.len() - 1 { + match namespace_hint { + Some(ns) => res.matches_ns(ns), + None => true, + } + } else { + res.matches_ns(Namespace::TypeNS) + } + }; + let def_id = res.def_id(); - if let Some(item) = item_child_by_name(tcx, def_id, segment) { + if let Some(item) = item_child_by_name(tcx, def_id, segment, matches_ns) { Some(item) } else if matches!(res, Res::Def(DefKind::Enum | DefKind::Struct, _)) { // it is not a child item so check inherent impl items tcx.inherent_impls(def_id) .iter() - .find_map(|&impl_def_id| item_child_by_name(tcx, impl_def_id, segment)) + .find_map(|&impl_def_id| item_child_by_name(tcx, impl_def_id, segment, matches_ns)) } else { None } @@ -628,8 +645,10 @@ pub fn def_path_res(cx: &LateContext<'_>, path: &[&str]) -> Res { /// Convenience function to get the `DefId` of a trait by path. /// It could be a trait or trait alias. +/// +/// This function is expensive and should be used sparingly. pub fn get_trait_def_id(cx: &LateContext<'_>, path: &[&str]) -> Option { - match def_path_res(cx, path) { + match def_path_res(cx, path, Some(Namespace::TypeNS)) { Res::Def(DefKind::Trait | DefKind::TraitAlias, trait_id) => Some(trait_id), _ => None, } diff --git a/src/docs.rs b/src/docs.rs index 1b727e1a10049..3bf488ab4779b 100644 --- a/src/docs.rs +++ b/src/docs.rs @@ -106,6 +106,7 @@ docs! { "derive_hash_xor_eq", "derive_ord_xor_partial_ord", "derive_partial_eq_without_eq", + "disallowed_macros", "disallowed_methods", "disallowed_names", "disallowed_script_idents", diff --git a/src/docs/disallowed_macros.txt b/src/docs/disallowed_macros.txt new file mode 100644 index 0000000000000..96fa15afabfd2 --- /dev/null +++ b/src/docs/disallowed_macros.txt @@ -0,0 +1,36 @@ +### What it does +Denies the configured macros in clippy.toml + +Note: Even though this lint is warn-by-default, it will only trigger if +macros are defined in the clippy.toml file. + +### Why is this bad? +Some macros are undesirable in certain contexts, and it's beneficial to +lint for them as needed. + +### Example +An example clippy.toml configuration: +``` +disallowed-macros = [ + # Can use a string as the path of the disallowed macro. + "std::print", + # Can also use an inline table with a `path` key. + { path = "std::println" }, + # When using an inline table, can add a `reason` for why the macro + # is disallowed. + { path = "serde::Serialize", reason = "no serializing" }, +] +``` +``` +use serde::Serialize; + +// Example code where clippy issues a warning +println!("warns"); + +// The diagnostic will contain the message "no serializing" +#[derive(Serialize)] +struct Data { + name: String, + value: usize, +} +``` \ No newline at end of file diff --git a/tests/ui-toml/disallowed_macros/auxiliary/macros.rs b/tests/ui-toml/disallowed_macros/auxiliary/macros.rs new file mode 100644 index 0000000000000..fcaeace0e9890 --- /dev/null +++ b/tests/ui-toml/disallowed_macros/auxiliary/macros.rs @@ -0,0 +1,32 @@ +#[macro_export] +macro_rules! expr { + () => { + 1 + }; +} + +#[macro_export] +macro_rules! stmt { + () => { + let _x = (); + }; +} + +#[macro_export] +macro_rules! ty { + () => { &'static str }; +} + +#[macro_export] +macro_rules! pat { + () => { + _ + }; +} + +#[macro_export] +macro_rules! item { + () => { + const ITEM: usize = 1; + }; +} diff --git a/tests/ui-toml/disallowed_macros/clippy.toml b/tests/ui-toml/disallowed_macros/clippy.toml new file mode 100644 index 0000000000000..c8fe8be9a7704 --- /dev/null +++ b/tests/ui-toml/disallowed_macros/clippy.toml @@ -0,0 +1,11 @@ +disallowed-macros = [ + "std::println", + "std::vec", + { path = "std::cfg" }, + { path = "serde::Serialize", reason = "no serializing" }, + "macros::expr", + "macros::stmt", + "macros::ty", + "macros::pat", + "macros::item", +] diff --git a/tests/ui-toml/disallowed_macros/disallowed_macros.rs b/tests/ui-toml/disallowed_macros/disallowed_macros.rs new file mode 100644 index 0000000000000..2bb5376076e28 --- /dev/null +++ b/tests/ui-toml/disallowed_macros/disallowed_macros.rs @@ -0,0 +1,39 @@ +// aux-build:macros.rs + +#![allow(unused)] + +extern crate macros; + +use serde::Serialize; + +fn main() { + println!("one"); + println!("two"); + cfg!(unix); + vec![1, 2, 3]; + + #[derive(Serialize)] + struct Derive; + + let _ = macros::expr!(); + macros::stmt!(); + let macros::pat!() = 1; + let _: macros::ty!() = ""; + macros::item!(); + + eprintln!("allowed"); +} + +struct S; + +impl S { + macros::item!(); +} + +trait Y { + macros::item!(); +} + +impl Y for S { + macros::item!(); +} diff --git a/tests/ui-toml/disallowed_macros/disallowed_macros.stderr b/tests/ui-toml/disallowed_macros/disallowed_macros.stderr new file mode 100644 index 0000000000000..aed9feb6f796c --- /dev/null +++ b/tests/ui-toml/disallowed_macros/disallowed_macros.stderr @@ -0,0 +1,84 @@ +error: use of a disallowed macro `std::println` + --> $DIR/disallowed_macros.rs:10:5 + | +LL | println!("one"); + | ^^^^^^^^^^^^^^^ + | + = note: `-D clippy::disallowed-macros` implied by `-D warnings` + +error: use of a disallowed macro `std::println` + --> $DIR/disallowed_macros.rs:11:5 + | +LL | println!("two"); + | ^^^^^^^^^^^^^^^ + +error: use of a disallowed macro `std::cfg` + --> $DIR/disallowed_macros.rs:12:5 + | +LL | cfg!(unix); + | ^^^^^^^^^^ + +error: use of a disallowed macro `std::vec` + --> $DIR/disallowed_macros.rs:13:5 + | +LL | vec![1, 2, 3]; + | ^^^^^^^^^^^^^ + +error: use of a disallowed macro `serde::Serialize` + --> $DIR/disallowed_macros.rs:15:14 + | +LL | #[derive(Serialize)] + | ^^^^^^^^^ + | + = note: no serializing (from clippy.toml) + +error: use of a disallowed macro `macros::expr` + --> $DIR/disallowed_macros.rs:18:13 + | +LL | let _ = macros::expr!(); + | ^^^^^^^^^^^^^^^ + +error: use of a disallowed macro `macros::stmt` + --> $DIR/disallowed_macros.rs:19:5 + | +LL | macros::stmt!(); + | ^^^^^^^^^^^^^^^ + +error: use of a disallowed macro `macros::pat` + --> $DIR/disallowed_macros.rs:20:9 + | +LL | let macros::pat!() = 1; + | ^^^^^^^^^^^^^^ + +error: use of a disallowed macro `macros::ty` + --> $DIR/disallowed_macros.rs:21:12 + | +LL | let _: macros::ty!() = ""; + | ^^^^^^^^^^^^^ + +error: use of a disallowed macro `macros::item` + --> $DIR/disallowed_macros.rs:22:5 + | +LL | macros::item!(); + | ^^^^^^^^^^^^^^^ + +error: use of a disallowed macro `macros::item` + --> $DIR/disallowed_macros.rs:30:5 + | +LL | macros::item!(); + | ^^^^^^^^^^^^^^^ + +error: use of a disallowed macro `macros::item` + --> $DIR/disallowed_macros.rs:34:5 + | +LL | macros::item!(); + | ^^^^^^^^^^^^^^^ + +error: use of a disallowed macro `macros::item` + --> $DIR/disallowed_macros.rs:38:5 + | +LL | macros::item!(); + | ^^^^^^^^^^^^^^^ + +error: aborting due to 13 previous errors + diff --git a/tests/ui-toml/toml_disallowed_methods/clippy.toml b/tests/ui-toml/toml_disallowed_methods/clippy.toml index c902d21123dce..28774db625bb7 100644 --- a/tests/ui-toml/toml_disallowed_methods/clippy.toml +++ b/tests/ui-toml/toml_disallowed_methods/clippy.toml @@ -3,6 +3,7 @@ disallowed-methods = [ "std::iter::Iterator::sum", "f32::clamp", "slice::sort_unstable", + "futures::stream::select_all", # can give path and reason with an inline table { path = "regex::Regex::is_match", reason = "no matching allowed" }, # can use an inline table but omit reason diff --git a/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs b/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs index 3397fa1ec6927..b483f16002897 100644 --- a/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs +++ b/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs @@ -1,6 +1,9 @@ #![warn(clippy::disallowed_methods)] +extern crate futures; extern crate regex; + +use futures::stream::{empty, select_all}; use regex::Regex; fn main() { @@ -20,4 +23,7 @@ fn main() { let in_call = Box::new(f32::clamp); let in_method_call = ["^", "$"].into_iter().map(Regex::new); + + // resolve ambiguity between `futures::stream::select_all` the module and the function + let same_name_as_module = select_all(vec![empty::<()>()]); } diff --git a/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr b/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr index 5cbb567546c08..6d78c32e127ee 100644 --- a/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr +++ b/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr @@ -1,5 +1,5 @@ error: use of a disallowed method `regex::Regex::new` - --> $DIR/conf_disallowed_methods.rs:7:14 + --> $DIR/conf_disallowed_methods.rs:10:14 | LL | let re = Regex::new(r"ab.*c").unwrap(); | ^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | let re = Regex::new(r"ab.*c").unwrap(); = note: `-D clippy::disallowed-methods` implied by `-D warnings` error: use of a disallowed method `regex::Regex::is_match` - --> $DIR/conf_disallowed_methods.rs:8:5 + --> $DIR/conf_disallowed_methods.rs:11:5 | LL | re.is_match("abc"); | ^^^^^^^^^^^^^^^^^^ @@ -15,40 +15,46 @@ LL | re.is_match("abc"); = note: no matching allowed (from clippy.toml) error: use of a disallowed method `std::iter::Iterator::sum` - --> $DIR/conf_disallowed_methods.rs:11:5 + --> $DIR/conf_disallowed_methods.rs:14:5 | LL | a.iter().sum::(); | ^^^^^^^^^^^^^^^^^^^^^ error: use of a disallowed method `slice::sort_unstable` - --> $DIR/conf_disallowed_methods.rs:13:5 + --> $DIR/conf_disallowed_methods.rs:16:5 | LL | a.sort_unstable(); | ^^^^^^^^^^^^^^^^^ error: use of a disallowed method `f32::clamp` - --> $DIR/conf_disallowed_methods.rs:15:13 + --> $DIR/conf_disallowed_methods.rs:18:13 | LL | let _ = 2.0f32.clamp(3.0f32, 4.0f32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of a disallowed method `regex::Regex::new` - --> $DIR/conf_disallowed_methods.rs:18:61 + --> $DIR/conf_disallowed_methods.rs:21:61 | LL | let indirect: fn(&str) -> Result = Regex::new; | ^^^^^^^^^^ error: use of a disallowed method `f32::clamp` - --> $DIR/conf_disallowed_methods.rs:21:28 + --> $DIR/conf_disallowed_methods.rs:24:28 | LL | let in_call = Box::new(f32::clamp); | ^^^^^^^^^^ error: use of a disallowed method `regex::Regex::new` - --> $DIR/conf_disallowed_methods.rs:22:53 + --> $DIR/conf_disallowed_methods.rs:25:53 | LL | let in_method_call = ["^", "$"].into_iter().map(Regex::new); | ^^^^^^^^^^ -error: aborting due to 8 previous errors +error: use of a disallowed method `futures::stream::select_all` + --> $DIR/conf_disallowed_methods.rs:28:31 + | +LL | let same_name_as_module = select_all(vec![empty::<()>()]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 9 previous errors diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index f27f78d15d3a0..82ee805413217 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -11,6 +11,7 @@ error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown fie cargo-ignore-publish cognitive-complexity-threshold cyclomatic-complexity-threshold + disallowed-macros disallowed-methods disallowed-names disallowed-types From 9226066bcb40745dbb91965c3d5d9210294b1c88 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Wed, 5 Oct 2022 16:10:52 +0000 Subject: [PATCH 110/114] FormatArgsExpn: Find comma spans and ignore weird proc macro spans --- clippy_lints/src/format_args.rs | 13 +- clippy_lints/src/write.rs | 6 +- clippy_utils/src/macros.rs | 109 +++++++++++++++- tests/ui/expect_fun_call.fixed | 6 + tests/ui/expect_fun_call.rs | 6 + tests/ui/expect_fun_call.stderr | 14 ++- tests/ui/uninlined_format_args.fixed | 22 ++-- tests/ui/uninlined_format_args.rs | 24 ++-- tests/ui/uninlined_format_args.stderr | 172 +++++++++++++++----------- 9 files changed, 262 insertions(+), 110 deletions(-) diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index 89d81bdd4850e..88502b7261801 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -1,13 +1,13 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::macros::FormatParamKind::{Implicit, Named, Numbered, Starred}; use clippy_utils::macros::{is_format_macro, FormatArgsExpn, FormatParam, FormatParamUsage}; -use clippy_utils::source::{expand_past_previous_comma, snippet_opt}; +use clippy_utils::source::snippet_opt; use clippy_utils::ty::implements_trait; use clippy_utils::{is_diag_trait_item, meets_msrv, msrvs}; use if_chain::if_chain; use itertools::Itertools; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, HirId, Path, QPath}; +use rustc_hir::{Expr, ExprKind, HirId, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::adjustment::{Adjust, Adjustment}; use rustc_middle::ty::Ty; @@ -169,7 +169,7 @@ fn check_uninlined_args(cx: &LateContext<'_>, args: &FormatArgsExpn<'_>, call_si // we cannot remove any other arguments in the format string, // because the index numbers might be wrong after inlining. // Example of an un-inlinable format: print!("{}{1}", foo, 2) - if !args.params().all(|p| check_one_arg(cx, &p, &mut fixes)) || fixes.is_empty() { + if !args.params().all(|p| check_one_arg(args, &p, &mut fixes)) || fixes.is_empty() { return; } @@ -196,11 +196,11 @@ fn check_uninlined_args(cx: &LateContext<'_>, args: &FormatArgsExpn<'_>, call_si ); } -fn check_one_arg(cx: &LateContext<'_>, param: &FormatParam<'_>, fixes: &mut Vec<(Span, String)>) -> bool { +fn check_one_arg(args: &FormatArgsExpn<'_>, param: &FormatParam<'_>, fixes: &mut Vec<(Span, String)>) -> bool { if matches!(param.kind, Implicit | Starred | Named(_) | Numbered) && let ExprKind::Path(QPath::Resolved(None, path)) = param.value.kind - && let Path { span, segments, .. } = path - && let [segment] = segments + && let [segment] = path.segments + && let Some(arg_span) = args.value_with_prev_comma_span(param.value.hir_id) { let replacement = match param.usage { FormatParamUsage::Argument => segment.ident.name.to_string(), @@ -208,7 +208,6 @@ fn check_one_arg(cx: &LateContext<'_>, param: &FormatParam<'_>, fixes: &mut Vec< FormatParamUsage::Precision => format!(".{}$", segment.ident.name), }; fixes.push((param.span, replacement)); - let arg_span = expand_past_previous_comma(cx, *span); fixes.push((arg_span, String::new())); true // successful inlining, continue checking } else { diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index 3d3686604b72a..36574198f9174 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -475,11 +475,11 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgsExpn<'_>, name: & value.span, "literal with an empty format string", |diag| { - if let Some(replacement) = replacement { + if let Some(replacement) = replacement // `format!("{}", "a")`, `format!("{named}", named = "b") // ~~~~~ ~~~~~~~~~~~~~ - let value_span = expand_past_previous_comma(cx, value.span); - + && let Some(value_span) = format_args.value_with_prev_comma_span(value.hir_id) + { let replacement = replacement.replace('{', "{{").replace('}', "}}"); diag.multipart_suggestion( "try this", diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs index dda21b903901f..dd0ce1da65759 100644 --- a/clippy_utils/src/macros.rs +++ b/clippy_utils/src/macros.rs @@ -16,6 +16,7 @@ use rustc_parse_format::{self as rpf, Alignment}; use rustc_span::def_id::DefId; use rustc_span::hygiene::{self, MacroKind, SyntaxContext}; use rustc_span::{sym, BytePos, ExpnData, ExpnId, ExpnKind, Pos, Span, SpanData, Symbol}; +use std::iter::{once, zip}; use std::ops::ControlFlow; const FORMAT_MACRO_DIAG_ITEMS: &[Symbol] = &[ @@ -412,7 +413,8 @@ impl FormatString { } struct FormatArgsValues<'tcx> { - /// See `FormatArgsExpn::value_args` + /// Values passed after the format string and implicit captures. `[1, z + 2, x]` for + /// `format!("{x} {} {y}", 1, z + 2)`. value_args: Vec<&'tcx Expr<'tcx>>, /// Maps an `rt::v1::Argument::position` or an `rt::v1::Count::Param` to its index in /// `value_args` @@ -765,12 +767,82 @@ pub struct FormatArgsExpn<'tcx> { /// Has an added newline due to `println!()`/`writeln!()`/etc. The last format string part will /// include this added newline. pub newline: bool, - /// Values passed after the format string and implicit captures. `[1, z + 2, x]` for + /// Spans of the commas between the format string and explicit values, excluding any trailing + /// comma + /// + /// ```ignore + /// format!("..", 1, 2, 3,) + /// // ^ ^ ^ + /// ``` + comma_spans: Vec, + /// Explicit values passed after the format string, ignoring implicit captures. `[1, z + 2]` for /// `format!("{x} {} {y}", 1, z + 2)`. - value_args: Vec<&'tcx Expr<'tcx>>, + explicit_values: Vec<&'tcx Expr<'tcx>>, } impl<'tcx> FormatArgsExpn<'tcx> { + /// Gets the spans of the commas inbetween the format string and explicit args, not including + /// any trailing comma + /// + /// ```ignore + /// format!("{} {}", a, b) + /// // ^ ^ + /// ``` + /// + /// Ensures that the format string and values aren't coming from a proc macro that sets the + /// output span to that of its input + fn comma_spans(cx: &LateContext<'_>, explicit_values: &[&Expr<'_>], fmt_span: Span) -> Option> { + // `format!("{} {} {c}", "one", "two", c = "three")` + // ^^^^^ ^^^^^ ^^^^^^^ + let value_spans = explicit_values + .iter() + .map(|val| hygiene::walk_chain(val.span, fmt_span.ctxt())); + + // `format!("{} {} {c}", "one", "two", c = "three")` + // ^^ ^^ ^^^^^^ + let between_spans = once(fmt_span) + .chain(value_spans) + .tuple_windows() + .map(|(start, end)| start.between(end)); + + let mut comma_spans = Vec::new(); + for between_span in between_spans { + let mut offset = 0; + let mut seen_comma = false; + + for token in tokenize(&snippet_opt(cx, between_span)?) { + match token.kind { + TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } | TokenKind::Whitespace => {}, + TokenKind::Comma if !seen_comma => { + seen_comma = true; + + let base = between_span.data(); + comma_spans.push(Span::new( + base.lo + BytePos(offset), + base.lo + BytePos(offset + 1), + base.ctxt, + base.parent, + )); + }, + // named arguments, `start_val, name = end_val` + // ^^^^^^^^^ between_span + TokenKind::Ident | TokenKind::Eq if seen_comma => {}, + // An unexpected token usually indicates the format string or a value came from a proc macro output + // that sets the span of its output to an input, e.g. `println!(some_proc_macro!("input"), ..)` that + // emits a string literal with the span set to that of `"input"` + _ => return None, + } + offset += token.len; + } + + if !seen_comma { + return None; + } + } + + Some(comma_spans) + } + pub fn parse(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option { let macro_name = macro_backtrace(expr.span) .map(|macro_call| cx.tcx.item_name(macro_call.def_id)) @@ -845,11 +917,22 @@ impl<'tcx> FormatArgsExpn<'tcx> { }) .collect::>>()?; + let mut explicit_values = values.value_args; + // remove values generated for implicitly captured vars + let len = explicit_values + .iter() + .take_while(|val| !format_string.span.contains(val.span)) + .count(); + explicit_values.truncate(len); + + let comma_spans = Self::comma_spans(cx, &explicit_values, format_string.span)?; + Some(Self { format_string, args, - value_args: values.value_args, newline, + comma_spans, + explicit_values, }) } else { None @@ -875,7 +958,7 @@ impl<'tcx> FormatArgsExpn<'tcx> { /// Source callsite span of all inputs pub fn inputs_span(&self) -> Span { - match *self.value_args { + match *self.explicit_values { [] => self.format_string.span, [.., last] => self .format_string @@ -884,6 +967,22 @@ impl<'tcx> FormatArgsExpn<'tcx> { } } + /// Get the span of a value expanded to the previous comma, e.g. for the value `10` + /// + /// ```ignore + /// format("{}.{}", 10, 11) + /// // ^^^^ + /// ``` + pub fn value_with_prev_comma_span(&self, value_id: HirId) -> Option { + for (comma_span, value) in zip(&self.comma_spans, &self.explicit_values) { + if value.hir_id == value_id { + return Some(comma_span.to(hygiene::walk_chain(value.span, comma_span.ctxt()))); + } + } + + None + } + /// Iterator of all format params, both values and those referenced by `width`/`precision`s. pub fn params(&'tcx self) -> impl Iterator> { self.args diff --git a/tests/ui/expect_fun_call.fixed b/tests/ui/expect_fun_call.fixed index c118403b77320..15172ae345c2e 100644 --- a/tests/ui/expect_fun_call.fixed +++ b/tests/ui/expect_fun_call.fixed @@ -100,4 +100,10 @@ fn main() { let opt_ref = &opt; opt_ref.unwrap_or_else(|| panic!("{:?}", opt_ref)); } + + let format_capture: Option = None; + format_capture.unwrap_or_else(|| panic!("{error_code}")); + + let format_capture_and_value: Option = None; + format_capture_and_value.unwrap_or_else(|| panic!("{error_code}, {}", 1)); } diff --git a/tests/ui/expect_fun_call.rs b/tests/ui/expect_fun_call.rs index 7f4a8bc7aa68d..0f448d004174f 100644 --- a/tests/ui/expect_fun_call.rs +++ b/tests/ui/expect_fun_call.rs @@ -100,4 +100,10 @@ fn main() { let opt_ref = &opt; opt_ref.expect(&format!("{:?}", opt_ref)); } + + let format_capture: Option = None; + format_capture.expect(&format!("{error_code}")); + + let format_capture_and_value: Option = None; + format_capture_and_value.expect(&format!("{error_code}, {}", 1)); } diff --git a/tests/ui/expect_fun_call.stderr b/tests/ui/expect_fun_call.stderr index e76c03ecf16ef..cb55e32aee02e 100644 --- a/tests/ui/expect_fun_call.stderr +++ b/tests/ui/expect_fun_call.stderr @@ -78,5 +78,17 @@ error: use of `expect` followed by a function call LL | opt_ref.expect(&format!("{:?}", opt_ref)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("{:?}", opt_ref))` -error: aborting due to 13 previous errors +error: use of `expect` followed by a function call + --> $DIR/expect_fun_call.rs:105:20 + | +LL | format_capture.expect(&format!("{error_code}")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("{error_code}"))` + +error: use of `expect` followed by a function call + --> $DIR/expect_fun_call.rs:108:30 + | +LL | format_capture_and_value.expect(&format!("{error_code}, {}", 1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("{error_code}, {}", 1))` + +error: aborting due to 15 previous errors diff --git a/tests/ui/uninlined_format_args.fixed b/tests/ui/uninlined_format_args.fixed index 931916819ce2e..dcf10ed60a259 100644 --- a/tests/ui/uninlined_format_args.fixed +++ b/tests/ui/uninlined_format_args.fixed @@ -1,21 +1,19 @@ +// aux-build:proc_macro_with_span.rs // run-rustfix #![feature(custom_inner_attributes)] #![warn(clippy::uninlined_format_args)] #![allow(named_arguments_used_positionally, unused_imports, unused_macros, unused_variables)] #![allow(clippy::eq_op, clippy::format_in_format_args, clippy::print_literal)] +extern crate proc_macro_with_span; +use proc_macro_with_span::with_span; + macro_rules! no_param_str { () => { "{}" }; } -macro_rules! pass_through { - ($expr:expr) => { - $expr - }; -} - macro_rules! my_println { ($($args:tt),*) => {{ println!($($args),*) @@ -140,11 +138,13 @@ fn tester(fn_arg: i32) { ); println!(no_param_str!(), local_i32); - // FIXME: bugs! - // println!(pass_through!("foo={local_i32}"), local_i32 = local_i32); - // println!(pass_through!("foo={}"), local_i32); - // println!(indoc!("foo={}"), local_i32); - // printdoc!("foo={}", local_i32); + println!( + "{val}", + ); + println!("{val}"); + + println!(with_span!("{0} {1}" "{1} {0}"), local_i32, local_f64); + println!("{}", with_span!(span val)); } fn main() { diff --git a/tests/ui/uninlined_format_args.rs b/tests/ui/uninlined_format_args.rs index 0a9086775143b..924191f4324cf 100644 --- a/tests/ui/uninlined_format_args.rs +++ b/tests/ui/uninlined_format_args.rs @@ -1,21 +1,19 @@ +// aux-build:proc_macro_with_span.rs // run-rustfix #![feature(custom_inner_attributes)] #![warn(clippy::uninlined_format_args)] #![allow(named_arguments_used_positionally, unused_imports, unused_macros, unused_variables)] #![allow(clippy::eq_op, clippy::format_in_format_args, clippy::print_literal)] +extern crate proc_macro_with_span; +use proc_macro_with_span::with_span; + macro_rules! no_param_str { () => { "{}" }; } -macro_rules! pass_through { - ($expr:expr) => { - $expr - }; -} - macro_rules! my_println { ($($args:tt),*) => {{ println!($($args),*) @@ -143,11 +141,15 @@ fn tester(fn_arg: i32) { ); println!(no_param_str!(), local_i32); - // FIXME: bugs! - // println!(pass_through!("foo={local_i32}"), local_i32 = local_i32); - // println!(pass_through!("foo={}"), local_i32); - // println!(indoc!("foo={}"), local_i32); - // printdoc!("foo={}", local_i32); + println!( + "{}", + // comment with a comma , in it + val, + ); + println!("{}", /* comment with a comma , in it */ val); + + println!(with_span!("{0} {1}" "{1} {0}"), local_i32, local_f64); + println!("{}", with_span!(span val)); } fn main() { diff --git a/tests/ui/uninlined_format_args.stderr b/tests/ui/uninlined_format_args.stderr index 6c8f3f4334807..1b4dada28daca 100644 --- a/tests/ui/uninlined_format_args.stderr +++ b/tests/ui/uninlined_format_args.stderr @@ -1,5 +1,5 @@ error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:43:5 + --> $DIR/uninlined_format_args.rs:41:5 | LL | println!("val='{}'", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -12,7 +12,7 @@ LL + println!("val='{local_i32}'"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:44:5 + --> $DIR/uninlined_format_args.rs:42:5 | LL | println!("val='{ }'", local_i32); // 3 spaces | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL + println!("val='{local_i32}'"); // 3 spaces | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:45:5 + --> $DIR/uninlined_format_args.rs:43:5 | LL | println!("val='{ }'", local_i32); // tab | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -36,7 +36,7 @@ LL + println!("val='{local_i32}'"); // tab | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:46:5 + --> $DIR/uninlined_format_args.rs:44:5 | LL | println!("val='{ }'", local_i32); // space+tab | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -48,7 +48,7 @@ LL + println!("val='{local_i32}'"); // space+tab | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:47:5 + --> $DIR/uninlined_format_args.rs:45:5 | LL | println!("val='{ }'", local_i32); // tab+space | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -60,7 +60,7 @@ LL + println!("val='{local_i32}'"); // tab+space | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:48:5 + --> $DIR/uninlined_format_args.rs:46:5 | LL | / println!( LL | | "val='{ @@ -76,7 +76,7 @@ LL + "val='{local_i32}'" | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:53:5 + --> $DIR/uninlined_format_args.rs:51:5 | LL | println!("{}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -88,7 +88,7 @@ LL + println!("{local_i32}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:54:5 + --> $DIR/uninlined_format_args.rs:52:5 | LL | println!("{}", fn_arg); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -100,7 +100,7 @@ LL + println!("{fn_arg}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:55:5 + --> $DIR/uninlined_format_args.rs:53:5 | LL | println!("{:?}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -112,7 +112,7 @@ LL + println!("{local_i32:?}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:56:5 + --> $DIR/uninlined_format_args.rs:54:5 | LL | println!("{:#?}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -124,7 +124,7 @@ LL + println!("{local_i32:#?}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:57:5 + --> $DIR/uninlined_format_args.rs:55:5 | LL | println!("{:4}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -136,7 +136,7 @@ LL + println!("{local_i32:4}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:58:5 + --> $DIR/uninlined_format_args.rs:56:5 | LL | println!("{:04}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -148,7 +148,7 @@ LL + println!("{local_i32:04}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:59:5 + --> $DIR/uninlined_format_args.rs:57:5 | LL | println!("{:<3}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -160,7 +160,7 @@ LL + println!("{local_i32:<3}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:60:5 + --> $DIR/uninlined_format_args.rs:58:5 | LL | println!("{:#010x}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -172,7 +172,7 @@ LL + println!("{local_i32:#010x}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:61:5 + --> $DIR/uninlined_format_args.rs:59:5 | LL | println!("{:.1}", local_f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -184,7 +184,7 @@ LL + println!("{local_f64:.1}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:62:5 + --> $DIR/uninlined_format_args.rs:60:5 | LL | println!("Hello {} is {:.*}", "x", local_i32, local_f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -196,7 +196,7 @@ LL + println!("Hello {} is {local_f64:.local_i32$}", "x"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:63:5 + --> $DIR/uninlined_format_args.rs:61:5 | LL | println!("Hello {} is {:.*}", local_i32, 5, local_f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -208,7 +208,7 @@ LL + println!("Hello {local_i32} is {local_f64:.*}", 5); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:64:5 + --> $DIR/uninlined_format_args.rs:62:5 | LL | println!("Hello {} is {2:.*}", local_i32, 5, local_f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -220,7 +220,7 @@ LL + println!("Hello {local_i32} is {local_f64:.*}", 5); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:65:5 + --> $DIR/uninlined_format_args.rs:63:5 | LL | println!("{} {}", local_i32, local_f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -232,7 +232,7 @@ LL + println!("{local_i32} {local_f64}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:66:5 + --> $DIR/uninlined_format_args.rs:64:5 | LL | println!("{}, {}", local_i32, local_opt.unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -244,7 +244,7 @@ LL + println!("{local_i32}, {}", local_opt.unwrap()); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:67:5 + --> $DIR/uninlined_format_args.rs:65:5 | LL | println!("{}", val); | ^^^^^^^^^^^^^^^^^^^ @@ -256,7 +256,7 @@ LL + println!("{val}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:68:5 + --> $DIR/uninlined_format_args.rs:66:5 | LL | println!("{}", v = val); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -268,7 +268,7 @@ LL + println!("{val}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:70:5 + --> $DIR/uninlined_format_args.rs:68:5 | LL | println!("val='{/t }'", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -280,7 +280,7 @@ LL + println!("val='{local_i32}'"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:71:5 + --> $DIR/uninlined_format_args.rs:69:5 | LL | println!("val='{/n }'", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -292,7 +292,7 @@ LL + println!("val='{local_i32}'"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:72:5 + --> $DIR/uninlined_format_args.rs:70:5 | LL | println!("val='{local_i32}'", local_i32 = local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -304,7 +304,7 @@ LL + println!("val='{local_i32}'"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:73:5 + --> $DIR/uninlined_format_args.rs:71:5 | LL | println!("val='{local_i32}'", local_i32 = fn_arg); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -316,7 +316,7 @@ LL + println!("val='{fn_arg}'"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:74:5 + --> $DIR/uninlined_format_args.rs:72:5 | LL | println!("{0}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -328,7 +328,7 @@ LL + println!("{local_i32}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:75:5 + --> $DIR/uninlined_format_args.rs:73:5 | LL | println!("{0:?}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -340,7 +340,7 @@ LL + println!("{local_i32:?}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:76:5 + --> $DIR/uninlined_format_args.rs:74:5 | LL | println!("{0:#?}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -352,7 +352,7 @@ LL + println!("{local_i32:#?}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:77:5 + --> $DIR/uninlined_format_args.rs:75:5 | LL | println!("{0:04}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -364,7 +364,7 @@ LL + println!("{local_i32:04}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:78:5 + --> $DIR/uninlined_format_args.rs:76:5 | LL | println!("{0:<3}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -376,7 +376,7 @@ LL + println!("{local_i32:<3}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:79:5 + --> $DIR/uninlined_format_args.rs:77:5 | LL | println!("{0:#010x}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -388,7 +388,7 @@ LL + println!("{local_i32:#010x}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:80:5 + --> $DIR/uninlined_format_args.rs:78:5 | LL | println!("{0:.1}", local_f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -400,7 +400,7 @@ LL + println!("{local_f64:.1}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:81:5 + --> $DIR/uninlined_format_args.rs:79:5 | LL | println!("{0} {0}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -412,7 +412,7 @@ LL + println!("{local_i32} {local_i32}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:82:5 + --> $DIR/uninlined_format_args.rs:80:5 | LL | println!("{1} {} {0} {}", local_i32, local_f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -424,7 +424,7 @@ LL + println!("{local_f64} {local_i32} {local_i32} {local_f64}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:83:5 + --> $DIR/uninlined_format_args.rs:81:5 | LL | println!("{0} {1}", local_i32, local_f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -436,7 +436,7 @@ LL + println!("{local_i32} {local_f64}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:84:5 + --> $DIR/uninlined_format_args.rs:82:5 | LL | println!("{1} {0}", local_i32, local_f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -448,7 +448,7 @@ LL + println!("{local_f64} {local_i32}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:85:5 + --> $DIR/uninlined_format_args.rs:83:5 | LL | println!("{1} {0} {1} {0}", local_i32, local_f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -460,7 +460,7 @@ LL + println!("{local_f64} {local_i32} {local_f64} {local_i32}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:87:5 + --> $DIR/uninlined_format_args.rs:85:5 | LL | println!("{v}", v = local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -472,7 +472,7 @@ LL + println!("{local_i32}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:88:5 + --> $DIR/uninlined_format_args.rs:86:5 | LL | println!("{local_i32:0$}", width); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -484,7 +484,7 @@ LL + println!("{local_i32:width$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:89:5 + --> $DIR/uninlined_format_args.rs:87:5 | LL | println!("{local_i32:w$}", w = width); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -496,7 +496,7 @@ LL + println!("{local_i32:width$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:90:5 + --> $DIR/uninlined_format_args.rs:88:5 | LL | println!("{local_i32:.0$}", prec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -508,7 +508,7 @@ LL + println!("{local_i32:.prec$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:91:5 + --> $DIR/uninlined_format_args.rs:89:5 | LL | println!("{local_i32:.p$}", p = prec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -520,7 +520,7 @@ LL + println!("{local_i32:.prec$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:92:5 + --> $DIR/uninlined_format_args.rs:90:5 | LL | println!("{:0$}", v = val); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -532,7 +532,7 @@ LL + println!("{val:val$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:93:5 + --> $DIR/uninlined_format_args.rs:91:5 | LL | println!("{0:0$}", v = val); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -544,7 +544,7 @@ LL + println!("{val:val$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:94:5 + --> $DIR/uninlined_format_args.rs:92:5 | LL | println!("{:0$.0$}", v = val); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -556,7 +556,7 @@ LL + println!("{val:val$.val$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:95:5 + --> $DIR/uninlined_format_args.rs:93:5 | LL | println!("{0:0$.0$}", v = val); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -568,7 +568,7 @@ LL + println!("{val:val$.val$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:96:5 + --> $DIR/uninlined_format_args.rs:94:5 | LL | println!("{0:0$.v$}", v = val); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -580,7 +580,7 @@ LL + println!("{val:val$.val$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:97:5 + --> $DIR/uninlined_format_args.rs:95:5 | LL | println!("{0:v$.0$}", v = val); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -592,7 +592,7 @@ LL + println!("{val:val$.val$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:98:5 + --> $DIR/uninlined_format_args.rs:96:5 | LL | println!("{v:0$.0$}", v = val); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -604,7 +604,7 @@ LL + println!("{val:val$.val$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:99:5 + --> $DIR/uninlined_format_args.rs:97:5 | LL | println!("{v:v$.0$}", v = val); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -616,7 +616,7 @@ LL + println!("{val:val$.val$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:100:5 + --> $DIR/uninlined_format_args.rs:98:5 | LL | println!("{v:0$.v$}", v = val); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -628,7 +628,7 @@ LL + println!("{val:val$.val$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:101:5 + --> $DIR/uninlined_format_args.rs:99:5 | LL | println!("{v:v$.v$}", v = val); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -640,7 +640,7 @@ LL + println!("{val:val$.val$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:102:5 + --> $DIR/uninlined_format_args.rs:100:5 | LL | println!("{:0$}", width); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -652,7 +652,7 @@ LL + println!("{width:width$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:103:5 + --> $DIR/uninlined_format_args.rs:101:5 | LL | println!("{:1$}", local_i32, width); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -664,7 +664,7 @@ LL + println!("{local_i32:width$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:104:5 + --> $DIR/uninlined_format_args.rs:102:5 | LL | println!("{:w$}", w = width); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -676,7 +676,7 @@ LL + println!("{width:width$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:105:5 + --> $DIR/uninlined_format_args.rs:103:5 | LL | println!("{:w$}", local_i32, w = width); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -688,7 +688,7 @@ LL + println!("{local_i32:width$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:106:5 + --> $DIR/uninlined_format_args.rs:104:5 | LL | println!("{:.0$}", prec); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -700,7 +700,7 @@ LL + println!("{prec:.prec$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:107:5 + --> $DIR/uninlined_format_args.rs:105:5 | LL | println!("{:.1$}", local_i32, prec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -712,7 +712,7 @@ LL + println!("{local_i32:.prec$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:108:5 + --> $DIR/uninlined_format_args.rs:106:5 | LL | println!("{:.p$}", p = prec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -724,7 +724,7 @@ LL + println!("{prec:.prec$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:109:5 + --> $DIR/uninlined_format_args.rs:107:5 | LL | println!("{:.p$}", local_i32, p = prec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -736,7 +736,7 @@ LL + println!("{local_i32:.prec$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:110:5 + --> $DIR/uninlined_format_args.rs:108:5 | LL | println!("{:0$.1$}", width, prec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -748,7 +748,7 @@ LL + println!("{width:width$.prec$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:111:5 + --> $DIR/uninlined_format_args.rs:109:5 | LL | println!("{:0$.w$}", width, w = prec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -760,7 +760,7 @@ LL + println!("{width:width$.prec$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:112:5 + --> $DIR/uninlined_format_args.rs:110:5 | LL | println!("{:1$.2$}", local_f64, width, prec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -772,7 +772,7 @@ LL + println!("{local_f64:width$.prec$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:113:5 + --> $DIR/uninlined_format_args.rs:111:5 | LL | println!("{:1$.2$} {0} {1} {2}", local_f64, width, prec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -784,7 +784,7 @@ LL + println!("{local_f64:width$.prec$} {local_f64} {width} {prec}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:114:5 + --> $DIR/uninlined_format_args.rs:112:5 | LL | / println!( LL | | "{0:1$.2$} {0:2$.1$} {1:0$.2$} {1:2$.0$} {2:0$.1$} {2:1$.0$}", @@ -803,7 +803,7 @@ LL ~ "{0:1$.2$} {0:2$.1$} {1:0$.2$} {1:2$.0$} {2:0$.1$} {2:1$.0$}", | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:125:5 + --> $DIR/uninlined_format_args.rs:123:5 | LL | println!("Width = {}, value with width = {:0$}", local_i32, local_f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -815,7 +815,7 @@ LL + println!("Width = {local_i32}, value with width = {local_f64:local_i32$ | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:126:5 + --> $DIR/uninlined_format_args.rs:124:5 | LL | println!("{:w$.p$}", local_i32, w = width, p = prec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -827,7 +827,7 @@ LL + println!("{local_i32:width$.prec$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:127:5 + --> $DIR/uninlined_format_args.rs:125:5 | LL | println!("{:w$.p$}", w = width, p = prec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -839,7 +839,7 @@ LL + println!("{width:width$.prec$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:128:20 + --> $DIR/uninlined_format_args.rs:126:20 | LL | println!("{}", format!("{}", local_i32)); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -851,7 +851,35 @@ LL + println!("{}", format!("{local_i32}")); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:166:5 + --> $DIR/uninlined_format_args.rs:144:5 + | +LL | / println!( +LL | | "{}", +LL | | // comment with a comma , in it +LL | | val, +LL | | ); + | |_____^ + | +help: change this to + | +LL - "{}", +LL + "{val}", + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:149:5 + | +LL | println!("{}", /* comment with a comma , in it */ val); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("{}", /* comment with a comma , in it */ val); +LL + println!("{val}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:168:5 | LL | println!("expand='{}'", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -862,5 +890,5 @@ LL - println!("expand='{}'", local_i32); LL + println!("expand='{local_i32}'"); | -error: aborting due to 71 previous errors +error: aborting due to 73 previous errors From ad1814dde9003bb711fd0f318e2df0c8f3579c9f Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 6 Oct 2022 09:19:51 +0200 Subject: [PATCH 111/114] Bump nightly version -> 2022-10-06 --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index b6976366dafc9..49b13cb54e71e 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2022-09-08" +channel = "nightly-2022-10-06" components = ["cargo", "llvm-tools-preview", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] From db490d0f8451083a6a40281777a517827fc4aa73 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 6 Oct 2022 09:45:08 +0200 Subject: [PATCH 112/114] Update Cargo.lock --- Cargo.lock | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a5336477e0ed5..027121774d4ec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -387,7 +387,7 @@ dependencies = [ "directories", "rustc-build-sysroot", "rustc-workspace-hack", - "rustc_tools_util 0.2.1", + "rustc_tools_util", "rustc_version", "serde", "serde_json", @@ -655,7 +655,7 @@ dependencies = [ [[package]] name = "clippy" -version = "0.1.65" +version = "0.1.66" dependencies = [ "clippy_lints", "clippy_utils", @@ -670,7 +670,7 @@ dependencies = [ "regex", "rustc-semver", "rustc-workspace-hack", - "rustc_tools_util 0.2.0", + "rustc_tools_util", "semver", "serde", "syn", @@ -698,7 +698,7 @@ dependencies = [ [[package]] name = "clippy_lints" -version = "0.1.65" +version = "0.1.66" dependencies = [ "cargo_metadata 0.14.0", "clippy_utils", @@ -720,7 +720,7 @@ dependencies = [ [[package]] name = "clippy_utils" -version = "0.1.65" +version = "0.1.66" dependencies = [ "arrayvec", "if_chain", @@ -829,9 +829,9 @@ dependencies = [ [[package]] name = "compiletest_rs" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "262134ef87408da1ddfe45e33daa0ca43b75286d6b1076446e602d264cf9847e" +checksum = "70489bbb718aea4f92e5f48f2e3b5be670c2051de30e57cb6e5377b4aa08b372" dependencies = [ "diff", "filetime", @@ -4162,10 +4162,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "rustc_tools_util" -version = "0.2.0" - [[package]] name = "rustc_tools_util" version = "0.2.1" From c251f8d8dd010ac454deec0a39e7a6f3c19204c3 Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Thu, 6 Oct 2022 08:54:07 -0400 Subject: [PATCH 113/114] lint: fix a few comments --- clippy_lints/src/format_args.rs | 12 ------------ clippy_utils/src/macros.rs | 2 +- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index 88502b7261801..d4bb357fb4f57 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -173,18 +173,6 @@ fn check_uninlined_args(cx: &LateContext<'_>, args: &FormatArgsExpn<'_>, call_si return; } - // FIXME: Properly ignore a rare case where the format string is wrapped in a macro. - // Example: `format!(indoc!("{}"), foo);` - // If inlined, they will cause a compilation error: - // > to avoid ambiguity, `format_args!` cannot capture variables - // > when the format string is expanded from a macro - // @Alexendoo explanation: - // > indoc! is a proc macro that is producing a string literal with its span - // > set to its input it's not marked as from expansion, and since it's compatible - // > tokenization wise clippy_utils::is_from_proc_macro wouldn't catch it either - // This might be a relatively expensive test, so do it only we are ready to replace. - // See more examples in tests/ui/uninlined_format_args.rs - span_lint_and_then( cx, UNINLINED_FORMAT_ARGS, diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs index dd0ce1da65759..5a63c290a315f 100644 --- a/clippy_utils/src/macros.rs +++ b/clippy_utils/src/macros.rs @@ -414,7 +414,7 @@ impl FormatString { struct FormatArgsValues<'tcx> { /// Values passed after the format string and implicit captures. `[1, z + 2, x]` for - /// `format!("{x} {} {y}", 1, z + 2)`. + /// `format!("{x} {} {}", 1, z + 2)`. value_args: Vec<&'tcx Expr<'tcx>>, /// Maps an `rt::v1::Argument::position` or an `rt::v1::Count::Param` to its index in /// `value_args` From cfd6c8d19d1db6f2da66415dd60a82f2c706363e Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Thu, 6 Oct 2022 09:12:37 -0400 Subject: [PATCH 114/114] Add a temporary workaround for multiline formart arg inlining per suggestion in https://github.com/rust-lang/rust/pull/102729#discussion_r988990080 workaround for an internal crash when handling multi-line format argument inlining. --- clippy_lints/src/format_args.rs | 7 +++- tests/ui/uninlined_format_args.fixed | 11 ++++-- tests/ui/uninlined_format_args.stderr | 53 +-------------------------- 3 files changed, 15 insertions(+), 56 deletions(-) diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index d4bb357fb4f57..45ed21e066ad8 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -8,7 +8,7 @@ use if_chain::if_chain; use itertools::Itertools; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, HirId, QPath}; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::adjustment::{Adjust, Adjustment}; use rustc_middle::ty::Ty; use rustc_semver::RustcVersion; @@ -173,6 +173,11 @@ fn check_uninlined_args(cx: &LateContext<'_>, args: &FormatArgsExpn<'_>, call_si return; } + // Temporarily ignore multiline spans: https://github.com/rust-lang/rust/pull/102729#discussion_r988704308 + if fixes.iter().any(|(span, _)| cx.sess().source_map().is_multiline(*span)) { + return; + } + span_lint_and_then( cx, UNINLINED_FORMAT_ARGS, diff --git a/tests/ui/uninlined_format_args.fixed b/tests/ui/uninlined_format_args.fixed index dcf10ed60a259..3ca7a40190253 100644 --- a/tests/ui/uninlined_format_args.fixed +++ b/tests/ui/uninlined_format_args.fixed @@ -44,7 +44,9 @@ fn tester(fn_arg: i32) { println!("val='{local_i32}'"); // space+tab println!("val='{local_i32}'"); // tab+space println!( - "val='{local_i32}'" + "val='{ + }'", + local_i32 ); println!("{local_i32}"); println!("{fn_arg}"); @@ -108,7 +110,8 @@ fn tester(fn_arg: i32) { println!("{local_f64:width$.prec$}"); println!("{local_f64:width$.prec$} {local_f64} {width} {prec}"); println!( - "{local_i32:width$.prec$} {local_i32:prec$.width$} {width:local_i32$.prec$} {width:prec$.local_i32$} {prec:local_i32$.width$} {prec:width$.local_i32$}", + "{0:1$.2$} {0:2$.1$} {1:0$.2$} {1:2$.0$} {2:0$.1$} {2:1$.0$}", + local_i32, width, prec, ); println!( "{0:1$.2$} {0:2$.1$} {1:0$.2$} {1:2$.0$} {2:0$.1$} {2:1$.0$} {3}", @@ -139,7 +142,9 @@ fn tester(fn_arg: i32) { println!(no_param_str!(), local_i32); println!( - "{val}", + "{}", + // comment with a comma , in it + val, ); println!("{val}"); diff --git a/tests/ui/uninlined_format_args.stderr b/tests/ui/uninlined_format_args.stderr index 1b4dada28daca..d1a7749263429 100644 --- a/tests/ui/uninlined_format_args.stderr +++ b/tests/ui/uninlined_format_args.stderr @@ -59,22 +59,6 @@ LL - println!("val='{ }'", local_i32); // tab+space LL + println!("val='{local_i32}'"); // tab+space | -error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:46:5 - | -LL | / println!( -LL | | "val='{ -LL | | }'", -LL | | local_i32 -LL | | ); - | |_____^ - | -help: change this to - | -LL - "val='{ -LL + "val='{local_i32}'" - | - error: variables can be used directly in the `format!` string --> $DIR/uninlined_format_args.rs:51:5 | @@ -783,25 +767,6 @@ LL - println!("{:1$.2$} {0} {1} {2}", local_f64, width, prec); LL + println!("{local_f64:width$.prec$} {local_f64} {width} {prec}"); | -error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:112:5 - | -LL | / println!( -LL | | "{0:1$.2$} {0:2$.1$} {1:0$.2$} {1:2$.0$} {2:0$.1$} {2:1$.0$}", -LL | | local_i32, width, prec, -LL | | ); - | |_____^ - | -help: change this to - | -LL ~ "{local_i32:width$.prec$} {local_i32:prec$.width$} {width:local_i32$.prec$} {width:prec$.local_i32$} {prec:local_i32$.width$} {prec:width$.local_i32$}", width, prec, -LL ~ "{0:1$.2$} {0:2$.1$} {1:0$.2$} {1:2$.0$} {2:0$.1$} {2:1$.0$}", width, prec, -LL ~ "{0:1$.2$} {0:2$.1$} {1:0$.2$} {1:2$.0$} {2:0$.1$} {2:1$.0$}", width, prec, -LL ~ "{0:1$.2$} {0:2$.1$} {1:0$.2$} {1:2$.0$} {2:0$.1$} {2:1$.0$}", width, prec, -LL ~ "{0:1$.2$} {0:2$.1$} {1:0$.2$} {1:2$.0$} {2:0$.1$} {2:1$.0$}", width, prec, -LL ~ "{0:1$.2$} {0:2$.1$} {1:0$.2$} {1:2$.0$} {2:0$.1$} {2:1$.0$}", - | - error: variables can be used directly in the `format!` string --> $DIR/uninlined_format_args.rs:123:5 | @@ -850,22 +815,6 @@ LL - println!("{}", format!("{}", local_i32)); LL + println!("{}", format!("{local_i32}")); | -error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:144:5 - | -LL | / println!( -LL | | "{}", -LL | | // comment with a comma , in it -LL | | val, -LL | | ); - | |_____^ - | -help: change this to - | -LL - "{}", -LL + "{val}", - | - error: variables can be used directly in the `format!` string --> $DIR/uninlined_format_args.rs:149:5 | @@ -890,5 +839,5 @@ LL - println!("expand='{}'", local_i32); LL + println!("expand='{local_i32}'"); | -error: aborting due to 73 previous errors +error: aborting due to 70 previous errors