From 1309e8f3f37c90153c84334e586785f276b65b34 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Wed, 23 Oct 2024 09:52:56 +0200 Subject: [PATCH 01/45] allow conditional `Send` futures in `future_not_send` --- clippy_lints/src/future_not_send.rs | 67 ++++++++++++++++++++++++----- tests/ui/crashes/ice-10645.rs | 7 --- tests/ui/crashes/ice-10645.stderr | 17 -------- tests/ui/future_not_send.rs | 18 +++++++- tests/ui/future_not_send.stderr | 51 +++++++++++----------- 5 files changed, 101 insertions(+), 59 deletions(-) delete mode 100644 tests/ui/crashes/ice-10645.rs delete mode 100644 tests/ui/crashes/ice-10645.stderr diff --git a/clippy_lints/src/future_not_send.rs b/clippy_lints/src/future_not_send.rs index cf08c16458b..bb2dc9995df 100644 --- a/clippy_lints/src/future_not_send.rs +++ b/clippy_lints/src/future_not_send.rs @@ -1,3 +1,5 @@ +use std::ops::ControlFlow; + use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::return_ty; use rustc_hir::intravisit::FnKind; @@ -5,7 +7,9 @@ use rustc_hir::{Body, FnDecl}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::print::PrintTraitRefExt; -use rustc_middle::ty::{self, AliasTy, ClauseKind, PredicateKind}; +use rustc_middle::ty::{ + self, AliasTy, Binder, ClauseKind, PredicateKind, Ty, TyCtxt, TypeVisitable, TypeVisitableExt, TypeVisitor, +}; use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{Span, sym}; @@ -15,9 +19,16 @@ use rustc_trait_selection::traits::{self, FulfillmentError, ObligationCtxt}; declare_clippy_lint! { /// ### 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. + /// functions and methods to implement the `Send` marker trait, + /// ignoring type parameters. + /// + /// If a function is generic and its Future conditionally implements `Send` + /// based on a generic parameter then it is considered `Send` and no warning is emitted. + /// + /// This can be used by library authors (public and internal) to ensure + /// their functions are compatible with both multi-threaded runtimes that require `Send` futures, + /// as well as single-threaded runtimes where callers may choose `!Send` types + /// for generic parameters. /// /// ### Why is this bad? /// A Future implementation captures some state that it @@ -64,22 +75,46 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { return; } let ret_ty = return_ty(cx, cx.tcx.local_def_id_to_hir_id(fn_def_id).expect_owner()); - if let ty::Alias(ty::Opaque, AliasTy { def_id, args, .. }) = *ret_ty.kind() { + if let ty::Alias(ty::Opaque, AliasTy { def_id, args, .. }) = *ret_ty.kind() + && let Some(future_trait) = cx.tcx.lang_items().future_trait() + && let Some(send_trait) = cx.tcx.get_diagnostic_item(sym::Send) + { let preds = cx.tcx.explicit_item_super_predicates(def_id); let is_future = preds.iter_instantiated_copied(cx.tcx, args).any(|(p, _)| { - p.as_trait_clause().is_some_and(|trait_pred| { - Some(trait_pred.skip_binder().trait_ref.def_id) == cx.tcx.lang_items().future_trait() - }) + p.as_trait_clause() + .is_some_and(|trait_pred| trait_pred.skip_binder().trait_ref.def_id == future_trait) }); if is_future { - let send_trait = cx.tcx.get_diagnostic_item(sym::Send).unwrap(); let span = decl.output.span(); let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode()); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let cause = traits::ObligationCause::misc(span, fn_def_id); ocx.register_bound(cause, cx.param_env, ret_ty, send_trait); let send_errors = ocx.select_all_or_error(); - if !send_errors.is_empty() { + + // Allow errors that try to prove `Send` for types that "mention" a generic parameter at the "top + // level". + // For example, allow errors that `T: Send` can't be proven, but reject `Rc: Send` errors, + // which is always unconditionally `!Send` for any possible type `T`. + // + // We also allow associated type projections if the self type is either itself a projection or a + // type parameter. + // This is to prevent emitting warnings for e.g. holding a `::Output` across await + // points, where `Fut` is a type parameter. + + let is_send = send_errors.iter().all(|err| { + err.obligation + .predicate + .as_trait_clause() + .map(Binder::skip_binder) + .is_some_and(|pred| { + pred.def_id() == send_trait + && pred.self_ty().has_param() + && TyParamAtTopLevelVisitor.visit_ty(pred.self_ty()) == ControlFlow::Break(true) + }) + }); + + if !is_send { span_lint_and_then( cx, FUTURE_NOT_SEND, @@ -107,3 +142,15 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { } } } + +struct TyParamAtTopLevelVisitor; +impl<'tcx> TypeVisitor> for TyParamAtTopLevelVisitor { + type Result = ControlFlow; + fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result { + match ty.kind() { + ty::Param(_) => ControlFlow::Break(true), + ty::Alias(ty::AliasTyKind::Projection, ty) => ty.visit_with(self), + _ => ControlFlow::Break(false), + } + } +} diff --git a/tests/ui/crashes/ice-10645.rs b/tests/ui/crashes/ice-10645.rs deleted file mode 100644 index 6e126aff751..00000000000 --- a/tests/ui/crashes/ice-10645.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@compile-flags: --cap-lints=warn -// https://github.com/rust-lang/rust-clippy/issues/10645 - -#![warn(clippy::future_not_send)] -pub async fn bar<'a, T: 'a>(_: T) {} - -fn main() {} diff --git a/tests/ui/crashes/ice-10645.stderr b/tests/ui/crashes/ice-10645.stderr deleted file mode 100644 index 0269072b88b..00000000000 --- a/tests/ui/crashes/ice-10645.stderr +++ /dev/null @@ -1,17 +0,0 @@ -warning: future cannot be sent between threads safely - --> tests/ui/crashes/ice-10645.rs:5:1 - | -LL | pub async fn bar<'a, T: 'a>(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `bar` is not `Send` - | -note: captured value is not `Send` - --> tests/ui/crashes/ice-10645.rs:5:29 - | -LL | pub async fn bar<'a, T: 'a>(_: T) {} - | ^ has type `T` which is not `Send` - = note: `T` doesn't implement `std::marker::Send` - = note: `-D clippy::future-not-send` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::future_not_send)]` - -warning: 1 warning emitted - diff --git a/tests/ui/future_not_send.rs b/tests/ui/future_not_send.rs index 9274340b5ca..626ee6de9e4 100644 --- a/tests/ui/future_not_send.rs +++ b/tests/ui/future_not_send.rs @@ -1,6 +1,7 @@ #![warn(clippy::future_not_send)] use std::cell::Cell; +use std::future::Future; use std::rc::Rc; use std::sync::Arc; @@ -63,6 +64,22 @@ where t } +async fn maybe_send_generic_future(t: T) -> T { + async { true }.await; + t +} + +async fn maybe_send_generic_future2 Fut, Fut: Future>(f: F) { + async { true }.await; + let res = f(); + async { true }.await; +} + +async fn generic_future_always_unsend(_: Rc) { + //~^ ERROR: future cannot be sent between threads safely + async { true }.await; +} + async fn generic_future_send(t: T) where T: Send, @@ -71,7 +88,6 @@ where } async fn unclear_future(t: T) {} -//~^ ERROR: future cannot be sent between threads safely fn main() { let rc = Rc::new([1, 2, 3]); diff --git a/tests/ui/future_not_send.stderr b/tests/ui/future_not_send.stderr index 67677d6367a..3807c747013 100644 --- a/tests/ui/future_not_send.stderr +++ b/tests/ui/future_not_send.stderr @@ -1,11 +1,11 @@ error: future cannot be sent between threads safely - --> tests/ui/future_not_send.rs:7:1 + --> tests/ui/future_not_send.rs:8:1 | LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell) -> bool { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `private_future` is not `Send` | note: future is not `Send` as this value is used across an await - --> tests/ui/future_not_send.rs:9:20 + --> tests/ui/future_not_send.rs:10:20 | LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell) -> bool { | -- has type `std::rc::Rc<[u8]>` which is not `Send` @@ -14,7 +14,7 @@ LL | async { true }.await | ^^^^^ await occurs here, with `rc` maybe used later = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send` note: captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync` - --> tests/ui/future_not_send.rs:7:39 + --> tests/ui/future_not_send.rs:8:39 | LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell) -> bool { | ^^^^ has type `&std::cell::Cell` which is not `Send`, because `std::cell::Cell` is not `Sync` @@ -23,13 +23,13 @@ LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell) -> bool { = help: to override `-D warnings` add `#[allow(clippy::future_not_send)]` error: future cannot be sent between threads safely - --> tests/ui/future_not_send.rs:12:1 + --> tests/ui/future_not_send.rs:13:1 | LL | pub async fn public_future(rc: Rc<[u8]>) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `public_future` is not `Send` | note: future is not `Send` as this value is used across an await - --> tests/ui/future_not_send.rs:14:20 + --> tests/ui/future_not_send.rs:15:20 | LL | pub async fn public_future(rc: Rc<[u8]>) { | -- has type `std::rc::Rc<[u8]>` which is not `Send` @@ -39,45 +39,45 @@ LL | async { true }.await; = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send` error: future cannot be sent between threads safely - --> tests/ui/future_not_send.rs:21:1 + --> tests/ui/future_not_send.rs:22:1 | LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell) -> bool { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `private_future2` is not `Send` | note: captured value is not `Send` - --> tests/ui/future_not_send.rs:21:26 + --> tests/ui/future_not_send.rs:22:26 | LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell) -> bool { | ^^ has type `std::rc::Rc<[u8]>` which is not `Send` = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send` note: captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync` - --> tests/ui/future_not_send.rs:21:40 + --> tests/ui/future_not_send.rs:22:40 | LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell) -> bool { | ^^^^ has type `&std::cell::Cell` which is not `Send`, because `std::cell::Cell` is not `Sync` = note: `std::cell::Cell` doesn't implement `std::marker::Sync` error: future cannot be sent between threads safely - --> tests/ui/future_not_send.rs:26:1 + --> tests/ui/future_not_send.rs:27:1 | LL | pub async fn public_future2(rc: Rc<[u8]>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `public_future2` is not `Send` | note: captured value is not `Send` - --> tests/ui/future_not_send.rs:26:29 + --> tests/ui/future_not_send.rs:27:29 | LL | pub async fn public_future2(rc: Rc<[u8]>) {} | ^^ has type `std::rc::Rc<[u8]>` which is not `Send` = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send` error: future cannot be sent between threads safely - --> tests/ui/future_not_send.rs:38:5 + --> tests/ui/future_not_send.rs:39:5 | LL | async fn private_future(&self) -> usize { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `private_future` is not `Send` | note: future is not `Send` as this value is used across an await - --> tests/ui/future_not_send.rs:40:24 + --> tests/ui/future_not_send.rs:41:24 | LL | async fn private_future(&self) -> usize { | ----- has type `&Dummy` which is not `Send` @@ -87,20 +87,20 @@ LL | async { true }.await; = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Sync` error: future cannot be sent between threads safely - --> tests/ui/future_not_send.rs:44:5 + --> tests/ui/future_not_send.rs:45:5 | LL | pub async fn public_future(&self) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `public_future` is not `Send` | note: captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync` - --> tests/ui/future_not_send.rs:44:32 + --> tests/ui/future_not_send.rs:45:32 | LL | pub async fn public_future(&self) { | ^^^^^ has type `&Dummy` which is not `Send`, because `Dummy` is not `Sync` = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Sync` error: future cannot be sent between threads safely - --> tests/ui/future_not_send.rs:55:1 + --> tests/ui/future_not_send.rs:56:1 | LL | / async fn generic_future(t: T) -> T LL | | @@ -109,7 +109,7 @@ LL | | T: Send, | |____________^ future returned by `generic_future` is not `Send` | note: future is not `Send` as this value is used across an await - --> tests/ui/future_not_send.rs:61:20 + --> tests/ui/future_not_send.rs:62:20 | LL | let rt = &t; | -- has type `&T` which is not `Send` @@ -118,17 +118,20 @@ LL | async { true }.await; = note: `T` doesn't implement `std::marker::Sync` error: future cannot be sent between threads safely - --> tests/ui/future_not_send.rs:73:1 + --> tests/ui/future_not_send.rs:78:1 | -LL | async fn unclear_future(t: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `unclear_future` is not `Send` +LL | async fn generic_future_always_unsend(_: Rc) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `generic_future_always_unsend` is not `Send` | -note: captured value is not `Send` - --> tests/ui/future_not_send.rs:73:28 +note: future is not `Send` as this value is used across an await + --> tests/ui/future_not_send.rs:80:20 | -LL | async fn unclear_future(t: T) {} - | ^ has type `T` which is not `Send` - = note: `T` doesn't implement `std::marker::Send` +LL | async fn generic_future_always_unsend(_: Rc) { + | - has type `std::rc::Rc` which is not `Send` +LL | +LL | async { true }.await; + | ^^^^^ await occurs here, with `_` maybe used later + = note: `std::rc::Rc` doesn't implement `std::marker::Send` error: aborting due to 8 previous errors From 1ceaa9041331c277c143078942ba5683d888a98c Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 14 Nov 2024 19:35:26 +0100 Subject: [PATCH 02/45] Merge commit '786fbd6d683933cd0e567fdcd25d449a69b4320c' into clippy-subtree-update --- CHANGELOG.md | 1 + clippy_dev/src/setup/vscode.rs | 2 +- clippy_lints/src/attrs/useless_attribute.rs | 2 +- clippy_lints/src/attrs/utils.rs | 4 +- clippy_lints/src/bool_assert_comparison.rs | 4 +- clippy_lints/src/booleans.rs | 2 +- clippy_lints/src/box_default.rs | 8 +- clippy_lints/src/casts/unnecessary_cast.rs | 3 +- clippy_lints/src/comparison_chain.rs | 2 +- clippy_lints/src/copies.rs | 16 +- clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/default_numeric_fallback.rs | 2 +- clippy_lints/src/derivable_impls.rs | 2 +- clippy_lints/src/derive.rs | 2 +- clippy_lints/src/doc/missing_headers.rs | 2 +- clippy_lints/src/drop_forget_ref.rs | 2 +- clippy_lints/src/eta_reduction.rs | 2 +- .../src/functions/not_unsafe_ptr_arg_deref.rs | 2 +- clippy_lints/src/infinite_iter.rs | 8 +- clippy_lints/src/item_name_repetitions.rs | 4 +- .../src/iter_not_returning_iterator.rs | 2 +- clippy_lints/src/large_const_arrays.rs | 3 +- clippy_lints/src/large_include_file.rs | 2 + clippy_lints/src/len_zero.rs | 2 +- clippy_lints/src/lifetimes.rs | 2 +- clippy_lints/src/loops/manual_find.rs | 2 +- clippy_lints/src/loops/manual_memcpy.rs | 2 +- clippy_lints/src/loops/mut_range_bound.rs | 2 +- clippy_lints/src/loops/same_item_push.rs | 2 +- clippy_lints/src/loops/utils.rs | 7 +- clippy_lints/src/manual_clamp.rs | 2 +- clippy_lints/src/manual_strip.rs | 4 +- .../src/matches/match_like_matches.rs | 2 +- .../src/matches/redundant_pattern_match.rs | 2 +- clippy_lints/src/matches/single_match.rs | 2 +- clippy_lints/src/matches/try_err.rs | 2 +- clippy_lints/src/methods/expect_fun_call.rs | 2 +- clippy_lints/src/methods/filter_next.rs | 7 +- clippy_lints/src/methods/manual_next_back.rs | 4 +- clippy_lints/src/methods/manual_str_repeat.rs | 4 +- clippy_lints/src/methods/map_clone.rs | 2 +- clippy_lints/src/methods/mod.rs | 32 ++- clippy_lints/src/methods/needless_collect.rs | 2 +- .../src/methods/option_as_ref_deref.rs | 2 +- clippy_lints/src/methods/or_fun_call.rs | 4 +- clippy_lints/src/methods/str_splitn.rs | 2 +- .../src/methods/unnecessary_map_or.rs | 131 ++++++++++++ .../src/methods/unnecessary_sort_by.rs | 7 +- clippy_lints/src/methods/useless_asref.rs | 2 +- clippy_lints/src/misc_early/mod.rs | 2 +- .../src/needless_borrows_for_generic_args.rs | 10 +- clippy_lints/src/needless_continue.rs | 4 +- clippy_lints/src/nonstandard_macro_braces.rs | 2 +- clippy_lints/src/only_used_in_recursion.rs | 4 +- .../src/operators/arithmetic_side_effects.rs | 2 +- clippy_lints/src/operators/cmp_owned.rs | 6 +- clippy_lints/src/operators/identity_op.rs | 190 ++++++++---------- .../src/operators/numeric_arithmetic.rs | 2 +- clippy_lints/src/pass_by_ref_or_value.rs | 2 +- clippy_lints/src/ptr.rs | 5 +- clippy_lints/src/question_mark.rs | 172 +++++++++++++++- clippy_lints/src/redundant_slicing.rs | 4 +- clippy_lints/src/swap.rs | 4 +- clippy_lints/src/types/borrowed_box.rs | 3 +- clippy_lints/src/unit_types/let_unit_value.rs | 2 +- clippy_lints/src/vec_init_then_push.rs | 2 +- clippy_lints/src/write.rs | 2 +- clippy_utils/src/check_proc_macro.rs | 6 +- clippy_utils/src/hir_utils.rs | 8 +- clippy_utils/src/lib.rs | 31 ++- clippy_utils/src/numeric_literal.rs | 2 +- clippy_utils/src/sugg.rs | 2 +- clippy_utils/src/ty.rs | 12 +- clippy_utils/src/visitors.rs | 10 +- rust-toolchain | 2 +- tests/ui-internal/unnecessary_def_path.fixed | 1 + tests/ui-internal/unnecessary_def_path.rs | 1 + tests/ui-internal/unnecessary_def_path.stderr | 30 +-- tests/ui-toml/large_include_file/empty.txt | 0 .../large_include_file/large_include_file.rs | 6 +- ...sensitive_file_extension_comparisons.fixed | 1 + ...se_sensitive_file_extension_comparisons.rs | 1 + ...ensitive_file_extension_comparisons.stderr | 12 +- tests/ui/identity_op.fixed | 46 ++++- tests/ui/identity_op.rs | 44 ++++ tests/ui/identity_op.stderr | 70 ++++++- tests/ui/question_mark.fixed | 56 ++++++ tests/ui/question_mark.rs | 71 +++++++ tests/ui/question_mark.stderr | 63 +++++- tests/ui/unnecessary_map_or.fixed | 64 ++++++ tests/ui/unnecessary_map_or.rs | 67 ++++++ tests/ui/unnecessary_map_or.stderr | 99 +++++++++ 92 files changed, 1149 insertions(+), 286 deletions(-) create mode 100644 clippy_lints/src/methods/unnecessary_map_or.rs create mode 100644 tests/ui-toml/large_include_file/empty.txt create mode 100644 tests/ui/unnecessary_map_or.fixed create mode 100644 tests/ui/unnecessary_map_or.rs create mode 100644 tests/ui/unnecessary_map_or.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 161fa630ed4..dd3124ee9a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6071,6 +6071,7 @@ Released 2018-09-13 [`unnecessary_literal_bound`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_literal_bound [`unnecessary_literal_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_literal_unwrap [`unnecessary_map_on_constructor`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_map_on_constructor +[`unnecessary_map_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_map_or [`unnecessary_min_or_max`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_min_or_max [`unnecessary_mut_passed`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_mut_passed [`unnecessary_operation`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_operation diff --git a/clippy_dev/src/setup/vscode.rs b/clippy_dev/src/setup/vscode.rs index 204f4af2cf1..a37c873eed4 100644 --- a/clippy_dev/src/setup/vscode.rs +++ b/clippy_dev/src/setup/vscode.rs @@ -84,7 +84,7 @@ fn delete_vs_task_file(path: &Path) -> bool { /// It may fail silently. fn try_delete_vs_directory_if_empty() { let path = Path::new(VSCODE_DIR); - if path.read_dir().map_or(false, |mut iter| iter.next().is_none()) { + if path.read_dir().is_ok_and(|mut iter| iter.next().is_none()) { // The directory is empty. We just try to delete it but allow a silence // fail as an empty `.vscode` directory is still valid let _silence_result = fs::remove_dir(path); diff --git a/clippy_lints/src/attrs/useless_attribute.rs b/clippy_lints/src/attrs/useless_attribute.rs index dc5a6857089..e21853598c3 100644 --- a/clippy_lints/src/attrs/useless_attribute.rs +++ b/clippy_lints/src/attrs/useless_attribute.rs @@ -16,7 +16,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, item: &Item, attrs: &[Attribute]) { return; } if let Some(lint_list) = &attr.meta_item_list() { - if attr.ident().map_or(false, |ident| is_lint_level(ident.name, attr.id)) { + if attr.ident().is_some_and(|ident| is_lint_level(ident.name, attr.id)) { for lint in lint_list { match item.kind { ItemKind::Use(..) => { diff --git a/clippy_lints/src/attrs/utils.rs b/clippy_lints/src/attrs/utils.rs index 9b10ae83651..3bb02688bf2 100644 --- a/clippy_lints/src/attrs/utils.rs +++ b/clippy_lints/src/attrs/utils.rs @@ -50,7 +50,7 @@ fn is_relevant_block(cx: &LateContext<'_>, typeck_results: &ty::TypeckResults<'_ block .expr .as_ref() - .map_or(false, |e| is_relevant_expr(cx, typeck_results, e)), + .is_some_and(|e| is_relevant_expr(cx, typeck_results, e)), |stmt| match &stmt.kind { StmtKind::Let(_) => true, StmtKind::Expr(expr) | StmtKind::Semi(expr) => is_relevant_expr(cx, typeck_results, expr), @@ -60,7 +60,7 @@ fn is_relevant_block(cx: &LateContext<'_>, typeck_results: &ty::TypeckResults<'_ } fn is_relevant_expr(cx: &LateContext<'_>, typeck_results: &ty::TypeckResults<'_>, expr: &Expr<'_>) -> bool { - if macro_backtrace(expr.span).last().map_or(false, |macro_call| { + if macro_backtrace(expr.span).last().is_some_and(|macro_call| { is_panic(cx, macro_call.def_id) || cx.tcx.item_name(macro_call.def_id) == sym::unreachable }) { return false; diff --git a/clippy_lints/src/bool_assert_comparison.rs b/clippy_lints/src/bool_assert_comparison.rs index db5792188dd..7d89195eeca 100644 --- a/clippy_lints/src/bool_assert_comparison.rs +++ b/clippy_lints/src/bool_assert_comparison.rs @@ -60,8 +60,8 @@ fn is_impl_not_trait_with_bool_out<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) - trait_id, ) }) - .map_or(false, |assoc_item| { - let proj = Ty::new_projection_from_args(cx.tcx, assoc_item.def_id, cx.tcx.mk_args_trait(ty, [])); + .is_some_and(|assoc_item| { + let proj = Ty::new_projection(cx.tcx, assoc_item.def_id, cx.tcx.mk_args_trait(ty, [])); let nty = cx.tcx.normalize_erasing_regions(cx.param_env, proj); nty.is_bool() diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 26a20bc99a0..896bd5fd03d 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -667,5 +667,5 @@ fn implements_ord(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { let ty = cx.typeck_results().expr_ty(expr); cx.tcx .get_diagnostic_item(sym::Ord) - .map_or(false, |id| implements_trait(cx, ty, id, &[])) + .is_some_and(|id| implements_trait(cx, ty, id, &[])) } diff --git a/clippy_lints/src/box_default.rs b/clippy_lints/src/box_default.rs index bf1d077fec2..a1ca23e65ff 100644 --- a/clippy_lints/src/box_default.rs +++ b/clippy_lints/src/box_default.rs @@ -45,7 +45,7 @@ impl LateLintPass<'_> for BoxDefault { // And that method is `new` && seg.ident.name == sym::new // And the call is that of a `Box` method - && path_def_id(cx, ty).map_or(false, |id| Some(id) == cx.tcx.lang_items().owned_box()) + && path_def_id(cx, ty).is_some_and(|id| Some(id) == cx.tcx.lang_items().owned_box()) // And the single argument to the call is another function call // This is the `T::default()` (or default equivalent) of `Box::new(T::default())` && let ExprKind::Call(arg_path, _) = arg.kind @@ -83,9 +83,9 @@ fn is_plain_default(cx: &LateContext<'_>, arg_path: &Expr<'_>) -> bool { } fn is_local_vec_expn(cx: &LateContext<'_>, expr: &Expr<'_>, ref_expr: &Expr<'_>) -> bool { - macro_backtrace(expr.span).next().map_or(false, |call| { - cx.tcx.is_diagnostic_item(sym::vec_macro, call.def_id) && call.span.eq_ctxt(ref_expr.span) - }) + macro_backtrace(expr.span) + .next() + .is_some_and(|call| cx.tcx.is_diagnostic_item(sym::vec_macro, call.def_id) && call.span.eq_ctxt(ref_expr.span)) } #[derive(Default)] diff --git a/clippy_lints/src/casts/unnecessary_cast.rs b/clippy_lints/src/casts/unnecessary_cast.rs index abd80abffe6..332e897def7 100644 --- a/clippy_lints/src/casts/unnecessary_cast.rs +++ b/clippy_lints/src/casts/unnecessary_cast.rs @@ -159,8 +159,7 @@ pub(super) fn check<'tcx>( // The same is true if the expression encompassing the cast expression is a unary // expression or an addressof expression. let needs_block = matches!(cast_expr.kind, ExprKind::Unary(..) | ExprKind::AddrOf(..)) - || get_parent_expr(cx, expr) - .map_or(false, |e| matches!(e.kind, ExprKind::Unary(..) | ExprKind::AddrOf(..))); + || get_parent_expr(cx, expr).is_some_and(|e| matches!(e.kind, ExprKind::Unary(..) | ExprKind::AddrOf(..))); span_lint_and_sugg( cx, diff --git a/clippy_lints/src/comparison_chain.rs b/clippy_lints/src/comparison_chain.rs index b9baf9af248..c85e3500ebd 100644 --- a/clippy_lints/src/comparison_chain.rs +++ b/clippy_lints/src/comparison_chain.rs @@ -110,7 +110,7 @@ impl<'tcx> LateLintPass<'tcx> for ComparisonChain { let is_ord = cx .tcx .get_diagnostic_item(sym::Ord) - .map_or(false, |id| implements_trait(cx, ty, id, &[])); + .is_some_and(|id| implements_trait(cx, ty, id, &[])); if !is_ord { return; diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index c4afdc757d8..3ecd36d3711 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -345,7 +345,7 @@ fn eq_binding_names(s: &Stmt<'_>, names: &[(HirId, Symbol)]) -> bool { let mut i = 0usize; let mut res = true; l.pat.each_binding_or_first(&mut |_, _, _, name| { - if names.get(i).map_or(false, |&(_, n)| n == name.name) { + if names.get(i).is_some_and(|&(_, n)| n == name.name) { i += 1; } else { res = false; @@ -389,12 +389,10 @@ fn eq_stmts( let new_bindings = &moved_bindings[old_count..]; blocks .iter() - .all(|b| get_stmt(b).map_or(false, |s| eq_binding_names(s, new_bindings))) + .all(|b| get_stmt(b).is_some_and(|s| eq_binding_names(s, new_bindings))) } else { true - }) && blocks - .iter() - .all(|b| get_stmt(b).map_or(false, |s| eq.eq_stmt(s, stmt))) + }) && blocks.iter().all(|b| get_stmt(b).is_some_and(|s| eq.eq_stmt(s, stmt))) } #[expect(clippy::too_many_lines)] @@ -451,9 +449,7 @@ fn scan_block_for_eq<'tcx>( // x + 50 let expr_hash_eq = if let Some(e) = block.expr { let hash = hash_expr(cx, e); - blocks - .iter() - .all(|b| b.expr.map_or(false, |e| hash_expr(cx, e) == hash)) + blocks.iter().all(|b| b.expr.is_some_and(|e| hash_expr(cx, e) == hash)) } else { blocks.iter().all(|b| b.expr.is_none()) }; @@ -514,7 +510,7 @@ fn scan_block_for_eq<'tcx>( }); if let Some(e) = block.expr { for block in blocks { - if block.expr.map_or(false, |expr| !eq.eq_expr(expr, e)) { + if block.expr.is_some_and(|expr| !eq.eq_expr(expr, e)) { moved_locals.truncate(moved_locals_at_start); return BlockEq { start_end_eq, @@ -533,7 +529,7 @@ fn scan_block_for_eq<'tcx>( } fn check_for_warn_of_moved_symbol(cx: &LateContext<'_>, symbols: &[(HirId, Symbol)], if_expr: &Expr<'_>) -> bool { - get_enclosing_block(cx, if_expr.hir_id).map_or(false, |block| { + get_enclosing_block(cx, if_expr.hir_id).is_some_and(|block| { let ignore_span = block.span.shrink_to_lo().to(if_expr.span); symbols diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index edb52851e0c..dff60f76b74 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -481,6 +481,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::methods::UNNECESSARY_JOIN_INFO, crate::methods::UNNECESSARY_LAZY_EVALUATIONS_INFO, crate::methods::UNNECESSARY_LITERAL_UNWRAP_INFO, + crate::methods::UNNECESSARY_MAP_OR_INFO, crate::methods::UNNECESSARY_MIN_OR_MAX_INFO, crate::methods::UNNECESSARY_RESULT_MAP_OR_ELSE_INFO, crate::methods::UNNECESSARY_SORT_BY_INFO, diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs index 4808c372754..ef6b141920d 100644 --- a/clippy_lints/src/default_numeric_fallback.rs +++ b/clippy_lints/src/default_numeric_fallback.rs @@ -253,6 +253,6 @@ impl<'tcx> From> for ExplicitTyBound { impl<'tcx> From>> for ExplicitTyBound { fn from(v: Option>) -> Self { - Self(v.map_or(false, Ty::is_numeric)) + Self(v.is_some_and(Ty::is_numeric)) } } diff --git a/clippy_lints/src/derivable_impls.rs b/clippy_lints/src/derivable_impls.rs index 2b6bfafe695..767dda552bc 100644 --- a/clippy_lints/src/derivable_impls.rs +++ b/clippy_lints/src/derivable_impls.rs @@ -81,7 +81,7 @@ fn is_path_self(e: &Expr<'_>) -> bool { fn contains_trait_object(ty: Ty<'_>) -> bool { match ty.kind() { ty::Ref(_, ty, _) => contains_trait_object(*ty), - ty::Adt(def, args) => def.is_box() && args[0].as_type().map_or(false, contains_trait_object), + ty::Adt(def, args) => def.is_box() && args[0].as_type().is_some_and(contains_trait_object), ty::Dynamic(..) => true, _ => false, } diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index e569c4dc786..0db6a822ec0 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -327,7 +327,7 @@ fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &h // there's a Copy impl for any instance of the adt. if !is_copy(cx, ty) { if ty_subs.non_erasable_generics().next().is_some() { - let has_copy_impl = cx.tcx.all_local_trait_impls(()).get(©_id).map_or(false, |impls| { + let has_copy_impl = cx.tcx.all_local_trait_impls(()).get(©_id).is_some_and(|impls| { impls.iter().any(|&id| { matches!(cx.tcx.type_of(id).instantiate_identity().kind(), ty::Adt(adt, _) if ty_adt.did() == adt.did()) diff --git a/clippy_lints/src/doc/missing_headers.rs b/clippy_lints/src/doc/missing_headers.rs index c9173030a55..40377dd841e 100644 --- a/clippy_lints/src/doc/missing_headers.rs +++ b/clippy_lints/src/doc/missing_headers.rs @@ -47,7 +47,7 @@ pub fn check( ), _ => (), } - if !headers.panics && panic_info.map_or(false, |el| !el.1) { + if !headers.panics && panic_info.is_some_and(|el| !el.1) { span_lint_and_note( cx, MISSING_PANICS_DOC, diff --git a/clippy_lints/src/drop_forget_ref.rs b/clippy_lints/src/drop_forget_ref.rs index c7dd7292a14..55afdbf22e1 100644 --- a/clippy_lints/src/drop_forget_ref.rs +++ b/clippy_lints/src/drop_forget_ref.rs @@ -112,7 +112,7 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef { MEM_FORGET, Cow::Owned(format!( "usage of `mem::forget` on {}", - if arg_ty.ty_adt_def().map_or(false, |def| def.has_dtor(cx.tcx)) { + if arg_ty.ty_adt_def().is_some_and(|def| def.has_dtor(cx.tcx)) { "`Drop` type" } else { "type with `Drop` fields" diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index de10b7bf533..6c87a05ace3 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -196,7 +196,7 @@ fn check_clousure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tc { span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure", |diag| { if let Some(mut snippet) = snippet_opt(cx, callee.span) { - if path_to_local(callee).map_or(false, |l| { + if path_to_local(callee).is_some_and(|l| { // FIXME: Do we really need this `local_used_in` check? // Isn't it checking something like... `callee(callee)`? // If somehow this check is needed, add some test for it, 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 c2b40ae01d4..4986a311eba 100644 --- a/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs +++ b/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs @@ -87,7 +87,7 @@ fn raw_ptr_arg(cx: &LateContext<'_>, arg: &hir::Param<'_>) -> Option { } fn check_arg(cx: &LateContext<'_>, raw_ptrs: &HirIdSet, arg: &hir::Expr<'_>) { - if path_to_local(arg).map_or(false, |id| raw_ptrs.contains(&id)) { + if path_to_local(arg).is_some_and(|id| raw_ptrs.contains(&id)) { span_lint( cx, NOT_UNSAFE_PTR_ARG_DEREF, diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs index 48874d6064b..d3aade31f14 100644 --- a/clippy_lints/src/infinite_iter.rs +++ b/clippy_lints/src/infinite_iter.rs @@ -171,13 +171,13 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { 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)) + .is_some_and(|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(), + ExprKind::Struct(..) => higher::Range::hir(expr).is_some_and(|r| r.end.is_none()).into(), _ => Finite, } } @@ -228,9 +228,7 @@ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { 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, &[]) - }); + .is_some_and(|id| !implements_trait(cx, cx.typeck_results().expr_ty(receiver), id, &[])); if not_double_ended { return is_infinite(cx, receiver); } diff --git a/clippy_lints/src/item_name_repetitions.rs b/clippy_lints/src/item_name_repetitions.rs index dd90e2a6e94..6363f717a5c 100644 --- a/clippy_lints/src/item_name_repetitions.rs +++ b/clippy_lints/src/item_name_repetitions.rs @@ -309,8 +309,8 @@ fn check_enum_start(cx: &LateContext<'_>, item_name: &str, variant: &Variant<'_> let item_name_chars = item_name.chars().count(); if count_match_start(item_name, name).char_count == item_name_chars - && name.chars().nth(item_name_chars).map_or(false, |c| !c.is_lowercase()) - && name.chars().nth(item_name_chars + 1).map_or(false, |c| !c.is_numeric()) + && name.chars().nth(item_name_chars).is_some_and(|c| !c.is_lowercase()) + && name.chars().nth(item_name_chars + 1).is_some_and(|c| !c.is_numeric()) { span_lint_hir( cx, diff --git a/clippy_lints/src/iter_not_returning_iterator.rs b/clippy_lints/src/iter_not_returning_iterator.rs index b19b348c743..25105817ad9 100644 --- a/clippy_lints/src/iter_not_returning_iterator.rs +++ b/clippy_lints/src/iter_not_returning_iterator.rs @@ -75,7 +75,7 @@ fn check_sig(cx: &LateContext<'_>, name: Symbol, sig: &FnSig<'_>, fn_id: LocalDe if cx .tcx .get_diagnostic_item(sym::Iterator) - .map_or(false, |iter_id| !implements_trait(cx, ret_ty, iter_id, &[])) + .is_some_and(|iter_id| !implements_trait(cx, ret_ty, iter_id, &[])) { span_lint( cx, diff --git a/clippy_lints/src/large_const_arrays.rs b/clippy_lints/src/large_const_arrays.rs index 44b9d6adaaa..c5a2760234f 100644 --- a/clippy_lints/src/large_const_arrays.rs +++ b/clippy_lints/src/large_const_arrays.rs @@ -56,7 +56,8 @@ impl<'tcx> LateLintPass<'tcx> for LargeConstArrays { && !item.span.from_expansion() && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity() && let ty::Array(element_type, cst) = ty.kind() - && let Some((ty::ValTree::Leaf(element_count), _)) = cx.tcx.try_normalize_erasing_regions(ParamEnv::empty(), *cst).unwrap_or(*cst).try_to_valtree() + && let Some((ty::ValTree::Leaf(element_count), _)) = cx.tcx + .try_normalize_erasing_regions(ParamEnv::empty(), *cst).unwrap_or(*cst).try_to_valtree() && let element_count = element_count.to_target_usize(cx.tcx) && let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes()) && u128::from(self.maximum_allowed_size) < u128::from(element_count) * u128::from(element_size) diff --git a/clippy_lints/src/large_include_file.rs b/clippy_lints/src/large_include_file.rs index ab3d19f89c3..4f22931a4de 100644 --- a/clippy_lints/src/large_include_file.rs +++ b/clippy_lints/src/large_include_file.rs @@ -94,6 +94,8 @@ impl LateLintPass<'_> for LargeIncludeFile { // Currently, rustc limits the usage of macro at the top-level of attributes, // so we don't need to recurse into each level. && let AttrKind::Normal(ref normal) = attr.kind + && let Some(doc) = attr.doc_str() + && doc.as_str().len() as u64 > self.max_file_size && let AttrArgs::Eq(_, AttrArgsEq::Hir(ref meta)) = normal.item.args && !attr.span.contains(meta.span) // Since the `include_str` is already expanded at this point, we can only take the diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index b7887ef76a5..3ea758e176f 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -622,7 +622,7 @@ fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { let ty = &cx.typeck_results().expr_ty(expr).peel_refs(); match ty.kind() { - ty::Dynamic(tt, ..) => tt.principal().map_or(false, |principal| { + ty::Dynamic(tt, ..) => tt.principal().is_some_and(|principal| { let is_empty = sym!(is_empty); cx.tcx .associated_items(principal.def_id()) diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index d55be2b036a..ce0e1a24a7b 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -737,7 +737,7 @@ fn elision_suggestions( suggestions.extend( usages .iter() - .filter(|usage| named_lifetime(usage).map_or(false, |id| elidable_lts.contains(&id))) + .filter(|usage| named_lifetime(usage).is_some_and(|id| elidable_lts.contains(&id))) .map(|usage| { match cx.tcx.parent_hir_node(usage.hir_id) { Node::Ty(Ty { diff --git a/clippy_lints/src/loops/manual_find.rs b/clippy_lints/src/loops/manual_find.rs index bfe2e68b5d1..1721f569541 100644 --- a/clippy_lints/src/loops/manual_find.rs +++ b/clippy_lints/src/loops/manual_find.rs @@ -58,7 +58,7 @@ pub(super) fn check<'tcx>( .tcx .lang_items() .copy_trait() - .map_or(false, |id| implements_trait(cx, ty, id, &[])) + .is_some_and(|id| implements_trait(cx, ty, id, &[])) { snippet.push_str( &format!( diff --git a/clippy_lints/src/loops/manual_memcpy.rs b/clippy_lints/src/loops/manual_memcpy.rs index af089451759..701567a7d84 100644 --- a/clippy_lints/src/loops/manual_memcpy.rs +++ b/clippy_lints/src/loops/manual_memcpy.rs @@ -416,7 +416,7 @@ fn get_assignments<'a, 'tcx>( .chain(*expr) .filter(move |e| { if let ExprKind::AssignOp(_, place, _) = e.kind { - path_to_local(place).map_or(false, |id| { + path_to_local(place).is_some_and(|id| { !loop_counters .iter() // skip the first item which should be `StartKind::Range` diff --git a/clippy_lints/src/loops/mut_range_bound.rs b/clippy_lints/src/loops/mut_range_bound.rs index 094b1947324..39e5e140b7a 100644 --- a/clippy_lints/src/loops/mut_range_bound.rs +++ b/clippy_lints/src/loops/mut_range_bound.rs @@ -126,7 +126,7 @@ impl BreakAfterExprVisitor { break_after_expr: false, }; - get_enclosing_block(cx, hir_id).map_or(false, |block| { + get_enclosing_block(cx, hir_id).is_some_and(|block| { visitor.visit_block(block); visitor.break_after_expr }) diff --git a/clippy_lints/src/loops/same_item_push.rs b/clippy_lints/src/loops/same_item_push.rs index d255fea3af2..951ebc9caef 100644 --- a/clippy_lints/src/loops/same_item_push.rs +++ b/clippy_lints/src/loops/same_item_push.rs @@ -50,7 +50,7 @@ pub(super) fn check<'tcx>( .tcx .lang_items() .clone_trait() - .map_or(false, |id| implements_trait(cx, ty, id, &[])) + .is_some_and(|id| implements_trait(cx, ty, id, &[])) { // Make sure that the push does not involve possibly mutating values match pushed_item.kind { diff --git a/clippy_lints/src/loops/utils.rs b/clippy_lints/src/loops/utils.rs index c4c504e1ae4..51fde5288ab 100644 --- a/clippy_lints/src/loops/utils.rs +++ b/clippy_lints/src/loops/utils.rs @@ -256,9 +256,10 @@ fn is_conditional(expr: &Expr<'_>) -> bool { /// If `arg` was the argument to a `for` loop, return the "cleanest" way of writing the /// actual `Iterator` that the loop uses. pub(super) fn make_iterator_snippet(cx: &LateContext<'_>, arg: &Expr<'_>, applic_ref: &mut Applicability) -> String { - let impls_iterator = cx.tcx.get_diagnostic_item(sym::Iterator).map_or(false, |id| { - implements_trait(cx, cx.typeck_results().expr_ty(arg), id, &[]) - }); + let impls_iterator = cx + .tcx + .get_diagnostic_item(sym::Iterator) + .is_some_and(|id| implements_trait(cx, cx.typeck_results().expr_ty(arg), id, &[])); if impls_iterator { format!( "{}", diff --git a/clippy_lints/src/manual_clamp.rs b/clippy_lints/src/manual_clamp.rs index fd66cacdfe9..016ec7320a6 100644 --- a/clippy_lints/src/manual_clamp.rs +++ b/clippy_lints/src/manual_clamp.rs @@ -226,7 +226,7 @@ impl TypeClampability { } else if cx .tcx .get_diagnostic_item(sym::Ord) - .map_or(false, |id| implements_trait(cx, ty, id, &[])) + .is_some_and(|id| implements_trait(cx, ty, id, &[])) { Some(TypeClampability::Ord) } else { diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index 828c5a3f6ff..3f401eff6bd 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -162,9 +162,9 @@ fn eq_pattern_length<'tcx>(cx: &LateContext<'tcx>, pattern: &Expr<'_>, expr: &'t .. }) = expr.kind { - constant_length(cx, pattern).map_or(false, |length| *n == length) + constant_length(cx, pattern).is_some_and(|length| *n == length) } else { - len_arg(cx, expr).map_or(false, |arg| eq_expr_value(cx, pattern, arg)) + len_arg(cx, expr).is_some_and(|arg| eq_expr_value(cx, pattern, arg)) } } diff --git a/clippy_lints/src/matches/match_like_matches.rs b/clippy_lints/src/matches/match_like_matches.rs index 6d62b530ae7..47472ab831f 100644 --- a/clippy_lints/src/matches/match_like_matches.rs +++ b/clippy_lints/src/matches/match_like_matches.rs @@ -74,7 +74,7 @@ where && b0 != b1 && (first_guard.is_none() || iter.len() == 0) && first_attrs.is_empty() - && iter.all(|arm| find_bool_lit(&arm.2.kind).map_or(false, |b| b == b0) && arm.3.is_none() && arm.0.is_empty()) + && iter.all(|arm| find_bool_lit(&arm.2.kind).is_some_and(|b| b == b0) && arm.3.is_none() && arm.0.is_empty()) { if let Some(last_pat) = last_pat_opt { if !is_wild(last_pat) { diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs index ca45ed6ea59..264458a86ef 100644 --- a/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/clippy_lints/src/matches/redundant_pattern_match.rs @@ -447,7 +447,7 @@ fn is_pat_variant(cx: &LateContext<'_>, pat: &Pat<'_>, path: &QPath<'_>, expecte .tcx .lang_items() .get(expected_lang_item) - .map_or(false, |expected_id| cx.tcx.parent(id) == expected_id), + .is_some_and(|expected_id| cx.tcx.parent(id) == expected_id), Item::Diag(expected_ty, expected_variant) => { let ty = cx.typeck_results().pat_ty(pat); diff --git a/clippy_lints/src/matches/single_match.rs b/clippy_lints/src/matches/single_match.rs index 2aea25b5f12..95a4bf6f60d 100644 --- a/clippy_lints/src/matches/single_match.rs +++ b/clippy_lints/src/matches/single_match.rs @@ -175,7 +175,7 @@ impl<'tcx> Visitor<'tcx> for PatVisitor<'tcx> { if matches!(pat.kind, PatKind::Binding(..)) { ControlFlow::Break(()) } else { - self.has_enum |= self.typeck.pat_ty(pat).ty_adt_def().map_or(false, AdtDef::is_enum); + self.has_enum |= self.typeck.pat_ty(pat).ty_adt_def().is_some_and(AdtDef::is_enum); walk_pat(self, pat) } } diff --git a/clippy_lints/src/matches/try_err.rs b/clippy_lints/src/matches/try_err.rs index c7e1b70d19e..6c02207af49 100644 --- a/clippy_lints/src/matches/try_err.rs +++ b/clippy_lints/src/matches/try_err.rs @@ -58,7 +58,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, scrutine let span = hygiene::walk_chain(err_arg.span, try_arg.span.ctxt()); let mut applicability = Applicability::MachineApplicable; let origin_snippet = snippet_with_applicability(cx, span, "_", &mut applicability); - let ret_prefix = if get_parent_expr(cx, expr).map_or(false, |e| matches!(e.kind, ExprKind::Ret(_))) { + let ret_prefix = if get_parent_expr(cx, expr).is_some_and(|e| matches!(e.kind, ExprKind::Ret(_))) { "" // already returns } else { "return " diff --git a/clippy_lints/src/methods/expect_fun_call.rs b/clippy_lints/src/methods/expect_fun_call.rs index c288dbdabe9..6dc48c26ba9 100644 --- a/clippy_lints/src/methods/expect_fun_call.rs +++ b/clippy_lints/src/methods/expect_fun_call.rs @@ -83,7 +83,7 @@ pub(super) fn check<'tcx>( hir::ExprKind::MethodCall(..) => { cx.typeck_results() .type_dependent_def_id(arg.hir_id) - .map_or(false, |method_id| { + .is_some_and(|method_id| { matches!( cx.tcx.fn_sig(method_id).instantiate_identity().output().skip_binder().kind(), ty::Ref(re, ..) if re.is_static() diff --git a/clippy_lints/src/methods/filter_next.rs b/clippy_lints/src/methods/filter_next.rs index e697ba656f5..6c1a14fc882 100644 --- a/clippy_lints/src/methods/filter_next.rs +++ b/clippy_lints/src/methods/filter_next.rs @@ -32,9 +32,10 @@ pub(super) fn check<'tcx>( filter_arg: &'tcx hir::Expr<'_>, ) { // lint if caller of `.filter().next()` is an Iterator - let recv_impls_iterator = cx.tcx.get_diagnostic_item(sym::Iterator).map_or(false, |id| { - implements_trait(cx, cx.typeck_results().expr_ty(recv), id, &[]) - }); + let recv_impls_iterator = cx + .tcx + .get_diagnostic_item(sym::Iterator) + .is_some_and(|id| implements_trait(cx, cx.typeck_results().expr_ty(recv), id, &[])); if recv_impls_iterator { let msg = "called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling \ `.find(..)` instead"; diff --git a/clippy_lints/src/methods/manual_next_back.rs b/clippy_lints/src/methods/manual_next_back.rs index 5f3fec53827..9a03559b223 100644 --- a/clippy_lints/src/methods/manual_next_back.rs +++ b/clippy_lints/src/methods/manual_next_back.rs @@ -19,9 +19,7 @@ pub(super) fn check<'tcx>( if cx .tcx .get_diagnostic_item(sym::DoubleEndedIterator) - .map_or(false, |double_ended_iterator| { - implements_trait(cx, rev_recv_ty, double_ended_iterator, &[]) - }) + .is_some_and(|double_ended_iterator| implements_trait(cx, rev_recv_ty, double_ended_iterator, &[])) && is_trait_method(cx, rev_call, sym::Iterator) && is_trait_method(cx, expr, sym::Iterator) { diff --git a/clippy_lints/src/methods/manual_str_repeat.rs b/clippy_lints/src/methods/manual_str_repeat.rs index 61e74369cb0..098721dc046 100644 --- a/clippy_lints/src/methods/manual_str_repeat.rs +++ b/clippy_lints/src/methods/manual_str_repeat.rs @@ -36,8 +36,8 @@ fn parse_repeat_arg(cx: &LateContext<'_>, e: &Expr<'_>) -> Option { } else { let ty = cx.typeck_results().expr_ty(e); if is_type_lang_item(cx, ty, LangItem::String) - || (is_type_lang_item(cx, ty, LangItem::OwnedBox) && 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)) + || (is_type_lang_item(cx, ty, LangItem::OwnedBox) && get_ty_param(ty).is_some_and(Ty::is_str)) + || (is_type_diagnostic_item(cx, ty, sym::Cow) && get_ty_param(ty).is_some_and(Ty::is_str)) { Some(RepeatKind::String) } else { diff --git a/clippy_lints/src/methods/map_clone.rs b/clippy_lints/src/methods/map_clone.rs index 515d4a11ed5..d5594b21db5 100644 --- a/clippy_lints/src/methods/map_clone.rs +++ b/clippy_lints/src/methods/map_clone.rs @@ -70,7 +70,7 @@ pub(super) fn check(cx: &LateContext<'_>, e: &hir::Expr<'_>, recv: &hir::Expr<'_ if ident_eq(name, obj) && method.ident.name == sym::clone && let Some(fn_id) = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id) && let Some(trait_id) = cx.tcx.trait_of_item(fn_id) - && cx.tcx.lang_items().clone_trait().map_or(false, |id| id == trait_id) + && cx.tcx.lang_items().clone_trait() == Some(trait_id) // no autoderefs && !cx.typeck_results().expr_adjustments(obj).iter() .any(|a| matches!(a.kind, Adjust::Deref(Some(..)))) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index b1809796355..795e041ffd9 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -121,6 +121,7 @@ mod unnecessary_iter_cloned; mod unnecessary_join; mod unnecessary_lazy_eval; mod unnecessary_literal_unwrap; +mod unnecessary_map_or; mod unnecessary_min_or_max; mod unnecessary_result_map_or_else; mod unnecessary_sort_by; @@ -4099,6 +4100,33 @@ declare_clippy_lint! { "is_empty() called on strings known at compile time" } +declare_clippy_lint! { + /// ### What it does + /// Converts some constructs mapping an Enum value for equality comparison. + /// + /// ### Why is this bad? + /// Calls such as `opt.map_or(false, |val| val == 5)` are needlessly long and cumbersome, + /// and can be reduced to, for example, `opt == Some(5)` assuming `opt` implements `PartialEq`. + /// This lint offers readability and conciseness improvements. + /// + /// ### Example + /// ```no_run + /// pub fn a(x: Option) -> bool { + /// x.map_or(false, |n| n == 5) + /// } + /// ``` + /// Use instead: + /// ```no_run + /// pub fn a(x: Option) -> bool { + /// x == Some(5) + /// } + /// ``` + #[clippy::version = "1.75.0"] + pub UNNECESSARY_MAP_OR, + style, + "reduce unnecessary pattern matching for constructs that implement `PartialEq`" +} + declare_clippy_lint! { /// ### What it does /// Checks if an iterator is used to check if a string is ascii. @@ -4417,6 +4445,7 @@ impl_lint_pass!(Methods => [ NEEDLESS_AS_BYTES, MAP_ALL_ANY_IDENTITY, MAP_WITH_UNUSED_ARGUMENT_OVER_RANGES, + UNNECESSARY_MAP_OR, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -4950,6 +4979,7 @@ impl Methods { option_map_or_none::check(cx, expr, recv, def, map); manual_ok_or::check(cx, expr, recv, def, map); option_map_or_err_ok::check(cx, expr, recv, def, map); + unnecessary_map_or::check(cx, expr, recv, def, map, &self.msrv); }, ("map_or_else", [def, map]) => { result_map_or_else_none::check(cx, expr, recv, def, map); @@ -5343,7 +5373,7 @@ impl SelfKind { boxed_ty == parent_ty } else if is_type_diagnostic_item(cx, ty, sym::Rc) || is_type_diagnostic_item(cx, ty, sym::Arc) { if let ty::Adt(_, args) = ty.kind() { - args.types().next().map_or(false, |t| t == parent_ty) + args.types().next() == Some(parent_ty) } else { false } diff --git a/clippy_lints/src/methods/needless_collect.rs b/clippy_lints/src/methods/needless_collect.rs index 055107068ae..9c41528e647 100644 --- a/clippy_lints/src/methods/needless_collect.rs +++ b/clippy_lints/src/methods/needless_collect.rs @@ -193,7 +193,7 @@ fn check_collect_into_intoiterator<'tcx>( /// Checks if the given method call matches the expected signature of `([&[mut]] self) -> bool` fn is_is_empty_sig(cx: &LateContext<'_>, call_id: HirId) -> bool { - cx.typeck_results().type_dependent_def_id(call_id).map_or(false, |id| { + cx.typeck_results().type_dependent_def_id(call_id).is_some_and(|id| { let sig = cx.tcx.fn_sig(id).instantiate_identity().skip_binder(); sig.inputs().len() == 1 && sig.output().is_bool() }) diff --git a/clippy_lints/src/methods/option_as_ref_deref.rs b/clippy_lints/src/methods/option_as_ref_deref.rs index 389e02056b2..998bdee0157 100644 --- a/clippy_lints/src/methods/option_as_ref_deref.rs +++ b/clippy_lints/src/methods/option_as_ref_deref.rs @@ -45,7 +45,7 @@ pub(super) fn check( hir::ExprKind::Path(ref expr_qpath) => { cx.qpath_res(expr_qpath, map_arg.hir_id) .opt_def_id() - .map_or(false, |fun_def_id| { + .is_some_and(|fun_def_id| { cx.tcx.is_diagnostic_item(sym::deref_method, fun_def_id) || cx.tcx.is_diagnostic_item(sym::deref_mut_method, fun_def_id) || deref_aliases diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index b685a466b72..6b39b753885 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -59,9 +59,7 @@ pub(super) fn check<'tcx>( let output_ty = cx.tcx.fn_sig(def_id).instantiate(cx.tcx, args).skip_binder().output(); cx.tcx .get_diagnostic_item(sym::Default) - .map_or(false, |default_trait_id| { - implements_trait(cx, output_ty, default_trait_id, &[]) - }) + .is_some_and(|default_trait_id| implements_trait(cx, output_ty, default_trait_id, &[])) } else { false } diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs index a2a7de905ca..1cee28e1986 100644 --- a/clippy_lints/src/methods/str_splitn.rs +++ b/clippy_lints/src/methods/str_splitn.rs @@ -348,7 +348,7 @@ fn parse_iter_usage<'tcx>( && cx .typeck_results() .type_dependent_def_id(e.hir_id) - .map_or(false, |id| is_diag_item_method(cx, id, sym::Option)) => + .is_some_and(|id| is_diag_item_method(cx, id, sym::Option)) => { (Some(UnwrapKind::Unwrap), e.span) }, diff --git a/clippy_lints/src/methods/unnecessary_map_or.rs b/clippy_lints/src/methods/unnecessary_map_or.rs new file mode 100644 index 00000000000..adc27cd437f --- /dev/null +++ b/clippy_lints/src/methods/unnecessary_map_or.rs @@ -0,0 +1,131 @@ +use std::borrow::Cow; + +use clippy_config::msrvs::{self, Msrv}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::eager_or_lazy::switch_to_eager_eval; +use clippy_utils::source::snippet_opt; +use clippy_utils::sugg::{Sugg, make_binop}; +use clippy_utils::ty::{get_type_diagnostic_name, implements_trait}; +use clippy_utils::visitors::is_local_used; +use clippy_utils::{is_from_proc_macro, path_to_local_id}; +use rustc_ast::LitKind::Bool; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Expr, ExprKind, PatKind}; +use rustc_lint::LateContext; +use rustc_span::sym; + +use super::UNNECESSARY_MAP_OR; + +pub(super) enum Variant { + Ok, + Some, +} +impl Variant { + pub fn variant_name(&self) -> &'static str { + match self { + Variant::Ok => "Ok", + Variant::Some => "Some", + } + } + + pub fn method_name(&self) -> &'static str { + match self { + Variant::Ok => "is_ok_and", + Variant::Some => "is_some_and", + } + } +} + +pub(super) fn check<'a>( + cx: &LateContext<'a>, + expr: &Expr<'a>, + recv: &Expr<'_>, + def: &Expr<'_>, + map: &Expr<'_>, + msrv: &Msrv, +) { + let ExprKind::Lit(def_kind) = def.kind else { + return; + }; + + let recv_ty = cx.typeck_results().expr_ty(recv); + + let Bool(def_bool) = def_kind.node else { + return; + }; + + let variant = match get_type_diagnostic_name(cx, recv_ty) { + Some(sym::Option) => Variant::Some, + Some(sym::Result) => Variant::Ok, + Some(_) | None => return, + }; + + let (sugg, method) = if let ExprKind::Closure(map_closure) = map.kind + && let closure_body = cx.tcx.hir().body(map_closure.body) + && let closure_body_value = closure_body.value.peel_blocks() + && let ExprKind::Binary(op, l, r) = closure_body_value.kind + && let Some(param) = closure_body.params.first() + && let PatKind::Binding(_, hir_id, _, _) = param.pat.kind + // checking that map_or is one of the following: + // .map_or(false, |x| x == y) + // .map_or(false, |x| y == x) - swapped comparison + // .map_or(true, |x| x != y) + // .map_or(true, |x| y != x) - swapped comparison + && ((BinOpKind::Eq == op.node && !def_bool) || (BinOpKind::Ne == op.node && def_bool)) + && let non_binding_location = if path_to_local_id(l, hir_id) { r } else { l } + && switch_to_eager_eval(cx, non_binding_location) + // xor, because if its both then thats a strange edge case and + // we can just ignore it, since by default clippy will error on this + && (path_to_local_id(l, hir_id) ^ path_to_local_id(r, hir_id)) + && !is_local_used(cx, non_binding_location, hir_id) + && let typeck_results = cx.typeck_results() + && typeck_results.expr_ty(l) == typeck_results.expr_ty(r) + && let Some(partial_eq) = cx.tcx.get_diagnostic_item(sym::PartialEq) + && implements_trait(cx, recv_ty, partial_eq, &[recv_ty.into()]) + { + let wrap = variant.variant_name(); + + // we may need to add parens around the suggestion + // in case the parent expression has additional method calls, + // since for example `Some(5).map_or(false, |x| x == 5).then(|| 1)` + // being converted to `Some(5) == Some(5).then(|| 1)` isnt + // the same thing + + let inner_non_binding = Sugg::NonParen(Cow::Owned(format!( + "{wrap}({})", + Sugg::hir(cx, non_binding_location, "") + ))); + + let binop = make_binop(op.node, &Sugg::hir(cx, recv, ".."), &inner_non_binding) + .maybe_par() + .into_string(); + + (binop, "a standard comparison") + } else if !def_bool + && msrv.meets(msrvs::OPTION_RESULT_IS_VARIANT_AND) + && let Some(recv_callsite) = snippet_opt(cx, recv.span.source_callsite()) + && let Some(span_callsite) = snippet_opt(cx, map.span.source_callsite()) + { + let suggested_name = variant.method_name(); + ( + format!("{recv_callsite}.{suggested_name}({span_callsite})",), + suggested_name, + ) + } else { + return; + }; + + if is_from_proc_macro(cx, expr) { + return; + } + + span_lint_and_sugg( + cx, + UNNECESSARY_MAP_OR, + expr.span, + "this `map_or` is redundant", + format!("use {method} instead"), + sugg, + Applicability::MaybeIncorrect, + ); +} diff --git a/clippy_lints/src/methods/unnecessary_sort_by.rs b/clippy_lints/src/methods/unnecessary_sort_by.rs index 6911da69b94..603916e06c9 100644 --- a/clippy_lints/src/methods/unnecessary_sort_by.rs +++ b/clippy_lints/src/methods/unnecessary_sort_by.rs @@ -166,9 +166,10 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Exp }, )) = &left_expr.kind && left_name == left_ident - && cx.tcx.get_diagnostic_item(sym::Ord).map_or(false, |id| { - implements_trait(cx, cx.typeck_results().expr_ty(left_expr), id, &[]) - }) + && cx + .tcx + .get_diagnostic_item(sym::Ord) + .is_some_and(|id| implements_trait(cx, cx.typeck_results().expr_ty(left_expr), id, &[])) { return Some(LintTrigger::Sort(SortDetection { vec_name })); } diff --git a/clippy_lints/src/methods/useless_asref.rs b/clippy_lints/src/methods/useless_asref.rs index c309e778116..82313257e5c 100644 --- a/clippy_lints/src/methods/useless_asref.rs +++ b/clippy_lints/src/methods/useless_asref.rs @@ -124,7 +124,7 @@ fn is_calling_clone(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool { && let Some(fn_id) = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id) && let Some(trait_id) = cx.tcx.trait_of_item(fn_id) // We check it's the `Clone` trait. - && cx.tcx.lang_items().clone_trait().map_or(false, |id| id == trait_id) + && cx.tcx.lang_items().clone_trait().is_some_and(|id| id == trait_id) // no autoderefs && !cx.typeck_results().expr_adjustments(obj).iter() .any(|a| matches!(a.kind, Adjust::Deref(Some(..)))) diff --git a/clippy_lints/src/misc_early/mod.rs b/clippy_lints/src/misc_early/mod.rs index 4cba13a05c2..37d7427f9a5 100644 --- a/clippy_lints/src/misc_early/mod.rs +++ b/clippy_lints/src/misc_early/mod.rs @@ -427,7 +427,7 @@ impl MiscEarlyLints { // See for a regression. // FIXME: Find a better way to detect those cases. let lit_snip = match snippet_opt(cx, span) { - Some(snip) if snip.chars().next().map_or(false, |c| c.is_ascii_digit()) => snip, + Some(snip) if snip.chars().next().is_some_and(|c| c.is_ascii_digit()) => snip, _ => return, }; diff --git a/clippy_lints/src/needless_borrows_for_generic_args.rs b/clippy_lints/src/needless_borrows_for_generic_args.rs index f7fa31d83aa..c1424b9f1dc 100644 --- a/clippy_lints/src/needless_borrows_for_generic_args.rs +++ b/clippy_lints/src/needless_borrows_for_generic_args.rs @@ -134,9 +134,11 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowsForGenericArgs<'tcx> { } fn check_body_post(&mut self, cx: &LateContext<'tcx>, body: &Body<'_>) { - if self.possible_borrowers.last().map_or(false, |&(local_def_id, _)| { - local_def_id == cx.tcx.hir().body_owner_def_id(body.id()) - }) { + if self + .possible_borrowers + .last() + .is_some_and(|&(local_def_id, _)| local_def_id == cx.tcx.hir().body_owner_def_id(body.id())) + { self.possible_borrowers.pop(); } } @@ -232,7 +234,7 @@ fn needless_borrow_count<'tcx>( let mut check_reference_and_referent = |reference: &Expr<'tcx>, referent: &Expr<'tcx>| { if let ExprKind::Field(base, _) = &referent.kind { let base_ty = cx.typeck_results().expr_ty(base); - if drop_trait_def_id.map_or(false, |id| implements_trait(cx, base_ty, id, &[])) { + if drop_trait_def_id.is_some_and(|id| implements_trait(cx, base_ty, id, &[])) { return false; } } diff --git a/clippy_lints/src/needless_continue.rs b/clippy_lints/src/needless_continue.rs index c4836772933..c48232f9905 100644 --- a/clippy_lints/src/needless_continue.rs +++ b/clippy_lints/src/needless_continue.rs @@ -153,7 +153,7 @@ fn needless_continue_in_else(else_expr: &ast::Expr, label: Option<&ast::Label>) } fn is_first_block_stmt_continue(block: &ast::Block, label: Option<&ast::Label>) -> bool { - block.stmts.first().map_or(false, |stmt| match stmt.kind { + block.stmts.first().is_some_and(|stmt| match stmt.kind { ast::StmtKind::Semi(ref e) | ast::StmtKind::Expr(ref e) => { if let ast::ExprKind::Continue(ref l) = e.kind { compare_labels(label, l.as_ref()) @@ -390,7 +390,7 @@ fn check_and_warn(cx: &EarlyContext<'_>, expr: &ast::Expr) { #[must_use] fn erode_from_back(s: &str) -> String { let mut ret = s.to_string(); - while ret.pop().map_or(false, |c| c != '}') {} + while ret.pop().is_some_and(|c| c != '}') {} while let Some(c) = ret.pop() { if !c.is_whitespace() { ret.push(c); diff --git a/clippy_lints/src/nonstandard_macro_braces.rs b/clippy_lints/src/nonstandard_macro_braces.rs index a13391a5945..83f7d931969 100644 --- a/clippy_lints/src/nonstandard_macro_braces.rs +++ b/clippy_lints/src/nonstandard_macro_braces.rs @@ -88,7 +88,7 @@ fn is_offending_macro(cx: &EarlyContext<'_>, span: Span, mac_braces: &MacroBrace || span .macro_backtrace() .last() - .map_or(false, |e| e.macro_def_id.map_or(false, DefId::is_local)) + .is_some_and(|e| e.macro_def_id.is_some_and(DefId::is_local)) }; let span_call_site = span.ctxt().outer_expn_data().call_site; if let ExpnKind::Macro(MacroKind::Bang, mac_name) = span.ctxt().outer_expn_data().kind diff --git a/clippy_lints/src/only_used_in_recursion.rs b/clippy_lints/src/only_used_in_recursion.rs index 372128ac16f..13b3d240700 100644 --- a/clippy_lints/src/only_used_in_recursion.rs +++ b/clippy_lints/src/only_used_in_recursion.rs @@ -290,7 +290,7 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion { Some((Node::Expr(parent), child_id)) => match parent.kind { // Recursive call. Track which index the parameter is used in. ExprKind::Call(callee, args) - if path_def_id(cx, callee).map_or(false, |id| { + if path_def_id(cx, callee).is_some_and(|id| { id == param.fn_id && has_matching_args(param.fn_kind, typeck.node_args(callee.hir_id)) }) => { @@ -300,7 +300,7 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion { return; }, ExprKind::MethodCall(_, receiver, args, _) - if typeck.type_dependent_def_id(parent.hir_id).map_or(false, |id| { + if typeck.type_dependent_def_id(parent.hir_id).is_some_and(|id| { id == param.fn_id && has_matching_args(param.fn_kind, typeck.node_args(parent.hir_id)) }) => { diff --git a/clippy_lints/src/operators/arithmetic_side_effects.rs b/clippy_lints/src/operators/arithmetic_side_effects.rs index 8b9f899d82d..65ef56fd211 100644 --- a/clippy_lints/src/operators/arithmetic_side_effects.rs +++ b/clippy_lints/src/operators/arithmetic_side_effects.rs @@ -325,7 +325,7 @@ impl ArithmeticSideEffects { fn should_skip_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'tcx>) -> bool { is_lint_allowed(cx, ARITHMETIC_SIDE_EFFECTS, expr.hir_id) || self.expr_span.is_some() - || self.const_span.map_or(false, |sp| sp.contains(expr.span)) + || self.const_span.is_some_and(|sp| sp.contains(expr.span)) } } diff --git a/clippy_lints/src/operators/cmp_owned.rs b/clippy_lints/src/operators/cmp_owned.rs index 208b20a7a06..b0d872e98fd 100644 --- a/clippy_lints/src/operators/cmp_owned.rs +++ b/clippy_lints/src/operators/cmp_owned.rs @@ -42,14 +42,12 @@ fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) if typeck .type_dependent_def_id(expr.hir_id) .and_then(|id| cx.tcx.trait_of_item(id)) - .map_or(false, |id| { - matches!(cx.tcx.get_diagnostic_name(id), Some(sym::ToString | sym::ToOwned)) - }) => + .is_some_and(|id| matches!(cx.tcx.get_diagnostic_name(id), Some(sym::ToString | sym::ToOwned))) => { (arg, arg.span) }, ExprKind::Call(path, [arg]) - if path_def_id(cx, path).map_or(false, |did| { + if path_def_id(cx, path).is_some_and(|did| { if cx.tcx.is_diagnostic_item(sym::from_str_method, did) { true } else if cx.tcx.is_diagnostic_item(sym::from_fn, did) { diff --git a/clippy_lints/src/operators/identity_op.rs b/clippy_lints/src/operators/identity_op.rs index 830be50c8ba..1c2d6e90fc9 100644 --- a/clippy_lints/src/operators/identity_op.rs +++ b/clippy_lints/src/operators/identity_op.rs @@ -42,83 +42,43 @@ pub(crate) fn check<'tcx>( match op { BinOpKind::Add | BinOpKind::BitOr | BinOpKind::BitXor => { - let _ = check_op( - cx, - left, - 0, - expr.span, - peeled_right_span, - needs_parenthesis(cx, expr, right), - right_is_coerced_to_value, - ) || check_op( - cx, - right, - 0, - expr.span, - peeled_left_span, - Parens::Unneeded, - left_is_coerced_to_value, - ); + if is_redundant_op(cx, left, 0) { + let paren = needs_parenthesis(cx, expr, right); + span_ineffective_operation(cx, expr.span, peeled_right_span, paren, right_is_coerced_to_value); + } else if is_redundant_op(cx, right, 0) { + let paren = needs_parenthesis(cx, expr, left); + span_ineffective_operation(cx, expr.span, peeled_left_span, paren, left_is_coerced_to_value); + } }, BinOpKind::Shl | BinOpKind::Shr | BinOpKind::Sub => { - let _ = check_op( - cx, - right, - 0, - expr.span, - peeled_left_span, - Parens::Unneeded, - left_is_coerced_to_value, - ); + if is_redundant_op(cx, right, 0) { + let paren = needs_parenthesis(cx, expr, left); + span_ineffective_operation(cx, expr.span, peeled_left_span, paren, left_is_coerced_to_value); + } }, BinOpKind::Mul => { - let _ = check_op( - cx, - left, - 1, - expr.span, - peeled_right_span, - needs_parenthesis(cx, expr, right), - right_is_coerced_to_value, - ) || check_op( - cx, - right, - 1, - expr.span, - peeled_left_span, - Parens::Unneeded, - left_is_coerced_to_value, - ); + if is_redundant_op(cx, left, 1) { + let paren = needs_parenthesis(cx, expr, right); + span_ineffective_operation(cx, expr.span, peeled_right_span, paren, right_is_coerced_to_value); + } else if is_redundant_op(cx, right, 1) { + let paren = needs_parenthesis(cx, expr, left); + span_ineffective_operation(cx, expr.span, peeled_left_span, paren, left_is_coerced_to_value); + } }, BinOpKind::Div => { - let _ = check_op( - cx, - right, - 1, - expr.span, - peeled_left_span, - Parens::Unneeded, - left_is_coerced_to_value, - ); + if is_redundant_op(cx, right, 1) { + let paren = needs_parenthesis(cx, expr, left); + span_ineffective_operation(cx, expr.span, peeled_left_span, paren, left_is_coerced_to_value); + } }, BinOpKind::BitAnd => { - let _ = check_op( - cx, - left, - -1, - expr.span, - peeled_right_span, - needs_parenthesis(cx, expr, right), - right_is_coerced_to_value, - ) || check_op( - cx, - right, - -1, - expr.span, - peeled_left_span, - Parens::Unneeded, - left_is_coerced_to_value, - ); + if is_redundant_op(cx, left, -1) { + let paren = needs_parenthesis(cx, expr, right); + span_ineffective_operation(cx, expr.span, peeled_right_span, paren, right_is_coerced_to_value); + } else if is_redundant_op(cx, right, -1) { + let paren = needs_parenthesis(cx, expr, left); + span_ineffective_operation(cx, expr.span, peeled_left_span, paren, left_is_coerced_to_value); + } }, BinOpKind::Rem => check_remainder(cx, left, right, expr.span, left.span), _ => (), @@ -138,43 +98,70 @@ enum Parens { Unneeded, } -/// Checks if `left op right` needs parenthesis when reduced to `right` +/// Checks if a binary expression needs parenthesis when reduced to just its +/// right or left child. +/// +/// e.g. `-(x + y + 0)` cannot be reduced to `-x + y`, as the behavior changes silently. +/// e.g. `1u64 + ((x + y + 0i32) as u64)` cannot be reduced to `1u64 + x + y as u64`, since +/// the the cast expression will not apply to the same expression. /// e.g. `0 + if b { 1 } else { 2 } + if b { 3 } else { 4 }` cannot be reduced /// to `if b { 1 } else { 2 } + if b { 3 } else { 4 }` where the `if` could be -/// interpreted as a statement +/// interpreted as a statement. The same behavior happens for `match`, `loop`, +/// and blocks. +/// e.g. `2 * (0 + { a })` can be reduced to `2 * { a }` without the need for parenthesis, +/// but `1 * ({ a } + 4)` cannot be reduced to `{ a } + 4`, as a block at the start of a line +/// will be interpreted as a statement instead of an expression. /// -/// See #8724 -fn needs_parenthesis(cx: &LateContext<'_>, binary: &Expr<'_>, right: &Expr<'_>) -> Parens { - match right.kind { +/// See #8724, #13470 +fn needs_parenthesis(cx: &LateContext<'_>, binary: &Expr<'_>, child: &Expr<'_>) -> Parens { + match child.kind { ExprKind::Binary(_, lhs, _) | ExprKind::Cast(lhs, _) => { - // ensure we're checking against the leftmost expression of `right` - // - // ~~~ `lhs` - // 0 + {4} * 2 - // ~~~~~~~ `right` - return needs_parenthesis(cx, binary, lhs); + // For casts and binary expressions, we want to add parenthesis if + // the parent HIR node is an expression, or if the parent HIR node + // is a Block or Stmt, and the new left hand side would need + // parenthesis be treated as a statement rather than an expression. + if let Some((_, parent)) = cx.tcx.hir().parent_iter(binary.hir_id).next() { + match parent { + Node::Expr(_) => return Parens::Needed, + Node::Block(_) | Node::Stmt(_) => { + // ensure we're checking against the leftmost expression of `child` + // + // ~~~~~~~~~~~ `binary` + // ~~~ `lhs` + // 0 + {4} * 2 + // ~~~~~~~ `child` + return needs_parenthesis(cx, binary, lhs); + }, + _ => return Parens::Unneeded, + } + } + }, + ExprKind::If(..) | ExprKind::Match(..) | ExprKind::Block(..) | ExprKind::Loop(..) => { + // For if, match, block, and loop expressions, we want to add parenthesis if + // the closest ancestor node that is not an expression is a block or statement. + // This would mean that the rustfix suggestion will appear at the start of a line, which causes + // these expressions to be interpreted as statements if they do not have parenthesis. + let mut prev_id = binary.hir_id; + for (_, parent) in cx.tcx.hir().parent_iter(binary.hir_id) { + if let Node::Expr(expr) = parent + && let ExprKind::Binary(_, lhs, _) | ExprKind::Cast(lhs, _) | ExprKind::Unary(_, lhs) = expr.kind + && lhs.hir_id == prev_id + { + // keep going until we find a node that encompasses left of `binary` + prev_id = expr.hir_id; + continue; + } + + match parent { + Node::Block(_) | Node::Stmt(_) => return Parens::Needed, + _ => return Parens::Unneeded, + }; + } + }, + _ => { + return Parens::Unneeded; }, - ExprKind::If(..) | ExprKind::Match(..) | ExprKind::Block(..) | ExprKind::Loop(..) => {}, - _ => return Parens::Unneeded, } - - let mut prev_id = binary.hir_id; - for (_, node) in cx.tcx.hir().parent_iter(binary.hir_id) { - if let Node::Expr(expr) = node - && let ExprKind::Binary(_, lhs, _) | ExprKind::Cast(lhs, _) = expr.kind - && lhs.hir_id == prev_id - { - // keep going until we find a node that encompasses left of `binary` - prev_id = expr.hir_id; - continue; - } - - match node { - Node::Block(_) | Node::Stmt(_) => break, - _ => return Parens::Unneeded, - }; - } - Parens::Needed } @@ -199,7 +186,7 @@ fn check_remainder(cx: &LateContext<'_>, left: &Expr<'_>, right: &Expr<'_>, span } } -fn check_op(cx: &LateContext<'_>, e: &Expr<'_>, m: i8, span: Span, arg: Span, parens: Parens, is_erased: bool) -> bool { +fn is_redundant_op(cx: &LateContext<'_>, e: &Expr<'_>, m: i8) -> bool { if let Some(Constant::Int(v)) = ConstEvalCtxt::new(cx).eval_simple(e).map(Constant::peel_refs) { let check = match *cx.typeck_results().expr_ty(e).peel_refs().kind() { ty::Int(ity) => unsext(cx.tcx, -1_i128, ity), @@ -212,7 +199,6 @@ fn check_op(cx: &LateContext<'_>, e: &Expr<'_>, m: i8, span: Span, arg: Span, pa 1 => v == 1, _ => unreachable!(), } { - span_ineffective_operation(cx, span, arg, parens, is_erased); return true; } } diff --git a/clippy_lints/src/operators/numeric_arithmetic.rs b/clippy_lints/src/operators/numeric_arithmetic.rs index 565294bb40a..d369978b8be 100644 --- a/clippy_lints/src/operators/numeric_arithmetic.rs +++ b/clippy_lints/src/operators/numeric_arithmetic.rs @@ -14,7 +14,7 @@ pub struct Context { } impl Context { fn skip_expr(&mut self, e: &hir::Expr<'_>) -> bool { - self.expr_id.is_some() || self.const_span.map_or(false, |span| span.contains(e.span)) + self.expr_id.is_some() || self.const_span.is_some_and(|span| span.contains(e.span)) } pub fn check_binary<'tcx>( diff --git a/clippy_lints/src/pass_by_ref_or_value.rs b/clippy_lints/src/pass_by_ref_or_value.rs index 1bddfab39c6..b2089487a9f 100644 --- a/clippy_lints/src/pass_by_ref_or_value.rs +++ b/clippy_lints/src/pass_by_ref_or_value.rs @@ -192,7 +192,7 @@ impl PassByRefOrValue { continue; } } - let value_type = if fn_body.and_then(|body| body.params.get(index)).map_or(false, is_self) { + let value_type = if fn_body.and_then(|body| body.params.get(index)).is_some_and(is_self) { "self".into() } else { snippet(cx, decl_ty.span, "_").into() diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index a548c6ef3b1..ecc095f3859 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -727,9 +727,8 @@ fn get_ref_lm<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> Option<(&'tcx Lifetime, Mutabili fn is_null_path(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { if let ExprKind::Call(pathexp, []) = expr.kind { - path_def_id(cx, pathexp).map_or(false, |id| { - matches!(cx.tcx.get_diagnostic_name(id), Some(sym::ptr_null | sym::ptr_null_mut)) - }) + path_def_id(cx, pathexp) + .is_some_and(|id| matches!(cx.tcx.get_diagnostic_name(id), Some(sym::ptr_null | sym::ptr_null_mut))) } else { false } diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index cb374fcf20e..a00fd01a62e 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -8,18 +8,18 @@ use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use clippy_utils::{ eq_expr_value, higher, is_else_clause, is_in_const_context, is_lint_allowed, is_path_lang_item, is_res_lang_ctor, - pat_and_expr_can_be_question_mark, path_to_local, path_to_local_id, peel_blocks, peel_blocks_with_stmt, - span_contains_comment, + pat_and_expr_can_be_question_mark, path_res, path_to_local, path_to_local_id, peel_blocks, peel_blocks_with_stmt, + span_contains_cfg, span_contains_comment, }; use rustc_errors::Applicability; use rustc_hir::LangItem::{self, OptionNone, OptionSome, ResultErr, ResultOk}; use rustc_hir::def::Res; use rustc_hir::{ - BindingMode, Block, Body, ByRef, Expr, ExprKind, LetStmt, Mutability, Node, PatKind, PathSegment, QPath, Stmt, - StmtKind, + Arm, BindingMode, Block, Body, ByRef, Expr, ExprKind, FnRetTy, HirId, LetStmt, MatchSource, Mutability, Node, Pat, + PatKind, PathSegment, QPath, Stmt, StmtKind, }; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::Ty; +use rustc_middle::ty::{self, Ty}; use rustc_session::impl_lint_pass; use rustc_span::sym; use rustc_span::symbol::Symbol; @@ -58,6 +58,9 @@ pub struct QuestionMark { /// if it is greater than zero. /// As for why we need this in the first place: try_block_depth_stack: Vec, + /// Keeps track of the number of inferred return type closures we are inside, to avoid problems + /// with the `Err(x.into())` expansion being ambiguious. + inferred_ret_closure_stack: u16, } impl_lint_pass!(QuestionMark => [QUESTION_MARK, MANUAL_LET_ELSE]); @@ -68,6 +71,7 @@ impl QuestionMark { msrv: conf.msrv.clone(), matches_behaviour: conf.matches_for_let_else, try_block_depth_stack: Vec::new(), + inferred_ret_closure_stack: 0, } } } @@ -125,7 +129,7 @@ fn check_let_some_else_return_none(cx: &LateContext<'_>, stmt: &Stmt<'_>) { cx.tcx .lang_items() .try_trait() - .map_or(false, |did| implements_trait(cx, init_ty, did, &[])) + .is_some_and(|did| implements_trait(cx, init_ty, did, &[])) } if let StmtKind::Let(LetStmt { @@ -271,6 +275,135 @@ fn check_is_none_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: &Ex } } +#[derive(Clone, Copy, Debug)] +enum TryMode { + Result, + Option, +} + +fn find_try_mode<'tcx>(cx: &LateContext<'tcx>, scrutinee: &Expr<'tcx>) -> Option { + let scrutinee_ty = cx.typeck_results().expr_ty_adjusted(scrutinee); + let ty::Adt(scrutinee_adt_def, _) = scrutinee_ty.kind() else { + return None; + }; + + match cx.tcx.get_diagnostic_name(scrutinee_adt_def.did())? { + sym::Result => Some(TryMode::Result), + sym::Option => Some(TryMode::Option), + _ => None, + } +} + +// Check that `pat` is `{ctor_lang_item}(val)`, returning `val`. +fn extract_ctor_call<'a, 'tcx>( + cx: &LateContext<'tcx>, + expected_ctor: LangItem, + pat: &'a Pat<'tcx>, +) -> Option<&'a Pat<'tcx>> { + if let PatKind::TupleStruct(variant_path, [val_binding], _) = &pat.kind + && is_res_lang_ctor(cx, cx.qpath_res(variant_path, pat.hir_id), expected_ctor) + { + Some(val_binding) + } else { + None + } +} + +// Extracts the local ID of a plain `val` pattern. +fn extract_binding_pat(pat: &Pat<'_>) -> Option { + if let PatKind::Binding(BindingMode::NONE, binding, _, None) = pat.kind { + Some(binding) + } else { + None + } +} + +fn check_arm_is_some_or_ok<'tcx>(cx: &LateContext<'tcx>, mode: TryMode, arm: &Arm<'tcx>) -> bool { + let happy_ctor = match mode { + TryMode::Result => ResultOk, + TryMode::Option => OptionSome, + }; + + // Check for `Ok(val)` or `Some(val)` + if arm.guard.is_none() + && let Some(val_binding) = extract_ctor_call(cx, happy_ctor, arm.pat) + // Extract out `val` + && let Some(binding) = extract_binding_pat(val_binding) + // Check body is just `=> val` + && path_to_local_id(peel_blocks(arm.body), binding) + { + true + } else { + false + } +} + +fn check_arm_is_none_or_err<'tcx>(cx: &LateContext<'tcx>, mode: TryMode, arm: &Arm<'tcx>) -> bool { + if arm.guard.is_some() { + return false; + } + + let arm_body = peel_blocks(arm.body); + match mode { + TryMode::Result => { + // Check that pat is Err(val) + if let Some(ok_pat) = extract_ctor_call(cx, ResultErr, arm.pat) + && let Some(ok_val) = extract_binding_pat(ok_pat) + // check `=> return Err(...)` + && let ExprKind::Ret(Some(wrapped_ret_expr)) = arm_body.kind + && let ExprKind::Call(ok_ctor, [ret_expr]) = wrapped_ret_expr.kind + && is_res_lang_ctor(cx, path_res(cx, ok_ctor), ResultErr) + // check `...` is `val` from binding + && path_to_local_id(ret_expr, ok_val) + { + true + } else { + false + } + }, + TryMode::Option => { + // Check the pat is `None` + if is_res_lang_ctor(cx, path_res(cx, arm.pat), OptionNone) + // Check `=> return None` + && let ExprKind::Ret(Some(ret_expr)) = arm_body.kind + && is_res_lang_ctor(cx, path_res(cx, ret_expr), OptionNone) + && !ret_expr.span.from_expansion() + { + true + } else { + false + } + }, + } +} + +fn check_arms_are_try<'tcx>(cx: &LateContext<'tcx>, mode: TryMode, arm1: &Arm<'tcx>, arm2: &Arm<'tcx>) -> bool { + (check_arm_is_some_or_ok(cx, mode, arm1) && check_arm_is_none_or_err(cx, mode, arm2)) + || (check_arm_is_some_or_ok(cx, mode, arm2) && check_arm_is_none_or_err(cx, mode, arm1)) +} + +fn check_if_try_match<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { + if let ExprKind::Match(scrutinee, [arm1, arm2], MatchSource::Normal | MatchSource::Postfix) = expr.kind + && !expr.span.from_expansion() + && let Some(mode) = find_try_mode(cx, scrutinee) + && !span_contains_cfg(cx, expr.span) + && check_arms_are_try(cx, mode, arm1, arm2) + { + let mut applicability = Applicability::MachineApplicable; + let snippet = snippet_with_applicability(cx, scrutinee.span.source_callsite(), "..", &mut applicability); + + span_lint_and_sugg( + cx, + QUESTION_MARK, + expr.span, + "this `match` expression can be replaced with `?`", + "try instead", + snippet.into_owned() + "?", + applicability, + ); + } +} + fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { if let Some(higher::IfLet { let_pat, @@ -339,6 +472,17 @@ fn is_try_block(cx: &LateContext<'_>, bl: &Block<'_>) -> bool { } } +fn is_inferred_ret_closure(expr: &Expr<'_>) -> bool { + let ExprKind::Closure(closure) = expr.kind else { + return false; + }; + + match closure.fn_decl.output { + FnRetTy::Return(ret_ty) => ret_ty.is_suggestable_infer_ty(), + FnRetTy::DefaultReturn(_) => true, + } +} + impl<'tcx> LateLintPass<'tcx> for QuestionMark { fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { if !is_lint_allowed(cx, QUESTION_MARK_USED, stmt.hir_id) { @@ -350,11 +494,27 @@ impl<'tcx> LateLintPass<'tcx> for QuestionMark { } self.check_manual_let_else(cx, stmt); } + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if is_inferred_ret_closure(expr) { + self.inferred_ret_closure_stack += 1; + return; + } + if !self.inside_try_block() && !is_in_const_context(cx) && is_lint_allowed(cx, QUESTION_MARK_USED, expr.hir_id) { check_is_none_or_err_and_early_return(cx, expr); check_if_let_some_or_err_and_early_return(cx, expr); + + if self.inferred_ret_closure_stack == 0 { + check_if_try_match(cx, expr); + } + } + } + + fn check_expr_post(&mut self, _: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { + if is_inferred_ret_closure(expr) { + self.inferred_ret_closure_stack -= 1; } } diff --git a/clippy_lints/src/redundant_slicing.rs b/clippy_lints/src/redundant_slicing.rs index 030df535c35..dc66fb28fa8 100644 --- a/clippy_lints/src/redundant_slicing.rs +++ b/clippy_lints/src/redundant_slicing.rs @@ -85,7 +85,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing { let (expr_ty, expr_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(expr)); let (indexed_ty, indexed_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(indexed)); let parent_expr = get_parent_expr(cx, expr); - let needs_parens_for_prefix = parent_expr.map_or(false, |parent| parent.precedence().order() > PREC_PREFIX); + let needs_parens_for_prefix = parent_expr.is_some_and(|parent| parent.precedence().order() > PREC_PREFIX); if expr_ty == indexed_ty { if expr_ref_count > indexed_ref_count { @@ -107,7 +107,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing { kind: ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, _), .. }) - ) || cx.typeck_results().expr_adjustments(expr).first().map_or(false, |a| { + ) || cx.typeck_results().expr_adjustments(expr).first().is_some_and(|a| { matches!( a.kind, Adjust::Borrow(AutoBorrow::Ref(AutoBorrowMutability::Mut { .. })) diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index 23362506cca..78f0b7d121c 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -412,9 +412,7 @@ impl<'tcx> IndexBinding<'_, 'tcx> { } Self::is_used_slice_indexed(lhs, idx_ident) || Self::is_used_slice_indexed(rhs, idx_ident) }, - ExprKind::Path(QPath::Resolved(_, path)) => { - path.segments.first().map_or(false, |idx| idx.ident == idx_ident) - }, + ExprKind::Path(QPath::Resolved(_, path)) => path.segments.first().is_some_and(|idx| idx.ident == idx_ident), _ => false, } } diff --git a/clippy_lints/src/types/borrowed_box.rs b/clippy_lints/src/types/borrowed_box.rs index eb7ffbbe360..bde88ab61ad 100644 --- a/clippy_lints/src/types/borrowed_box.rs +++ b/clippy_lints/src/types/borrowed_box.rs @@ -51,8 +51,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, m 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) => + if get_bounds_if_impl_trait(cx, qpath, inner.hir_id).is_some_and(|bounds| bounds.len() > 1) => { format!("&{ltopt}({inner_snippet})") }, diff --git a/clippy_lints/src/unit_types/let_unit_value.rs b/clippy_lints/src/unit_types/let_unit_value.rs index 1a1284ce9c4..6eef582b4b2 100644 --- a/clippy_lints/src/unit_types/let_unit_value.rs +++ b/clippy_lints/src/unit_types/let_unit_value.rs @@ -38,7 +38,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx LetStmt<'_>) { return; } - if (local.ty.map_or(false, |ty| !matches!(ty.kind, TyKind::Infer)) + if (local.ty.is_some_and(|ty| !matches!(ty.kind, TyKind::Infer)) || matches!(local.pat.kind, PatKind::Tuple([], ddpos) if ddpos.as_opt_usize().is_none())) && expr_needs_inferred_result(cx, init) { diff --git a/clippy_lints/src/vec_init_then_push.rs b/clippy_lints/src/vec_init_then_push.rs index 91dff5a9523..cbc6885ae5d 100644 --- a/clippy_lints/src/vec_init_then_push.rs +++ b/clippy_lints/src/vec_init_then_push.rs @@ -98,7 +98,7 @@ impl VecPushSearcher { needs_mut |= cx.typeck_results().expr_ty_adjusted(last_place).ref_mutability() == Some(Mutability::Mut) || get_parent_expr(cx, last_place) - .map_or(false, |e| matches!(e.kind, ExprKind::AddrOf(_, Mutability::Mut, _))); + .is_some_and(|e| matches!(e.kind, ExprKind::AddrOf(_, Mutability::Mut, _))); }, ExprKind::MethodCall(_, recv, ..) if recv.hir_id == e.hir_id diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index 1dd46ed5a89..a42ddcdae35 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -295,7 +295,7 @@ impl<'tcx> LateLintPass<'tcx> for Write { .opts .crate_name .as_ref() - .map_or(false, |crate_name| crate_name == "build_script_build"); + .is_some_and(|crate_name| crate_name == "build_script_build"); let allowed_in_tests = self.allow_print_in_tests && is_in_test(cx.tcx, expr.hir_id); match diag_name { diff --git a/clippy_utils/src/check_proc_macro.rs b/clippy_utils/src/check_proc_macro.rs index 75169e05734..3269bf758ac 100644 --- a/clippy_utils/src/check_proc_macro.rs +++ b/clippy_utils/src/check_proc_macro.rs @@ -51,7 +51,7 @@ fn span_matches_pat(sess: &Session, span: Span, start_pat: Pat, end_pat: Pat) -> return false; }; let end = span.hi() - pos.sf.start_pos; - src.get(pos.pos.0 as usize..end.0 as usize).map_or(false, |s| { + src.get(pos.pos.0 as usize..end.0 as usize).is_some_and(|s| { // Spans can be wrapped in a mixture or parenthesis, whitespace, and trailing commas. let start_str = s.trim_start_matches(|c: char| c.is_whitespace() || c == '('); let end_str = s.trim_end_matches(|c: char| c.is_whitespace() || c == ')' || c == ','); @@ -60,13 +60,13 @@ fn span_matches_pat(sess: &Session, span: Span, start_pat: Pat, end_pat: Pat) -> Pat::MultiStr(texts) => texts.iter().any(|s| start_str.starts_with(s)), Pat::OwnedMultiStr(texts) => texts.iter().any(|s| start_str.starts_with(s)), Pat::Sym(sym) => start_str.starts_with(sym.as_str()), - Pat::Num => start_str.as_bytes().first().map_or(false, u8::is_ascii_digit), + Pat::Num => start_str.as_bytes().first().is_some_and(u8::is_ascii_digit), } && match end_pat { Pat::Str(text) => end_str.ends_with(text), Pat::MultiStr(texts) => texts.iter().any(|s| end_str.ends_with(s)), Pat::OwnedMultiStr(texts) => texts.iter().any(|s| end_str.ends_with(s)), Pat::Sym(sym) => end_str.ends_with(sym.as_str()), - Pat::Num => end_str.as_bytes().last().map_or(false, u8::is_ascii_hexdigit), + Pat::Num => end_str.as_bytes().last().is_some_and(u8::is_ascii_hexdigit), }) }) } diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index cb69f8e5a0e..c73ab4bfa68 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -258,7 +258,7 @@ impl HirEqInterExpr<'_, '_, '_> { } fn should_ignore(&mut self, expr: &Expr<'_>) -> bool { - macro_backtrace(expr.span).last().map_or(false, |macro_call| { + macro_backtrace(expr.span).last().is_some_and(|macro_call| { matches!( &self.inner.cx.tcx.get_diagnostic_name(macro_call.def_id), Some(sym::todo_macro | sym::unimplemented_macro) @@ -322,7 +322,7 @@ impl HirEqInterExpr<'_, '_, '_> { (&ExprKind::Block(l, _), &ExprKind::Block(r, _)) => self.eq_block(l, r), (&ExprKind::Binary(l_op, ll, lr), &ExprKind::Binary(r_op, rl, rr)) => { l_op.node == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr) - || swap_binop(l_op.node, ll, lr).map_or(false, |(l_op, ll, lr)| { + || swap_binop(l_op.node, ll, lr).is_some_and(|(l_op, ll, lr)| { l_op == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr) }) }, @@ -444,7 +444,7 @@ impl HirEqInterExpr<'_, '_, '_> { ) => false, }; (is_eq && (!self.should_ignore(left) || !self.should_ignore(right))) - || self.inner.expr_fallback.as_mut().map_or(false, |f| f(left, right)) + || self.inner.expr_fallback.as_mut().is_some_and(|f| f(left, right)) } fn eq_exprs(&mut self, left: &[Expr<'_>], right: &[Expr<'_>]) -> bool { @@ -724,7 +724,7 @@ fn swap_binop<'a>( /// `eq_fn`. pub fn both(l: Option<&X>, r: Option<&X>, mut eq_fn: impl FnMut(&X, &X) -> bool) -> bool { l.as_ref() - .map_or_else(|| r.is_none(), |x| r.as_ref().map_or(false, |y| eq_fn(x, y))) + .map_or_else(|| r.is_none(), |x| r.as_ref().is_some_and(|y| eq_fn(x, y))) } /// Checks if two slices are equal as per `eq_fn`. diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 50d334acf18..19316a90683 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -342,10 +342,9 @@ pub fn is_ty_alias(qpath: &QPath<'_>) -> bool { /// Checks if the method call given in `expr` belongs to the given trait. /// This is a deprecated function, consider using [`is_trait_method`]. pub fn match_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, path: &[&str]) -> bool { - cx.typeck_results() - .type_dependent_def_id(expr.hir_id) - .and_then(|defid| cx.tcx.trait_of_item(defid)) - .map_or(false, |trt_id| match_def_path(cx, trt_id, path)) + let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap(); + let trt_id = cx.tcx.trait_of_item(def_id); + trt_id.is_some_and(|trt_id| match_def_path(cx, trt_id, path)) } /// Checks if the given method call expression calls an inherent method. @@ -379,7 +378,7 @@ pub fn is_diag_trait_item(cx: &LateContext<'_>, def_id: DefId, diag_item: Symbol pub fn is_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) -> bool { cx.typeck_results() .type_dependent_def_id(expr.hir_id) - .map_or(false, |did| is_diag_trait_item(cx, did, diag_item)) + .is_some_and(|did| is_diag_trait_item(cx, did, diag_item)) } /// Checks if the `def_id` belongs to a function that is part of a trait impl. @@ -406,7 +405,7 @@ pub fn is_trait_item(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) - if let ExprKind::Path(ref qpath) = expr.kind { cx.qpath_res(qpath, expr.hir_id) .opt_def_id() - .map_or(false, |def_id| is_diag_trait_item(cx, def_id, diag_item)) + .is_some_and(|def_id| is_diag_trait_item(cx, def_id, diag_item)) } else { false } @@ -466,13 +465,13 @@ pub fn match_qpath(path: &QPath<'_>, segments: &[&str]) -> bool { /// /// Please use `is_path_diagnostic_item` if the target is a diagnostic item. pub fn is_expr_path_def_path(cx: &LateContext<'_>, expr: &Expr<'_>, segments: &[&str]) -> bool { - path_def_id(cx, expr).map_or(false, |id| match_def_path(cx, id, segments)) + path_def_id(cx, expr).is_some_and(|id| match_def_path(cx, id, segments)) } /// If `maybe_path` is a path node which resolves to an item, resolves it to a `DefId` and checks if /// it matches the given lang item. pub fn is_path_lang_item<'tcx>(cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx>, lang_item: LangItem) -> bool { - path_def_id(cx, maybe_path).map_or(false, |id| cx.tcx.lang_items().get(lang_item) == Some(id)) + path_def_id(cx, maybe_path).is_some_and(|id| cx.tcx.lang_items().get(lang_item) == Some(id)) } /// If `maybe_path` is a path node which resolves to an item, resolves it to a `DefId` and checks if @@ -482,7 +481,7 @@ pub fn is_path_diagnostic_item<'tcx>( maybe_path: &impl MaybePath<'tcx>, diag_item: Symbol, ) -> bool { - path_def_id(cx, maybe_path).map_or(false, |id| cx.tcx.is_diagnostic_item(diag_item, id)) + path_def_id(cx, maybe_path).is_some_and(|id| cx.tcx.is_diagnostic_item(diag_item, id)) } /// THIS METHOD IS DEPRECATED. Matches a `Path` against a slice of segment string literals. @@ -1315,7 +1314,7 @@ pub fn method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[&str]) -> Option, def_id: DefId) -> bool { cx.tcx .entry_fn(()) - .map_or(false, |(entry_fn_def_id, _)| def_id == entry_fn_def_id) + .is_some_and(|(entry_fn_def_id, _)| def_id == entry_fn_def_id) } /// Returns `true` if the expression is in the program's `#[panic_handler]`. @@ -1753,8 +1752,8 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool { match pat.kind { PatKind::Wild | PatKind::Never => false, // If `!` typechecked then the type is empty, so not refutable. - PatKind::Binding(_, _, _, pat) => pat.map_or(false, |pat| is_refutable(cx, pat)), - PatKind::Box(pat) | PatKind::Deref(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat), + PatKind::Binding(_, _, _, pat) => pat.is_some_and(|pat| is_refutable(cx, pat)), + PatKind::Box(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat), PatKind::Path(ref qpath) => is_enum_variant(cx, qpath, pat.hir_id), PatKind::Or(pats) => { // TODO: should be the honest check, that pats is exhaustive set @@ -1778,7 +1777,7 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool { }, } }, - PatKind::Lit(..) | PatKind::Range(..) | PatKind::Err(_) => true, + PatKind::Lit(..) | PatKind::Range(..) | PatKind::Err(_) | PatKind::Deref(_) => true, } } @@ -2021,7 +2020,7 @@ pub fn match_libc_symbol(cx: &LateContext<'_>, did: DefId, name: &str) -> bool { let path = cx.get_def_path(did); // libc is meant to be used as a flat list of names, but they're all actually defined in different // modules based on the target platform. Ignore everything but crate name and the item name. - path.first().map_or(false, |s| s.as_str() == "libc") && path.last().map_or(false, |s| s.as_str() == name) + path.first().is_some_and(|s| s.as_str() == "libc") && path.last().is_some_and(|s| s.as_str() == name) } /// Returns the list of condition expressions and the list of blocks in a @@ -2104,7 +2103,7 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { _ => None, }; - did.map_or(false, |did| cx.tcx.has_attr(did, sym::must_use)) + did.is_some_and(|did| cx.tcx.has_attr(did, sym::must_use)) } /// Checks if a function's body represents the identity function. Looks for bodies of the form: @@ -2211,7 +2210,7 @@ pub fn is_expr_untyped_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { match expr.kind { ExprKind::Closure(&Closure { body, .. }) => is_body_identity_function(cx, cx.tcx.hir().body(body)), - _ => path_def_id(cx, expr).map_or(false, |id| cx.tcx.is_diagnostic_item(sym::convert_identity, id)), + _ => path_def_id(cx, expr).is_some_and(|id| cx.tcx.is_diagnostic_item(sym::convert_identity, id)), } } diff --git a/clippy_utils/src/numeric_literal.rs b/clippy_utils/src/numeric_literal.rs index c5a34160e3d..2c49df9d807 100644 --- a/clippy_utils/src/numeric_literal.rs +++ b/clippy_utils/src/numeric_literal.rs @@ -53,7 +53,7 @@ impl<'a> NumericLiteral<'a> { .trim_start() .chars() .next() - .map_or(false, |c| c.is_ascii_digit()) + .is_some_and(|c| c.is_ascii_digit()) { let (unsuffixed, suffix) = split_suffix(src, lit_kind); let float = matches!(lit_kind, LitKind::Float(..)); diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index 3255c51d009..25ebe879192 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -905,7 +905,7 @@ impl<'tcx> DerefDelegate<'_, 'tcx> { _ => return false, }; - ty.map_or(false, |ty| matches!(ty.kind(), ty::Ref(_, inner, _) if inner.is_ref())) + ty.is_some_and(|ty| matches!(ty.kind(), ty::Ref(_, inner, _) if inner.is_ref())) } } diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index ce1a20e0066..770cd9c3786 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -45,7 +45,7 @@ pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { 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, &[])) + .is_some_and(|debug| implements_trait(cx, ty, debug, &[])) } /// Checks whether a type can be partially moved. @@ -487,7 +487,7 @@ pub fn needs_ordered_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { .tcx .lang_items() .drop_trait() - .map_or(false, |id| implements_trait(cx, ty, id, &[])) + .is_some_and(|id| implements_trait(cx, ty, id, &[])) { // This type doesn't implement drop, so no side effects here. // Check if any component type has any. @@ -718,7 +718,7 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option( && p.self_ty() == ty => { let i = pred.kind().rebind(p.trait_ref.args.type_at(1)); - if inputs.map_or(false, |inputs| i != inputs) { + if inputs.is_some_and(|inputs| i != inputs) { // Multiple different fn trait impls. Is this even allowed? return None; } @@ -794,7 +794,7 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: AliasTy<'tcx>) -> Option { let i = pred.kind().rebind(p.trait_ref.args.type_at(1)); - if inputs.map_or(false, |inputs| inputs != i) { + if inputs.is_some_and(|inputs| inputs != i) { // Multiple different fn trait impls. Is this even allowed? return None; } @@ -1291,7 +1291,7 @@ pub fn normalize_with_regions<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx> /// Checks if the type is `core::mem::ManuallyDrop<_>` pub fn is_manually_drop(ty: Ty<'_>) -> bool { - ty.ty_adt_def().map_or(false, AdtDef::is_manually_drop) + ty.ty_adt_def().is_some_and(AdtDef::is_manually_drop) } /// Returns the deref chain of a type, starting with the type itself. diff --git a/clippy_utils/src/visitors.rs b/clippy_utils/src/visitors.rs index 8f5ec185bf1..a79be5ca7d4 100644 --- a/clippy_utils/src/visitors.rs +++ b/clippy_utils/src/visitors.rs @@ -344,13 +344,13 @@ pub fn is_const_evaluatable<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> .cx .qpath_res(p, hir_id) .opt_def_id() - .map_or(false, |id| self.cx.tcx.is_const_fn(id)) => {}, + .is_some_and(|id| self.cx.tcx.is_const_fn(id)) => {}, ExprKind::MethodCall(..) if self .cx .typeck_results() .type_dependent_def_id(e.hir_id) - .map_or(false, |id| self.cx.tcx.is_const_fn(id)) => {}, + .is_some_and(|id| self.cx.tcx.is_const_fn(id)) => {}, ExprKind::Binary(_, lhs, rhs) if self.cx.typeck_results().expr_ty(lhs).peel_refs().is_primitive_ty() && self.cx.typeck_results().expr_ty(rhs).peel_refs().is_primitive_ty() => {}, @@ -426,9 +426,7 @@ pub fn is_expr_unsafe<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> bool { .cx .typeck_results() .type_dependent_def_id(e.hir_id) - .map_or(false, |id| { - self.cx.tcx.fn_sig(id).skip_binder().safety() == Safety::Unsafe - }) => + .is_some_and(|id| self.cx.tcx.fn_sig(id).skip_binder().safety() == Safety::Unsafe) => { ControlFlow::Break(()) }, @@ -444,7 +442,7 @@ pub fn is_expr_unsafe<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> bool { .cx .qpath_res(p, e.hir_id) .opt_def_id() - .map_or(false, |id| self.cx.tcx.is_mutable_static(id)) => + .is_some_and(|id| self.cx.tcx.is_mutable_static(id)) => { ControlFlow::Break(()) }, diff --git a/rust-toolchain b/rust-toolchain index 37d9cce2465..e32e0cb3604 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2024-11-07" +channel = "nightly-2024-11-14" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] profile = "minimal" diff --git a/tests/ui-internal/unnecessary_def_path.fixed b/tests/ui-internal/unnecessary_def_path.fixed index 0a994842834..d3fab60f9e3 100644 --- a/tests/ui-internal/unnecessary_def_path.fixed +++ b/tests/ui-internal/unnecessary_def_path.fixed @@ -1,6 +1,7 @@ //@aux-build:paths.rs #![deny(clippy::internal)] #![feature(rustc_private)] +#![allow(clippy::unnecessary_map_or)] extern crate clippy_utils; extern crate paths; diff --git a/tests/ui-internal/unnecessary_def_path.rs b/tests/ui-internal/unnecessary_def_path.rs index ba68de6c6d0..1b36f6b09e9 100644 --- a/tests/ui-internal/unnecessary_def_path.rs +++ b/tests/ui-internal/unnecessary_def_path.rs @@ -1,6 +1,7 @@ //@aux-build:paths.rs #![deny(clippy::internal)] #![feature(rustc_private)] +#![allow(clippy::unnecessary_map_or)] extern crate clippy_utils; extern crate paths; diff --git a/tests/ui-internal/unnecessary_def_path.stderr b/tests/ui-internal/unnecessary_def_path.stderr index 79da1731613..79521c5037a 100644 --- a/tests/ui-internal/unnecessary_def_path.stderr +++ b/tests/ui-internal/unnecessary_def_path.stderr @@ -1,5 +1,5 @@ error: use of a def path to a diagnostic item - --> tests/ui-internal/unnecessary_def_path.rs:36:13 + --> tests/ui-internal/unnecessary_def_path.rs:37:13 | LL | let _ = match_type(cx, ty, &OPTION); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Option)` @@ -12,61 +12,61 @@ 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 - --> tests/ui-internal/unnecessary_def_path.rs:37:13 + --> tests/ui-internal/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 - --> tests/ui-internal/unnecessary_def_path.rs:38:13 + --> tests/ui-internal/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 - --> tests/ui-internal/unnecessary_def_path.rs:42:13 + --> tests/ui-internal/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 - --> tests/ui-internal/unnecessary_def_path.rs:44:13 + --> tests/ui-internal/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 - --> tests/ui-internal/unnecessary_def_path.rs:45:13 + --> tests/ui-internal/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` - --> tests/ui-internal/unnecessary_def_path.rs:47:13 + --> tests/ui-internal/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 - --> tests/ui-internal/unnecessary_def_path.rs:48:13 + --> tests/ui-internal/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` - --> tests/ui-internal/unnecessary_def_path.rs:50:13 + --> tests/ui-internal/unnecessary_def_path.rs:51:13 | LL | let _ = match_def_path(cx, did, &["alloc", "boxed", "Box"]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cx.tcx.lang_items().get(LangItem::OwnedBox) == Some(did)` error: use of a def path to a diagnostic item - --> tests/ui-internal/unnecessary_def_path.rs:51:13 + --> tests/ui-internal/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` - --> tests/ui-internal/unnecessary_def_path.rs:52:13 + --> tests/ui-internal/unnecessary_def_path.rs:53:13 | LL | let _ = match_def_path(cx, did, &["core", "option", "Option", "Some"]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cx.tcx.lang_items().get(LangItem::OptionSome) == Some(did)` @@ -74,25 +74,25 @@ LL | let _ = match_def_path(cx, did, &["core", "option", "Option", "Some"]); = 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 - --> tests/ui-internal/unnecessary_def_path.rs:54:13 + --> tests/ui-internal/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 - --> tests/ui-internal/unnecessary_def_path.rs:56:13 + --> tests/ui-internal/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` - --> tests/ui-internal/unnecessary_def_path.rs:57:13 + --> tests/ui-internal/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().get(LangItem::IteratorNext) == Some(id))` error: use of a def path to a `LangItem` - --> tests/ui-internal/unnecessary_def_path.rs:58:13 + --> tests/ui-internal/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)` diff --git a/tests/ui-toml/large_include_file/empty.txt b/tests/ui-toml/large_include_file/empty.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/ui-toml/large_include_file/large_include_file.rs b/tests/ui-toml/large_include_file/large_include_file.rs index dc9349f75a0..8a6dd36501c 100644 --- a/tests/ui-toml/large_include_file/large_include_file.rs +++ b/tests/ui-toml/large_include_file/large_include_file.rs @@ -15,5 +15,9 @@ const TOO_BIG_INCLUDE_BYTES: &[u8; 654] = include_bytes!("too_big.txt"); const TOO_BIG_INCLUDE_STR: &str = include_str!("too_big.txt"); //~^ large_include_file -#[doc = include_str!("too_big.txt")] //~ large_include_file +#[doc = include_str!("too_big.txt")] +//~^ large_include_file +// Should not lint! +// Regression test for . +#[doc = include_str!("empty.txt")] fn main() {} diff --git a/tests/ui/case_sensitive_file_extension_comparisons.fixed b/tests/ui/case_sensitive_file_extension_comparisons.fixed index 8b4a165a97c..c4d77f24f12 100644 --- a/tests/ui/case_sensitive_file_extension_comparisons.fixed +++ b/tests/ui/case_sensitive_file_extension_comparisons.fixed @@ -1,4 +1,5 @@ #![warn(clippy::case_sensitive_file_extension_comparisons)] +#![allow(clippy::unnecessary_map_or)] use std::string::String; diff --git a/tests/ui/case_sensitive_file_extension_comparisons.rs b/tests/ui/case_sensitive_file_extension_comparisons.rs index e4b8178110b..690e93c2639 100644 --- a/tests/ui/case_sensitive_file_extension_comparisons.rs +++ b/tests/ui/case_sensitive_file_extension_comparisons.rs @@ -1,4 +1,5 @@ #![warn(clippy::case_sensitive_file_extension_comparisons)] +#![allow(clippy::unnecessary_map_or)] use std::string::String; diff --git a/tests/ui/case_sensitive_file_extension_comparisons.stderr b/tests/ui/case_sensitive_file_extension_comparisons.stderr index d203f91b832..e21815f251b 100644 --- a/tests/ui/case_sensitive_file_extension_comparisons.stderr +++ b/tests/ui/case_sensitive_file_extension_comparisons.stderr @@ -1,5 +1,5 @@ error: case-sensitive file extension comparison - --> tests/ui/case_sensitive_file_extension_comparisons.rs:13:5 + --> tests/ui/case_sensitive_file_extension_comparisons.rs:14:5 | LL | filename.ends_with(".rs") | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -15,7 +15,7 @@ LL + .map_or(false, |ext| ext.eq_ignore_ascii_case("rs")) | error: case-sensitive file extension comparison - --> tests/ui/case_sensitive_file_extension_comparisons.rs:18:13 + --> tests/ui/case_sensitive_file_extension_comparisons.rs:19:13 | LL | let _ = String::new().ends_with(".ext12"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -29,7 +29,7 @@ LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12")); | error: case-sensitive file extension comparison - --> tests/ui/case_sensitive_file_extension_comparisons.rs:19:13 + --> tests/ui/case_sensitive_file_extension_comparisons.rs:20:13 | LL | let _ = "str".ends_with(".ext12"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -43,7 +43,7 @@ LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12")); | error: case-sensitive file extension comparison - --> tests/ui/case_sensitive_file_extension_comparisons.rs:23:17 + --> tests/ui/case_sensitive_file_extension_comparisons.rs:24:17 | LL | let _ = "str".ends_with(".ext12"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -57,7 +57,7 @@ LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12")); | error: case-sensitive file extension comparison - --> tests/ui/case_sensitive_file_extension_comparisons.rs:30:13 + --> tests/ui/case_sensitive_file_extension_comparisons.rs:31:13 | LL | let _ = String::new().ends_with(".EXT12"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -71,7 +71,7 @@ LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12")); | error: case-sensitive file extension comparison - --> tests/ui/case_sensitive_file_extension_comparisons.rs:31:13 + --> tests/ui/case_sensitive_file_extension_comparisons.rs:32:13 | LL | let _ = "str".ends_with(".EXT12"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/identity_op.fixed b/tests/ui/identity_op.fixed index b18d8560f6f..2e8e2366de6 100644 --- a/tests/ui/identity_op.fixed +++ b/tests/ui/identity_op.fixed @@ -116,7 +116,7 @@ fn main() { //~^ ERROR: this operation has no effect (match a { 0 => 10, _ => 20 }) + if b { 3 } else { 4 }; //~^ ERROR: this operation has no effect - (if b { 1 } else { 2 }); + ((if b { 1 } else { 2 })); //~^ ERROR: this operation has no effect ({ a }) + 3; @@ -212,3 +212,47 @@ fn issue_12050() { //~^ ERROR: this operation has no effect } } + +fn issue_13470() { + let x = 1i32; + let y = 1i32; + // Removes the + 0i32 while keeping the parentheses around x + y so the cast operation works + let _: u64 = (x + y) as u64; + //~^ ERROR: this operation has no effect + // both of the next two lines should look the same after rustfix + let _: u64 = 1u64 & (x + y) as u64; + //~^ ERROR: this operation has no effect + // Same as above, but with extra redundant parenthesis + let _: u64 = 1u64 & ((x + y)) as u64; + //~^ ERROR: this operation has no effect + // Should maintain parenthesis even if the surrounding expr has the same precedence + let _: u64 = 5u64 + ((x + y)) as u64; + //~^ ERROR: this operation has no effect + + // If we don't maintain the parens here, the behavior changes + let _ = -(x + y); + //~^ ERROR: this operation has no effect + // Similarly, we need to maintain parens here + let _ = -(x / y); + //~^ ERROR: this operation has no effect + // Maintain parenthesis if the parent expr is of higher precedence + let _ = 2i32 * (x + y); + //~^ ERROR: this operation has no effect + // Maintain parenthesis if the parent expr is the same precedence + // as not all operations are associative + let _ = 2i32 - (x - y); + //~^ ERROR: this operation has no effect + // But make sure that inner parens still exist + let z = 1i32; + let _ = 2 + (x + (y * z)); + //~^ ERROR: this operation has no effect + // Maintain parenthesis if the parent expr is of lower precedence + // This is for clarity, and clippy will not warn on these being unnecessary + let _ = 2i32 + (x * y); + //~^ ERROR: this operation has no effect + + let x = 1i16; + let y = 1i16; + let _: u64 = 1u64 + ((x as i32 + y as i32) as u64); + //~^ ERROR: this operation has no effect +} diff --git a/tests/ui/identity_op.rs b/tests/ui/identity_op.rs index f1f01b42447..3e20fa6f2b8 100644 --- a/tests/ui/identity_op.rs +++ b/tests/ui/identity_op.rs @@ -212,3 +212,47 @@ fn issue_12050() { //~^ ERROR: this operation has no effect } } + +fn issue_13470() { + let x = 1i32; + let y = 1i32; + // Removes the + 0i32 while keeping the parentheses around x + y so the cast operation works + let _: u64 = (x + y + 0i32) as u64; + //~^ ERROR: this operation has no effect + // both of the next two lines should look the same after rustfix + let _: u64 = 1u64 & (x + y + 0i32) as u64; + //~^ ERROR: this operation has no effect + // Same as above, but with extra redundant parenthesis + let _: u64 = 1u64 & ((x + y) + 0i32) as u64; + //~^ ERROR: this operation has no effect + // Should maintain parenthesis even if the surrounding expr has the same precedence + let _: u64 = 5u64 + ((x + y) + 0i32) as u64; + //~^ ERROR: this operation has no effect + + // If we don't maintain the parens here, the behavior changes + let _ = -(x + y + 0i32); + //~^ ERROR: this operation has no effect + // Similarly, we need to maintain parens here + let _ = -(x / y / 1i32); + //~^ ERROR: this operation has no effect + // Maintain parenthesis if the parent expr is of higher precedence + let _ = 2i32 * (x + y + 0i32); + //~^ ERROR: this operation has no effect + // Maintain parenthesis if the parent expr is the same precedence + // as not all operations are associative + let _ = 2i32 - (x - y - 0i32); + //~^ ERROR: this operation has no effect + // But make sure that inner parens still exist + let z = 1i32; + let _ = 2 + (x + (y * z) + 0); + //~^ ERROR: this operation has no effect + // Maintain parenthesis if the parent expr is of lower precedence + // This is for clarity, and clippy will not warn on these being unnecessary + let _ = 2i32 + (x * y * 1i32); + //~^ ERROR: this operation has no effect + + let x = 1i16; + let y = 1i16; + let _: u64 = 1u64 + ((x as i32 + y as i32) as u64 + 0u64); + //~^ ERROR: this operation has no effect +} diff --git a/tests/ui/identity_op.stderr b/tests/ui/identity_op.stderr index 9fff86b86f9..99a58ef2c1b 100644 --- a/tests/ui/identity_op.stderr +++ b/tests/ui/identity_op.stderr @@ -149,7 +149,7 @@ error: this operation has no effect --> tests/ui/identity_op.rs:119:5 | LL | (if b { 1 } else { 2 }) + 0; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(if b { 1 } else { 2 })` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `((if b { 1 } else { 2 }))` error: this operation has no effect --> tests/ui/identity_op.rs:122:5 @@ -313,5 +313,71 @@ error: this operation has no effect LL | let _: i32 = **&&*&x + 0; | ^^^^^^^^^^^ help: consider reducing it to: `***&&*&x` -error: aborting due to 52 previous errors +error: this operation has no effect + --> tests/ui/identity_op.rs:220:18 + | +LL | let _: u64 = (x + y + 0i32) as u64; + | ^^^^^^^^^^^^^^ help: consider reducing it to: `(x + y)` + +error: this operation has no effect + --> tests/ui/identity_op.rs:223:25 + | +LL | let _: u64 = 1u64 & (x + y + 0i32) as u64; + | ^^^^^^^^^^^^^^ help: consider reducing it to: `(x + y)` + +error: this operation has no effect + --> tests/ui/identity_op.rs:226:25 + | +LL | let _: u64 = 1u64 & ((x + y) + 0i32) as u64; + | ^^^^^^^^^^^^^^^^ help: consider reducing it to: `((x + y))` + +error: this operation has no effect + --> tests/ui/identity_op.rs:229:25 + | +LL | let _: u64 = 5u64 + ((x + y) + 0i32) as u64; + | ^^^^^^^^^^^^^^^^ help: consider reducing it to: `((x + y))` + +error: this operation has no effect + --> tests/ui/identity_op.rs:233:14 + | +LL | let _ = -(x + y + 0i32); + | ^^^^^^^^^^^^^^ help: consider reducing it to: `(x + y)` + +error: this operation has no effect + --> tests/ui/identity_op.rs:236:14 + | +LL | let _ = -(x / y / 1i32); + | ^^^^^^^^^^^^^^ help: consider reducing it to: `(x / y)` + +error: this operation has no effect + --> tests/ui/identity_op.rs:239:20 + | +LL | let _ = 2i32 * (x + y + 0i32); + | ^^^^^^^^^^^^^^ help: consider reducing it to: `(x + y)` + +error: this operation has no effect + --> tests/ui/identity_op.rs:243:20 + | +LL | let _ = 2i32 - (x - y - 0i32); + | ^^^^^^^^^^^^^^ help: consider reducing it to: `(x - y)` + +error: this operation has no effect + --> tests/ui/identity_op.rs:247:17 + | +LL | let _ = 2 + (x + (y * z) + 0); + | ^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(x + (y * z))` + +error: this operation has no effect + --> tests/ui/identity_op.rs:251:20 + | +LL | let _ = 2i32 + (x * y * 1i32); + | ^^^^^^^^^^^^^^ help: consider reducing it to: `(x * y)` + +error: this operation has no effect + --> tests/ui/identity_op.rs:256:25 + | +LL | let _: u64 = 1u64 + ((x as i32 + y as i32) as u64 + 0u64); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `((x as i32 + y as i32) as u64)` + +error: aborting due to 63 previous errors diff --git a/tests/ui/question_mark.fixed b/tests/ui/question_mark.fixed index 679388372e6..b6e148e9f77 100644 --- a/tests/ui/question_mark.fixed +++ b/tests/ui/question_mark.fixed @@ -96,12 +96,42 @@ impl MoveStruct { } fn func() -> Option { + macro_rules! opt_none { + () => { + None + }; + } + fn f() -> Option { Some(String::new()) } f()?; + let _val = f()?; + + let s: &str = match &Some(String::new()) { + Some(v) => v, + None => return None, + }; + + f()?; + + opt_none!()?; + + match f() { + Some(x) => x, + None => return opt_none!(), + }; + + match f() { + Some(val) => { + println!("{val}"); + val + }, + None => return None, + }; + Some(0) } @@ -114,6 +144,10 @@ fn result_func(x: Result) -> Result { x?; + let _val = func_returning_result()?; + + func_returning_result()?; + // No warning let y = if let Ok(x) = x { x @@ -157,6 +191,28 @@ fn result_func(x: Result) -> Result { Ok(y) } +fn infer_check() { + let closure = |x: Result| { + // `?` would fail here, as it expands to `Err(val.into())` which is not constrained. + let _val = match x { + Ok(val) => val, + Err(val) => return Err(val), + }; + + Ok(()) + }; + + let closure = |x: Result| -> Result<(), _> { + // `?` would fail here, as it expands to `Err(val.into())` which is not constrained. + let _val = match x { + Ok(val) => val, + Err(val) => return Err(val), + }; + + Ok(()) + }; +} + // see issue #8019 pub enum NotOption { None, diff --git a/tests/ui/question_mark.rs b/tests/ui/question_mark.rs index 601ab78bf5a..48dc9eb0a62 100644 --- a/tests/ui/question_mark.rs +++ b/tests/ui/question_mark.rs @@ -124,6 +124,12 @@ impl MoveStruct { } fn func() -> Option { + macro_rules! opt_none { + () => { + None + }; + } + fn f() -> Option { Some(String::new()) } @@ -132,6 +138,39 @@ fn func() -> Option { return None; } + let _val = match f() { + Some(val) => val, + None => return None, + }; + + let s: &str = match &Some(String::new()) { + Some(v) => v, + None => return None, + }; + + match f() { + Some(val) => val, + None => return None, + }; + + match opt_none!() { + Some(x) => x, + None => return None, + }; + + match f() { + Some(x) => x, + None => return opt_none!(), + }; + + match f() { + Some(val) => { + println!("{val}"); + val + }, + None => return None, + }; + Some(0) } @@ -146,6 +185,16 @@ fn result_func(x: Result) -> Result { return x; } + let _val = match func_returning_result() { + Ok(val) => val, + Err(err) => return Err(err), + }; + + match func_returning_result() { + Ok(val) => val, + Err(err) => return Err(err), + }; + // No warning let y = if let Ok(x) = x { x @@ -189,6 +238,28 @@ fn result_func(x: Result) -> Result { Ok(y) } +fn infer_check() { + let closure = |x: Result| { + // `?` would fail here, as it expands to `Err(val.into())` which is not constrained. + let _val = match x { + Ok(val) => val, + Err(val) => return Err(val), + }; + + Ok(()) + }; + + let closure = |x: Result| -> Result<(), _> { + // `?` would fail here, as it expands to `Err(val.into())` which is not constrained. + let _val = match x { + Ok(val) => val, + Err(val) => return Err(val), + }; + + Ok(()) + }; +} + // see issue #8019 pub enum NotOption { None, diff --git a/tests/ui/question_mark.stderr b/tests/ui/question_mark.stderr index 5f26a7ea2c3..0a48c4e80cb 100644 --- a/tests/ui/question_mark.stderr +++ b/tests/ui/question_mark.stderr @@ -94,29 +94,76 @@ LL | | }; | |_________^ help: replace it with: `self.opt?` error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:131:5 + --> tests/ui/question_mark.rs:137:5 | LL | / if f().is_none() { LL | | return None; LL | | } | |_____^ help: replace it with: `f()?;` +error: this `match` expression can be replaced with `?` + --> tests/ui/question_mark.rs:141:16 + | +LL | let _val = match f() { + | ________________^ +LL | | Some(val) => val, +LL | | None => return None, +LL | | }; + | |_____^ help: try instead: `f()?` + +error: this `match` expression can be replaced with `?` + --> tests/ui/question_mark.rs:151:5 + | +LL | / match f() { +LL | | Some(val) => val, +LL | | None => return None, +LL | | }; + | |_____^ help: try instead: `f()?` + +error: this `match` expression can be replaced with `?` + --> tests/ui/question_mark.rs:156:5 + | +LL | / match opt_none!() { +LL | | Some(x) => x, +LL | | None => return None, +LL | | }; + | |_____^ help: try instead: `opt_none!()?` + error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:143:13 + --> tests/ui/question_mark.rs:182:13 | LL | let _ = if let Ok(x) = x { x } else { return x }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `x?` error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:145:5 + --> tests/ui/question_mark.rs:184:5 | LL | / if x.is_err() { LL | | return x; LL | | } | |_____^ help: replace it with: `x?;` +error: this `match` expression can be replaced with `?` + --> tests/ui/question_mark.rs:188:16 + | +LL | let _val = match func_returning_result() { + | ________________^ +LL | | Ok(val) => val, +LL | | Err(err) => return Err(err), +LL | | }; + | |_____^ help: try instead: `func_returning_result()?` + +error: this `match` expression can be replaced with `?` + --> tests/ui/question_mark.rs:193:5 + | +LL | / match func_returning_result() { +LL | | Ok(val) => val, +LL | | Err(err) => return Err(err), +LL | | }; + | |_____^ help: try instead: `func_returning_result()?` + error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:213:5 + --> tests/ui/question_mark.rs:284:5 | LL | / if let Err(err) = func_returning_result() { LL | | return Err(err); @@ -124,7 +171,7 @@ LL | | } | |_____^ help: replace it with: `func_returning_result()?;` error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:220:5 + --> tests/ui/question_mark.rs:291:5 | LL | / if let Err(err) = func_returning_result() { LL | | return Err(err); @@ -132,7 +179,7 @@ LL | | } | |_____^ help: replace it with: `func_returning_result()?;` error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:297:13 + --> tests/ui/question_mark.rs:368:13 | LL | / if a.is_none() { LL | | return None; @@ -142,12 +189,12 @@ LL | | } | |_____________^ help: replace it with: `a?;` error: this `let...else` may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:357:5 + --> tests/ui/question_mark.rs:428:5 | LL | / let Some(v) = bar.foo.owned.clone() else { LL | | return None; LL | | }; | |______^ help: replace it with: `let v = bar.foo.owned.clone()?;` -error: aborting due to 17 previous errors +error: aborting due to 22 previous errors diff --git a/tests/ui/unnecessary_map_or.fixed b/tests/ui/unnecessary_map_or.fixed new file mode 100644 index 00000000000..2d932a70e9d --- /dev/null +++ b/tests/ui/unnecessary_map_or.fixed @@ -0,0 +1,64 @@ +//@aux-build:proc_macros.rs +#![warn(clippy::unnecessary_map_or)] +#![allow(clippy::no_effect)] +#![allow(clippy::eq_op)] +#![allow(clippy::unnecessary_lazy_evaluations)] +#[clippy::msrv = "1.70.0"] +#[macro_use] +extern crate proc_macros; + +fn main() { + // should trigger + let _ = (Some(5) == Some(5)); + let _ = (Some(5) != Some(5)); + let _ = (Some(5) == Some(5)); + let _ = Some(5).is_some_and(|n| { + let _ = n; + 6 >= 5 + }); + let _ = Some(vec![5]).is_some_and(|n| n == [5]); + let _ = Some(vec![1]).is_some_and(|n| vec![2] == n); + let _ = Some(5).is_some_and(|n| n == n); + let _ = Some(5).is_some_and(|n| n == if 2 > 1 { n } else { 0 }); + let _ = Ok::, i32>(vec![5]).is_ok_and(|n| n == [5]); + let _ = (Ok::(5) == Ok(5)); + let _ = (Some(5) == Some(5)).then(|| 1); + + // shouldnt trigger + let _ = Some(5).map_or(true, |n| n == 5); + let _ = Some(5).map_or(true, |n| 5 == n); + macro_rules! x { + () => { + Some(1) + }; + } + // methods lints dont fire on macros + let _ = x!().map_or(false, |n| n == 1); + let _ = x!().map_or(false, |n| n == vec![1][0]); + + msrv_1_69(); + + external! { + let _ = Some(5).map_or(false, |n| n == 5); + } + + with_span! { + let _ = Some(5).map_or(false, |n| n == 5); + } + + // check for presence of PartialEq, and alter suggestion to use `is_ok_and` if absent + struct S; + let r: Result = Ok(3); + let _ = r.is_ok_and(|x| x == 7); + + #[derive(PartialEq)] + struct S2; + let r: Result = Ok(4); + let _ = (r == Ok(8)); +} + +#[clippy::msrv = "1.69.0"] +fn msrv_1_69() { + // is_some_and added in 1.70.0 + let _ = Some(5).map_or(false, |n| n == if 2 > 1 { n } else { 0 }); +} diff --git a/tests/ui/unnecessary_map_or.rs b/tests/ui/unnecessary_map_or.rs new file mode 100644 index 00000000000..4a9d69be1e9 --- /dev/null +++ b/tests/ui/unnecessary_map_or.rs @@ -0,0 +1,67 @@ +//@aux-build:proc_macros.rs +#![warn(clippy::unnecessary_map_or)] +#![allow(clippy::no_effect)] +#![allow(clippy::eq_op)] +#![allow(clippy::unnecessary_lazy_evaluations)] +#[clippy::msrv = "1.70.0"] +#[macro_use] +extern crate proc_macros; + +fn main() { + // should trigger + let _ = Some(5).map_or(false, |n| n == 5); + let _ = Some(5).map_or(true, |n| n != 5); + let _ = Some(5).map_or(false, |n| { + let _ = 1; + n == 5 + }); + let _ = Some(5).map_or(false, |n| { + let _ = n; + 6 >= 5 + }); + let _ = Some(vec![5]).map_or(false, |n| n == [5]); + let _ = Some(vec![1]).map_or(false, |n| vec![2] == n); + let _ = Some(5).map_or(false, |n| n == n); + let _ = Some(5).map_or(false, |n| n == if 2 > 1 { n } else { 0 }); + let _ = Ok::, i32>(vec![5]).map_or(false, |n| n == [5]); + let _ = Ok::(5).map_or(false, |n| n == 5); + let _ = Some(5).map_or(false, |n| n == 5).then(|| 1); + + // shouldnt trigger + let _ = Some(5).map_or(true, |n| n == 5); + let _ = Some(5).map_or(true, |n| 5 == n); + macro_rules! x { + () => { + Some(1) + }; + } + // methods lints dont fire on macros + let _ = x!().map_or(false, |n| n == 1); + let _ = x!().map_or(false, |n| n == vec![1][0]); + + msrv_1_69(); + + external! { + let _ = Some(5).map_or(false, |n| n == 5); + } + + with_span! { + let _ = Some(5).map_or(false, |n| n == 5); + } + + // check for presence of PartialEq, and alter suggestion to use `is_ok_and` if absent + struct S; + let r: Result = Ok(3); + let _ = r.map_or(false, |x| x == 7); + + #[derive(PartialEq)] + struct S2; + let r: Result = Ok(4); + let _ = r.map_or(false, |x| x == 8); +} + +#[clippy::msrv = "1.69.0"] +fn msrv_1_69() { + // is_some_and added in 1.70.0 + let _ = Some(5).map_or(false, |n| n == if 2 > 1 { n } else { 0 }); +} diff --git a/tests/ui/unnecessary_map_or.stderr b/tests/ui/unnecessary_map_or.stderr new file mode 100644 index 00000000000..299a4e5da7a --- /dev/null +++ b/tests/ui/unnecessary_map_or.stderr @@ -0,0 +1,99 @@ +error: this `map_or` is redundant + --> tests/ui/unnecessary_map_or.rs:12:13 + | +LL | let _ = Some(5).map_or(false, |n| n == 5); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(Some(5) == Some(5))` + | + = note: `-D clippy::unnecessary-map-or` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_map_or)]` + +error: this `map_or` is redundant + --> tests/ui/unnecessary_map_or.rs:13:13 + | +LL | let _ = Some(5).map_or(true, |n| n != 5); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(Some(5) != Some(5))` + +error: this `map_or` is redundant + --> tests/ui/unnecessary_map_or.rs:14:13 + | +LL | let _ = Some(5).map_or(false, |n| { + | _____________^ +LL | | let _ = 1; +LL | | n == 5 +LL | | }); + | |______^ help: use a standard comparison instead: `(Some(5) == Some(5))` + +error: this `map_or` is redundant + --> tests/ui/unnecessary_map_or.rs:18:13 + | +LL | let _ = Some(5).map_or(false, |n| { + | _____________^ +LL | | let _ = n; +LL | | 6 >= 5 +LL | | }); + | |______^ + | +help: use is_some_and instead + | +LL ~ let _ = Some(5).is_some_and(|n| { +LL + let _ = n; +LL + 6 >= 5 +LL ~ }); + | + +error: this `map_or` is redundant + --> tests/ui/unnecessary_map_or.rs:22:13 + | +LL | let _ = Some(vec![5]).map_or(false, |n| n == [5]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_some_and instead: `Some(vec![5]).is_some_and(|n| n == [5])` + +error: this `map_or` is redundant + --> tests/ui/unnecessary_map_or.rs:23:13 + | +LL | let _ = Some(vec![1]).map_or(false, |n| vec![2] == n); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_some_and instead: `Some(vec![1]).is_some_and(|n| vec![2] == n)` + +error: this `map_or` is redundant + --> tests/ui/unnecessary_map_or.rs:24:13 + | +LL | let _ = Some(5).map_or(false, |n| n == n); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_some_and instead: `Some(5).is_some_and(|n| n == n)` + +error: this `map_or` is redundant + --> tests/ui/unnecessary_map_or.rs:25:13 + | +LL | let _ = Some(5).map_or(false, |n| n == if 2 > 1 { n } else { 0 }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_some_and instead: `Some(5).is_some_and(|n| n == if 2 > 1 { n } else { 0 })` + +error: this `map_or` is redundant + --> tests/ui/unnecessary_map_or.rs:26:13 + | +LL | let _ = Ok::, i32>(vec![5]).map_or(false, |n| n == [5]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_ok_and instead: `Ok::, i32>(vec![5]).is_ok_and(|n| n == [5])` + +error: this `map_or` is redundant + --> tests/ui/unnecessary_map_or.rs:27:13 + | +LL | let _ = Ok::(5).map_or(false, |n| n == 5); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(Ok::(5) == Ok(5))` + +error: this `map_or` is redundant + --> tests/ui/unnecessary_map_or.rs:28:13 + | +LL | let _ = Some(5).map_or(false, |n| n == 5).then(|| 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(Some(5) == Some(5))` + +error: this `map_or` is redundant + --> tests/ui/unnecessary_map_or.rs:55:13 + | +LL | let _ = r.map_or(false, |x| x == 7); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_ok_and instead: `r.is_ok_and(|x| x == 7)` + +error: this `map_or` is redundant + --> tests/ui/unnecessary_map_or.rs:60:13 + | +LL | let _ = r.map_or(false, |x| x == 8); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(r == Ok(8))` + +error: aborting due to 13 previous errors + From 4460db085001e76352f9979d0e852baa23f99bc7 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Fri, 15 Nov 2024 19:24:27 +0100 Subject: [PATCH 03/45] Move MSRV implementation to clippy_utils --- clippy_config/src/conf.rs | 2 +- clippy_config/src/lib.rs | 6 ------ clippy_utils/Cargo.toml | 1 + clippy_utils/src/lib.rs | 2 ++ {clippy_config => clippy_utils}/src/msrvs.rs | 0 clippy_utils/src/paths.rs | 2 +- clippy_utils/src/qualify_min_const_fn.rs | 2 +- 7 files changed, 6 insertions(+), 9 deletions(-) rename {clippy_config => clippy_utils}/src/msrvs.rs (100%) diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index 600d5b6e2c8..c3b1fc83af0 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -1,10 +1,10 @@ use crate::ClippyConfiguration; -use crate::msrvs::Msrv; use crate::types::{ DisallowedPath, MacroMatcher, MatchLintBehaviour, PubUnderscoreFieldsBehaviour, Rename, SourceItemOrdering, SourceItemOrderingCategory, SourceItemOrderingModuleItemGroupings, SourceItemOrderingModuleItemKind, SourceItemOrderingTraitAssocItemKind, SourceItemOrderingTraitAssocItemKinds, }; +use clippy_utils::msrvs::Msrv; use rustc_errors::Applicability; use rustc_session::Session; use rustc_span::edit_distance::edit_distance; diff --git a/clippy_config/src/lib.rs b/clippy_config/src/lib.rs index 1c3f32c2514..4acd54fa037 100644 --- a/clippy_config/src/lib.rs +++ b/clippy_config/src/lib.rs @@ -13,18 +13,12 @@ rustc::untranslatable_diagnostic )] -extern crate rustc_ast; -extern crate rustc_attr; -#[allow(unused_extern_crates)] -extern crate rustc_driver; extern crate rustc_errors; extern crate rustc_session; extern crate rustc_span; -extern crate smallvec; mod conf; mod metadata; -pub mod msrvs; pub mod types; pub use conf::{Conf, get_configuration_metadata, lookup_conf_file, sanitize_explanation}; diff --git a/clippy_utils/Cargo.toml b/clippy_utils/Cargo.toml index d8d5733da1c..745890ee183 100644 --- a/clippy_utils/Cargo.toml +++ b/clippy_utils/Cargo.toml @@ -10,6 +10,7 @@ arrayvec = { version = "0.7", default-features = false } itertools = "0.12" # FIXME(f16_f128): remove when no longer needed for parsing rustc_apfloat = "0.2.0" +serde = { version = "1.0", features = ["derive"] } [package.metadata.rust-analyzer] # This crate uses #[feature(rustc_private)] diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 19316a90683..42de0e20e96 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -50,6 +50,7 @@ extern crate rustc_session; extern crate rustc_span; extern crate rustc_target; extern crate rustc_trait_selection; +extern crate smallvec; #[macro_use] pub mod sym_helper; @@ -65,6 +66,7 @@ pub mod higher; mod hir_utils; pub mod macros; pub mod mir; +pub mod msrvs; pub mod numeric_literal; pub mod paths; pub mod ptr; diff --git a/clippy_config/src/msrvs.rs b/clippy_utils/src/msrvs.rs similarity index 100% rename from clippy_config/src/msrvs.rs rename to clippy_utils/src/msrvs.rs diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 11a98b02f33..bb40a9430a7 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -36,7 +36,7 @@ pub const CHILD_KILL: [&str; 4] = ["std", "process", "Child", "kill"]; pub const PANIC_ANY: [&str; 3] = ["std", "panic", "panic_any"]; // Paths in clippy itself -pub const MSRV: [&str; 3] = ["clippy_config", "msrvs", "Msrv"]; +pub const MSRV: [&str; 3] = ["clippy_utils", "msrvs", "Msrv"]; // Paths in external crates #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index 971f8eeb1b3..d4d00f1abe3 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -3,7 +3,7 @@ // of terminologies might not be relevant in the context of Clippy. Note that its behavior might // differ from the time of `rustc` even if the name stays the same. -use clippy_config::msrvs::{self, Msrv}; +use crate::msrvs::{self, Msrv}; use hir::LangItem; use rustc_attr::StableSince; use rustc_const_eval::check_consts::ConstCx; From 81483d4a6c94d37b7f3af135598dfcb9e4a331b2 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Fri, 15 Nov 2024 19:28:20 +0100 Subject: [PATCH 04/45] Move create_disallowed_map to clippy_config --- clippy_config/Cargo.toml | 2 ++ clippy_config/src/lib.rs | 2 ++ clippy_config/src/types.rs | 15 +++++++++++++++ clippy_lints/src/await_holding_invalid.rs | 3 ++- clippy_lints/src/disallowed_macros.rs | 2 +- clippy_lints/src/disallowed_methods.rs | 2 +- clippy_utils/Cargo.toml | 2 -- clippy_utils/src/lib.rs | 15 +-------------- 8 files changed, 24 insertions(+), 19 deletions(-) diff --git a/clippy_config/Cargo.toml b/clippy_config/Cargo.toml index d21df202dca..0cd0cabc3a6 100644 --- a/clippy_config/Cargo.toml +++ b/clippy_config/Cargo.toml @@ -2,10 +2,12 @@ name = "clippy_config" version = "0.1.84" edition = "2021" +publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +clippy_utils = { path = "../clippy_utils" } itertools = "0.12" serde = { version = "1.0", features = ["derive"] } toml = "0.7.3" diff --git a/clippy_config/src/lib.rs b/clippy_config/src/lib.rs index 4acd54fa037..5d6e8b87516 100644 --- a/clippy_config/src/lib.rs +++ b/clippy_config/src/lib.rs @@ -14,6 +14,8 @@ )] extern crate rustc_errors; +extern crate rustc_hir; +extern crate rustc_middle; extern crate rustc_session; extern crate rustc_span; diff --git a/clippy_config/src/types.rs b/clippy_config/src/types.rs index fe576424148..c949db9109d 100644 --- a/clippy_config/src/types.rs +++ b/clippy_config/src/types.rs @@ -1,3 +1,6 @@ +use clippy_utils::def_path_def_ids; +use rustc_hir::def_id::DefIdMap; +use rustc_middle::ty::TyCtxt; use serde::de::{self, Deserializer, Visitor}; use serde::{Deserialize, Serialize, ser}; use std::collections::HashMap; @@ -31,6 +34,18 @@ impl DisallowedPath { } } +/// Creates a map of disallowed items to the reason they were disallowed. +pub fn create_disallowed_map( + tcx: TyCtxt<'_>, + disallowed: &'static [DisallowedPath], +) -> DefIdMap<(&'static str, Option<&'static str>)> { + disallowed + .iter() + .map(|x| (x.path(), x.path().split("::").collect::>(), x.reason())) + .flat_map(|(name, path, reason)| def_path_def_ids(tcx, &path).map(move |id| (id, (name, reason)))) + .collect() +} + #[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)] pub enum MatchLintBehaviour { AllTypes, diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs index 6948cf560a5..2eb0566bf9a 100644 --- a/clippy_lints/src/await_holding_invalid.rs +++ b/clippy_lints/src/await_holding_invalid.rs @@ -1,6 +1,7 @@ use clippy_config::Conf; +use clippy_config::types::create_disallowed_map; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::{create_disallowed_map, match_def_path, paths}; +use clippy_utils::{match_def_path, paths}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, DefIdMap}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/disallowed_macros.rs b/clippy_lints/src/disallowed_macros.rs index bdd49bf8aa7..a0cb36f88dc 100644 --- a/clippy_lints/src/disallowed_macros.rs +++ b/clippy_lints/src/disallowed_macros.rs @@ -1,5 +1,5 @@ use clippy_config::Conf; -use clippy_utils::create_disallowed_map; +use clippy_config::types::create_disallowed_map; use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::macros::macro_backtrace; use rustc_data_structures::fx::FxHashSet; diff --git a/clippy_lints/src/disallowed_methods.rs b/clippy_lints/src/disallowed_methods.rs index 5a01d76a2a6..1e660b1957a 100644 --- a/clippy_lints/src/disallowed_methods.rs +++ b/clippy_lints/src/disallowed_methods.rs @@ -1,5 +1,5 @@ use clippy_config::Conf; -use clippy_utils::create_disallowed_map; +use clippy_config::types::create_disallowed_map; use clippy_utils::diagnostics::span_lint_and_then; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefIdMap; diff --git a/clippy_utils/Cargo.toml b/clippy_utils/Cargo.toml index 745890ee183..d136f3bc6f1 100644 --- a/clippy_utils/Cargo.toml +++ b/clippy_utils/Cargo.toml @@ -2,10 +2,8 @@ name = "clippy_utils" version = "0.1.84" edition = "2021" -publish = false [dependencies] -clippy_config = { path = "../clippy_config" } arrayvec = { version = "0.7", default-features = false } itertools = "0.12" # FIXME(f16_f128): remove when no longer needed for parsing diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 42de0e20e96..927ce5b6f16 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -91,7 +91,6 @@ use std::hash::BuildHasherDefault; use std::iter::{once, repeat}; use std::sync::{Mutex, MutexGuard, OnceLock}; -use clippy_config::types::DisallowedPath; use itertools::Itertools; use rustc_ast::ast::{self, LitKind, RangeLimits}; use rustc_data_structures::fx::FxHashMap; @@ -99,7 +98,7 @@ use rustc_data_structures::packed::Pu128; use rustc_data_structures::unhash::UnhashMap; use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk}; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE, LocalDefId, LocalModDefId}; +use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId, LocalModDefId}; use rustc_hir::definitions::{DefPath, DefPathData}; use rustc_hir::hir_id::{HirIdMap, HirIdSet}; use rustc_hir::intravisit::{FnKind, Visitor, walk_expr}; @@ -750,18 +749,6 @@ pub fn def_path_def_ids(tcx: TyCtxt<'_>, path: &[&str]) -> impl Iterator, - disallowed: &'static [DisallowedPath], -) -> DefIdMap<(&'static str, Option<&'static str>)> { - disallowed - .iter() - .map(|x| (x.path(), x.path().split("::").collect::>(), x.reason())) - .flat_map(|(name, path, reason)| def_path_def_ids(tcx, &path).map(move |id| (id, (name, reason)))) - .collect() -} - /// Convenience function to get the `DefId` of a trait by path. /// It could be a trait or trait alias. /// From 5c1811ab94bcf0961ff5cdd57f428d94d4d08227 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Fri, 15 Nov 2024 19:33:39 +0100 Subject: [PATCH 05/45] Rename all clippy_config::msrvs -> clippy_utils::msrvs --- book/src/development/adding_lints.md | 4 ++-- clippy_dev/src/new_lint.rs | 4 ++-- clippy_lints/src/almost_complete_range.rs | 2 +- clippy_lints/src/approx_const.rs | 2 +- clippy_lints/src/assigning_clones.rs | 2 +- clippy_lints/src/attrs/deprecated_cfg_attr.rs | 2 +- clippy_lints/src/attrs/mod.rs | 2 +- clippy_lints/src/booleans.rs | 2 +- clippy_lints/src/casts/cast_abs_to_unsigned.rs | 2 +- clippy_lints/src/casts/cast_lossless.rs | 2 +- clippy_lints/src/casts/cast_slice_different_sizes.rs | 2 +- clippy_lints/src/casts/cast_slice_from_raw_parts.rs | 2 +- clippy_lints/src/casts/mod.rs | 2 +- clippy_lints/src/casts/ptr_as_ptr.rs | 2 +- clippy_lints/src/casts/ptr_cast_constness.rs | 2 +- clippy_lints/src/checked_conversions.rs | 2 +- clippy_lints/src/derivable_impls.rs | 2 +- clippy_lints/src/format_args.rs | 2 +- clippy_lints/src/from_over_into.rs | 2 +- clippy_lints/src/if_then_some_else_none.rs | 2 +- clippy_lints/src/implicit_saturating_sub.rs | 2 +- clippy_lints/src/incompatible_msrv.rs | 2 +- clippy_lints/src/index_refutable_slice.rs | 2 +- clippy_lints/src/instant_subtraction.rs | 2 +- clippy_lints/src/legacy_numeric_constants.rs | 6 +++--- clippy_lints/src/loops/explicit_iter_loop.rs | 2 +- clippy_lints/src/loops/mod.rs | 2 +- clippy_lints/src/manual_bits.rs | 2 +- clippy_lints/src/manual_clamp.rs | 2 +- clippy_lints/src/manual_div_ceil.rs | 2 +- clippy_lints/src/manual_float_methods.rs | 4 ++-- clippy_lints/src/manual_hash_one.rs | 2 +- clippy_lints/src/manual_is_ascii_check.rs | 2 +- clippy_lints/src/manual_let_else.rs | 3 +-- clippy_lints/src/manual_main_separator_str.rs | 2 +- clippy_lints/src/manual_non_exhaustive.rs | 2 +- clippy_lints/src/manual_rem_euclid.rs | 2 +- clippy_lints/src/manual_retain.rs | 2 +- clippy_lints/src/manual_strip.rs | 2 +- clippy_lints/src/matches/collapsible_match.rs | 2 +- clippy_lints/src/matches/mod.rs | 2 +- clippy_lints/src/matches/redundant_guards.rs | 2 +- clippy_lints/src/mem_replace.rs | 2 +- clippy_lints/src/methods/cloned_instead_of_copied.rs | 2 +- clippy_lints/src/methods/err_expect.rs | 2 +- clippy_lints/src/methods/filter_map_next.rs | 2 +- clippy_lints/src/methods/is_digit_ascii_radix.rs | 2 +- clippy_lints/src/methods/iter_kv_map.rs | 2 +- clippy_lints/src/methods/manual_c_str_literals.rs | 2 +- clippy_lints/src/methods/manual_inspect.rs | 2 +- clippy_lints/src/methods/manual_is_variant_and.rs | 4 ++-- clippy_lints/src/methods/manual_try_fold.rs | 2 +- clippy_lints/src/methods/map_clone.rs | 2 +- clippy_lints/src/methods/map_unwrap_or.rs | 2 +- .../src/methods/map_with_unused_argument_over_ranges.rs | 2 +- clippy_lints/src/methods/mod.rs | 2 +- clippy_lints/src/methods/option_as_ref_deref.rs | 2 +- clippy_lints/src/methods/option_map_unwrap_or.rs | 2 +- clippy_lints/src/methods/path_ends_with_ext.rs | 2 +- clippy_lints/src/methods/str_splitn.rs | 2 +- clippy_lints/src/methods/string_lit_chars_any.rs | 2 +- clippy_lints/src/methods/unnecessary_map_or.rs | 2 +- clippy_lints/src/methods/unnecessary_to_owned.rs | 2 +- clippy_lints/src/missing_const_for_fn.rs | 2 +- clippy_lints/src/missing_const_for_thread_local.rs | 2 +- clippy_lints/src/needless_borrows_for_generic_args.rs | 2 +- clippy_lints/src/question_mark.rs | 2 +- clippy_lints/src/ranges.rs | 2 +- clippy_lints/src/redundant_field_names.rs | 2 +- clippy_lints/src/redundant_static_lifetimes.rs | 2 +- clippy_lints/src/std_instead_of_core.rs | 2 +- clippy_lints/src/string_patterns.rs | 2 +- clippy_lints/src/trait_bounds.rs | 2 +- clippy_lints/src/transmute/mod.rs | 2 +- clippy_lints/src/transmute/transmute_float_to_int.rs | 2 +- clippy_lints/src/transmute/transmute_int_to_float.rs | 2 +- clippy_lints/src/transmute/transmute_num_to_bytes.rs | 2 +- clippy_lints/src/transmute/transmute_ptr_to_ptr.rs | 2 +- clippy_lints/src/transmute/transmute_ptr_to_ref.rs | 2 +- clippy_lints/src/tuple_array_conversions.rs | 2 +- clippy_lints/src/unnested_or_patterns.rs | 2 +- clippy_lints/src/unused_trait_names.rs | 2 +- clippy_lints/src/use_self.rs | 2 +- clippy_lints/src/vec.rs | 2 +- tests/ui-internal/invalid_msrv_attr_impl.fixed | 2 +- tests/ui-internal/invalid_msrv_attr_impl.rs | 2 +- 86 files changed, 92 insertions(+), 93 deletions(-) diff --git a/book/src/development/adding_lints.md b/book/src/development/adding_lints.md index 963e02e5c16..c07568697d0 100644 --- a/book/src/development/adding_lints.md +++ b/book/src/development/adding_lints.md @@ -438,7 +438,7 @@ need to ensure that the MSRV configured for the project is >= the MSRV of the required Rust feature. If multiple features are required, just use the one with a lower MSRV. -First, add an MSRV alias for the required feature in [`clippy_config::msrvs`]. +First, add an MSRV alias for the required feature in [`clippy_utils::msrvs`]. This can be accessed later as `msrvs::STR_STRIP_PREFIX`, for example. ```rust @@ -517,7 +517,7 @@ define_Conf! { } ``` -[`clippy_config::msrvs`]: https://doc.rust-lang.org/nightly/nightly-rustc/clippy_config/msrvs/index.html +[`clippy_utils::msrvs`]: https://doc.rust-lang.org/nightly/nightly-rustc/clippy_config/msrvs/index.html Afterwards update the documentation for the book as described in [Adding configuration to a lint](#adding-configuration-to-a-lint). diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index 8b32dc6b888..ee626d60b86 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -273,7 +273,7 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { result.push_str(&if enable_msrv { formatdoc!( r" - use clippy_config::msrvs::{{self, Msrv}}; + use clippy_utils::msrvs::{{self, Msrv}}; use clippy_config::Conf; {pass_import} use rustc_lint::{{{context_import}, {pass_type}, LintContext}}; @@ -399,7 +399,7 @@ fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::R let _: fmt::Result = writedoc!( lint_file_contents, r#" - use clippy_config::msrvs::{{self, Msrv}}; + use clippy_utils::msrvs::{{self, Msrv}}; use rustc_lint::{{{context_import}, LintContext}}; use super::{name_upper}; diff --git a/clippy_lints/src/almost_complete_range.rs b/clippy_lints/src/almost_complete_range.rs index 370f0c482fd..2af5178920d 100644 --- a/clippy_lints/src/almost_complete_range.rs +++ b/clippy_lints/src/almost_complete_range.rs @@ -1,6 +1,6 @@ use clippy_config::Conf; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::{trim_span, walk_span_to_context}; use rustc_ast::ast::{Expr, ExprKind, LitKind, Pat, PatKind, RangeEnd, RangeLimits}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/approx_const.rs b/clippy_lints/src/approx_const.rs index 4f8f091a095..2f7f5e07ac7 100644 --- a/clippy_lints/src/approx_const.rs +++ b/clippy_lints/src/approx_const.rs @@ -1,6 +1,6 @@ use clippy_config::Conf; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::msrvs::{self, Msrv}; use rustc_ast::ast::{FloatTy, LitFloatType, LitKind}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/assigning_clones.rs b/clippy_lints/src/assigning_clones.rs index 0b82c0cd04c..3a402a53e1c 100644 --- a/clippy_lints/src/assigning_clones.rs +++ b/clippy_lints/src/assigning_clones.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::mir::{PossibleBorrowerMap, enclosing_mir}; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::sugg::Sugg; use clippy_utils::{is_diag_trait_item, is_in_test, last_path_segment, local_is_initialized, path_to_local}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/attrs/deprecated_cfg_attr.rs b/clippy_lints/src/attrs/deprecated_cfg_attr.rs index abf924f7542..3a462018e3e 100644 --- a/clippy_lints/src/attrs/deprecated_cfg_attr.rs +++ b/clippy_lints/src/attrs/deprecated_cfg_attr.rs @@ -1,6 +1,6 @@ use super::{Attribute, DEPRECATED_CFG_ATTR, DEPRECATED_CLIPPY_CFG_ATTR, unnecessary_clippy_cfg}; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::{self, Msrv}; use rustc_ast::AttrStyle; use rustc_errors::Applicability; use rustc_lint::EarlyContext; diff --git a/clippy_lints/src/attrs/mod.rs b/clippy_lints/src/attrs/mod.rs index c29c9f08cf7..a9766597d50 100644 --- a/clippy_lints/src/attrs/mod.rs +++ b/clippy_lints/src/attrs/mod.rs @@ -13,7 +13,7 @@ mod useless_attribute; mod utils; use clippy_config::Conf; -use clippy_config::msrvs::{self, Msrv}; +use clippy_utils::msrvs::{self, Msrv}; use rustc_ast::{self as ast, Attribute, MetaItemInner, MetaItemKind}; use rustc_hir::{ImplItem, Item, TraitItem}; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 896bd5fd03d..6eef0d42a55 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; use clippy_utils::eq_expr_value; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use rustc_ast::ast::LitKind; diff --git a/clippy_lints/src/casts/cast_abs_to_unsigned.rs b/clippy_lints/src/casts/cast_abs_to_unsigned.rs index b7b63250864..ae433773193 100644 --- a/clippy_lints/src/casts/cast_abs_to_unsigned.rs +++ b/clippy_lints/src/casts/cast_abs_to_unsigned.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::sugg::Sugg; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; diff --git a/clippy_lints/src/casts/cast_lossless.rs b/clippy_lints/src/casts/cast_lossless.rs index 84a44b14dde..4ad39d9160d 100644 --- a/clippy_lints/src/casts/cast_lossless.rs +++ b/clippy_lints/src/casts/cast_lossless.rs @@ -1,6 +1,6 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_in_const_context; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::SpanRangeExt; use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_isize_or_usize; diff --git a/clippy_lints/src/casts/cast_slice_different_sizes.rs b/clippy_lints/src/casts/cast_slice_different_sizes.rs index 285f0357112..030c2d322db 100644 --- a/clippy_lints/src/casts/cast_slice_different_sizes.rs +++ b/clippy_lints/src/casts/cast_slice_different_sizes.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source; use rustc_ast::Mutability; use rustc_hir::{Expr, ExprKind, Node}; diff --git a/clippy_lints/src/casts/cast_slice_from_raw_parts.rs b/clippy_lints/src/casts/cast_slice_from_raw_parts.rs index 1d89f6c75e1..c3bc5c0c9f2 100644 --- a/clippy_lints/src/casts/cast_slice_from_raw_parts.rs +++ b/clippy_lints/src/casts/cast_slice_from_raw_parts.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_context; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index 3acd4eca420..8b884399f92 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -24,8 +24,8 @@ mod utils; mod zero_ptr; use clippy_config::Conf; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::is_hir_ty_cfg_dependant; +use clippy_utils::msrvs::{self, Msrv}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; diff --git a/clippy_lints/src/casts/ptr_as_ptr.rs b/clippy_lints/src/casts/ptr_as_ptr.rs index 86c5f6b9f0b..451d6510017 100644 --- a/clippy_lints/src/casts/ptr_as_ptr.rs +++ b/clippy_lints/src/casts/ptr_as_ptr.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; use rustc_errors::Applicability; diff --git a/clippy_lints/src/casts/ptr_cast_constness.rs b/clippy_lints/src/casts/ptr_cast_constness.rs index 7518dd2435a..945c05ee943 100644 --- a/clippy_lints/src/casts/ptr_cast_constness.rs +++ b/clippy_lints/src/casts/ptr_cast_constness.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::std_or_core; use clippy_utils::sugg::Sugg; use rustc_errors::Applicability; diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs index f76e399517c..364f5c7dc7a 100644 --- a/clippy_lints/src/checked_conversions.rs +++ b/clippy_lints/src/checked_conversions.rs @@ -1,6 +1,6 @@ use clippy_config::Conf; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::{SpanlessEq, is_in_const_context, is_integer_literal}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/derivable_impls.rs b/clippy_lints/src/derivable_impls.rs index 767dda552bc..2b264421322 100644 --- a/clippy_lints/src/derivable_impls.rs +++ b/clippy_lints/src/derivable_impls.rs @@ -1,6 +1,6 @@ use clippy_config::Conf; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::indent_of; use clippy_utils::{is_default_equivalent, peel_blocks}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index 4c043f8dc14..da5825b7ab2 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -1,6 +1,5 @@ use arrayvec::ArrayVec; use clippy_config::Conf; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::is_diag_trait_item; use clippy_utils::macros::{ @@ -8,6 +7,7 @@ use clippy_utils::macros::{ format_placeholder_format_span, is_assert_macro, is_format_macro, is_panic, matching_root_macro_call, root_macro_call_first_node, }; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::{implements_trait, is_type_lang_item}; use itertools::Itertools; diff --git a/clippy_lints/src/from_over_into.rs b/clippy_lints/src/from_over_into.rs index 14da0b515a5..4c5a366f884 100644 --- a/clippy_lints/src/from_over_into.rs +++ b/clippy_lints/src/from_over_into.rs @@ -1,9 +1,9 @@ use std::ops::ControlFlow; use clippy_config::Conf; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::span_is_local; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::path_def_id; use clippy_utils::source::SpanRangeExt; use rustc_errors::Applicability; diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs index d63c18c0eda..3fc0a696522 100644 --- a/clippy_lints/src/if_then_some_else_none.rs +++ b/clippy_lints/src/if_then_some_else_none.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::eager_or_lazy::switch_to_eager_eval; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_context; use clippy_utils::sugg::Sugg; use clippy_utils::{ diff --git a/clippy_lints/src/implicit_saturating_sub.rs b/clippy_lints/src/implicit_saturating_sub.rs index 3b84b569c3e..37481dc7feb 100644 --- a/clippy_lints/src/implicit_saturating_sub.rs +++ b/clippy_lints/src/implicit_saturating_sub.rs @@ -1,6 +1,6 @@ use clippy_config::Conf; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_opt; use clippy_utils::{ SpanlessEq, higher, is_in_const_context, is_integer_literal, path_to_local, peel_blocks, peel_blocks_with_stmt, diff --git a/clippy_lints/src/incompatible_msrv.rs b/clippy_lints/src/incompatible_msrv.rs index 0b3a6ee1bea..f3467adacc5 100644 --- a/clippy_lints/src/incompatible_msrv.rs +++ b/clippy_lints/src/incompatible_msrv.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; -use clippy_config::msrvs::Msrv; use clippy_utils::diagnostics::span_lint; use clippy_utils::is_in_test; +use clippy_utils::msrvs::Msrv; use rustc_attr::{StabilityLevel, StableSince}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::{Expr, ExprKind, HirId}; diff --git a/clippy_lints/src/index_refutable_slice.rs b/clippy_lints/src/index_refutable_slice.rs index 96550c4d1cb..c2030a5ab09 100644 --- a/clippy_lints/src/index_refutable_slice.rs +++ b/clippy_lints/src/index_refutable_slice.rs @@ -1,8 +1,8 @@ use clippy_config::Conf; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::IfLet; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::ty::is_copy; use clippy_utils::{is_expn_of, is_lint_allowed, path_to_local}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; diff --git a/clippy_lints/src/instant_subtraction.rs b/clippy_lints/src/instant_subtraction.rs index 66931a7f98c..f4e41dc826b 100644 --- a/clippy_lints/src/instant_subtraction.rs +++ b/clippy_lints/src/instant_subtraction.rs @@ -1,6 +1,6 @@ use clippy_config::Conf; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_context; use clippy_utils::sugg::Sugg; use clippy_utils::ty; diff --git a/clippy_lints/src/legacy_numeric_constants.rs b/clippy_lints/src/legacy_numeric_constants.rs index e17d6213679..fb46bdcab6e 100644 --- a/clippy_lints/src/legacy_numeric_constants.rs +++ b/clippy_lints/src/legacy_numeric_constants.rs @@ -1,6 +1,6 @@ use clippy_config::Conf; -use clippy_config::msrvs::{Msrv, NUMERIC_ASSOCIATED_CONSTANTS}; use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::{get_parent_expr, is_from_proc_macro}; use hir::def_id::DefId; use rustc_errors::Applicability; @@ -53,7 +53,7 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants { // Integer modules are "TBD" deprecated, and the contents are too, // so lint on the `use` statement directly. if let ItemKind::Use(path, kind @ (UseKind::Single | UseKind::Glob)) = item.kind - && self.msrv.meets(NUMERIC_ASSOCIATED_CONSTANTS) + && self.msrv.meets(msrvs::NUMERIC_ASSOCIATED_CONSTANTS) && !in_external_macro(cx.sess(), item.span) && let Some(def_id) = path.res[0].opt_def_id() { @@ -138,7 +138,7 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants { return; }; - if self.msrv.meets(NUMERIC_ASSOCIATED_CONSTANTS) + if self.msrv.meets(msrvs::NUMERIC_ASSOCIATED_CONSTANTS) && !in_external_macro(cx.sess(), expr.span) && !is_from_proc_macro(cx, expr) { diff --git a/clippy_lints/src/loops/explicit_iter_loop.rs b/clippy_lints/src/loops/explicit_iter_loop.rs index ee561ea85ed..c9d72315803 100644 --- a/clippy_lints/src/loops/explicit_iter_loop.rs +++ b/clippy_lints/src/loops/explicit_iter_loop.rs @@ -1,6 +1,6 @@ use super::EXPLICIT_ITER_LOOP; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{ implements_trait, implements_trait_with_env, is_copy, is_type_lang_item, make_normalized_projection, diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs index 17215621d2a..f3ca4a4a571 100644 --- a/clippy_lints/src/loops/mod.rs +++ b/clippy_lints/src/loops/mod.rs @@ -23,8 +23,8 @@ mod while_let_loop; mod while_let_on_iterator; use clippy_config::Conf; -use clippy_config::msrvs::Msrv; use clippy_utils::higher; +use clippy_utils::msrvs::Msrv; use rustc_ast::Label; use rustc_hir::{Expr, ExprKind, LoopSource, Pat}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/manual_bits.rs b/clippy_lints/src/manual_bits.rs index fd71167f814..c31656f8a05 100644 --- a/clippy_lints/src/manual_bits.rs +++ b/clippy_lints/src/manual_bits.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::get_parent_expr; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_context; use rustc_ast::ast::LitKind; use rustc_data_structures::packed::Pu128; diff --git a/clippy_lints/src/manual_clamp.rs b/clippy_lints/src/manual_clamp.rs index 016ec7320a6..484a7ba256b 100644 --- a/clippy_lints/src/manual_clamp.rs +++ b/clippy_lints/src/manual_clamp.rs @@ -1,8 +1,8 @@ use clippy_config::Conf; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::higher::If; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::implements_trait; use clippy_utils::visitors::is_const_evaluatable; diff --git a/clippy_lints/src/manual_div_ceil.rs b/clippy_lints/src/manual_div_ceil.rs index 4c171e6d890..07af2ddb0de 100644 --- a/clippy_lints/src/manual_div_ceil.rs +++ b/clippy_lints/src/manual_div_ceil.rs @@ -1,6 +1,6 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::SpanlessEq; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; use rustc_ast::{BinOpKind, LitKind}; diff --git a/clippy_lints/src/manual_float_methods.rs b/clippy_lints/src/manual_float_methods.rs index a269ea11397..b12f575e81a 100644 --- a/clippy_lints/src/manual_float_methods.rs +++ b/clippy_lints/src/manual_float_methods.rs @@ -1,7 +1,7 @@ -use clippy_config::msrvs::Msrv; -use clippy_config::{Conf, msrvs}; +use clippy_config::Conf; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::SpanRangeExt; use clippy_utils::{is_from_proc_macro, path_to_local}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/manual_hash_one.rs b/clippy_lints/src/manual_hash_one.rs index 7a9c9963742..7e092d11f1b 100644 --- a/clippy_lints/src/manual_hash_one.rs +++ b/clippy_lints/src/manual_hash_one.rs @@ -1,6 +1,6 @@ use clippy_config::Conf; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_hir_and_then; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::SpanRangeExt; use clippy_utils::visitors::{is_local_used, local_used_once}; use clippy_utils::{is_trait_method, path_to_local_id}; diff --git a/clippy_lints/src/manual_is_ascii_check.rs b/clippy_lints/src/manual_is_ascii_check.rs index dec8c5d85de..3f01f3cf30a 100644 --- a/clippy_lints/src/manual_is_ascii_check.rs +++ b/clippy_lints/src/manual_is_ascii_check.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::matching_root_macro_call; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::sugg::Sugg; use clippy_utils::{higher, is_in_const_context, path_to_local, peel_ref_operators}; use rustc_ast::LitKind::{Byte, Char}; diff --git a/clippy_lints/src/manual_let_else.rs b/clippy_lints/src/manual_let_else.rs index 17185df5d76..a70955a7c78 100644 --- a/clippy_lints/src/manual_let_else.rs +++ b/clippy_lints/src/manual_let_else.rs @@ -1,11 +1,10 @@ use crate::question_mark::{QUESTION_MARK, QuestionMark}; -use clippy_config::msrvs; use clippy_config::types::MatchLintBehaviour; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::IfLetOrMatch; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{is_lint_allowed, is_never_expr, pat_and_expr_can_be_question_mark, peel_blocks}; +use clippy_utils::{is_lint_allowed, is_never_expr, msrvs, pat_and_expr_can_be_question_mark, peel_blocks}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, MatchSource, Pat, PatKind, QPath, Stmt, StmtKind}; diff --git a/clippy_lints/src/manual_main_separator_str.rs b/clippy_lints/src/manual_main_separator_str.rs index 85e99a92cf5..b7563a2508d 100644 --- a/clippy_lints/src/manual_main_separator_str.rs +++ b/clippy_lints/src/manual_main_separator_str.rs @@ -1,6 +1,6 @@ use clippy_config::Conf; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::{is_trait_method, peel_hir_expr_refs}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; diff --git a/clippy_lints/src/manual_non_exhaustive.rs b/clippy_lints/src/manual_non_exhaustive.rs index 25868ccae40..00800231fe4 100644 --- a/clippy_lints/src/manual_non_exhaustive.rs +++ b/clippy_lints/src/manual_non_exhaustive.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::is_doc_hidden; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_indent; use itertools::Itertools; use rustc_ast::attr; diff --git a/clippy_lints/src/manual_rem_euclid.rs b/clippy_lints/src/manual_rem_euclid.rs index 86293169ea2..5e58054a986 100644 --- a/clippy_lints/src/manual_rem_euclid.rs +++ b/clippy_lints/src/manual_rem_euclid.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{ConstEvalCtxt, FullInt}; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_context; use clippy_utils::{is_in_const_context, path_to_local}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/manual_retain.rs b/clippy_lints/src/manual_retain.rs index a60163be770..708980ac503 100644 --- a/clippy_lints/src/manual_retain.rs +++ b/clippy_lints/src/manual_retain.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::SpanlessEq; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet; use clippy_utils::ty::{get_type_diagnostic_name, is_type_lang_item}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index 3f401eff6bd..79de41db343 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet; use clippy_utils::usage::mutated_variables; use clippy_utils::{eq_expr_value, higher}; diff --git a/clippy_lints/src/matches/collapsible_match.rs b/clippy_lints/src/matches/collapsible_match.rs index 50e6dfc6298..95a73e5f05d 100644 --- a/clippy_lints/src/matches/collapsible_match.rs +++ b/clippy_lints/src/matches/collapsible_match.rs @@ -1,6 +1,6 @@ -use clippy_config::msrvs::Msrv; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::IfLetOrMatch; +use clippy_utils::msrvs::Msrv; use clippy_utils::source::snippet; use clippy_utils::visitors::is_local_used; use clippy_utils::{ diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs index 28adcc2f227..64969271764 100644 --- a/clippy_lints/src/matches/mod.rs +++ b/clippy_lints/src/matches/mod.rs @@ -25,7 +25,7 @@ mod try_err; mod wild_in_or_pats; use clippy_config::Conf; -use clippy_config::msrvs::{self, Msrv}; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::walk_span_to_context; use clippy_utils::{higher, is_direct_expn_of, is_in_const_context, is_span_match, span_contains_cfg}; use rustc_hir::{Arm, Expr, ExprKind, LetStmt, MatchSource, Pat, PatKind}; diff --git a/clippy_lints/src/matches/redundant_guards.rs b/clippy_lints/src/matches/redundant_guards.rs index 9e54475033c..a7ef28ff8da 100644 --- a/clippy_lints/src/matches/redundant_guards.rs +++ b/clippy_lints/src/matches/redundant_guards.rs @@ -1,6 +1,6 @@ -use clippy_config::msrvs::Msrv; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::matching_root_macro_call; +use clippy_utils::msrvs::Msrv; use clippy_utils::source::snippet; use clippy_utils::visitors::{for_each_expr_without_closures, is_local_used}; use clippy_utils::{is_in_const_context, path_to_local}; diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index 146748734cf..5597cd85abc 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -1,6 +1,6 @@ use clippy_config::Conf; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_non_aggregate_primitive_type; diff --git a/clippy_lints/src/methods/cloned_instead_of_copied.rs b/clippy_lints/src/methods/cloned_instead_of_copied.rs index fa04f74eec1..2a0a9d3710d 100644 --- a/clippy_lints/src/methods/cloned_instead_of_copied.rs +++ b/clippy_lints/src/methods/cloned_instead_of_copied.rs @@ -1,6 +1,6 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_trait_method; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::ty::{get_iterator_item_ty, is_copy}; use rustc_errors::Applicability; use rustc_hir::Expr; diff --git a/clippy_lints/src/methods/err_expect.rs b/clippy_lints/src/methods/err_expect.rs index 3b1adb16b80..44b55570eea 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_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::ty::{has_debug_impl, is_type_diagnostic_item}; use rustc_errors::Applicability; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/filter_map_next.rs b/clippy_lints/src/methods/filter_map_next.rs index f94fe221833..3f89e593148 100644 --- a/clippy_lints/src/methods/filter_map_next.rs +++ b/clippy_lints/src/methods/filter_map_next.rs @@ -1,6 +1,6 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; use clippy_utils::is_trait_method; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/is_digit_ascii_radix.rs b/clippy_lints/src/methods/is_digit_ascii_radix.rs index 40b48ccca5d..d8bb9e377a0 100644 --- a/clippy_lints/src/methods/is_digit_ascii_radix.rs +++ b/clippy_lints/src/methods/is_digit_ascii_radix.rs @@ -1,7 +1,7 @@ use super::IS_DIGIT_ASCII_RADIX; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{ConstEvalCtxt, FullInt}; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; use rustc_hir::Expr; diff --git a/clippy_lints/src/methods/iter_kv_map.rs b/clippy_lints/src/methods/iter_kv_map.rs index 390dd24b505..299f6d10112 100644 --- a/clippy_lints/src/methods/iter_kv_map.rs +++ b/clippy_lints/src/methods/iter_kv_map.rs @@ -1,6 +1,6 @@ use super::ITER_KV_MAP; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::pat_is_wild; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; diff --git a/clippy_lints/src/methods/manual_c_str_literals.rs b/clippy_lints/src/methods/manual_c_str_literals.rs index 22f4748de70..7d5ebdedd0c 100644 --- a/clippy_lints/src/methods/manual_c_str_literals.rs +++ b/clippy_lints/src/methods/manual_c_str_literals.rs @@ -1,6 +1,6 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::get_parent_expr; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet; use rustc_ast::{LitKind, StrStyle}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/manual_inspect.rs b/clippy_lints/src/methods/manual_inspect.rs index 223b0630bfd..f3a576b822e 100644 --- a/clippy_lints/src/methods/manual_inspect.rs +++ b/clippy_lints/src/methods/manual_inspect.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::{IntoSpan, SpanRangeExt}; use clippy_utils::ty::get_field_by_name; use clippy_utils::visitors::{for_each_expr, for_each_expr_without_closures}; diff --git a/clippy_lints/src/methods/manual_is_variant_and.rs b/clippy_lints/src/methods/manual_is_variant_and.rs index c377abd6237..90e502f244f 100644 --- a/clippy_lints/src/methods/manual_is_variant_and.rs +++ b/clippy_lints/src/methods/manual_is_variant_and.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{Msrv, OPTION_RESULT_IS_VARIANT_AND}; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; @@ -36,7 +36,7 @@ pub(super) fn check<'tcx>( } // 4. msrv doesn't meet `OPTION_RESULT_IS_VARIANT_AND` - if !msrv.meets(OPTION_RESULT_IS_VARIANT_AND) { + if !msrv.meets(msrvs::OPTION_RESULT_IS_VARIANT_AND) { return; } diff --git a/clippy_lints/src/methods/manual_try_fold.rs b/clippy_lints/src/methods/manual_try_fold.rs index 31449d41770..4a48d4b547c 100644 --- a/clippy_lints/src/methods/manual_try_fold.rs +++ b/clippy_lints/src/methods/manual_try_fold.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::implements_trait; use clippy_utils::{is_from_proc_macro, is_trait_method}; diff --git a/clippy_lints/src/methods/map_clone.rs b/clippy_lints/src/methods/map_clone.rs index d5594b21db5..1252f7ccd35 100644 --- a/clippy_lints/src/methods/map_clone.rs +++ b/clippy_lints/src/methods/map_clone.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{is_copy, is_type_diagnostic_item, should_call_clone_as_function}; use clippy_utils::{is_diag_trait_item, peel_blocks}; diff --git a/clippy_lints/src/methods/map_unwrap_or.rs b/clippy_lints/src/methods/map_unwrap_or.rs index 3226fa9cd3f..428da0cf107 100644 --- a/clippy_lints/src/methods/map_unwrap_or.rs +++ b/clippy_lints/src/methods/map_unwrap_or.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::usage::mutated_variables; diff --git a/clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs b/clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs index fc656fd78ba..80703618a11 100644 --- a/clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs +++ b/clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs @@ -1,6 +1,6 @@ use crate::methods::MAP_WITH_UNUSED_ARGUMENT_OVER_RANGES; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; use clippy_utils::{eager_or_lazy, higher, usage}; diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 795e041ffd9..6023cade579 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -137,10 +137,10 @@ mod wrong_self_convention; mod zst_offset; use clippy_config::Conf; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::macros::FormatArgsStorage; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::ty::{contains_ty_adt_constructor_opaque, implements_trait, is_copy, is_type_diagnostic_item}; use clippy_utils::{contains_return, is_bool, is_trait_method, iter_input_pats, peel_blocks, return_ty}; pub use path_ends_with_ext::DEFAULT_ALLOWED_DOTFILES; diff --git a/clippy_lints/src/methods/option_as_ref_deref.rs b/clippy_lints/src/methods/option_as_ref_deref.rs index 998bdee0157..8d97d1c72a6 100644 --- a/clippy_lints/src/methods/option_as_ref_deref.rs +++ b/clippy_lints/src/methods/option_as_ref_deref.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{path_to_local_id, peel_blocks}; diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs index 528e2204cf8..7c4dc4ffb20 100644 --- a/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{is_copy, is_type_diagnostic_item}; use rustc_data_structures::fx::FxHashSet; diff --git a/clippy_lints/src/methods/path_ends_with_ext.rs b/clippy_lints/src/methods/path_ends_with_ext.rs index cfb823dbf5d..febd7fd5cf2 100644 --- a/clippy_lints/src/methods/path_ends_with_ext.rs +++ b/clippy_lints/src/methods/path_ends_with_ext.rs @@ -1,6 +1,6 @@ use super::PATH_ENDS_WITH_EXT; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use rustc_ast::{LitKind, StrStyle}; diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs index 1cee28e1986..c91be33b1cd 100644 --- a/clippy_lints/src/methods/str_splitn.rs +++ b/clippy_lints/src/methods/str_splitn.rs @@ -1,6 +1,6 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_context; use clippy_utils::usage::local_used_after_expr; use clippy_utils::visitors::{Descend, for_each_expr}; diff --git a/clippy_lints/src/methods/string_lit_chars_any.rs b/clippy_lints/src/methods/string_lit_chars_any.rs index cc0d432b799..cb719b34b1f 100644 --- a/clippy_lints/src/methods/string_lit_chars_any.rs +++ b/clippy_lints/src/methods/string_lit_chars_any.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::SpanRangeExt; use clippy_utils::{is_from_proc_macro, is_trait_method, path_to_local}; use itertools::Itertools; diff --git a/clippy_lints/src/methods/unnecessary_map_or.rs b/clippy_lints/src/methods/unnecessary_map_or.rs index adc27cd437f..1dacec1032d 100644 --- a/clippy_lints/src/methods/unnecessary_map_or.rs +++ b/clippy_lints/src/methods/unnecessary_map_or.rs @@ -1,8 +1,8 @@ use std::borrow::Cow; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::eager_or_lazy::switch_to_eager_eval; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_opt; use clippy_utils::sugg::{Sugg, make_binop}; use clippy_utils::ty::{get_type_diagnostic_name, implements_trait}; diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index 82549413fa9..6dc0f9409bd 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -1,7 +1,7 @@ use super::implicit_clone::is_clone_like; use super::unnecessary_iter_cloned::{self, is_into_iter}; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::{SpanRangeExt, snippet}; use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy, is_type_diagnostic_item, is_type_lang_item}; use clippy_utils::visitors::find_all_ret_expressions; diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index eea0459e026..121c4326d64 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -1,6 +1,6 @@ use clippy_config::Conf; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::qualify_min_const_fn::is_min_const_fn; use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, is_from_proc_macro, trait_ref_of_method}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/missing_const_for_thread_local.rs b/clippy_lints/src/missing_const_for_thread_local.rs index c2f524a6353..9a44a3c980c 100644 --- a/clippy_lints/src/missing_const_for_thread_local.rs +++ b/clippy_lints/src/missing_const_for_thread_local.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::macros::macro_backtrace; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::qualify_min_const_fn::is_min_const_fn; use clippy_utils::source::snippet; use clippy_utils::{fn_has_unsatisfiable_preds, peel_blocks}; diff --git a/clippy_lints/src/needless_borrows_for_generic_args.rs b/clippy_lints/src/needless_borrows_for_generic_args.rs index c1424b9f1dc..dd2e48f4831 100644 --- a/clippy_lints/src/needless_borrows_for_generic_args.rs +++ b/clippy_lints/src/needless_borrows_for_generic_args.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::mir::{PossibleBorrowerMap, enclosing_mir, expr_local, local_assignments, used_exactly_once}; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{implements_trait, is_copy}; use clippy_utils::{DefinedTy, ExprUseNode, expr_use_ctxt, peel_n_hir_expr_refs}; diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index a00fd01a62e..c38783642df 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -1,9 +1,9 @@ use crate::manual_let_else::MANUAL_LET_ELSE; use crate::question_mark_used::QUESTION_MARK_USED; use clippy_config::Conf; -use clippy_config::msrvs::Msrv; use clippy_config::types::MatchLintBehaviour; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::Msrv; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use clippy_utils::{ diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 21cd3367262..1b0c0a4956f 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::{SpanRangeExt, snippet, snippet_with_applicability}; use clippy_utils::sugg::Sugg; use clippy_utils::{get_parent_expr, higher, is_in_const_context, is_integer_const, path_to_local}; diff --git a/clippy_lints/src/redundant_field_names.rs b/clippy_lints/src/redundant_field_names.rs index d0dbff081f9..347540e7344 100644 --- a/clippy_lints/src/redundant_field_names.rs +++ b/clippy_lints/src/redundant_field_names.rs @@ -1,6 +1,6 @@ use clippy_config::Conf; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::{self, Msrv}; use rustc_ast::ast::{Expr, ExprKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; diff --git a/clippy_lints/src/redundant_static_lifetimes.rs b/clippy_lints/src/redundant_static_lifetimes.rs index b27bb2e78af..06c85433806 100644 --- a/clippy_lints/src/redundant_static_lifetimes.rs +++ b/clippy_lints/src/redundant_static_lifetimes.rs @@ -1,6 +1,6 @@ use clippy_config::Conf; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet; use rustc_ast::ast::{ConstItem, Item, ItemKind, StaticItem, Ty, TyKind}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/std_instead_of_core.rs b/clippy_lints/src/std_instead_of_core.rs index 8dd99858793..2941b9c3960 100644 --- a/clippy_lints/src/std_instead_of_core.rs +++ b/clippy_lints/src/std_instead_of_core.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; -use clippy_config::msrvs::Msrv; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_from_proc_macro; +use clippy_utils::msrvs::Msrv; use rustc_attr::{StabilityLevel, StableSince}; use rustc_errors::Applicability; use rustc_hir::def::Res; diff --git a/clippy_lints/src/string_patterns.rs b/clippy_lints/src/string_patterns.rs index ba2ddac2ec3..0d85b1b858a 100644 --- a/clippy_lints/src/string_patterns.rs +++ b/clippy_lints/src/string_patterns.rs @@ -1,10 +1,10 @@ use std::ops::ControlFlow; use clippy_config::Conf; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::eager_or_lazy::switch_to_eager_eval; use clippy_utils::macros::matching_root_macro_call; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::path_to_local_id; use clippy_utils::source::{snippet, str_literal_to_char_literal}; use clippy_utils::visitors::{Descend, for_each_expr}; diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index 07bf4319ff0..e641822b5d9 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -1,6 +1,6 @@ use clippy_config::Conf; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::{SpanRangeExt, snippet, snippet_with_applicability}; use clippy_utils::{SpanlessEq, SpanlessHash, is_from_proc_macro}; use core::hash::{Hash, Hasher}; diff --git a/clippy_lints/src/transmute/mod.rs b/clippy_lints/src/transmute/mod.rs index 25fec9f688c..1cb0f837227 100644 --- a/clippy_lints/src/transmute/mod.rs +++ b/clippy_lints/src/transmute/mod.rs @@ -20,8 +20,8 @@ mod utils; mod wrong_transmute; use clippy_config::Conf; -use clippy_config::msrvs::Msrv; use clippy_utils::is_in_const_context; +use clippy_utils::msrvs::Msrv; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; diff --git a/clippy_lints/src/transmute/transmute_float_to_int.rs b/clippy_lints/src/transmute/transmute_float_to_int.rs index 3507eb9a124..f0b8abf9af6 100644 --- a/clippy_lints/src/transmute/transmute_float_to_int.rs +++ b/clippy_lints/src/transmute/transmute_float_to_int.rs @@ -1,6 +1,6 @@ use super::TRANSMUTE_FLOAT_TO_INT; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::sugg; use rustc_ast as ast; use rustc_errors::Applicability; diff --git a/clippy_lints/src/transmute/transmute_int_to_float.rs b/clippy_lints/src/transmute/transmute_int_to_float.rs index c5c7ed6d398..e5b9aea6423 100644 --- a/clippy_lints/src/transmute/transmute_int_to_float.rs +++ b/clippy_lints/src/transmute/transmute_int_to_float.rs @@ -1,6 +1,6 @@ use super::TRANSMUTE_INT_TO_FLOAT; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::sugg; use rustc_errors::Applicability; use rustc_hir::Expr; diff --git a/clippy_lints/src/transmute/transmute_num_to_bytes.rs b/clippy_lints/src/transmute/transmute_num_to_bytes.rs index a94cd27c7fd..6d828bad9b3 100644 --- a/clippy_lints/src/transmute/transmute_num_to_bytes.rs +++ b/clippy_lints/src/transmute/transmute_num_to_bytes.rs @@ -1,6 +1,6 @@ use super::TRANSMUTE_NUM_TO_BYTES; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::sugg; use rustc_errors::Applicability; use rustc_hir::Expr; diff --git a/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs b/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs index 0772b284968..89f76d28612 100644 --- a/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs +++ b/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs @@ -1,6 +1,6 @@ use super::TRANSMUTE_PTR_TO_PTR; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::sugg; use rustc_errors::Applicability; use rustc_hir::Expr; diff --git a/clippy_lints/src/transmute/transmute_ptr_to_ref.rs b/clippy_lints/src/transmute/transmute_ptr_to_ref.rs index eaf927c0005..ef18633d945 100644 --- a/clippy_lints/src/transmute/transmute_ptr_to_ref.rs +++ b/clippy_lints/src/transmute/transmute_ptr_to_ref.rs @@ -1,6 +1,6 @@ use super::TRANSMUTE_PTR_TO_REF; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg; use rustc_errors::Applicability; diff --git a/clippy_lints/src/tuple_array_conversions.rs b/clippy_lints/src/tuple_array_conversions.rs index 07d0f59b91c..99a55f9fc35 100644 --- a/clippy_lints/src/tuple_array_conversions.rs +++ b/clippy_lints/src/tuple_array_conversions.rs @@ -1,6 +1,6 @@ use clippy_config::Conf; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::visitors::for_each_local_use_after_expr; use clippy_utils::{is_from_proc_macro, path_to_local}; use itertools::Itertools; diff --git a/clippy_lints/src/unnested_or_patterns.rs b/clippy_lints/src/unnested_or_patterns.rs index c7c837de505..9d26bf930a1 100644 --- a/clippy_lints/src/unnested_or_patterns.rs +++ b/clippy_lints/src/unnested_or_patterns.rs @@ -1,9 +1,9 @@ #![allow(clippy::wildcard_imports, clippy::enum_glob_use)] use clippy_config::Conf; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::ast_utils::{eq_field_pat, eq_id, eq_maybe_qself, eq_pat, eq_path}; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::over; use rustc_ast::PatKind::*; use rustc_ast::mut_visit::*; diff --git a/clippy_lints/src/unused_trait_names.rs b/clippy_lints/src/unused_trait_names.rs index 9fd6ebccd02..17ee5fc20ca 100644 --- a/clippy_lints/src/unused_trait_names.rs +++ b/clippy_lints/src/unused_trait_names.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_from_proc_macro; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_opt; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index f5cf4a586fd..65aea6a87c8 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_from_proc_macro; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::ty::same_type_and_consts; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index 9bcff9d7bce..ef1c46154d2 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -2,9 +2,9 @@ use std::collections::BTreeMap; use std::ops::ControlFlow; use clippy_config::Conf; -use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_hir_and_then; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::is_copy; use clippy_utils::visitors::for_each_local_use_after_expr; diff --git a/tests/ui-internal/invalid_msrv_attr_impl.fixed b/tests/ui-internal/invalid_msrv_attr_impl.fixed index 9b5bf736f13..928596d0809 100644 --- a/tests/ui-internal/invalid_msrv_attr_impl.fixed +++ b/tests/ui-internal/invalid_msrv_attr_impl.fixed @@ -8,8 +8,8 @@ extern crate rustc_lint; extern crate rustc_middle; #[macro_use] extern crate rustc_session; -use clippy_config::msrvs::Msrv; use clippy_utils::extract_msrv_attr; +use clippy_utils::msrvs::Msrv; use rustc_hir::Expr; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; diff --git a/tests/ui-internal/invalid_msrv_attr_impl.rs b/tests/ui-internal/invalid_msrv_attr_impl.rs index c5bde47e4ce..50b28648ccc 100644 --- a/tests/ui-internal/invalid_msrv_attr_impl.rs +++ b/tests/ui-internal/invalid_msrv_attr_impl.rs @@ -8,8 +8,8 @@ extern crate rustc_lint; extern crate rustc_middle; #[macro_use] extern crate rustc_session; -use clippy_config::msrvs::Msrv; use clippy_utils::extract_msrv_attr; +use clippy_utils::msrvs::Msrv; use rustc_hir::Expr; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; From 81dceed8baf324960ea05e9079b749305b16a7cc Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Tue, 28 Mar 2023 17:04:30 -0400 Subject: [PATCH 06/45] Support user format-like macros Add support for `#[clippy::format_args]` attribute that can be attached to any macro to indicate that it functions the same as the built-in format macros like `format!`, `println!` and `write!` --- book/src/SUMMARY.md | 1 + book/src/attribs.md | 53 ++++++++++++++++++++++ clippy_utils/src/attrs.rs | 3 ++ clippy_utils/src/macros.rs | 7 ++- tests/ui/format_args_unfixable.rs | 29 ++++++++++++ tests/ui/format_args_unfixable.stderr | 65 ++++++++++++++++++++++++++- tests/ui/uninlined_format_args.fixed | 21 ++++++++- tests/ui/uninlined_format_args.rs | 21 ++++++++- tests/ui/uninlined_format_args.stderr | 50 ++++++++++++++++++++- tests/ui/unused_format_specs.1.fixed | 35 +++++++++++++++ tests/ui/unused_format_specs.2.fixed | 35 +++++++++++++++ tests/ui/unused_format_specs.rs | 35 +++++++++++++++ tests/ui/unused_format_specs.stderr | 60 ++++++++++++++++++++++++- 13 files changed, 406 insertions(+), 9 deletions(-) create mode 100644 book/src/attribs.md diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index be13fcbe260..19328fdd3cd 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -7,6 +7,7 @@ - [Configuration](configuration.md) - [Lint Configuration](lint_configuration.md) - [Clippy's Lints](lints.md) +- [Attributes for Crate Authors](attribs.md) - [Continuous Integration](continuous_integration/README.md) - [GitHub Actions](continuous_integration/github_actions.md) - [GitLab CI](continuous_integration/gitlab.md) diff --git a/book/src/attribs.md b/book/src/attribs.md new file mode 100644 index 00000000000..cf99497bc0f --- /dev/null +++ b/book/src/attribs.md @@ -0,0 +1,53 @@ +# Attributes for Crate Authors + +In some cases it is possible to extend Clippy coverage to 3rd party libraries. +To do this, Clippy provides attributes that can be applied to items in the 3rd party crate. + +## `#[clippy::format_args]` + +_Available since Clippy v1.84_ + +This attribute can be added to a macro that supports `format!`, `println!`, or similar syntax. +It tells Clippy that the macro is a formatting macro, and that the arguments to the macro +should be linted as if they were arguments to `format!`. Any lint that would apply to a +`format!` call will also apply to the macro call. The macro may have additional arguments +before the format string, and these will be ignored. + +### Example + +```rust +/// A macro that prints a message if a condition is true. +#[macro_export] +#[clippy::format_args] +macro_rules! print_if { + ($condition:expr, $($args:tt)+) => {{ + if $condition { + println!($($args)+) + } + }}; +} +``` + +## `#[clippy::has_significant_drop]` + +_Available since Clippy v1.60_ + +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. + +### Example + +```rust +#[clippy::has_significant_drop] +struct CounterWrapper<'a> { + counter: &'a Counter, +} + +impl<'a> Drop for CounterWrapper<'a> { + fn drop(&mut self) { + self.counter.i.fetch_sub(1, Ordering::Relaxed); + } +} +``` diff --git a/clippy_utils/src/attrs.rs b/clippy_utils/src/attrs.rs index edc9c6ccdff..b2a6657baad 100644 --- a/clippy_utils/src/attrs.rs +++ b/clippy_utils/src/attrs.rs @@ -27,7 +27,10 @@ pub const BUILTIN_ATTRIBUTES: &[(&str, DeprecationStatus)] = &[ ("cyclomatic_complexity", DeprecationStatus::Replaced("cognitive_complexity")), ("dump", DeprecationStatus::None), ("msrv", DeprecationStatus::None), + // The following attributes are for the 3rd party crate authors. + // See book/src/attribs.md ("has_significant_drop", DeprecationStatus::None), + ("format_args", DeprecationStatus::None), ]; pub struct LimitStack { diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs index 9c4d19ac1f1..01261ea6e8d 100644 --- a/clippy_utils/src/macros.rs +++ b/clippy_utils/src/macros.rs @@ -1,5 +1,6 @@ #![allow(clippy::similar_names)] // `expr` and `expn` +use crate::get_unique_attr; use crate::visitors::{Descend, for_each_expr_without_closures}; use arrayvec::ArrayVec; @@ -7,7 +8,7 @@ use rustc_ast::{FormatArgs, FormatArgument, FormatPlaceholder}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::{Lrc, OnceLock}; use rustc_hir::{self as hir, Expr, ExprKind, HirId, Node, QPath}; -use rustc_lint::LateContext; +use rustc_lint::{LateContext, LintContext}; use rustc_span::def_id::DefId; use rustc_span::hygiene::{self, MacroKind, SyntaxContext}; use rustc_span::{BytePos, ExpnData, ExpnId, ExpnKind, Span, SpanData, Symbol, sym}; @@ -36,7 +37,9 @@ pub fn is_format_macro(cx: &LateContext<'_>, macro_def_id: DefId) -> bool { if let Some(name) = cx.tcx.get_diagnostic_name(macro_def_id) { FORMAT_MACRO_DIAG_ITEMS.contains(&name) } else { - false + // Allow users to tag any macro as being format!-like + // TODO: consider deleting FORMAT_MACRO_DIAG_ITEMS and using just this method + get_unique_attr(cx.sess(), cx.tcx.get_attrs_unchecked(macro_def_id), "format_args").is_some() } } diff --git a/tests/ui/format_args_unfixable.rs b/tests/ui/format_args_unfixable.rs index f04715f4f01..7590de3751a 100644 --- a/tests/ui/format_args_unfixable.rs +++ b/tests/ui/format_args_unfixable.rs @@ -119,3 +119,32 @@ fn test2() { format!("something failed at {}", Location::caller()) ); } + +#[clippy::format_args] +macro_rules! usr_println { + ($target:expr, $($args:tt)*) => {{ + if $target { + println!($($args)*) + } + }}; +} + +fn user_format() { + let error = Error::new(ErrorKind::Other, "bad thing"); + let x = 'x'; + + usr_println!(true, "error: {}", format!("boom at {}", Location::caller())); + //~^ ERROR: `format!` in `usr_println!` args + usr_println!(true, "{}: {}", error, format!("boom at {}", Location::caller())); + //~^ ERROR: `format!` in `usr_println!` args + usr_println!(true, "{:?}: {}", error, format!("boom at {}", Location::caller())); + //~^ ERROR: `format!` in `usr_println!` args + usr_println!(true, "{{}}: {}", format!("boom at {}", Location::caller())); + //~^ ERROR: `format!` in `usr_println!` args + usr_println!(true, r#"error: "{}""#, format!("boom at {}", Location::caller())); + //~^ ERROR: `format!` in `usr_println!` args + usr_println!(true, "error: {}", format!(r#"boom at "{}""#, Location::caller())); + //~^ ERROR: `format!` in `usr_println!` args + usr_println!(true, "error: {}", format!("boom at {} {0}", Location::caller())); + //~^ ERROR: `format!` in `usr_println!` args +} diff --git a/tests/ui/format_args_unfixable.stderr b/tests/ui/format_args_unfixable.stderr index 20cd0bb8c55..1b4b683fd6c 100644 --- a/tests/ui/format_args_unfixable.stderr +++ b/tests/ui/format_args_unfixable.stderr @@ -174,5 +174,68 @@ LL | panic!("error: {}", format!("something failed at {}", Location::caller( = help: combine the `format!(..)` arguments with the outer `panic!(..)` call = help: or consider changing `format!` to `format_args!` -error: aborting due to 18 previous errors +error: `format!` in `usr_println!` args + --> tests/ui/format_args_unfixable.rs:136:5 + | +LL | usr_println!(true, "error: {}", format!("boom at {}", Location::caller())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: combine the `format!(..)` arguments with the outer `usr_println!(..)` call + = help: or consider changing `format!` to `format_args!` + +error: `format!` in `usr_println!` args + --> tests/ui/format_args_unfixable.rs:138:5 + | +LL | usr_println!(true, "{}: {}", error, format!("boom at {}", Location::caller())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: combine the `format!(..)` arguments with the outer `usr_println!(..)` call + = help: or consider changing `format!` to `format_args!` + +error: `format!` in `usr_println!` args + --> tests/ui/format_args_unfixable.rs:140:5 + | +LL | usr_println!(true, "{:?}: {}", error, format!("boom at {}", Location::caller())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: combine the `format!(..)` arguments with the outer `usr_println!(..)` call + = help: or consider changing `format!` to `format_args!` + +error: `format!` in `usr_println!` args + --> tests/ui/format_args_unfixable.rs:142:5 + | +LL | usr_println!(true, "{{}}: {}", format!("boom at {}", Location::caller())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: combine the `format!(..)` arguments with the outer `usr_println!(..)` call + = help: or consider changing `format!` to `format_args!` + +error: `format!` in `usr_println!` args + --> tests/ui/format_args_unfixable.rs:144:5 + | +LL | usr_println!(true, r#"error: "{}""#, format!("boom at {}", Location::caller())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: combine the `format!(..)` arguments with the outer `usr_println!(..)` call + = help: or consider changing `format!` to `format_args!` + +error: `format!` in `usr_println!` args + --> tests/ui/format_args_unfixable.rs:146:5 + | +LL | usr_println!(true, "error: {}", format!(r#"boom at "{}""#, Location::caller())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: combine the `format!(..)` arguments with the outer `usr_println!(..)` call + = help: or consider changing `format!` to `format_args!` + +error: `format!` in `usr_println!` args + --> tests/ui/format_args_unfixable.rs:148:5 + | +LL | usr_println!(true, "error: {}", format!("boom at {} {0}", Location::caller())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: combine the `format!(..)` arguments with the outer `usr_println!(..)` call + = help: or consider changing `format!` to `format_args!` + +error: aborting due to 25 previous errors diff --git a/tests/ui/uninlined_format_args.fixed b/tests/ui/uninlined_format_args.fixed index 3f5b0e52ece..111a2e1987c 100644 --- a/tests/ui/uninlined_format_args.fixed +++ b/tests/ui/uninlined_format_args.fixed @@ -257,8 +257,6 @@ fn tester2() { my_concat!("{}", local_i32); my_good_macro!("{}", local_i32); my_good_macro!("{}", local_i32,); - - // FIXME: Broken false positives, currently unhandled my_bad_macro!("{}", local_i32); my_bad_macro2!("{}", local_i32); used_twice! { @@ -267,3 +265,22 @@ fn tester2() { local_i32, }; } + +#[clippy::format_args] +macro_rules! usr_println { + ($target:expr, $($args:tt)*) => {{ + if $target { + println!($($args)*) + } + }}; +} + +fn user_format() { + let local_i32 = 1; + let local_f64 = 2.0; + + usr_println!(true, "val='{local_i32}'"); + usr_println!(true, "{local_i32}"); + usr_println!(true, "{local_i32:#010x}"); + usr_println!(true, "{local_f64:.1}"); +} diff --git a/tests/ui/uninlined_format_args.rs b/tests/ui/uninlined_format_args.rs index b311aa4912c..81fe2476567 100644 --- a/tests/ui/uninlined_format_args.rs +++ b/tests/ui/uninlined_format_args.rs @@ -262,8 +262,6 @@ fn tester2() { my_concat!("{}", local_i32); my_good_macro!("{}", local_i32); my_good_macro!("{}", local_i32,); - - // FIXME: Broken false positives, currently unhandled my_bad_macro!("{}", local_i32); my_bad_macro2!("{}", local_i32); used_twice! { @@ -272,3 +270,22 @@ fn tester2() { local_i32, }; } + +#[clippy::format_args] +macro_rules! usr_println { + ($target:expr, $($args:tt)*) => {{ + if $target { + println!($($args)*) + } + }}; +} + +fn user_format() { + let local_i32 = 1; + let local_f64 = 2.0; + + usr_println!(true, "val='{}'", local_i32); + usr_println!(true, "{}", local_i32); + usr_println!(true, "{:#010x}", local_i32); + usr_println!(true, "{:.1}", local_f64); +} diff --git a/tests/ui/uninlined_format_args.stderr b/tests/ui/uninlined_format_args.stderr index 5a7ff3bc4f5..77961fea2c5 100644 --- a/tests/ui/uninlined_format_args.stderr +++ b/tests/ui/uninlined_format_args.stderr @@ -845,5 +845,53 @@ LL - println!("expand='{}'", local_i32); LL + println!("expand='{local_i32}'"); | -error: aborting due to 71 previous errors +error: variables can be used directly in the `format!` string + --> tests/ui/uninlined_format_args.rs:287:5 + | +LL | usr_println!(true, "val='{}'", local_i32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - usr_println!(true, "val='{}'", local_i32); +LL + usr_println!(true, "val='{local_i32}'"); + | + +error: variables can be used directly in the `format!` string + --> tests/ui/uninlined_format_args.rs:288:5 + | +LL | usr_println!(true, "{}", local_i32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - usr_println!(true, "{}", local_i32); +LL + usr_println!(true, "{local_i32}"); + | + +error: variables can be used directly in the `format!` string + --> tests/ui/uninlined_format_args.rs:289:5 + | +LL | usr_println!(true, "{:#010x}", local_i32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - usr_println!(true, "{:#010x}", local_i32); +LL + usr_println!(true, "{local_i32:#010x}"); + | + +error: variables can be used directly in the `format!` string + --> tests/ui/uninlined_format_args.rs:290:5 + | +LL | usr_println!(true, "{:.1}", local_f64); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - usr_println!(true, "{:.1}", local_f64); +LL + usr_println!(true, "{local_f64:.1}"); + | + +error: aborting due to 75 previous errors diff --git a/tests/ui/unused_format_specs.1.fixed b/tests/ui/unused_format_specs.1.fixed index b7d1cce2870..157c2b08d3c 100644 --- a/tests/ui/unused_format_specs.1.fixed +++ b/tests/ui/unused_format_specs.1.fixed @@ -33,3 +33,38 @@ fn should_not_lint() { let args = format_args!(""); println!("{args}"); } + +#[clippy::format_args] +macro_rules! usr_println { + ($target:expr, $($args:tt)*) => {{ + if $target { + println!($($args)*) + } + }}; +} + +fn should_lint_user() { + // prints `.`, not ` .` + usr_println!(true, "{:5}.", format!("")); + //~^ ERROR: format specifiers have no effect on `format_args!()` + //prints `abcde`, not `abc` + usr_println!(true, "{:.3}", format!("abcde")); + //~^ ERROR: format specifiers have no effect on `format_args!()` + + usr_println!(true, "{}.", format_args_from_macro!()); + //~^ ERROR: format specifiers have no effect on `format_args!()` + + let args = format_args!(""); + usr_println!(true, "{args}"); + //~^ ERROR: format specifiers have no effect on `format_args!()` +} + +fn should_not_lint_user() { + usr_println!(true, "{}", format_args!("")); + // Technically the same as `{}`, but the `format_args` docs specifically mention that you can use + // debug formatting so allow it + usr_println!(true, "{:?}", format_args!("")); + + let args = format_args!(""); + usr_println!(true, "{args}"); +} diff --git a/tests/ui/unused_format_specs.2.fixed b/tests/ui/unused_format_specs.2.fixed index 94bb6b7036b..92c7b951f3c 100644 --- a/tests/ui/unused_format_specs.2.fixed +++ b/tests/ui/unused_format_specs.2.fixed @@ -33,3 +33,38 @@ fn should_not_lint() { let args = format_args!(""); println!("{args}"); } + +#[clippy::format_args] +macro_rules! usr_println { + ($target:expr, $($args:tt)*) => {{ + if $target { + println!($($args)*) + } + }}; +} + +fn should_lint_user() { + // prints `.`, not ` .` + usr_println!(true, "{}.", format_args!("")); + //~^ ERROR: format specifiers have no effect on `format_args!()` + //prints `abcde`, not `abc` + usr_println!(true, "{}", format_args!("abcde")); + //~^ ERROR: format specifiers have no effect on `format_args!()` + + usr_println!(true, "{}.", format_args_from_macro!()); + //~^ ERROR: format specifiers have no effect on `format_args!()` + + let args = format_args!(""); + usr_println!(true, "{args}"); + //~^ ERROR: format specifiers have no effect on `format_args!()` +} + +fn should_not_lint_user() { + usr_println!(true, "{}", format_args!("")); + // Technically the same as `{}`, but the `format_args` docs specifically mention that you can use + // debug formatting so allow it + usr_println!(true, "{:?}", format_args!("")); + + let args = format_args!(""); + usr_println!(true, "{args}"); +} diff --git a/tests/ui/unused_format_specs.rs b/tests/ui/unused_format_specs.rs index 2c85e371149..a5df4d8a866 100644 --- a/tests/ui/unused_format_specs.rs +++ b/tests/ui/unused_format_specs.rs @@ -33,3 +33,38 @@ fn should_not_lint() { let args = format_args!(""); println!("{args}"); } + +#[clippy::format_args] +macro_rules! usr_println { + ($target:expr, $($args:tt)*) => {{ + if $target { + println!($($args)*) + } + }}; +} + +fn should_lint_user() { + // prints `.`, not ` .` + usr_println!(true, "{:5}.", format_args!("")); + //~^ ERROR: format specifiers have no effect on `format_args!()` + //prints `abcde`, not `abc` + usr_println!(true, "{:.3}", format_args!("abcde")); + //~^ ERROR: format specifiers have no effect on `format_args!()` + + usr_println!(true, "{:5}.", format_args_from_macro!()); + //~^ ERROR: format specifiers have no effect on `format_args!()` + + let args = format_args!(""); + usr_println!(true, "{args:5}"); + //~^ ERROR: format specifiers have no effect on `format_args!()` +} + +fn should_not_lint_user() { + usr_println!(true, "{}", format_args!("")); + // Technically the same as `{}`, but the `format_args` docs specifically mention that you can use + // debug formatting so allow it + usr_println!(true, "{:?}", format_args!("")); + + let args = format_args!(""); + usr_println!(true, "{args}"); +} diff --git a/tests/ui/unused_format_specs.stderr b/tests/ui/unused_format_specs.stderr index 2b5c81c63d6..df61d59130e 100644 --- a/tests/ui/unused_format_specs.stderr +++ b/tests/ui/unused_format_specs.stderr @@ -58,5 +58,63 @@ LL - println!("{args:5}"); LL + println!("{args}"); | -error: aborting due to 4 previous errors +error: format specifiers have no effect on `format_args!()` + --> tests/ui/unused_format_specs.rs:48:25 + | +LL | usr_println!(true, "{:5}.", format_args!("")); + | ^^^^ + | +help: for the width to apply consider using `format!()` + | +LL | usr_println!(true, "{:5}.", format!("")); + | ~~~~~~ +help: if the current behavior is intentional, remove the format specifiers + | +LL - usr_println!(true, "{:5}.", format_args!("")); +LL + usr_println!(true, "{}.", format_args!("")); + | + +error: format specifiers have no effect on `format_args!()` + --> tests/ui/unused_format_specs.rs:51:25 + | +LL | usr_println!(true, "{:.3}", format_args!("abcde")); + | ^^^^^ + | +help: for the precision to apply consider using `format!()` + | +LL | usr_println!(true, "{:.3}", format!("abcde")); + | ~~~~~~ +help: if the current behavior is intentional, remove the format specifiers + | +LL - usr_println!(true, "{:.3}", format_args!("abcde")); +LL + usr_println!(true, "{}", format_args!("abcde")); + | + +error: format specifiers have no effect on `format_args!()` + --> tests/ui/unused_format_specs.rs:54:25 + | +LL | usr_println!(true, "{:5}.", format_args_from_macro!()); + | ^^^^ + | + = help: for the width to apply consider using `format!()` +help: if the current behavior is intentional, remove the format specifiers + | +LL - usr_println!(true, "{:5}.", format_args_from_macro!()); +LL + usr_println!(true, "{}.", format_args_from_macro!()); + | + +error: format specifiers have no effect on `format_args!()` + --> tests/ui/unused_format_specs.rs:58:25 + | +LL | usr_println!(true, "{args:5}"); + | ^^^^^^^^ + | + = help: for the width to apply consider using `format!()` +help: if the current behavior is intentional, remove the format specifiers + | +LL - usr_println!(true, "{args:5}"); +LL + usr_println!(true, "{args}"); + | + +error: aborting due to 8 previous errors From d1688b53f13f1d486ccb7acd79d51e54c396ea2d Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Tue, 5 Nov 2024 00:25:47 +0100 Subject: [PATCH 07/45] `unnecessary_map_or`: add non-comparaison tests --- tests/ui/unnecessary_map_or.fixed | 6 ++++++ tests/ui/unnecessary_map_or.rs | 6 ++++++ tests/ui/unnecessary_map_or.stderr | 14 +++++++++++++- 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/tests/ui/unnecessary_map_or.fixed b/tests/ui/unnecessary_map_or.fixed index 2d932a70e9d..d645cd3f3c4 100644 --- a/tests/ui/unnecessary_map_or.fixed +++ b/tests/ui/unnecessary_map_or.fixed @@ -51,6 +51,12 @@ fn main() { let r: Result = Ok(3); let _ = r.is_ok_and(|x| x == 7); + // lint constructs that are not comparaisons as well + let func = |_x| true; + let r: Result = Ok(3); + let _ = r.is_ok_and(func); + let _ = Some(5).is_some_and(func); + #[derive(PartialEq)] struct S2; let r: Result = Ok(4); diff --git a/tests/ui/unnecessary_map_or.rs b/tests/ui/unnecessary_map_or.rs index 4a9d69be1e9..4939d52fd43 100644 --- a/tests/ui/unnecessary_map_or.rs +++ b/tests/ui/unnecessary_map_or.rs @@ -54,6 +54,12 @@ fn main() { let r: Result = Ok(3); let _ = r.map_or(false, |x| x == 7); + // lint constructs that are not comparaisons as well + let func = |_x| true; + let r: Result = Ok(3); + let _ = r.map_or(false, func); + let _ = Some(5).map_or(false, func); + #[derive(PartialEq)] struct S2; let r: Result = Ok(4); diff --git a/tests/ui/unnecessary_map_or.stderr b/tests/ui/unnecessary_map_or.stderr index 299a4e5da7a..56295594ddc 100644 --- a/tests/ui/unnecessary_map_or.stderr +++ b/tests/ui/unnecessary_map_or.stderr @@ -92,8 +92,20 @@ LL | let _ = r.map_or(false, |x| x == 7); error: this `map_or` is redundant --> tests/ui/unnecessary_map_or.rs:60:13 | +LL | let _ = r.map_or(false, func); + | ^^^^^^^^^^^^^^^^^^^^^ help: use is_ok_and instead: `r.is_ok_and(func)` + +error: this `map_or` is redundant + --> tests/ui/unnecessary_map_or.rs:61:13 + | +LL | let _ = Some(5).map_or(false, func); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_some_and instead: `Some(5).is_some_and(func)` + +error: this `map_or` is redundant + --> tests/ui/unnecessary_map_or.rs:66:13 + | LL | let _ = r.map_or(false, |x| x == 8); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(r == Ok(8))` -error: aborting due to 13 previous errors +error: aborting due to 15 previous errors From ca963b653ef4b4374f3def53b8e64de2b600683b Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Tue, 5 Nov 2024 00:02:57 +0100 Subject: [PATCH 08/45] =?UTF-8?q?Simplify=20instances=20of=20`Option::map?= =?UTF-8?q?=5For(true,=20=E2=80=A6)`=20in=20Clippy=20sources?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- clippy_lints/src/approx_const.rs | 2 +- clippy_lints/src/assigning_clones.rs | 4 ++-- clippy_lints/src/borrow_deref_ref.rs | 2 +- clippy_lints/src/cargo/common_metadata.rs | 2 +- clippy_lints/src/casts/cast_possible_truncation.rs | 2 +- clippy_lints/src/copies.rs | 4 ++-- clippy_lints/src/dereference.rs | 2 +- clippy_lints/src/eta_reduction.rs | 2 +- clippy_lints/src/excessive_bools.rs | 2 +- clippy_lints/src/from_over_into.rs | 2 +- clippy_lints/src/if_let_mutex.rs | 2 +- clippy_lints/src/loops/explicit_iter_loop.rs | 2 +- clippy_lints/src/matches/collapsible_match.rs | 5 ++--- clippy_lints/src/methods/clone_on_copy.rs | 2 +- clippy_lints/src/methods/mod.rs | 2 +- clippy_lints/src/methods/unnecessary_filter_map.rs | 2 +- clippy_lints/src/misc.rs | 2 +- clippy_lints/src/needless_borrows_for_generic_args.rs | 2 +- clippy_lints/src/no_effect.rs | 2 +- clippy_lints/src/non_copy_const.rs | 2 +- clippy_lints/src/only_used_in_recursion.rs | 2 +- clippy_lints/src/operators/assign_op_pattern.rs | 2 +- clippy_lints/src/ptr.rs | 4 +--- clippy_lints/src/redundant_async_block.rs | 2 +- clippy_lints/src/single_call_fn.rs | 2 +- clippy_lints/src/undocumented_unsafe_blocks.rs | 2 +- clippy_lints/src/unit_types/let_unit_value.rs | 2 +- clippy_lints/src/upper_case_acronyms.rs | 2 +- clippy_lints/src/use_self.rs | 2 +- clippy_utils/src/consts.rs | 4 ++-- clippy_utils/src/lib.rs | 4 ++-- clippy_utils/src/macros.rs | 2 +- clippy_utils/src/msrvs.rs | 2 +- clippy_utils/src/usage.rs | 2 +- 34 files changed, 39 insertions(+), 42 deletions(-) diff --git a/clippy_lints/src/approx_const.rs b/clippy_lints/src/approx_const.rs index 2f7f5e07ac7..ebd35fd2b27 100644 --- a/clippy_lints/src/approx_const.rs +++ b/clippy_lints/src/approx_const.rs @@ -91,7 +91,7 @@ impl ApproxConstant { let s = s.as_str(); if s.parse::().is_ok() { for &(constant, name, min_digits, msrv) in &KNOWN_CONSTS { - if is_approx_const(constant, s, min_digits) && msrv.map_or(true, |msrv| self.msrv.meets(msrv)) { + if is_approx_const(constant, s, min_digits) && msrv.is_none_or(|msrv| self.msrv.meets(msrv)) { span_lint_and_help( cx, APPROX_CONSTANT, diff --git a/clippy_lints/src/assigning_clones.rs b/clippy_lints/src/assigning_clones.rs index 3a402a53e1c..c4debff3cb5 100644 --- a/clippy_lints/src/assigning_clones.rs +++ b/clippy_lints/src/assigning_clones.rs @@ -100,13 +100,13 @@ impl<'tcx> LateLintPass<'tcx> for AssigningClones { // TODO: This check currently bails if the local variable has no initializer. // That is overly conservative - the lint should fire even if there was no initializer, // but the variable has been initialized before `lhs` was evaluated. - && path_to_local(lhs).map_or(true, |lhs| local_is_initialized(cx, lhs)) + && path_to_local(lhs).is_none_or(|lhs| local_is_initialized(cx, lhs)) && let Some(resolved_impl) = cx.tcx.impl_of_method(resolved_fn.def_id()) // Derived forms don't implement `clone_from`/`clone_into`. // See https://github.com/rust-lang/rust/pull/98445#issuecomment-1190681305 && !cx.tcx.is_builtin_derived(resolved_impl) // Don't suggest calling a function we're implementing. - && resolved_impl.as_local().map_or(true, |block_id| { + && resolved_impl.as_local().is_none_or(|block_id| { cx.tcx.hir().parent_owner_iter(e.hir_id).all(|(id, _)| id.def_id != block_id) }) && let resolved_assoc_items = cx.tcx.associated_items(resolved_impl) diff --git a/clippy_lints/src/borrow_deref_ref.rs b/clippy_lints/src/borrow_deref_ref.rs index f2551a05b1a..8892a9e6b6b 100644 --- a/clippy_lints/src/borrow_deref_ref.rs +++ b/clippy_lints/src/borrow_deref_ref.rs @@ -57,7 +57,7 @@ impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef { && !addrof_target.span.from_expansion() && let ref_ty = cx.typeck_results().expr_ty(deref_target) && let ty::Ref(_, inner_ty, Mutability::Not) = ref_ty.kind() - && get_parent_expr(cx, e).map_or(true, |parent| { + && get_parent_expr(cx, e).is_none_or(|parent| { match parent.kind { // `*&*foo` should lint `deref_addrof` instead. ExprKind::Unary(UnOp::Deref, _) => is_lint_allowed(cx, DEREF_ADDROF, parent.hir_id), diff --git a/clippy_lints/src/cargo/common_metadata.rs b/clippy_lints/src/cargo/common_metadata.rs index 6714c053913..80514cb52e6 100644 --- a/clippy_lints/src/cargo/common_metadata.rs +++ b/clippy_lints/src/cargo/common_metadata.rs @@ -43,7 +43,7 @@ fn missing_warning(cx: &LateContext<'_>, package: &cargo_metadata::Package, fiel } fn is_empty_str>(value: Option<&T>) -> bool { - value.map_or(true, |s| s.as_ref().is_empty()) + value.is_none_or(|s| s.as_ref().is_empty()) } fn is_empty_vec(value: &[String]) -> bool { diff --git a/clippy_lints/src/casts/cast_possible_truncation.rs b/clippy_lints/src/casts/cast_possible_truncation.rs index 40a1a9d1ce8..48e9f1d690e 100644 --- a/clippy_lints/src/casts/cast_possible_truncation.rs +++ b/clippy_lints/src/casts/cast_possible_truncation.rs @@ -134,7 +134,7 @@ pub(super) fn check( }; let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx); - let cast_from_ptr_size = def.repr().int.map_or(true, |ty| matches!(ty, IntegerType::Pointer(_),)); + let cast_from_ptr_size = def.repr().int.is_none_or(|ty| matches!(ty, IntegerType::Pointer(_),)); let suffix = match (cast_from_ptr_size, is_isize_or_usize(cast_to)) { (_, false) if from_nbits > to_nbits => "", (false, true) if from_nbits > 64 => "", diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index 3ecd36d3711..89808d38b9f 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -212,7 +212,7 @@ fn lint_if_same_then_else(cx: &LateContext<'_>, conds: &[&Expr<'_>], blocks: &[& .array_windows::<2>() .enumerate() .fold(true, |all_eq, (i, &[lhs, rhs])| { - if eq.eq_block(lhs, rhs) && !contains_let(conds[i]) && conds.get(i + 1).map_or(true, |e| !contains_let(e)) { + if eq.eq_block(lhs, rhs) && !contains_let(conds[i]) && conds.get(i + 1).is_none_or(|e| !contains_let(e)) { span_lint_and_note( cx, IF_SAME_THEN_ELSE, @@ -470,7 +470,7 @@ fn scan_block_for_eq<'tcx>( b.stmts // the bounds check will catch the underflow .get(b.stmts.len().wrapping_sub(offset + 1)) - .map_or(true, |s| hash != hash_stmt(cx, s)) + .is_none_or(|s| hash != hash_stmt(cx, s)) }) }) .map_or(block.stmts.len() - start_end_eq, |(i, _)| i); diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index b167d7f2208..a270bdf8129 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -452,7 +452,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { )); } else if stability.is_deref_stable() // Auto-deref doesn't combine with other adjustments - && next_adjust.map_or(true, |a| matches!(a.kind, Adjust::Deref(_) | Adjust::Borrow(_))) + && next_adjust.is_none_or(|a| matches!(a.kind, Adjust::Deref(_) | Adjust::Borrow(_))) && iter.all(|a| matches!(a.kind, Adjust::Deref(_) | Adjust::Borrow(_))) { self.state = Some((State::Borrow { mutability }, StateData { diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index 6c87a05ace3..8c22e43349f 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -276,7 +276,7 @@ fn check_inputs( && typeck .expr_adjustments(arg) .last() - .map_or(true, |a| a.target == typeck.expr_ty(arg)) + .is_none_or(|a| a.target == typeck.expr_ty(arg)) }) } diff --git a/clippy_lints/src/excessive_bools.rs b/clippy_lints/src/excessive_bools.rs index c88fb50b5af..0011da03dda 100644 --- a/clippy_lints/src/excessive_bools.rs +++ b/clippy_lints/src/excessive_bools.rs @@ -165,7 +165,7 @@ impl<'tcx> LateLintPass<'tcx> for ExcessiveBools { && fn_header.abi == Abi::Rust && fn_decl.inputs.len() as u64 > self.max_fn_params_bools && get_parent_as_impl(cx.tcx, cx.tcx.local_def_id_to_hir_id(def_id)) - .map_or(true, |impl_item| impl_item.of_trait.is_none()) + .is_none_or(|impl_item| impl_item.of_trait.is_none()) { check_fn_decl(cx, fn_decl, span, self.max_fn_params_bools); } diff --git a/clippy_lints/src/from_over_into.rs b/clippy_lints/src/from_over_into.rs index 4c5a366f884..e43c311eb85 100644 --- a/clippy_lints/src/from_over_into.rs +++ b/clippy_lints/src/from_over_into.rs @@ -92,7 +92,7 @@ impl<'tcx> LateLintPass<'tcx> for FromOverInto { |diag| { // If the target type is likely foreign mention the orphan rules as it's a common source of // confusion - if path_def_id(cx, target_ty.peel_refs()).map_or(true, |id| !id.is_local()) { + if path_def_id(cx, target_ty.peel_refs()).is_none_or(|id| !id.is_local()) { diag.help( "`impl From for Foreign` is allowed by the orphan rules, for more information see\n\ https://doc.rust-lang.org/reference/items/implementations.html#trait-implementation-coherence" diff --git a/clippy_lints/src/if_let_mutex.rs b/clippy_lints/src/if_let_mutex.rs index ba80c099a01..212d75e1617 100644 --- a/clippy_lints/src/if_let_mutex.rs +++ b/clippy_lints/src/if_let_mutex.rs @@ -86,7 +86,7 @@ fn mutex_lock_call<'tcx>( && path.ident.as_str() == "lock" && let ty = cx.typeck_results().expr_ty(self_arg).peel_refs() && is_type_diagnostic_item(cx, ty, sym::Mutex) - && op_mutex.map_or(true, |op| eq_expr_value(cx, self_arg, op)) + && op_mutex.is_none_or(|op| eq_expr_value(cx, self_arg, op)) { ControlFlow::Break(self_arg) } else { diff --git a/clippy_lints/src/loops/explicit_iter_loop.rs b/clippy_lints/src/loops/explicit_iter_loop.rs index c9d72315803..2577459d073 100644 --- a/clippy_lints/src/loops/explicit_iter_loop.rs +++ b/clippy_lints/src/loops/explicit_iter_loop.rs @@ -29,7 +29,7 @@ pub(super) fn check( if !msrv.meets(msrvs::ARRAY_INTO_ITERATOR) { return; } - } else if count.try_to_target_usize(cx.tcx).map_or(true, |x| x > 32) && !msrv.meets(msrvs::ARRAY_IMPL_ANY_LEN) { + } else if count.try_to_target_usize(cx.tcx).is_none_or(|x| x > 32) && !msrv.meets(msrvs::ARRAY_IMPL_ANY_LEN) { return; } } diff --git a/clippy_lints/src/matches/collapsible_match.rs b/clippy_lints/src/matches/collapsible_match.rs index 95a73e5f05d..99a7b8c74be 100644 --- a/clippy_lints/src/matches/collapsible_match.rs +++ b/clippy_lints/src/matches/collapsible_match.rs @@ -72,14 +72,13 @@ fn check_arm<'tcx>( (Some(a), Some(b)) => SpanlessEq::new(cx).eq_expr(a, b), } // the binding must not be used in the if guard - && outer_guard.map_or( - true, + && outer_guard.is_none_or( |e| !is_local_used(cx, e, binding_id) ) // ...or anywhere in the inner expression && match inner { IfLetOrMatch::IfLet(_, _, body, els, _) => { - !is_local_used(cx, body, binding_id) && els.map_or(true, |e| !is_local_used(cx, e, binding_id)) + !is_local_used(cx, body, binding_id) && els.is_none_or(|e| !is_local_used(cx, e, binding_id)) }, IfLetOrMatch::Match(_, arms, ..) => !arms.iter().any(|arm| is_local_used(cx, arm, binding_id)), } diff --git a/clippy_lints/src/methods/clone_on_copy.rs b/clippy_lints/src/methods/clone_on_copy.rs index c9604c7b2e2..1ee27d90d05 100644 --- a/clippy_lints/src/methods/clone_on_copy.rs +++ b/clippy_lints/src/methods/clone_on_copy.rs @@ -30,7 +30,7 @@ pub(super) fn check( .type_dependent_def_id(expr.hir_id) .and_then(|id| cx.tcx.trait_of_item(id)) .zip(cx.tcx.lang_items().clone_trait()) - .map_or(true, |(x, y)| x != y) + .is_none_or(|(x, y)| x != y) { return; } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 6023cade579..15b192c9c10 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -4531,7 +4531,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { && 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 + && first_arg_ty_opt.is_none_or(|first_arg_ty| method_config .self_kind.matches(cx, self_ty, first_arg_ty) ) && fn_header_equals(method_config.fn_header, sig.header) diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs index bab439015c5..3de51bc661e 100644 --- a/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -23,7 +23,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, a 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 mutates_arg = mutated_variables(body.value, cx).is_none_or(|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); diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 408dbef9cb1..8aba650472b 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -351,7 +351,7 @@ fn used_underscore_binding<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { /// `unused_variables`'s idea /// of what it means for an expression to be "used". fn is_used(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - get_parent_expr(cx, expr).map_or(true, |parent| match parent.kind { + get_parent_expr(cx, expr).is_none_or(|parent| match parent.kind { ExprKind::Assign(_, rhs, _) | ExprKind::AssignOp(_, _, rhs) => SpanlessEq::new(cx).eq_expr(rhs, expr), _ => is_used(cx, parent), }) diff --git a/clippy_lints/src/needless_borrows_for_generic_args.rs b/clippy_lints/src/needless_borrows_for_generic_args.rs index dd2e48f4831..776c86398ad 100644 --- a/clippy_lints/src/needless_borrows_for_generic_args.rs +++ b/clippy_lints/src/needless_borrows_for_generic_args.rs @@ -362,7 +362,7 @@ fn referent_used_exactly_once<'tcx>( let body_owner_local_def_id = cx.tcx.hir().enclosing_body_owner(reference.hir_id); if possible_borrowers .last() - .map_or(true, |&(local_def_id, _)| local_def_id != body_owner_local_def_id) + .is_none_or(|&(local_def_id, _)| local_def_id != body_owner_local_def_id) { possible_borrowers.push((body_owner_local_def_id, PossibleBorrowerMap::new(cx, mir))); } diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index 74536028b5d..8ecff9c3f9b 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -238,7 +238,7 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { ExprKind::Struct(_, fields, ref base) => { !has_drop(cx, cx.typeck_results().expr_ty(expr)) && fields.iter().all(|field| has_no_effect(cx, field.expr)) - && base.as_ref().map_or(true, |base| has_no_effect(cx, base)) + && base.as_ref().is_none_or(|base| has_no_effect(cx, base)) }, ExprKind::Call(callee, args) => { if let ExprKind::Path(ref qpath) = callee.kind { diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 5e20b406426..3be70b36334 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -335,7 +335,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> { // i.e. having an enum doesn't necessary mean a type has a frozen variant. // And, implementing it isn't a trivial task; it'll probably end up // re-implementing the trait predicate evaluation specific to `Freeze`. - && body_id_opt.map_or(true, |body_id| Self::is_value_unfrozen_poly(cx, body_id, normalized)) + && body_id_opt.is_none_or(|body_id| Self::is_value_unfrozen_poly(cx, body_id, normalized)) { lint(cx, Source::Assoc { item: trait_item.span }); } diff --git a/clippy_lints/src/only_used_in_recursion.rs b/clippy_lints/src/only_used_in_recursion.rs index 13b3d240700..6de203e068b 100644 --- a/clippy_lints/src/only_used_in_recursion.rs +++ b/clippy_lints/src/only_used_in_recursion.rs @@ -200,7 +200,7 @@ impl Params { if self .get_by_fn(param.fn_id, usage.idx) // If the parameter can't be found, then it's used for more than just recursion. - .map_or(true, |p| self.try_disable_lint_for_param(p, eval_stack)) + .is_none_or(|p| self.try_disable_lint_for_param(p, eval_stack)) { param.apply_lint.set(false); eval_stack.pop(); diff --git a/clippy_lints/src/operators/assign_op_pattern.rs b/clippy_lints/src/operators/assign_op_pattern.rs index 0dcaec1c9a7..1315c3dfc12 100644 --- a/clippy_lints/src/operators/assign_op_pattern.rs +++ b/clippy_lints/src/operators/assign_op_pattern.rs @@ -27,7 +27,7 @@ pub(super) fn check<'tcx>( if let Some((_, lang_item)) = binop_traits(op.node) && let Some(trait_id) = cx.tcx.lang_items().get(lang_item) && let parent_fn = cx.tcx.hir().get_parent_item(e.hir_id).def_id - && trait_ref_of_method(cx, parent_fn).map_or(true, |t| t.path.res.def_id() != trait_id) + && trait_ref_of_method(cx, parent_fn).is_none_or(|t| t.path.res.def_id() != trait_id) && implements_trait(cx, ty, trait_id, &[rty.into()]) { // Primitive types execute assign-ops right-to-left. Every other type is left-to-right. diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index ecc095f3859..dec4c18a309 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -541,9 +541,7 @@ fn check_mut_from_ref<'tcx>(cx: &LateContext<'tcx>, sig: &FnSig<'_>, body: Optio .collect(); if let Some(args) = args && !args.is_empty() - && body.map_or(true, |body| { - sig.header.safety == Safety::Unsafe || contains_unsafe_block(cx, body.value) - }) + && body.is_none_or(|body| sig.header.safety == Safety::Unsafe || contains_unsafe_block(cx, body.value)) { span_lint_and_then( cx, diff --git a/clippy_lints/src/redundant_async_block.rs b/clippy_lints/src/redundant_async_block.rs index 313e4083256..3ade6bcee84 100644 --- a/clippy_lints/src/redundant_async_block.rs +++ b/clippy_lints/src/redundant_async_block.rs @@ -88,7 +88,7 @@ fn desugar_async_block<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Op cx.typeck_results() .closure_min_captures .get(def_id) - .map_or(true, |m| { + .is_none_or(|m| { m.values().all(|places| { places .iter() diff --git a/clippy_lints/src/single_call_fn.rs b/clippy_lints/src/single_call_fn.rs index abe13a97c0d..0176077c70e 100644 --- a/clippy_lints/src/single_call_fn.rs +++ b/clippy_lints/src/single_call_fn.rs @@ -93,7 +93,7 @@ impl SingleCallFn { .tcx .hir() .maybe_body_owned_by(fn_def_id) - .map_or(true, |body| is_in_test_function(cx.tcx, body.value.hir_id)) + .is_none_or(|body| is_in_test_function(cx.tcx, body.value.hir_id)) || match cx.tcx.hir_node(fn_hir_id) { Node::Item(item) => is_from_proc_macro(cx, item), Node::ImplItem(item) => is_from_proc_macro(cx, item), diff --git a/clippy_lints/src/undocumented_unsafe_blocks.rs b/clippy_lints/src/undocumented_unsafe_blocks.rs index 0bba611116b..b79e59f857b 100644 --- a/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -337,7 +337,7 @@ fn is_unsafe_from_proc_macro(cx: &LateContext<'_>, span: Span) -> bool { .src .as_deref() .and_then(|src| src.get(file_pos.pos.to_usize()..)) - .map_or(true, |src| !src.starts_with("unsafe")) + .is_none_or(|src| !src.starts_with("unsafe")) } // Checks if any parent {expression, statement, block, local, const, static} diff --git a/clippy_lints/src/unit_types/let_unit_value.rs b/clippy_lints/src/unit_types/let_unit_value.rs index 6eef582b4b2..0702f6d1e74 100644 --- a/clippy_lints/src/unit_types/let_unit_value.rs +++ b/clippy_lints/src/unit_types/let_unit_value.rs @@ -145,7 +145,7 @@ fn expr_needs_inferred_result<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) - } while let Some(id) = locals_to_check.pop() { if let Node::LetStmt(l) = cx.tcx.parent_hir_node(id) { - if !l.ty.map_or(true, |ty| matches!(ty.kind, TyKind::Infer)) { + if !l.ty.is_none_or(|ty| matches!(ty.kind, TyKind::Infer)) { return false; } if let Some(e) = l.init { diff --git a/clippy_lints/src/upper_case_acronyms.rs b/clippy_lints/src/upper_case_acronyms.rs index 8de062a8fc1..c3843279ba2 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, hir_id: HirId, be_aggressive while let Some(c) = s.next() { r.push( if replace(&mut prev_upper, c.is_ascii_uppercase()) - && s.clone().next().map_or(true, |c| c.is_ascii_uppercase()) + && s.clone().next().is_none_or(|c| c.is_ascii_uppercase()) { c.to_ascii_lowercase() } else { diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index 65aea6a87c8..05c5be03002 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -94,7 +94,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { && let parameters = &item_path.segments.last().expect(SEGMENTS_MSG).args && parameters .as_ref() - .map_or(true, |params| params.parenthesized == GenericArgsParentheses::No) + .is_none_or(|params| params.parenthesized == GenericArgsParentheses::No) && !item.span.from_expansion() && !is_from_proc_macro(cx, item) // expensive, should be last check diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 24a02c7ef87..d97987711c2 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -226,7 +226,7 @@ impl Constant<'_> { .zip(r) .zip(tys) .map(|((li, ri), cmp_type)| Self::partial_cmp(tcx, cmp_type, li, ri)) - .find(|r| r.map_or(true, |o| o != Ordering::Equal)) + .find(|r| r.is_none_or(|o| o != Ordering::Equal)) .unwrap_or_else(|| Some(l.len().cmp(&r.len()))), _ => None, }, @@ -236,7 +236,7 @@ impl Constant<'_> { }; iter::zip(l, r) .map(|(li, ri)| Self::partial_cmp(tcx, cmp_type, li, ri)) - .find(|r| r.map_or(true, |o| o != Ordering::Equal)) + .find(|r| r.is_none_or(|o| o != Ordering::Equal)) .unwrap_or_else(|| Some(l.len().cmp(&r.len()))) }, (Self::Repeat(lv, ls), Self::Repeat(rv, rs)) => { diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 927ce5b6f16..6ad796fdd61 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1570,7 +1570,7 @@ pub fn is_else_clause_in_let_else(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool { pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Option<&Path<'_>>) -> bool { let ty = cx.typeck_results().expr_ty(expr); if let Some(Range { start, end, limits }) = Range::hir(expr) { - let start_is_none_or_min = start.map_or(true, |start| { + let start_is_none_or_min = start.is_none_or(|start| { if let rustc_ty::Adt(_, subst) = ty.kind() && let bnd_ty = subst.type_at(0) && let Some(min_val) = bnd_ty.numeric_min_val(cx.tcx) @@ -1582,7 +1582,7 @@ pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Opti false } }); - let end_is_none_or_max = end.map_or(true, |end| match limits { + let end_is_none_or_max = end.is_none_or(|end| match limits { RangeLimits::Closed => { if let rustc_ty::Adt(_, subst) = ty.kind() && let bnd_ty = subst.type_at(0) diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs index 9c4d19ac1f1..967b54919fc 100644 --- a/clippy_utils/src/macros.rs +++ b/clippy_utils/src/macros.rs @@ -93,7 +93,7 @@ pub fn expn_is_local(expn: ExpnId) -> bool { std::iter::once((expn, data)) .chain(backtrace) .find_map(|(_, data)| data.macro_def_id) - .map_or(true, DefId::is_local) + .is_none_or(DefId::is_local) } /// Returns an iterator of macro expansions that created the given span. diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index 764ca8fb50a..1eb7d54e133 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -121,7 +121,7 @@ impl Msrv { } pub fn meets(&self, required: RustcVersion) -> bool { - self.current().map_or(true, |msrv| msrv >= required) + self.current().is_none_or(|msrv| msrv >= required) } fn parse_attr(sess: &Session, attrs: &[Attribute]) -> Option { diff --git a/clippy_utils/src/usage.rs b/clippy_utils/src/usage.rs index c8c25456f69..37f72966892 100644 --- a/clippy_utils/src/usage.rs +++ b/clippy_utils/src/usage.rs @@ -27,7 +27,7 @@ pub fn mutated_variables<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) -> } pub fn is_potentially_mutated<'tcx>(variable: HirId, expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) -> bool { - mutated_variables(expr, cx).map_or(true, |mutated| mutated.contains(&variable)) + mutated_variables(expr, cx).is_none_or(|mutated| mutated.contains(&variable)) } pub fn is_potentially_local_place(local_id: HirId, place: &Place<'_>) -> bool { From de03a05bc8f5f367b94f7ce49896eed82b431026 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Mon, 4 Nov 2024 19:04:30 +0100 Subject: [PATCH 09/45] =?UTF-8?q?unnecessary=5Fmap=5For:=20lint=20`.map=5F?= =?UTF-8?q?or(true,=20=E2=80=A6)`=20as=20well?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- clippy_lints/src/methods/mod.rs | 18 +++++++++---- .../src/methods/unnecessary_map_or.rs | 18 ++++++++++--- tests/ui/unnecessary_map_or.fixed | 16 +++++++++--- tests/ui/unnecessary_map_or.rs | 14 ++++++++-- tests/ui/unnecessary_map_or.stderr | 26 ++++++++++++++++--- 5 files changed, 75 insertions(+), 17 deletions(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 15b192c9c10..2e9f6ea4731 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -4107,24 +4107,32 @@ declare_clippy_lint! { /// ### Why is this bad? /// Calls such as `opt.map_or(false, |val| val == 5)` are needlessly long and cumbersome, /// and can be reduced to, for example, `opt == Some(5)` assuming `opt` implements `PartialEq`. + /// Also, calls such as `opt.map_or(true, |val| val == 5)` can be reduced to + /// `opt.is_none_or(|val| val == 5)`. /// This lint offers readability and conciseness improvements. /// /// ### Example /// ```no_run - /// pub fn a(x: Option) -> bool { - /// x.map_or(false, |n| n == 5) + /// pub fn a(x: Option) -> (bool, bool) { + /// ( + /// x.map_or(false, |n| n == 5), + /// x.map_or(true, |n| n > 5), + /// ) /// } /// ``` /// Use instead: /// ```no_run - /// pub fn a(x: Option) -> bool { - /// x == Some(5) + /// pub fn a(x: Option) -> (bool, bool) { + /// ( + /// x == Some(5), + /// x.is_none_or(|n| n > 5), + /// ) /// } /// ``` #[clippy::version = "1.75.0"] pub UNNECESSARY_MAP_OR, style, - "reduce unnecessary pattern matching for constructs that implement `PartialEq`" + "reduce unnecessary calls to `.map_or(bool, …)`" } declare_clippy_lint! { diff --git a/clippy_lints/src/methods/unnecessary_map_or.rs b/clippy_lints/src/methods/unnecessary_map_or.rs index 1dacec1032d..74c0c35f9aa 100644 --- a/clippy_lints/src/methods/unnecessary_map_or.rs +++ b/clippy_lints/src/methods/unnecessary_map_or.rs @@ -60,7 +60,7 @@ pub(super) fn check<'a>( Some(_) | None => return, }; - let (sugg, method) = if let ExprKind::Closure(map_closure) = map.kind + let (sugg, method, applicability) = if let ExprKind::Closure(map_closure) = map.kind && let closure_body = cx.tcx.hir().body(map_closure.body) && let closure_body_value = closure_body.value.peel_blocks() && let ExprKind::Binary(op, l, r) = closure_body_value.kind @@ -100,7 +100,7 @@ pub(super) fn check<'a>( .maybe_par() .into_string(); - (binop, "a standard comparison") + (binop, "a standard comparison", Applicability::MaybeIncorrect) } else if !def_bool && msrv.meets(msrvs::OPTION_RESULT_IS_VARIANT_AND) && let Some(recv_callsite) = snippet_opt(cx, recv.span.source_callsite()) @@ -110,6 +110,18 @@ pub(super) fn check<'a>( ( format!("{recv_callsite}.{suggested_name}({span_callsite})",), suggested_name, + Applicability::MachineApplicable, + ) + } else if def_bool + && matches!(variant, Variant::Some) + && msrv.meets(msrvs::IS_NONE_OR) + && let Some(recv_callsite) = snippet_opt(cx, recv.span.source_callsite()) + && let Some(span_callsite) = snippet_opt(cx, map.span.source_callsite()) + { + ( + format!("{recv_callsite}.is_none_or({span_callsite})"), + "is_none_or", + Applicability::MachineApplicable, ) } else { return; @@ -126,6 +138,6 @@ pub(super) fn check<'a>( "this `map_or` is redundant", format!("use {method} instead"), sugg, - Applicability::MaybeIncorrect, + applicability, ); } diff --git a/tests/ui/unnecessary_map_or.fixed b/tests/ui/unnecessary_map_or.fixed index d645cd3f3c4..70b78ceca50 100644 --- a/tests/ui/unnecessary_map_or.fixed +++ b/tests/ui/unnecessary_map_or.fixed @@ -23,10 +23,9 @@ fn main() { let _ = Ok::, i32>(vec![5]).is_ok_and(|n| n == [5]); let _ = (Ok::(5) == Ok(5)); let _ = (Some(5) == Some(5)).then(|| 1); + let _ = Some(5).is_none_or(|n| n == 5); + let _ = Some(5).is_none_or(|n| 5 == n); - // shouldnt trigger - let _ = Some(5).map_or(true, |n| n == 5); - let _ = Some(5).map_or(true, |n| 5 == n); macro_rules! x { () => { Some(1) @@ -56,11 +55,16 @@ fn main() { let r: Result = Ok(3); let _ = r.is_ok_and(func); let _ = Some(5).is_some_and(func); + let _ = Some(5).is_none_or(func); #[derive(PartialEq)] struct S2; let r: Result = Ok(4); let _ = (r == Ok(8)); + + // do not lint `Result::map_or(true, …)` + let r: Result = Ok(4); + let _ = r.map_or(true, |x| x == 8); } #[clippy::msrv = "1.69.0"] @@ -68,3 +72,9 @@ fn msrv_1_69() { // is_some_and added in 1.70.0 let _ = Some(5).map_or(false, |n| n == if 2 > 1 { n } else { 0 }); } + +#[clippy::msrv = "1.81.0"] +fn msrv_1_81() { + // is_none_or added in 1.82.0 + let _ = Some(5).map_or(true, |n| n == if 2 > 1 { n } else { 0 }); +} diff --git a/tests/ui/unnecessary_map_or.rs b/tests/ui/unnecessary_map_or.rs index 4939d52fd43..50757715977 100644 --- a/tests/ui/unnecessary_map_or.rs +++ b/tests/ui/unnecessary_map_or.rs @@ -26,10 +26,9 @@ fn main() { let _ = Ok::, i32>(vec![5]).map_or(false, |n| n == [5]); let _ = Ok::(5).map_or(false, |n| n == 5); let _ = Some(5).map_or(false, |n| n == 5).then(|| 1); - - // shouldnt trigger let _ = Some(5).map_or(true, |n| n == 5); let _ = Some(5).map_or(true, |n| 5 == n); + macro_rules! x { () => { Some(1) @@ -59,11 +58,16 @@ fn main() { let r: Result = Ok(3); let _ = r.map_or(false, func); let _ = Some(5).map_or(false, func); + let _ = Some(5).map_or(true, func); #[derive(PartialEq)] struct S2; let r: Result = Ok(4); let _ = r.map_or(false, |x| x == 8); + + // do not lint `Result::map_or(true, …)` + let r: Result = Ok(4); + let _ = r.map_or(true, |x| x == 8); } #[clippy::msrv = "1.69.0"] @@ -71,3 +75,9 @@ fn msrv_1_69() { // is_some_and added in 1.70.0 let _ = Some(5).map_or(false, |n| n == if 2 > 1 { n } else { 0 }); } + +#[clippy::msrv = "1.81.0"] +fn msrv_1_81() { + // is_none_or added in 1.82.0 + let _ = Some(5).map_or(true, |n| n == if 2 > 1 { n } else { 0 }); +} diff --git a/tests/ui/unnecessary_map_or.stderr b/tests/ui/unnecessary_map_or.stderr index 56295594ddc..025eb24d465 100644 --- a/tests/ui/unnecessary_map_or.stderr +++ b/tests/ui/unnecessary_map_or.stderr @@ -84,28 +84,46 @@ LL | let _ = Some(5).map_or(false, |n| n == 5).then(|| 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(Some(5) == Some(5))` error: this `map_or` is redundant - --> tests/ui/unnecessary_map_or.rs:55:13 + --> tests/ui/unnecessary_map_or.rs:29:13 + | +LL | let _ = Some(5).map_or(true, |n| n == 5); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_none_or instead: `Some(5).is_none_or(|n| n == 5)` + +error: this `map_or` is redundant + --> tests/ui/unnecessary_map_or.rs:30:13 + | +LL | let _ = Some(5).map_or(true, |n| 5 == n); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_none_or instead: `Some(5).is_none_or(|n| 5 == n)` + +error: this `map_or` is redundant + --> tests/ui/unnecessary_map_or.rs:54:13 | LL | let _ = r.map_or(false, |x| x == 7); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_ok_and instead: `r.is_ok_and(|x| x == 7)` error: this `map_or` is redundant - --> tests/ui/unnecessary_map_or.rs:60:13 + --> tests/ui/unnecessary_map_or.rs:59:13 | LL | let _ = r.map_or(false, func); | ^^^^^^^^^^^^^^^^^^^^^ help: use is_ok_and instead: `r.is_ok_and(func)` error: this `map_or` is redundant - --> tests/ui/unnecessary_map_or.rs:61:13 + --> tests/ui/unnecessary_map_or.rs:60:13 | LL | let _ = Some(5).map_or(false, func); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_some_and instead: `Some(5).is_some_and(func)` +error: this `map_or` is redundant + --> tests/ui/unnecessary_map_or.rs:61:13 + | +LL | let _ = Some(5).map_or(true, func); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_none_or instead: `Some(5).is_none_or(func)` + error: this `map_or` is redundant --> tests/ui/unnecessary_map_or.rs:66:13 | LL | let _ = r.map_or(false, |x| x == 8); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(r == Ok(8))` -error: aborting due to 15 previous errors +error: aborting due to 18 previous errors From 88598473733d8004d2366a88471fc922a9bc795d Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Sun, 17 Nov 2024 04:05:05 +0100 Subject: [PATCH 10/45] `redundant_guards`: lint float literals, don't lint cstr literals --- clippy_lints/src/matches/redundant_guards.rs | 7 +- tests/ui/redundant_guards.fixed | 15 +++- tests/ui/redundant_guards.rs | 11 ++- tests/ui/redundant_guards.stderr | 86 +++++++++++++------- 4 files changed, 78 insertions(+), 41 deletions(-) diff --git a/clippy_lints/src/matches/redundant_guards.rs b/clippy_lints/src/matches/redundant_guards.rs index 9e54475033c..bfff199af03 100644 --- a/clippy_lints/src/matches/redundant_guards.rs +++ b/clippy_lints/src/matches/redundant_guards.rs @@ -243,11 +243,6 @@ fn emit_redundant_guards<'tcx>( } /// Checks if the given `Expr` can also be represented as a `Pat`. -/// -/// All literals generally also work as patterns, however float literals are special. -/// They are currently (as of 2023/08/08) still allowed in patterns, but that will become -/// an error in the future, and rustc already actively warns against this (see rust#41620), -/// so we don't consider those as usable within patterns for linting purposes. fn expr_can_be_pat(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { for_each_expr_without_closures(expr, |expr| { if match expr.kind { @@ -267,7 +262,7 @@ fn expr_can_be_pat(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { | ExprKind::Tup(..) | ExprKind::Struct(..) | ExprKind::Unary(UnOp::Neg, _) => true, - ExprKind::Lit(lit) if !matches!(lit.node, LitKind::Float(..)) => true, + ExprKind::Lit(lit) if !matches!(lit.node, LitKind::CStr(..)) => true, _ => false, } { return ControlFlow::Continue(()); diff --git a/tests/ui/redundant_guards.fixed b/tests/ui/redundant_guards.fixed index ed4b1c21915..ff7b233f004 100644 --- a/tests/ui/redundant_guards.fixed +++ b/tests/ui/redundant_guards.fixed @@ -1,6 +1,6 @@ //@aux-build:proc_macros.rs #![feature(if_let_guard)] -#![allow(clippy::no_effect, unused, clippy::single_match)] +#![allow(clippy::no_effect, unused, clippy::single_match, invalid_nan_comparisons)] #![warn(clippy::redundant_guards)] #[macro_use] @@ -19,15 +19,24 @@ struct FloatWrapper(f32); fn issue11304() { match 0.1 { - x if x == 0.0 => todo!(), + 0.0 => todo!(), + // Pattern matching NAN is illegal + x if x == f64::NAN => todo!(), _ => todo!(), } match FloatWrapper(0.1) { - x if x == FloatWrapper(0.0) => todo!(), + FloatWrapper(0.0) => todo!(), _ => todo!(), } } +fn issue13681() { + match c"hi" { + x if x == c"hi" => (), + _ => (), + } +} + fn main() { let c = C(1, 2); match c { diff --git a/tests/ui/redundant_guards.rs b/tests/ui/redundant_guards.rs index adbc4ed16cd..b4d4ef5b170 100644 --- a/tests/ui/redundant_guards.rs +++ b/tests/ui/redundant_guards.rs @@ -1,6 +1,6 @@ //@aux-build:proc_macros.rs #![feature(if_let_guard)] -#![allow(clippy::no_effect, unused, clippy::single_match)] +#![allow(clippy::no_effect, unused, clippy::single_match, invalid_nan_comparisons)] #![warn(clippy::redundant_guards)] #[macro_use] @@ -20,6 +20,8 @@ struct FloatWrapper(f32); fn issue11304() { match 0.1 { x if x == 0.0 => todo!(), + // Pattern matching NAN is illegal + x if x == f64::NAN => todo!(), _ => todo!(), } match FloatWrapper(0.1) { @@ -28,6 +30,13 @@ fn issue11304() { } } +fn issue13681() { + match c"hi" { + x if x == c"hi" => (), + _ => (), + } +} + fn main() { let c = C(1, 2); match c { diff --git a/tests/ui/redundant_guards.stderr b/tests/ui/redundant_guards.stderr index fd12e083282..7512546450b 100644 --- a/tests/ui/redundant_guards.stderr +++ b/tests/ui/redundant_guards.stderr @@ -1,11 +1,35 @@ error: redundant guard - --> tests/ui/redundant_guards.rs:34:20 + --> tests/ui/redundant_guards.rs:22:14 + | +LL | x if x == 0.0 => todo!(), + | ^^^^^^^^ + | + = note: `-D clippy::redundant-guards` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::redundant_guards)]` +help: try + | +LL - x if x == 0.0 => todo!(), +LL + 0.0 => todo!(), + | + +error: redundant guard + --> tests/ui/redundant_guards.rs:28:14 + | +LL | x if x == FloatWrapper(0.0) => todo!(), + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL - x if x == FloatWrapper(0.0) => todo!(), +LL + FloatWrapper(0.0) => todo!(), + | + +error: redundant guard + --> tests/ui/redundant_guards.rs:43:20 | LL | C(x, y) if let 1 = y => .., | ^^^^^^^^^ | - = note: `-D clippy::redundant-guards` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::redundant_guards)]` help: try | LL - C(x, y) if let 1 = y => .., @@ -13,7 +37,7 @@ LL + C(x, 1) => .., | error: redundant guard - --> tests/ui/redundant_guards.rs:40:20 + --> tests/ui/redundant_guards.rs:49:20 | LL | Some(x) if matches!(x, Some(1) if true) => .., | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -24,7 +48,7 @@ LL | Some(Some(1)) if true => .., | ~~~~~~~ ~~~~~~~ error: redundant guard - --> tests/ui/redundant_guards.rs:41:20 + --> tests/ui/redundant_guards.rs:50:20 | LL | Some(x) if matches!(x, Some(1)) => { | ^^^^^^^^^^^^^^^^^^^^ @@ -36,7 +60,7 @@ LL + Some(Some(1)) => { | error: redundant guard - --> tests/ui/redundant_guards.rs:45:20 + --> tests/ui/redundant_guards.rs:54:20 | LL | Some(x) if let Some(1) = x => .., | ^^^^^^^^^^^^^^^ @@ -48,7 +72,7 @@ LL + Some(Some(1)) => .., | error: redundant guard - --> tests/ui/redundant_guards.rs:46:20 + --> tests/ui/redundant_guards.rs:55:20 | LL | Some(x) if x == Some(2) => .., | ^^^^^^^^^^^^ @@ -60,7 +84,7 @@ LL + Some(Some(2)) => .., | error: redundant guard - --> tests/ui/redundant_guards.rs:47:20 + --> tests/ui/redundant_guards.rs:56:20 | LL | Some(x) if Some(2) == x => .., | ^^^^^^^^^^^^ @@ -72,7 +96,7 @@ LL + Some(Some(2)) => .., | error: redundant guard - --> tests/ui/redundant_guards.rs:72:20 + --> tests/ui/redundant_guards.rs:81:20 | LL | B { e } if matches!(e, Some(A(2))) => .., | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -84,7 +108,7 @@ LL + B { e: Some(A(2)) } => .., | error: redundant guard - --> tests/ui/redundant_guards.rs:109:20 + --> tests/ui/redundant_guards.rs:118:20 | LL | E::A(y) if y == "not from an or pattern" => {}, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -96,7 +120,7 @@ LL + E::A("not from an or pattern") => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:116:14 + --> tests/ui/redundant_guards.rs:125:14 | LL | x if matches!(x, Some(0)) => .., | ^^^^^^^^^^^^^^^^^^^^ @@ -108,7 +132,7 @@ LL + Some(0) => .., | error: redundant guard - --> tests/ui/redundant_guards.rs:123:14 + --> tests/ui/redundant_guards.rs:132:14 | LL | i if i == -1 => {}, | ^^^^^^^ @@ -120,7 +144,7 @@ LL + -1 => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:124:14 + --> tests/ui/redundant_guards.rs:133:14 | LL | i if i == 1 => {}, | ^^^^^^ @@ -132,7 +156,7 @@ LL + 1 => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:186:28 + --> tests/ui/redundant_guards.rs:195:28 | LL | Some(ref x) if x == &1 => {}, | ^^^^^^^ @@ -144,7 +168,7 @@ LL + Some(1) => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:187:28 + --> tests/ui/redundant_guards.rs:196:28 | LL | Some(ref x) if &1 == x => {}, | ^^^^^^^ @@ -156,7 +180,7 @@ LL + Some(1) => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:188:28 + --> tests/ui/redundant_guards.rs:197:28 | LL | Some(ref x) if let &2 = x => {}, | ^^^^^^^^^^ @@ -168,7 +192,7 @@ LL + Some(2) => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:189:28 + --> tests/ui/redundant_guards.rs:198:28 | LL | Some(ref x) if matches!(x, &3) => {}, | ^^^^^^^^^^^^^^^ @@ -180,7 +204,7 @@ LL + Some(3) => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:209:32 + --> tests/ui/redundant_guards.rs:218:32 | LL | B { ref c, .. } if c == &1 => {}, | ^^^^^^^ @@ -192,7 +216,7 @@ LL + B { c: 1, .. } => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:210:32 + --> tests/ui/redundant_guards.rs:219:32 | LL | B { ref c, .. } if &1 == c => {}, | ^^^^^^^ @@ -204,7 +228,7 @@ LL + B { c: 1, .. } => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:211:32 + --> tests/ui/redundant_guards.rs:220:32 | LL | B { ref c, .. } if let &1 = c => {}, | ^^^^^^^^^^ @@ -216,7 +240,7 @@ LL + B { c: 1, .. } => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:212:32 + --> tests/ui/redundant_guards.rs:221:32 | LL | B { ref c, .. } if matches!(c, &1) => {}, | ^^^^^^^^^^^^^^^ @@ -228,7 +252,7 @@ LL + B { c: 1, .. } => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:222:26 + --> tests/ui/redundant_guards.rs:231:26 | LL | Some(Some(x)) if x.is_empty() => {}, | ^^^^^^^^^^^^ @@ -240,7 +264,7 @@ LL + Some(Some("")) => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:233:26 + --> tests/ui/redundant_guards.rs:242:26 | LL | Some(Some(x)) if x.is_empty() => {}, | ^^^^^^^^^^^^ @@ -252,7 +276,7 @@ LL + Some(Some([])) => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:238:26 + --> tests/ui/redundant_guards.rs:247:26 | LL | Some(Some(x)) if x.is_empty() => {}, | ^^^^^^^^^^^^ @@ -264,7 +288,7 @@ LL + Some(Some([])) => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:249:26 + --> tests/ui/redundant_guards.rs:258:26 | LL | Some(Some(x)) if x.starts_with(&[]) => {}, | ^^^^^^^^^^^^^^^^^^ @@ -276,7 +300,7 @@ LL + Some(Some([..])) => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:254:26 + --> tests/ui/redundant_guards.rs:263:26 | LL | Some(Some(x)) if x.starts_with(&[1]) => {}, | ^^^^^^^^^^^^^^^^^^^ @@ -288,7 +312,7 @@ LL + Some(Some([1, ..])) => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:259:26 + --> tests/ui/redundant_guards.rs:268:26 | LL | Some(Some(x)) if x.starts_with(&[1, 2]) => {}, | ^^^^^^^^^^^^^^^^^^^^^^ @@ -300,7 +324,7 @@ LL + Some(Some([1, 2, ..])) => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:264:26 + --> tests/ui/redundant_guards.rs:273:26 | LL | Some(Some(x)) if x.ends_with(&[1, 2]) => {}, | ^^^^^^^^^^^^^^^^^^^^ @@ -312,7 +336,7 @@ LL + Some(Some([.., 1, 2])) => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:286:18 + --> tests/ui/redundant_guards.rs:295:18 | LL | y if y.is_empty() => {}, | ^^^^^^^^^^^^ @@ -324,7 +348,7 @@ LL + "" => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:305:22 + --> tests/ui/redundant_guards.rs:314:22 | LL | y if y.is_empty() => {}, | ^^^^^^^^^^^^ @@ -335,5 +359,5 @@ LL - y if y.is_empty() => {}, LL + "" => {}, | -error: aborting due to 28 previous errors +error: aborting due to 30 previous errors From 74b95f2e65a1b6c7798e819c87de1ddc61b85610 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Fri, 15 Nov 2024 19:59:38 +0100 Subject: [PATCH 11/45] Prepare clippy_utils for publishing - Add metadata to clippy_utils/Cargo.toml file - Add clippy_utils README.md file --- clippy_utils/Cargo.toml | 6 ++++++ clippy_utils/README.md | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 clippy_utils/README.md diff --git a/clippy_utils/Cargo.toml b/clippy_utils/Cargo.toml index d136f3bc6f1..fb2acf700ab 100644 --- a/clippy_utils/Cargo.toml +++ b/clippy_utils/Cargo.toml @@ -2,6 +2,12 @@ name = "clippy_utils" version = "0.1.84" edition = "2021" +description = "Helpful tools for writing lints, provided as they are used in Clippy" +repository = "https://github.com/rust-lang/rust-clippy" +readme = "README.md" +license = "MIT OR Apache-2.0" +keywords = ["clippy", "lint", "utils"] +categories = ["development-tools"] [dependencies] arrayvec = { version = "0.7", default-features = false } diff --git a/clippy_utils/README.md b/clippy_utils/README.md new file mode 100644 index 00000000000..fb1a3f13f8c --- /dev/null +++ b/clippy_utils/README.md @@ -0,0 +1,40 @@ +# `clippy-utils` + +Helpful tools for writing lints, provided as they are used in Clippy. + +## Usage + +This crate is only guaranteed to build with this `nightly` toolchain: + + +``` +nightly-2024-11-14 +``` + + +To use `clippy-utils` in your lint, add the following to your `Cargo.toml`: + +``` +clippy_utils = "0.1.XY" +``` + +`XY` is the version of the nightly toolchain above and can be determined with `rustc +nightly-YYYY-MM-DD -V`. + +## :warning: Stability :warning: + +No stability guarantees are made for this crate! Use at your own risk. + +Function signatures can change or be removed without replacement without any prior notice. + +## LICENSE + + + +Copyright 2014-2024 The Rust Project Developers + +Licensed under the Apache License, Version 2.0 +<[https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0)> or the MIT license +<[https://opensource.org/licenses/MIT](https://opensource.org/licenses/MIT)>, at your option. Files in the project may +not be copied, modified, or distributed except according to those terms. + + From ef42a66afe1b97731e5fd1ddb4c1f6708edcb224 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sat, 16 Nov 2024 14:52:42 +0500 Subject: [PATCH 12/45] Do not trigger if_let_mutex strating from Edition 2024 --- clippy_lints/src/if_let_mutex.rs | 11 +++++++++++ ...t_mutex.stderr => if_let_mutex.edition2021.stderr} | 8 ++++---- tests/ui/if_let_mutex.rs | 11 ++++++++--- 3 files changed, 23 insertions(+), 7 deletions(-) rename tests/ui/{if_let_mutex.stderr => if_let_mutex.edition2021.stderr} (94%) diff --git a/clippy_lints/src/if_let_mutex.rs b/clippy_lints/src/if_let_mutex.rs index ba80c099a01..943713654de 100644 --- a/clippy_lints/src/if_let_mutex.rs +++ b/clippy_lints/src/if_let_mutex.rs @@ -7,6 +7,7 @@ use rustc_errors::Diag; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; +use rustc_span::edition::Edition::Edition2024; use rustc_span::sym; declare_clippy_lint! { @@ -14,6 +15,12 @@ declare_clippy_lint! { /// Checks for `Mutex::lock` calls in `if let` expression /// with lock calls in any of the else blocks. /// + /// ### Disabled starting in Edition 2024 + /// This lint is effectively disabled starting in + /// Edition 2024 as `if let ... else` scoping was reworked + /// such that this is no longer an issue. See + /// [Proposal: stabilize if_let_rescope for Edition 2024](https://github.com/rust-lang/rust/issues/131154) + /// /// ### Why is this bad? /// The Mutex lock remains held for the whole /// `if let ... else` block and deadlocks. @@ -45,6 +52,10 @@ declare_lint_pass!(IfLetMutex => [IF_LET_MUTEX]); impl<'tcx> LateLintPass<'tcx> for IfLetMutex { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { + if cx.tcx.sess.edition() >= Edition2024 { + return; + } + if let Some(higher::IfLet { let_expr, if_then, diff --git a/tests/ui/if_let_mutex.stderr b/tests/ui/if_let_mutex.edition2021.stderr similarity index 94% rename from tests/ui/if_let_mutex.stderr rename to tests/ui/if_let_mutex.edition2021.stderr index 45df4ac4d67..984d6adbb2a 100644 --- a/tests/ui/if_let_mutex.stderr +++ b/tests/ui/if_let_mutex.edition2021.stderr @@ -1,5 +1,5 @@ error: calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock - --> tests/ui/if_let_mutex.rs:11:5 + --> tests/ui/if_let_mutex.rs:16:5 | LL | if let Err(locked) = m.lock() { | ^ - this Mutex will remain locked for the entire `if let`-block... @@ -19,7 +19,7 @@ LL | | }; = help: to override `-D warnings` add `#[allow(clippy::if_let_mutex)]` error: calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock - --> tests/ui/if_let_mutex.rs:24:5 + --> tests/ui/if_let_mutex.rs:29:5 | LL | if let Some(locked) = m.lock().unwrap().deref() { | ^ - this Mutex will remain locked for the entire `if let`-block... @@ -37,7 +37,7 @@ LL | | }; = help: move the lock call outside of the `if let ...` expression error: calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock - --> tests/ui/if_let_mutex.rs:46:5 + --> tests/ui/if_let_mutex.rs:51:5 | LL | if let Ok(i) = mutex.lock() { | ^ ----- this Mutex will remain locked for the entire `if let`-block... @@ -54,7 +54,7 @@ LL | | }; = help: move the lock call outside of the `if let ...` expression error: calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock - --> tests/ui/if_let_mutex.rs:55:5 + --> tests/ui/if_let_mutex.rs:60:5 | LL | if let Ok(_) = m1.lock() { | ^ -- this Mutex will remain locked for the entire `if let`-block... diff --git a/tests/ui/if_let_mutex.rs b/tests/ui/if_let_mutex.rs index bb0eadfca1c..80eee293989 100644 --- a/tests/ui/if_let_mutex.rs +++ b/tests/ui/if_let_mutex.rs @@ -1,3 +1,8 @@ +//@ compile-flags: -Zunstable-options + +//@revisions: edition2021 edition2024 +//@[edition2021] edition:2021 +//@[edition2024] edition:2024 #![warn(clippy::if_let_mutex)] #![allow(clippy::redundant_pattern_matching)] @@ -9,7 +14,7 @@ fn do_stuff(_: T) {} fn if_let() { let m = Mutex::new(1_u8); if let Err(locked) = m.lock() { - //~^ ERROR: calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a d + //~[edition2021]^ if_let_mutex do_stuff(locked); } else { let lock = m.lock().unwrap(); @@ -22,7 +27,7 @@ fn if_let() { fn if_let_option() { let m = Mutex::new(Some(0_u8)); if let Some(locked) = m.lock().unwrap().deref() { - //~^ ERROR: calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a d + //~[edition2021]^ if_let_mutex do_stuff(locked); } else { let lock = m.lock().unwrap(); @@ -44,7 +49,7 @@ fn if_let_different_mutex() { fn mutex_ref(mutex: &Mutex) { if let Ok(i) = mutex.lock() { - //~^ ERROR: calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a d + //~[edition2021]^ if_let_mutex do_stuff(i); } else { let _x = mutex.lock(); From a2b6b6b085db2459e4331dd6becaac8191c1d84b Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 17 Nov 2024 12:25:19 -0800 Subject: [PATCH 13/45] Inline ExprPrecedence::order into Expr::precedence --- clippy_lints/src/dereference.rs | 10 +++++----- clippy_lints/src/loops/single_element_loop.rs | 2 +- clippy_lints/src/matches/manual_utils.rs | 2 +- clippy_lints/src/neg_multiply.rs | 2 +- clippy_lints/src/redundant_slicing.rs | 2 +- .../transmute/transmutes_expressible_as_ptr_casts.rs | 4 ++-- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index b167d7f2208..834606094ae 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -959,7 +959,7 @@ fn report<'tcx>( // expr_str (the suggestion) is never shown if is_final_ufcs is true, since it's // `expr.kind == ExprKind::Call`. Therefore, this is, afaik, always unnecessary. /* - expr_str = if !expr_is_macro_call && is_final_ufcs && expr.precedence().order() < PREC_PREFIX { + expr_str = if !expr_is_macro_call && is_final_ufcs && expr.precedence() < PREC_PREFIX { Cow::Owned(format!("({expr_str})")) } else { expr_str @@ -999,7 +999,7 @@ fn report<'tcx>( Node::Expr(e) => match e.kind { ExprKind::Call(callee, _) if callee.hir_id != data.first_expr.hir_id => (0, false), ExprKind::Call(..) => (PREC_UNAMBIGUOUS, matches!(expr.kind, ExprKind::Field(..))), - _ => (e.precedence().order(), false), + _ => (e.precedence(), false), }, _ => (0, false), }; @@ -1012,7 +1012,7 @@ fn report<'tcx>( ); let sugg = if !snip_is_macro - && (calls_field || expr.precedence().order() < precedence) + && (calls_field || expr.precedence() < precedence) && !has_enclosing_paren(&snip) && !is_in_tuple { @@ -1067,7 +1067,7 @@ fn report<'tcx>( let (snip, snip_is_macro) = snippet_with_context(cx, expr.span, data.first_expr.span.ctxt(), "..", &mut app); let sugg = - if !snip_is_macro && expr.precedence().order() < precedence && !has_enclosing_paren(&snip) { + if !snip_is_macro && expr.precedence() < precedence && !has_enclosing_paren(&snip) { format!("{prefix}({snip})") } else { format!("{prefix}{snip}") @@ -1154,7 +1154,7 @@ impl<'tcx> Dereferencing<'tcx> { }, Some(parent) if !parent.span.from_expansion() => { // Double reference might be needed at this point. - if parent.precedence().order() == PREC_UNAMBIGUOUS { + if parent.precedence() == PREC_UNAMBIGUOUS { // Parentheses would be needed here, don't lint. *outer_pat = None; } else { diff --git a/clippy_lints/src/loops/single_element_loop.rs b/clippy_lints/src/loops/single_element_loop.rs index 70f76ced09a..35dc8e9aa4e 100644 --- a/clippy_lints/src/loops/single_element_loop.rs +++ b/clippy_lints/src/loops/single_element_loop.rs @@ -84,7 +84,7 @@ pub(super) fn check<'tcx>( if !prefix.is_empty() && ( // Precedence of internal expression is less than or equal to precedence of `&expr`. - arg_expression.precedence().order() <= PREC_PREFIX || is_range_literal(arg_expression) + arg_expression.precedence() <= PREC_PREFIX || is_range_literal(arg_expression) ) { arg_snip = format!("({arg_snip})").into(); diff --git a/clippy_lints/src/matches/manual_utils.rs b/clippy_lints/src/matches/manual_utils.rs index d38560998a5..9c6df4d8ac0 100644 --- a/clippy_lints/src/matches/manual_utils.rs +++ b/clippy_lints/src/matches/manual_utils.rs @@ -117,7 +117,7 @@ where // it's being passed by value. 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.eq_ctxt(expr.span) && scrutinee.precedence().order() < PREC_UNAMBIGUOUS { + let scrutinee_str = if scrutinee.span.eq_ctxt(expr.span) && scrutinee.precedence() < PREC_UNAMBIGUOUS { format!("({scrutinee_str})") } else { scrutinee_str.into() diff --git a/clippy_lints/src/neg_multiply.rs b/clippy_lints/src/neg_multiply.rs index f84d9fadb85..a0ba2aaf552 100644 --- a/clippy_lints/src/neg_multiply.rs +++ b/clippy_lints/src/neg_multiply.rs @@ -58,7 +58,7 @@ fn check_mul(cx: &LateContext<'_>, span: Span, lit: &Expr<'_>, exp: &Expr<'_>) { { let mut applicability = Applicability::MachineApplicable; let (snip, from_macro) = snippet_with_context(cx, exp.span, span.ctxt(), "..", &mut applicability); - let suggestion = if !from_macro && exp.precedence().order() < PREC_PREFIX && !has_enclosing_paren(&snip) { + let suggestion = if !from_macro && exp.precedence() < PREC_PREFIX && !has_enclosing_paren(&snip) { format!("-({snip})") } else { format!("-{snip}") diff --git a/clippy_lints/src/redundant_slicing.rs b/clippy_lints/src/redundant_slicing.rs index dc66fb28fa8..159404e130d 100644 --- a/clippy_lints/src/redundant_slicing.rs +++ b/clippy_lints/src/redundant_slicing.rs @@ -85,7 +85,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing { let (expr_ty, expr_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(expr)); let (indexed_ty, indexed_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(indexed)); let parent_expr = get_parent_expr(cx, expr); - let needs_parens_for_prefix = parent_expr.is_some_and(|parent| parent.precedence().order() > PREC_PREFIX); + let needs_parens_for_prefix = parent_expr.is_some_and(|parent| parent.precedence() > PREC_PREFIX); if expr_ty == indexed_ty { if expr_ref_count > indexed_ref_count { 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 fca332dba40..cad15b1e982 100644 --- a/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs +++ b/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs @@ -1,7 +1,7 @@ use super::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::sugg::Sugg; -use rustc_ast::ExprPrecedence; +use rustc_ast::util::parser::AssocOp; use rustc_errors::Applicability; use rustc_hir::{Expr, Node}; use rustc_hir_typeck::cast::check_cast; @@ -44,7 +44,7 @@ pub(super) fn check<'tcx>( }; if let Node::Expr(parent) = cx.tcx.parent_hir_node(e.hir_id) - && parent.precedence().order() > ExprPrecedence::Cast.order() + && parent.precedence() > AssocOp::As.precedence() as i8 { sugg = format!("({sugg})"); } From 9c8d9504cedcf0088252c22a16698379e35f2099 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Sat, 4 May 2024 15:17:46 +0200 Subject: [PATCH 14/45] Introduce `utils` mod in clippy_dev There was some dependence between the different subcommands of clippy_dev. And this dependence will increased with the introduction of the sync and release subcommands. This moves the common functions to a `utils` module, to decouple the other modules. --- clippy_dev/src/dogfood.rs | 2 +- clippy_dev/src/fmt.rs | 2 +- clippy_dev/src/lib.rs | 60 +------------- clippy_dev/src/lint.rs | 2 +- clippy_dev/src/main.rs | 8 +- clippy_dev/src/new_lint.rs | 21 +---- clippy_dev/src/update_lints.rs | 71 +---------------- clippy_dev/src/utils.rs | 142 +++++++++++++++++++++++++++++++++ 8 files changed, 154 insertions(+), 154 deletions(-) create mode 100644 clippy_dev/src/utils.rs diff --git a/clippy_dev/src/dogfood.rs b/clippy_dev/src/dogfood.rs index a0d57f5ab48..75a4cbd2f92 100644 --- a/clippy_dev/src/dogfood.rs +++ b/clippy_dev/src/dogfood.rs @@ -1,4 +1,4 @@ -use crate::{clippy_project_root, exit_if_err}; +use crate::utils::{clippy_project_root, exit_if_err}; use std::process::Command; /// # Panics diff --git a/clippy_dev/src/fmt.rs b/clippy_dev/src/fmt.rs index 8c61c35533c..c6673859282 100644 --- a/clippy_dev/src/fmt.rs +++ b/clippy_dev/src/fmt.rs @@ -1,4 +1,4 @@ -use crate::clippy_project_root; +use crate::utils::clippy_project_root; use itertools::Itertools; use rustc_lexer::{TokenKind, tokenize}; use shell_escape::escape; diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs index ad385d5fbd2..d96b79ec26c 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -14,10 +14,6 @@ extern crate rustc_driver; extern crate rustc_lexer; -use std::io; -use std::path::PathBuf; -use std::process::{self, ExitStatus}; - pub mod dogfood; pub mod fmt; pub mod lint; @@ -25,58 +21,4 @@ pub mod new_lint; pub mod serve; pub mod setup; pub mod update_lints; - -#[cfg(not(windows))] -static CARGO_CLIPPY_EXE: &str = "cargo-clippy"; -#[cfg(windows)] -static CARGO_CLIPPY_EXE: &str = "cargo-clippy.exe"; - -/// Returns the path to the `cargo-clippy` binary -/// -/// # Panics -/// -/// Panics if the path of current executable could not be retrieved. -#[must_use] -pub fn cargo_clippy_path() -> PathBuf { - let mut path = std::env::current_exe().expect("failed to get current executable name"); - path.set_file_name(CARGO_CLIPPY_EXE); - path -} - -/// Returns the path to the Clippy project directory -/// -/// # Panics -/// -/// Panics if the current directory could not be retrieved, there was an error reading any of the -/// Cargo.toml files or ancestor directory is the clippy root directory -#[must_use] -pub fn clippy_project_root() -> PathBuf { - let current_dir = std::env::current_dir().unwrap(); - for path in current_dir.ancestors() { - let result = std::fs::read_to_string(path.join("Cargo.toml")); - if let Err(err) = &result { - if err.kind() == io::ErrorKind::NotFound { - continue; - } - } - - let content = result.unwrap(); - if content.contains("[package]\nname = \"clippy\"") { - return path.to_path_buf(); - } - } - panic!("error: Can't determine root of project. Please run inside a Clippy working dir."); -} - -/// # Panics -/// Panics if given command result was failed. -pub fn exit_if_err(status: io::Result) { - match status.expect("failed to run command").code() { - Some(0) => {}, - Some(n) => process::exit(n), - None => { - eprintln!("Killed by signal"); - process::exit(1); - }, - } -} +pub mod utils; diff --git a/clippy_dev/src/lint.rs b/clippy_dev/src/lint.rs index f308f5dfdfd..125195397e6 100644 --- a/clippy_dev/src/lint.rs +++ b/clippy_dev/src/lint.rs @@ -1,4 +1,4 @@ -use crate::{cargo_clippy_path, exit_if_err}; +use crate::utils::{cargo_clippy_path, exit_if_err}; use std::process::{self, Command}; use std::{env, fs}; diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index fc15913354c..f5055b42912 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -3,7 +3,7 @@ #![warn(rust_2018_idioms, unused_lifetimes)] use clap::{Args, Parser, Subcommand}; -use clippy_dev::{dogfood, fmt, lint, new_lint, serve, setup, update_lints}; +use clippy_dev::{dogfood, fmt, lint, new_lint, serve, setup, update_lints, utils}; use std::convert::Infallible; fn main() { @@ -23,9 +23,9 @@ fn main() { if print_only { update_lints::print_lints(); } else if check { - update_lints::update(update_lints::UpdateMode::Check); + update_lints::update(utils::UpdateMode::Check); } else { - update_lints::update(update_lints::UpdateMode::Change); + update_lints::update(utils::UpdateMode::Change); } }, DevCommand::NewLint { @@ -35,7 +35,7 @@ fn main() { r#type, msrv, } => match new_lint::create(&pass, &name, &category, r#type.as_deref(), msrv) { - Ok(()) => update_lints::update(update_lints::UpdateMode::Change), + Ok(()) => update_lints::update(utils::UpdateMode::Change), Err(e) => eprintln!("Unable to create lint: {e}"), }, DevCommand::Setup(SetupCommand { subcommand }) => match subcommand { diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index ee626d60b86..35dd986ff61 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -1,4 +1,4 @@ -use crate::clippy_project_root; +use crate::utils::{clippy_project_root, clippy_version}; use indoc::{formatdoc, writedoc}; use std::fmt; use std::fmt::Write as _; @@ -186,23 +186,8 @@ fn to_camel_case(name: &str) -> String { } pub(crate) fn get_stabilization_version() -> String { - fn parse_manifest(contents: &str) -> Option { - let version = contents - .lines() - .filter_map(|l| l.split_once('=')) - .find_map(|(k, v)| (k.trim() == "version").then(|| v.trim()))?; - let Some(("0", version)) = version.get(1..version.len() - 1)?.split_once('.') else { - return None; - }; - let (minor, patch) = version.split_once('.')?; - Some(format!( - "{}.{}.0", - minor.parse::().ok()?, - patch.parse::().ok()? - )) - } - let contents = fs::read_to_string("Cargo.toml").expect("Unable to read `Cargo.toml`"); - parse_manifest(&contents).expect("Unable to find package version in `Cargo.toml`") + let (minor, patch) = clippy_version(); + format!("{minor}.{patch}.0") } fn get_test_file_contents(lint_name: &str, msrv: bool) -> String { diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs index 795456ad3c5..612d1c0ae13 100644 --- a/clippy_dev/src/update_lints.rs +++ b/clippy_dev/src/update_lints.rs @@ -1,4 +1,4 @@ -use crate::clippy_project_root; +use crate::utils::{UpdateMode, clippy_project_root, exit_with_failure, replace_region_in_file}; use aho_corasick::AhoCorasickBuilder; use itertools::Itertools; use rustc_lexer::{LiteralKind, TokenKind, tokenize, unescape}; @@ -17,12 +17,6 @@ const GENERATED_FILE_COMMENT: &str = "// This file was generated by `cargo dev u const DOCS_LINK: &str = "https://rust-lang.github.io/rust-clippy/master/index.html"; -#[derive(Clone, Copy, PartialEq, Eq)] -pub enum UpdateMode { - Check, - Change, -} - /// Runs the `update_lints` command. /// /// This updates various generated values from the lint source code. @@ -511,14 +505,6 @@ fn process_file(path: impl AsRef, update_mode: UpdateMode, content: &str) } } -fn exit_with_failure() { - println!( - "Not all lints defined properly. \ - Please run `cargo dev update_lints` to make sure all lints are defined properly." - ); - std::process::exit(1); -} - /// Lint data parsed from the Clippy source code. #[derive(Clone, PartialEq, Eq, Debug)] struct Lint { @@ -851,61 +837,6 @@ fn remove_line_splices(s: &str) -> String { }); res } - -/// Replaces a region in a file delimited by two lines matching regexes. -/// -/// `path` is the relative path to the file on which you want to perform the replacement. -/// -/// See `replace_region_in_text` for documentation of the other options. -/// -/// # Panics -/// -/// Panics if the path could not read or then written -fn replace_region_in_file( - update_mode: UpdateMode, - path: &Path, - start: &str, - end: &str, - write_replacement: impl FnMut(&mut String), -) { - 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 `{delim}` in file `{}`", path.display()), - }; - - match update_mode { - UpdateMode::Check if contents != new_contents => exit_with_failure(), - UpdateMode::Check => (), - UpdateMode::Change => { - if let Err(e) = fs::write(path, new_contents.as_bytes()) { - panic!("Cannot write to `{}`: {e}", path.display()); - } - }, - } -} - -/// Replaces a region in a text delimited by two strings. Returns the new text if both delimiters -/// were found, or the missing delimiter if not. -fn replace_region_in_text<'a>( - text: &str, - start: &'a str, - end: &'a str, - mut write_replacement: impl FnMut(&mut String), -) -> Result { - let (text_start, rest) = text.split_once(start).ok_or(start)?; - let (_, text_end) = rest.split_once(end).ok_or(end)?; - - let mut res = String::with_capacity(text.len() + 4096); - res.push_str(text_start); - res.push_str(start); - write_replacement(&mut res); - res.push_str(end); - res.push_str(text_end); - - Ok(res) -} - fn try_rename_file(old_name: &Path, new_name: &Path) -> bool { match OpenOptions::new().create_new(true).write(true).open(new_name) { Ok(file) => drop(file), diff --git a/clippy_dev/src/utils.rs b/clippy_dev/src/utils.rs new file mode 100644 index 00000000000..b87fcca13b1 --- /dev/null +++ b/clippy_dev/src/utils.rs @@ -0,0 +1,142 @@ +use std::path::{Path, PathBuf}; +use std::process::{self, ExitStatus}; +use std::{fs, io}; + +#[cfg(not(windows))] +static CARGO_CLIPPY_EXE: &str = "cargo-clippy"; +#[cfg(windows)] +static CARGO_CLIPPY_EXE: &str = "cargo-clippy.exe"; + +/// Returns the path to the `cargo-clippy` binary +/// +/// # Panics +/// +/// Panics if the path of current executable could not be retrieved. +#[must_use] +pub fn cargo_clippy_path() -> PathBuf { + let mut path = std::env::current_exe().expect("failed to get current executable name"); + path.set_file_name(CARGO_CLIPPY_EXE); + path +} + +/// Returns the path to the Clippy project directory +/// +/// # Panics +/// +/// Panics if the current directory could not be retrieved, there was an error reading any of the +/// Cargo.toml files or ancestor directory is the clippy root directory +#[must_use] +pub fn clippy_project_root() -> PathBuf { + let current_dir = std::env::current_dir().unwrap(); + for path in current_dir.ancestors() { + let result = fs::read_to_string(path.join("Cargo.toml")); + if let Err(err) = &result { + if err.kind() == io::ErrorKind::NotFound { + continue; + } + } + + let content = result.unwrap(); + if content.contains("[package]\nname = \"clippy\"") { + return path.to_path_buf(); + } + } + panic!("error: Can't determine root of project. Please run inside a Clippy working dir."); +} + +/// # Panics +/// Panics if given command result was failed. +pub fn exit_if_err(status: io::Result) { + match status.expect("failed to run command").code() { + Some(0) => {}, + Some(n) => process::exit(n), + None => { + eprintln!("Killed by signal"); + process::exit(1); + }, + } +} + +pub(crate) fn clippy_version() -> (u32, u32) { + fn parse_manifest(contents: &str) -> Option<(u32, u32)> { + let version = contents + .lines() + .filter_map(|l| l.split_once('=')) + .find_map(|(k, v)| (k.trim() == "version").then(|| v.trim()))?; + let Some(("0", version)) = version.get(1..version.len() - 1)?.split_once('.') else { + return None; + }; + let (minor, patch) = version.split_once('.')?; + Some((minor.parse().ok()?, patch.parse().ok()?)) + } + let contents = fs::read_to_string("Cargo.toml").expect("Unable to read `Cargo.toml`"); + parse_manifest(&contents).expect("Unable to find package version in `Cargo.toml`") +} + +#[derive(Clone, Copy, PartialEq, Eq)] +pub enum UpdateMode { + Check, + Change, +} + +pub(crate) fn exit_with_failure() { + println!( + "Not all lints defined properly. \ + Please run `cargo dev update_lints` to make sure all lints are defined properly." + ); + process::exit(1); +} + +/// Replaces a region in a file delimited by two lines matching regexes. +/// +/// `path` is the relative path to the file on which you want to perform the replacement. +/// +/// See `replace_region_in_text` for documentation of the other options. +/// +/// # Panics +/// +/// Panics if the path could not read or then written +pub(crate) fn replace_region_in_file( + update_mode: UpdateMode, + path: &Path, + start: &str, + end: &str, + write_replacement: impl FnMut(&mut String), +) { + 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 `{delim}` in file `{}`", path.display()), + }; + + match update_mode { + UpdateMode::Check if contents != new_contents => exit_with_failure(), + UpdateMode::Check => (), + UpdateMode::Change => { + if let Err(e) = fs::write(path, new_contents.as_bytes()) { + panic!("Cannot write to `{}`: {e}", path.display()); + } + }, + } +} + +/// Replaces a region in a text delimited by two strings. Returns the new text if both delimiters +/// were found, or the missing delimiter if not. +pub(crate) fn replace_region_in_text<'a>( + text: &str, + start: &'a str, + end: &'a str, + mut write_replacement: impl FnMut(&mut String), +) -> Result { + let (text_start, rest) = text.split_once(start).ok_or(start)?; + let (_, text_end) = rest.split_once(end).ok_or(end)?; + + let mut res = String::with_capacity(text.len() + 4096); + res.push_str(text_start); + res.push_str(start); + write_replacement(&mut res); + res.push_str(end); + res.push_str(text_end); + + Ok(res) +} From bb93c23c0854bbb8aa6a523f0b4462da0f75f6da Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 15 Nov 2024 13:53:31 +0100 Subject: [PATCH 15/45] use `TypingEnv` when no `infcx` is available the behavior of the type system not only depends on the current assumptions, but also the currentnphase of the compiler. This is mostly necessary as we need to decide whether and how to reveal opaque types. We track this via the `TypingMode`. --- clippy_lints/src/assigning_clones.rs | 2 +- clippy_lints/src/bool_assert_comparison.rs | 2 +- clippy_lints/src/dereference.rs | 9 +++++---- clippy_lints/src/drop_forget_ref.rs | 4 ++-- .../src/iter_not_returning_iterator.rs | 2 +- clippy_lints/src/iter_without_into_iter.rs | 2 +- clippy_lints/src/large_const_arrays.rs | 4 ++-- clippy_lints/src/large_futures.rs | 2 +- clippy_lints/src/large_stack_frames.rs | 4 ++-- clippy_lints/src/loops/explicit_iter_loop.rs | 12 ++++++------ clippy_lints/src/methods/needless_collect.rs | 6 +++--- .../src/methods/unnecessary_min_or_max.rs | 2 +- .../src/methods/unnecessary_to_owned.rs | 2 +- clippy_lints/src/methods/zst_offset.rs | 2 +- .../src/needless_borrows_for_generic_args.rs | 2 +- clippy_lints/src/non_copy_const.rs | 18 +++++++++--------- .../src/operators/const_comparisons.rs | 2 +- clippy_lints/src/operators/erasing_op.rs | 2 +- clippy_lints/src/operators/float_cmp.rs | 3 +-- clippy_lints/src/redundant_slicing.rs | 2 +- clippy_lints/src/returns.rs | 2 +- .../src/significant_drop_tightening.rs | 2 +- clippy_lints/src/trailing_empty_array.rs | 2 +- clippy_lints/src/transmute/eager_transmute.rs | 4 ++-- .../src/transmute/transmute_undefined_repr.rs | 6 +++--- clippy_lints/src/transmute/utils.rs | 9 +++++---- clippy_lints/src/uninhabited_references.rs | 4 ++-- clippy_utils/src/consts.rs | 12 ++++++------ clippy_utils/src/eager_or_lazy.rs | 2 +- clippy_utils/src/hir_utils.rs | 6 +++--- clippy_utils/src/lib.rs | 2 +- clippy_utils/src/qualify_min_const_fn.rs | 10 ++++++---- clippy_utils/src/ty.rs | 17 +++++++++-------- 33 files changed, 83 insertions(+), 79 deletions(-) diff --git a/clippy_lints/src/assigning_clones.rs b/clippy_lints/src/assigning_clones.rs index 0b82c0cd04c..00626a37ef8 100644 --- a/clippy_lints/src/assigning_clones.rs +++ b/clippy_lints/src/assigning_clones.rs @@ -96,7 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for AssigningClones { }, _ => return, } - && let Ok(Some(resolved_fn)) = Instance::try_resolve(cx.tcx, cx.param_env, fn_id, fn_gen_args) + && let Ok(Some(resolved_fn)) = Instance::try_resolve(cx.tcx, cx.typing_env(), fn_id, fn_gen_args) // TODO: This check currently bails if the local variable has no initializer. // That is overly conservative - the lint should fire even if there was no initializer, // but the variable has been initialized before `lhs` was evaluated. diff --git a/clippy_lints/src/bool_assert_comparison.rs b/clippy_lints/src/bool_assert_comparison.rs index 7d89195eeca..adac2f27ea8 100644 --- a/clippy_lints/src/bool_assert_comparison.rs +++ b/clippy_lints/src/bool_assert_comparison.rs @@ -62,7 +62,7 @@ fn is_impl_not_trait_with_bool_out<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) - }) .is_some_and(|assoc_item| { let proj = Ty::new_projection(cx.tcx, assoc_item.def_id, cx.tcx.mk_args_trait(ty, [])); - let nty = cx.tcx.normalize_erasing_regions(cx.param_env, proj); + let nty = cx.tcx.normalize_erasing_regions(cx.typing_env(), proj); nty.is_bool() }) diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index b167d7f2208..f864b7a5a8a 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -17,7 +17,7 @@ use rustc_hir::{ }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; -use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt, TypeVisitableExt, TypeckResults}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, TypeckResults}; use rustc_session::impl_lint_pass; use rustc_span::symbol::sym; use rustc_span::{Span, Symbol}; @@ -755,7 +755,8 @@ impl TyCoercionStability { DefinedTy::Hir(ty) => Self::for_hir_ty(ty), DefinedTy::Mir(ty) => Self::for_mir_ty( cx.tcx, - ty.param_env, + // FIXME(#132279): convert `DefinedTy` to use `TypingEnv` instead. + ty::TypingEnv::from_param_env(ty.param_env), cx.tcx.instantiate_bound_regions_with_erased(ty.value), for_return, ), @@ -823,12 +824,12 @@ impl TyCoercionStability { } } - fn for_mir_ty<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>, for_return: bool) -> Self { + fn for_mir_ty<'tcx>(tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>, ty: Ty<'tcx>, for_return: bool) -> Self { let ty::Ref(_, mut ty, _) = *ty.kind() else { return Self::None; }; - ty = tcx.try_normalize_erasing_regions(param_env, ty).unwrap_or(ty); + ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty); loop { break match *ty.kind() { ty::Ref(_, ref_ty, _) => { diff --git a/clippy_lints/src/drop_forget_ref.rs b/clippy_lints/src/drop_forget_ref.rs index 55afdbf22e1..617982f4da3 100644 --- a/clippy_lints/src/drop_forget_ref.rs +++ b/clippy_lints/src/drop_forget_ref.rs @@ -99,7 +99,7 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef { sym::mem_forget if is_copy => return, sym::mem_drop if is_type_lang_item(cx, arg_ty, LangItem::ManuallyDrop) => return, sym::mem_drop - if !(arg_ty.needs_drop(cx.tcx, cx.param_env) + if !(arg_ty.needs_drop(cx.tcx, cx.typing_env()) || is_must_use_func_call(cx, arg) || is_must_use_ty(cx, arg_ty) || drop_is_single_call_in_arm) => @@ -107,7 +107,7 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef { (DROP_NON_DROP, DROP_NON_DROP_SUMMARY.into(), Some(arg.span)) }, sym::mem_forget => { - if arg_ty.needs_drop(cx.tcx, cx.param_env) { + if arg_ty.needs_drop(cx.tcx, cx.typing_env()) { ( MEM_FORGET, Cow::Owned(format!( diff --git a/clippy_lints/src/iter_not_returning_iterator.rs b/clippy_lints/src/iter_not_returning_iterator.rs index 25105817ad9..4bc6ad0798c 100644 --- a/clippy_lints/src/iter_not_returning_iterator.rs +++ b/clippy_lints/src/iter_not_returning_iterator.rs @@ -70,7 +70,7 @@ fn check_sig(cx: &LateContext<'_>, name: Symbol, sig: &FnSig<'_>, fn_id: LocalDe .instantiate_bound_regions_with_erased(cx.tcx.fn_sig(fn_id).instantiate_identity().output()); let ret_ty = cx .tcx - .try_normalize_erasing_regions(cx.param_env, ret_ty) + .try_normalize_erasing_regions(cx.typing_env(), ret_ty) .unwrap_or(ret_ty); if cx .tcx diff --git a/clippy_lints/src/iter_without_into_iter.rs b/clippy_lints/src/iter_without_into_iter.rs index 314d0dfa26c..906da81b183 100644 --- a/clippy_lints/src/iter_without_into_iter.rs +++ b/clippy_lints/src/iter_without_into_iter.rs @@ -215,7 +215,7 @@ impl {self_ty_without_ref} {{ && implements_trait(cx, ret_ty, iterator_did, &[]) && let Some(iter_ty) = make_normalized_projection( cx.tcx, - cx.param_env, + cx.typing_env(), iterator_did, sym::Item, [ret_ty], diff --git a/clippy_lints/src/large_const_arrays.rs b/clippy_lints/src/large_const_arrays.rs index c5a2760234f..644365c9fe5 100644 --- a/clippy_lints/src/large_const_arrays.rs +++ b/clippy_lints/src/large_const_arrays.rs @@ -4,7 +4,7 @@ use rustc_errors::Applicability; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf; -use rustc_middle::ty::{self, ParamEnv}; +use rustc_middle::ty; use rustc_session::impl_lint_pass; use rustc_span::{BytePos, Pos, Span}; @@ -57,7 +57,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeConstArrays { && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity() && let ty::Array(element_type, cst) = ty.kind() && let Some((ty::ValTree::Leaf(element_count), _)) = cx.tcx - .try_normalize_erasing_regions(ParamEnv::empty(), *cst).unwrap_or(*cst).try_to_valtree() + .try_normalize_erasing_regions(cx.typing_env(), *cst).unwrap_or(*cst).try_to_valtree() && let element_count = element_count.to_target_usize(cx.tcx) && let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes()) && u128::from(self.maximum_allowed_size) < u128::from(element_count) * u128::from(element_size) diff --git a/clippy_lints/src/large_futures.rs b/clippy_lints/src/large_futures.rs index 25f9be8b2d7..593704f206a 100644 --- a/clippy_lints/src/large_futures.rs +++ b/clippy_lints/src/large_futures.rs @@ -63,7 +63,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeFuture { && let ty = cx.typeck_results().expr_ty(arg) && let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() && implements_trait(cx, ty, future_trait_def_id, &[]) - && let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty)) + && let Ok(layout) = cx.tcx.layout_of(cx.typing_env().as_query_input(ty)) && let size = layout.layout.size() && size >= Size::from_bytes(self.future_size_threshold) { diff --git a/clippy_lints/src/large_stack_frames.rs b/clippy_lints/src/large_stack_frames.rs index d2bdf194ada..5ed948c02bb 100644 --- a/clippy_lints/src/large_stack_frames.rs +++ b/clippy_lints/src/large_stack_frames.rs @@ -150,11 +150,11 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackFrames { } let mir = cx.tcx.optimized_mir(def_id); - let param_env = cx.tcx.param_env(def_id); + let typing_env = mir.typing_env(cx.tcx); let sizes_of_locals = || { mir.local_decls.iter().filter_map(|local| { - let layout = cx.tcx.layout_of(param_env.and(local.ty)).ok()?; + let layout = cx.tcx.layout_of(typing_env.as_query_input(local.ty)).ok()?; Some((local, layout.size.bytes())) }) }; diff --git a/clippy_lints/src/loops/explicit_iter_loop.rs b/clippy_lints/src/loops/explicit_iter_loop.rs index ee561ea85ed..48318682f33 100644 --- a/clippy_lints/src/loops/explicit_iter_loop.rs +++ b/clippy_lints/src/loops/explicit_iter_loop.rs @@ -151,7 +151,7 @@ fn is_ref_iterable<'tcx>( // Using by value won't consume anything if implements_trait(cx, self_ty, trait_id, &[]) && let Some(ty) = - make_normalized_projection(cx.tcx, cx.param_env, trait_id, sym!(IntoIter), [self_ty]) + make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym!(IntoIter), [self_ty]) && ty == res_ty { return Some((AdjustKind::None, self_ty)); @@ -168,7 +168,7 @@ fn is_ref_iterable<'tcx>( }; if implements_trait(cx, self_ty, trait_id, &[]) && let Some(ty) = - make_normalized_projection(cx.tcx, cx.param_env, trait_id, sym!(IntoIter), [self_ty]) + make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym!(IntoIter), [self_ty]) && ty == res_ty { return Some((AdjustKind::reborrow(mutbl), self_ty)); @@ -181,7 +181,7 @@ fn is_ref_iterable<'tcx>( // Attempt to borrow let self_ty = Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, self_ty, mutbl); if implements_trait(cx, self_ty, trait_id, &[]) - && let Some(ty) = make_normalized_projection(cx.tcx, cx.param_env, trait_id, sym!(IntoIter), [self_ty]) + && let Some(ty) = make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym!(IntoIter), [self_ty]) && ty == res_ty { return Some((AdjustKind::borrow(mutbl), self_ty)); @@ -204,7 +204,7 @@ fn is_ref_iterable<'tcx>( && target != self_ty && implements_trait(cx, target, trait_id, &[]) && let Some(ty) = - make_normalized_projection(cx.tcx, cx.param_env, trait_id, sym!(IntoIter), [target]) + make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym!(IntoIter), [target]) && ty == res_ty { Some((AdjustKind::auto_reborrow(mutbl), target)) @@ -222,7 +222,7 @@ fn is_ref_iterable<'tcx>( if is_copy(cx, target) && implements_trait(cx, target, trait_id, &[]) && let Some(ty) = - make_normalized_projection(cx.tcx, cx.param_env, trait_id, sym!(IntoIter), [target]) + make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym!(IntoIter), [target]) && ty == res_ty { Some((AdjustKind::Deref, target)) @@ -240,7 +240,7 @@ fn is_ref_iterable<'tcx>( if self_ty.is_ref() && implements_trait(cx, target, trait_id, &[]) && let Some(ty) = - make_normalized_projection(cx.tcx, cx.param_env, trait_id, sym!(IntoIter), [target]) + make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym!(IntoIter), [target]) && ty == res_ty { Some((AdjustKind::auto_borrow(mutbl), target)) diff --git a/clippy_lints/src/methods/needless_collect.rs b/clippy_lints/src/methods/needless_collect.rs index 9c41528e647..c00b9b368c4 100644 --- a/clippy_lints/src/methods/needless_collect.rs +++ b/clippy_lints/src/methods/needless_collect.rs @@ -203,10 +203,10 @@ fn is_is_empty_sig(cx: &LateContext<'_>, call_id: HirId) -> bool { fn iterates_same_ty<'tcx>(cx: &LateContext<'tcx>, iter_ty: Ty<'tcx>, collect_ty: Ty<'tcx>) -> bool { if let Some(iter_trait) = cx.tcx.get_diagnostic_item(sym::Iterator) && let Some(into_iter_trait) = cx.tcx.get_diagnostic_item(sym::IntoIterator) - && let Some(iter_item_ty) = make_normalized_projection(cx.tcx, cx.param_env, iter_trait, sym::Item, [iter_ty]) + && let Some(iter_item_ty) = make_normalized_projection(cx.tcx, cx.typing_env(), iter_trait, sym::Item, [iter_ty]) && let Some(into_iter_item_proj) = make_projection(cx.tcx, into_iter_trait, sym::Item, [collect_ty]) && let Ok(into_iter_item_ty) = cx.tcx.try_normalize_erasing_regions( - cx.param_env, + cx.typing_env(), Ty::new_projection_from_args(cx.tcx, into_iter_item_proj.def_id, into_iter_item_proj.args), ) { @@ -237,7 +237,7 @@ fn is_contains_sig(cx: &LateContext<'_>, call_id: HirId, iter_expr: &Expr<'_>) - ) && let args = cx.tcx.mk_args(&[GenericArg::from(typeck.expr_ty_adjusted(iter_expr))]) && let proj_ty = Ty::new_projection_from_args(cx.tcx, iter_item.def_id, args) - && let Ok(item_ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, proj_ty) + && let Ok(item_ty) = cx.tcx.try_normalize_erasing_regions(cx.typing_env(), proj_ty) { item_ty == EarlyBinder::bind(search_ty).instantiate(cx.tcx, cx.typeck_results().node_args(call_id)) } else { diff --git a/clippy_lints/src/methods/unnecessary_min_or_max.rs b/clippy_lints/src/methods/unnecessary_min_or_max.rs index 062d1348555..7d01bdc2269 100644 --- a/clippy_lints/src/methods/unnecessary_min_or_max.rs +++ b/clippy_lints/src/methods/unnecessary_min_or_max.rs @@ -19,7 +19,7 @@ pub(super) fn check<'tcx>( arg: &'tcx Expr<'_>, ) { let typeck_results = cx.typeck_results(); - let ecx = ConstEvalCtxt::with_env(cx.tcx, cx.param_env, typeck_results); + let ecx = ConstEvalCtxt::with_env(cx.tcx, cx.typing_env(), typeck_results); if let Some(id) = typeck_results.type_dependent_def_id(expr.hir_id) && (cx.tcx.is_diagnostic_item(sym::cmp_ord_min, id) || cx.tcx.is_diagnostic_item(sym::cmp_ord_max, id)) { diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index 82549413fa9..84ea3554a35 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -578,7 +578,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< if output_ty.contains(param_ty) { if let Ok(new_ty) = cx.tcx.try_instantiate_and_normalize_erasing_regions( new_subst, - cx.param_env, + cx.typing_env(), bound_fn_sig.rebind(output_ty), ) { expr = parent_expr; diff --git a/clippy_lints/src/methods/zst_offset.rs b/clippy_lints/src/methods/zst_offset.rs index d33021c2a7b..102fa7bc895 100644 --- a/clippy_lints/src/methods/zst_offset.rs +++ b/clippy_lints/src/methods/zst_offset.rs @@ -7,7 +7,7 @@ use super::ZST_OFFSET; pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) { if let ty::RawPtr(ty, _) = cx.typeck_results().expr_ty(recv).kind() - && let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(*ty)) + && let Ok(layout) = cx.tcx.layout_of(cx.typing_env().as_query_input(*ty)) && layout.is_zst() { span_lint(cx, ZST_OFFSET, expr.span, "offset calculation on zero-sized value"); diff --git a/clippy_lints/src/needless_borrows_for_generic_args.rs b/clippy_lints/src/needless_borrows_for_generic_args.rs index c1424b9f1dc..43b885fbd2c 100644 --- a/clippy_lints/src/needless_borrows_for_generic_args.rs +++ b/clippy_lints/src/needless_borrows_for_generic_args.rs @@ -421,7 +421,7 @@ fn replace_types<'tcx>( .expect_ty(cx.tcx) .to_ty(cx.tcx); - if let Ok(projected_ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, projection) + if let Ok(projected_ty) = cx.tcx.try_normalize_erasing_regions(cx.typing_env(), projection) && args[term_param_ty.index as usize] != GenericArg::from(projected_ty) { deque.push_back((*term_param_ty, projected_ty)); diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 5e20b406426..57fa4797c5e 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -278,23 +278,23 @@ impl<'tcx> NonCopyConst<'tcx> { fn is_value_unfrozen_expr(cx: &LateContext<'tcx>, hir_id: HirId, def_id: DefId, ty: Ty<'tcx>) -> bool { let args = cx.typeck_results().node_args(hir_id); - let result = Self::const_eval_resolve(cx.tcx, cx.param_env, ty::UnevaluatedConst::new(def_id, args), DUMMY_SP); + let result = Self::const_eval_resolve(cx.tcx, cx.typing_env(), ty::UnevaluatedConst::new(def_id, args), DUMMY_SP); Self::is_value_unfrozen_raw(cx, result, ty) } pub fn const_eval_resolve( tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, ct: ty::UnevaluatedConst<'tcx>, span: Span, ) -> EvalToValTreeResult<'tcx> { - match ty::Instance::try_resolve(tcx, param_env, ct.def, ct.args) { + match ty::Instance::try_resolve(tcx, typing_env, ct.def, ct.args) { Ok(Some(instance)) => { let cid = GlobalId { instance, promoted: None, }; - tcx.const_eval_global_id_for_typeck(param_env, cid, span) + tcx.const_eval_global_id_for_typeck(typing_env.param_env, cid, span) }, Ok(None) => Err(ErrorHandled::TooGeneric(span)), Err(err) => Err(ErrorHandled::Reported(err.into(), span)), @@ -321,7 +321,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> { // Normalize assoc types because ones originated from generic params // bounded other traits could have their bound. - let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty); + let normalized = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty); if self.interior_mut.is_interior_mut_ty(cx, normalized) // When there's no default value, lint it only according to its type; // in other words, lint consts whose value *could* be unfrozen, not definitely is. @@ -361,12 +361,12 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> { .trait_item_def_id && cx .tcx - .layout_of(cx.tcx.param_env(of_trait_def_id).and( + .layout_of(ty::TypingEnv::post_analysis(cx.tcx, of_trait_def_id).as_query_input( // Normalize assoc types because ones originated from generic params // bounded other traits could have their bound at the trait defs; // and, in that case, the definition is *not* generic. cx.tcx.normalize_erasing_regions( - cx.tcx.param_env(of_trait_def_id), + ty::TypingEnv::post_analysis(cx.tcx, of_trait_def_id), cx.tcx.type_of(of_assoc_item).instantiate_identity(), ), )) @@ -376,7 +376,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> { // similar to unknown layouts. // e.g. `layout_of(...).is_err() || has_frozen_variant(...);` && let ty = cx.tcx.type_of(impl_item.owner_id).instantiate_identity() - && let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty) + && let normalized = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty) && self.interior_mut.is_interior_mut_ty(cx, normalized) && Self::is_value_unfrozen_poly(cx, *body_id, normalized) { @@ -386,7 +386,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> { ItemKind::Impl(Impl { of_trait: None, .. }) => { let ty = cx.tcx.type_of(impl_item.owner_id).instantiate_identity(); // Normalize assoc types originated from generic params. - let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty); + let normalized = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty); if self.interior_mut.is_interior_mut_ty(cx, normalized) && Self::is_value_unfrozen_poly(cx, *body_id, normalized) diff --git a/clippy_lints/src/operators/const_comparisons.rs b/clippy_lints/src/operators/const_comparisons.rs index 5d94cfab3b0..1a0bfd8b997 100644 --- a/clippy_lints/src/operators/const_comparisons.rs +++ b/clippy_lints/src/operators/const_comparisons.rs @@ -26,7 +26,7 @@ fn comparison_to_const<'tcx>( if let ExprKind::Binary(operator, left, right) = expr.kind && let Ok(cmp_op) = CmpOp::try_from(operator.node) { - let ecx = ConstEvalCtxt::with_env(cx.tcx, cx.param_env, typeck); + let ecx = ConstEvalCtxt::with_env(cx.tcx, cx.typing_env(), typeck); match (ecx.eval(left), ecx.eval(right)) { (Some(_), Some(_)) => None, (_, Some(con)) => Some((cmp_op, left, right, con, typeck.expr_ty(right))), diff --git a/clippy_lints/src/operators/erasing_op.rs b/clippy_lints/src/operators/erasing_op.rs index 24bfe2b050b..e3fc8d8fea7 100644 --- a/clippy_lints/src/operators/erasing_op.rs +++ b/clippy_lints/src/operators/erasing_op.rs @@ -39,7 +39,7 @@ fn check_op<'tcx>( other: &Expr<'tcx>, parent: &Expr<'tcx>, ) { - if ConstEvalCtxt::with_env(cx.tcx, cx.param_env, tck).eval_simple(op) == Some(Constant::Int(0)) { + if ConstEvalCtxt::with_env(cx.tcx, cx.typing_env(), tck).eval_simple(op) == Some(Constant::Int(0)) { if different_types(tck, other, parent) { return; } diff --git a/clippy_lints/src/operators/float_cmp.rs b/clippy_lints/src/operators/float_cmp.rs index ab5f91c1d67..8272d3643d4 100644 --- a/clippy_lints/src/operators/float_cmp.rs +++ b/clippy_lints/src/operators/float_cmp.rs @@ -17,8 +17,7 @@ pub(crate) fn check<'tcx>( right: &'tcx Expr<'_>, ) { if (op == BinOpKind::Eq || op == BinOpKind::Ne) && is_float(cx, left) { - let typeck = cx.typeck_results(); - let ecx = ConstEvalCtxt::with_env(cx.tcx, cx.param_env, typeck); + let ecx = ConstEvalCtxt::new(cx); let left_is_local = match ecx.eval_with_source(left) { Some((c, s)) if !is_allowed(&c) => s.is_local(), Some(_) => return, diff --git a/clippy_lints/src/redundant_slicing.rs b/clippy_lints/src/redundant_slicing.rs index dc66fb28fa8..0ac818c21d9 100644 --- a/clippy_lints/src/redundant_slicing.rs +++ b/clippy_lints/src/redundant_slicing.rs @@ -136,7 +136,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing { }); } else if let Some(target_id) = cx.tcx.lang_items().deref_target() { if let Ok(deref_ty) = cx.tcx.try_normalize_erasing_regions( - cx.param_env, + cx.typing_env(), Ty::new_projection_from_args(cx.tcx, target_id, cx.tcx.mk_args(&[GenericArg::from(indexed_ty)])), ) { if deref_ty == expr_ty { diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index 1e0f6dff1ab..aeff31d02d2 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -391,7 +391,7 @@ fn check_final_expr<'tcx>( if let Some(inner) = inner { if for_each_unconsumed_temporary(cx, inner, |temporary_ty| { - if temporary_ty.has_significant_drop(cx.tcx, cx.param_env) + if temporary_ty.has_significant_drop(cx.tcx, cx.typing_env()) && temporary_ty .walk() .any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(re) if !re.is_static())) diff --git a/clippy_lints/src/significant_drop_tightening.rs b/clippy_lints/src/significant_drop_tightening.rs index abd8363456d..1a5b958e6a6 100644 --- a/clippy_lints/src/significant_drop_tightening.rs +++ b/clippy_lints/src/significant_drop_tightening.rs @@ -154,7 +154,7 @@ impl<'cx, 'others, 'tcx> AttrChecker<'cx, 'others, 'tcx> { let ty = self .cx .tcx - .try_normalize_erasing_regions(self.cx.param_env, ty) + .try_normalize_erasing_regions(self.cx.typing_env(), ty) .unwrap_or(ty); match self.type_cache.entry(ty) { Entry::Occupied(e) => return *e.get(), diff --git a/clippy_lints/src/trailing_empty_array.rs b/clippy_lints/src/trailing_empty_array.rs index 52bb7c4bd68..50a1577b288 100644 --- a/clippy_lints/src/trailing_empty_array.rs +++ b/clippy_lints/src/trailing_empty_array.rs @@ -58,7 +58,7 @@ fn is_struct_with_trailing_zero_sized_array<'tcx>(cx: &LateContext<'tcx>, item: && let Some(last_field) = data.fields().last() && let field_ty = cx .tcx - .normalize_erasing_regions(cx.param_env, cx.tcx.type_of(last_field.def_id).instantiate_identity()) + .normalize_erasing_regions(cx.typing_env(), cx.tcx.type_of(last_field.def_id).instantiate_identity()) && let ty::Array(_, array_len) = *field_ty.kind() && let Some(0) = array_len.try_to_target_usize(cx.tcx) { diff --git a/clippy_lints/src/transmute/eager_transmute.rs b/clippy_lints/src/transmute/eager_transmute.rs index ca9daf2d2a0..1209bd5b34f 100644 --- a/clippy_lints/src/transmute/eager_transmute.rs +++ b/clippy_lints/src/transmute/eager_transmute.rs @@ -88,8 +88,8 @@ pub(super) fn check<'tcx>( && is_normalizable(cx, cx.param_env, to_ty) // we only want to lint if the target type has a niche that is larger than the one of the source type // e.g. `u8` to `NonZero` should lint, but `NonZero` to `u8` should not - && let Ok(from_layout) = cx.tcx.layout_of(cx.param_env.and(from_ty)) - && let Ok(to_layout) = cx.tcx.layout_of(cx.param_env.and(to_ty)) + && let Ok(from_layout) = cx.tcx.layout_of(cx.typing_env().as_query_input(from_ty)) + && let Ok(to_layout) = cx.tcx.layout_of(cx.typing_env().as_query_input(to_ty)) && match (from_layout.largest_niche, to_layout.largest_niche) { (Some(from_niche), Some(to_niche)) => !range_fully_contained(from_niche.valid_range, to_niche.valid_range), (None, Some(_)) => true, diff --git a/clippy_lints/src/transmute/transmute_undefined_repr.rs b/clippy_lints/src/transmute/transmute_undefined_repr.rs index 3b32e4396b9..4dc1290e8b1 100644 --- a/clippy_lints/src/transmute/transmute_undefined_repr.rs +++ b/clippy_lints/src/transmute/transmute_undefined_repr.rs @@ -244,7 +244,7 @@ enum ReducedTy<'tcx> { /// Reduce structs containing a single non-zero sized field to it's contained type. fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx> { loop { - ty = cx.tcx.try_normalize_erasing_regions(cx.param_env, ty).unwrap_or(ty); + ty = cx.tcx.try_normalize_erasing_regions(cx.typing_env(), ty).unwrap_or(ty); return match *ty.kind() { ty::Array(sub_ty, _) if matches!(sub_ty.kind(), ty::Int(_) | ty::Uint(_)) => { ReducedTy::TypeErasure { raw_ptr_only: false } @@ -297,8 +297,8 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx> } fn is_zero_sized_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { - if let Ok(ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, ty) - && let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty)) + if let Ok(ty) = cx.tcx.try_normalize_erasing_regions(cx.typing_env(), ty) + && let Ok(layout) = cx.tcx.layout_of(cx.typing_env().as_query_input(ty)) { layout.layout.size().bytes() == 0 } else { diff --git a/clippy_lints/src/transmute/utils.rs b/clippy_lints/src/transmute/utils.rs index e8ccd35b4da..5baa67b1f3e 100644 --- a/clippy_lints/src/transmute/utils.rs +++ b/clippy_lints/src/transmute/utils.rs @@ -4,10 +4,11 @@ use rustc_middle::ty::Ty; // 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 { - 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)) - && let Ok(to_layout) = cx.tcx.layout_of(cx.param_env.and(to)) + let typing_env = cx.typing_env(); + if let Ok(from) = cx.tcx.try_normalize_erasing_regions(typing_env, from) + && let Ok(to) = cx.tcx.try_normalize_erasing_regions(typing_env, to) + && let Ok(from_layout) = cx.tcx.layout_of(typing_env.as_query_input(from)) + && let Ok(to_layout) = cx.tcx.layout_of(typing_env.as_query_input(to)) { from_layout.size != to_layout.size || from_layout.align.abi != to_layout.align.abi } else { diff --git a/clippy_lints/src/uninhabited_references.rs b/clippy_lints/src/uninhabited_references.rs index cfa565cf803..ee9ef017253 100644 --- a/clippy_lints/src/uninhabited_references.rs +++ b/clippy_lints/src/uninhabited_references.rs @@ -46,7 +46,7 @@ impl LateLintPass<'_> for UninhabitedReferences { if let ExprKind::Unary(UnOp::Deref, _) = expr.kind { let ty = cx.typeck_results().expr_ty_adjusted(expr); - if ty.is_privately_uninhabited(cx.tcx, cx.param_env) { + if ty.is_privately_uninhabited(cx.tcx, cx.typing_env()) { span_lint( cx, UNINHABITED_REFERENCES, @@ -71,7 +71,7 @@ impl LateLintPass<'_> for UninhabitedReferences { } if let FnRetTy::Return(hir_ty) = fndecl.output && let TyKind::Ref(_, mut_ty) = hir_ty.kind - && lower_ty(cx.tcx, mut_ty.ty).is_privately_uninhabited(cx.tcx, cx.param_env) + && lower_ty(cx.tcx, mut_ty.ty).is_privately_uninhabited(cx.tcx, cx.typing_env()) { span_lint( cx, diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 24a02c7ef87..52c98646289 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -18,7 +18,7 @@ use rustc_lexer::tokenize; use rustc_lint::LateContext; use rustc_middle::mir::ConstValue; use rustc_middle::mir::interpret::{Scalar, alloc_range}; -use rustc_middle::ty::{self, FloatTy, IntTy, ParamEnv, ScalarInt, Ty, TyCtxt, TypeckResults, UintTy}; +use rustc_middle::ty::{self, FloatTy, IntTy, ScalarInt, Ty, TyCtxt, TypeckResults, UintTy}; use rustc_middle::{bug, mir, span_bug}; use rustc_span::def_id::DefId; use rustc_span::symbol::Ident; @@ -387,7 +387,7 @@ impl Ord for FullInt { /// See the module level documentation for some context. pub struct ConstEvalCtxt<'tcx> { tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, typeck: &'tcx TypeckResults<'tcx>, source: Cell, } @@ -398,17 +398,17 @@ impl<'tcx> ConstEvalCtxt<'tcx> { pub fn new(cx: &LateContext<'tcx>) -> Self { Self { tcx: cx.tcx, - param_env: cx.param_env, + typing_env: cx.typing_env(), typeck: cx.typeck_results(), source: Cell::new(ConstantSource::Local), } } /// Creates an evaluation context. - pub fn with_env(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, typeck: &'tcx TypeckResults<'tcx>) -> Self { + pub fn with_env(tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>, typeck: &'tcx TypeckResults<'tcx>) -> Self { Self { tcx, - param_env, + typing_env, typeck, source: Cell::new(ConstantSource::Local), } @@ -643,7 +643,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> { let args = self.typeck.node_args(id); let result = self .tcx - .const_eval_resolve(self.param_env, mir::UnevaluatedConst::new(def_id, args), qpath.span()) + .const_eval_resolve(self.typing_env, mir::UnevaluatedConst::new(def_id, args), qpath.span()) .ok() .map(|val| mir::Const::from_value(val, ty))?; f(self, result) diff --git a/clippy_utils/src/eager_or_lazy.rs b/clippy_utils/src/eager_or_lazy.rs index a2e97919d04..7f0363ac942 100644 --- a/clippy_utils/src/eager_or_lazy.rs +++ b/clippy_utils/src/eager_or_lazy.rs @@ -105,7 +105,7 @@ fn res_has_significant_drop(res: Res, cx: &LateContext<'_>, e: &Expr<'_>) -> boo { cx.typeck_results() .expr_ty(e) - .has_significant_drop(cx.tcx, cx.param_env) + .has_significant_drop(cx.tcx, cx.typing_env()) } else { false } diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index c73ab4bfa68..ea866a78d87 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -297,8 +297,8 @@ impl HirEqInterExpr<'_, '_, '_> { if let Some((typeck_lhs, typeck_rhs)) = self.inner.maybe_typeck_results && typeck_lhs.expr_ty(left) == typeck_rhs.expr_ty(right) && let (Some(l), Some(r)) = ( - ConstEvalCtxt::with_env(self.inner.cx.tcx, self.inner.cx.param_env, typeck_lhs).eval_simple(left), - ConstEvalCtxt::with_env(self.inner.cx.tcx, self.inner.cx.param_env, typeck_rhs).eval_simple(right), + ConstEvalCtxt::with_env(self.inner.cx.tcx, self.inner.cx.typing_env(), typeck_lhs).eval_simple(left), + ConstEvalCtxt::with_env(self.inner.cx.tcx, self.inner.cx.typing_env(), typeck_rhs).eval_simple(right), ) && l == r { @@ -813,7 +813,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { #[expect(clippy::too_many_lines)] pub fn hash_expr(&mut self, e: &Expr<'_>) { let simple_const = self.maybe_typeck_results.and_then(|typeck_results| { - ConstEvalCtxt::with_env(self.cx.tcx, self.cx.param_env, typeck_results).eval_simple(e) + ConstEvalCtxt::with_env(self.cx.tcx, self.cx.typing_env(), typeck_results).eval_simple(e) }); // const hashing may result in the same hash as some unrelated node, so add a sort of diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 19316a90683..f28e5c9ed0e 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1631,7 +1631,7 @@ pub fn is_integer_const(cx: &LateContext<'_>, e: &Expr<'_>, value: u128) -> bool } let enclosing_body = cx.tcx.hir().enclosing_body_owner(e.hir_id); if let Some(Constant::Int(v)) = - ConstEvalCtxt::with_env(cx.tcx, cx.tcx.param_env(enclosing_body), cx.tcx.typeck(enclosing_body)).eval(e) + ConstEvalCtxt::with_env(cx.tcx, cx.typing_env(), cx.tcx.typeck(enclosing_body)).eval(e) { return value == v; } diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index 971f8eeb1b3..abadca71400 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -142,7 +142,7 @@ fn check_rvalue<'tcx>( // We cannot allow this for now. return Err((span, "unsizing casts are only allowed for references right now".into())); }; - let unsized_ty = tcx.struct_tail_for_codegen(pointee_ty, tcx.param_env(def_id)); + let unsized_ty = tcx.struct_tail_for_codegen(pointee_ty, ty::TypingEnv::post_analysis(tcx, def_id)); if let ty::Slice(_) | ty::Str = unsized_ty.kind() { check_operand(tcx, op, span, body, msrv)?; // Casting/coercing things to slices is fine. @@ -408,15 +408,17 @@ fn is_ty_const_destruct<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, body: &Body<'tcx> return true; } + + let (infcx, param_env) = + tcx.infer_ctxt().build_with_typing_env(body.typing_env(tcx)); // FIXME(const_trait_impl) constness let obligation = Obligation::new( tcx, ObligationCause::dummy_with_span(body.span), - ConstCx::new(tcx, body).param_env, + param_env, TraitRef::new(tcx, tcx.require_lang_item(LangItem::Destruct, Some(body.span)), [ty]), ); - let infcx = tcx.infer_ctxt().build(body.typing_mode(tcx)); let mut selcx = SelectionContext::new(&infcx); let Some(impl_src) = selcx.select(&obligation).ok().flatten() else { return false; @@ -434,5 +436,5 @@ fn is_ty_const_destruct<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, body: &Body<'tcx> ocx.select_all_or_error().is_empty() } - !ty.needs_drop(tcx, ConstCx::new(tcx, body).param_env) + !ty.needs_drop(tcx, ConstCx::new(tcx, body).typing_env) } diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 770cd9c3786..2aad867dc0d 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -467,7 +467,7 @@ pub fn needs_ordered_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { if !seen.insert(ty) { return false; } - if !ty.has_significant_drop(cx.tcx, cx.param_env) { + if !ty.has_significant_drop(cx.tcx, cx.typing_env()) { false } // Check for std types which implement drop, but only for memory allocation. @@ -575,8 +575,9 @@ pub fn same_type_and_consts<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { /// Checks if a given type looks safe to be uninitialized. pub fn is_uninit_value_valid_for_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { + let typing_env = cx.typing_env().with_reveal_all_normalized(cx.tcx); cx.tcx - .check_validity_requirement((ValidityRequirement::Uninit, cx.param_env.and(ty))) + .check_validity_requirement((ValidityRequirement::Uninit, typing_env.as_query_input(ty))) .unwrap_or_else(|_| is_uninit_value_valid_for_ty_fallback(cx, ty)) } @@ -725,7 +726,7 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option None, } }, - ty::Alias(ty::Projection, proj) => match cx.tcx.try_normalize_erasing_regions(cx.param_env, ty) { + ty::Alias(ty::Projection, proj) => match cx.tcx.try_normalize_erasing_regions(cx.typing_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)), }, @@ -1111,12 +1112,12 @@ pub fn make_projection<'tcx>( /// succeeds as well as everything checked by `make_projection`. pub fn make_normalized_projection<'tcx>( tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, container_id: DefId, assoc_ty: Symbol, args: impl IntoIterator>>, ) -> Option> { - fn helper<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: AliasTy<'tcx>) -> Option> { + fn helper<'tcx>(tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>, ty: AliasTy<'tcx>) -> Option> { #[cfg(debug_assertions)] if let Some((i, arg)) = ty .args @@ -1132,7 +1133,7 @@ pub fn make_normalized_projection<'tcx>( ); return None; } - match tcx.try_normalize_erasing_regions(param_env, Ty::new_projection_from_args(tcx, ty.def_id, ty.args)) { + match tcx.try_normalize_erasing_regions(typing_env, Ty::new_projection_from_args(tcx, ty.def_id, ty.args)) { Ok(ty) => Some(ty), Err(e) => { debug_assert!(false, "failed to normalize type `{ty}`: {e:#?}"); @@ -1140,7 +1141,7 @@ pub fn make_normalized_projection<'tcx>( }, } } - helper(tcx, param_env, make_projection(tcx, container_id, assoc_ty, args)?) + helper(tcx, typing_env, make_projection(tcx, container_id, assoc_ty, args)?) } /// Helper to check if given type has inner mutability such as [`std::cell::Cell`] or @@ -1300,7 +1301,7 @@ pub fn deref_chain<'cx, 'tcx>(cx: &'cx LateContext<'tcx>, ty: Ty<'tcx>) -> impl if let Some(deref_did) = cx.tcx.lang_items().deref_trait() && implements_trait(cx, ty, deref_did, &[]) { - make_normalized_projection(cx.tcx, cx.param_env, deref_did, sym::Target, [ty]) + make_normalized_projection(cx.tcx, cx.typing_env(), deref_did, sym::Target, [ty]) } else { None } From d8423ca28c0285edf6b02d883e0f7e27b62a3b90 Mon Sep 17 00:00:00 2001 From: overlookmotel Date: Mon, 18 Nov 2024 14:03:16 +0000 Subject: [PATCH 16/45] `missing_safety_doc` accept capitalized "SAFETY" --- clippy_lints/src/doc/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/clippy_lints/src/doc/mod.rs b/clippy_lints/src/doc/mod.rs index df7c37a192a..a7041b3b649 100644 --- a/clippy_lints/src/doc/mod.rs +++ b/clippy_lints/src/doc/mod.rs @@ -917,6 +917,7 @@ fn check_doc<'a, Events: Iterator, Range Date: Mon, 18 Nov 2024 16:31:10 +0000 Subject: [PATCH 17/45] Remove extern vectorcall tests --- .../missing_const_for_fn/could_be_const.fixed | 6 +---- .../ui/missing_const_for_fn/could_be_const.rs | 6 +---- .../could_be_const.stderr | 24 +------------------ 3 files changed, 3 insertions(+), 33 deletions(-) diff --git a/tests/ui/missing_const_for_fn/could_be_const.fixed b/tests/ui/missing_const_for_fn/could_be_const.fixed index 754fe061c4a..014fbb85c7a 100644 --- a/tests/ui/missing_const_for_fn/could_be_const.fixed +++ b/tests/ui/missing_const_for_fn/could_be_const.fixed @@ -1,6 +1,6 @@ #![warn(clippy::missing_const_for_fn)] #![allow(incomplete_features, clippy::let_and_return, clippy::missing_transmute_annotations)] -#![feature(const_trait_impl, abi_vectorcall)] +#![feature(const_trait_impl)] use std::mem::transmute; @@ -211,8 +211,4 @@ mod extern_fn { //~^ ERROR: this could be a `const fn` const extern "system-unwind" fn system_unwind() {} //~^ ERROR: this could be a `const fn` - pub const extern "vectorcall" fn std_call() {} - //~^ ERROR: this could be a `const fn` - pub const extern "vectorcall-unwind" fn std_call_unwind() {} - //~^ ERROR: this could be a `const fn` } diff --git a/tests/ui/missing_const_for_fn/could_be_const.rs b/tests/ui/missing_const_for_fn/could_be_const.rs index 460be0733e0..4f7c2cbcf0b 100644 --- a/tests/ui/missing_const_for_fn/could_be_const.rs +++ b/tests/ui/missing_const_for_fn/could_be_const.rs @@ -1,6 +1,6 @@ #![warn(clippy::missing_const_for_fn)] #![allow(incomplete_features, clippy::let_and_return, clippy::missing_transmute_annotations)] -#![feature(const_trait_impl, abi_vectorcall)] +#![feature(const_trait_impl)] use std::mem::transmute; @@ -211,8 +211,4 @@ mod extern_fn { //~^ ERROR: this could be a `const fn` extern "system-unwind" fn system_unwind() {} //~^ ERROR: this could be a `const fn` - pub extern "vectorcall" fn std_call() {} - //~^ ERROR: this could be a `const fn` - pub extern "vectorcall-unwind" fn std_call_unwind() {} - //~^ ERROR: this could be a `const fn` } diff --git a/tests/ui/missing_const_for_fn/could_be_const.stderr b/tests/ui/missing_const_for_fn/could_be_const.stderr index d553c522556..cc7dfd0888d 100644 --- a/tests/ui/missing_const_for_fn/could_be_const.stderr +++ b/tests/ui/missing_const_for_fn/could_be_const.stderr @@ -316,27 +316,5 @@ help: make the function `const` LL | const extern "system-unwind" fn system_unwind() {} | +++++ -error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:214:5 - | -LL | pub extern "vectorcall" fn std_call() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: make the function `const` - | -LL | pub const extern "vectorcall" fn std_call() {} - | +++++ - -error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:216:5 - | -LL | pub extern "vectorcall-unwind" fn std_call_unwind() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: make the function `const` - | -LL | pub const extern "vectorcall-unwind" fn std_call_unwind() {} - | +++++ - -error: aborting due to 26 previous errors +error: aborting due to 24 previous errors From eaec0cab7e302263e8791c2724c6f399ddb31ad1 Mon Sep 17 00:00:00 2001 From: Samuel Moelius Date: Mon, 21 Oct 2024 20:37:19 -0400 Subject: [PATCH 18/45] Fix 13578 (#13583) changelog: don't consider lifetimes in bounded types unused (fix `extra_unused_lifetimes` FP #13578) --- clippy_lints/src/lifetimes.rs | 56 +++++++++++++++++++++++++----- tests/ui/extra_unused_lifetimes.rs | 7 ++++ 2 files changed, 55 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index ce0e1a24a7b..bf898d0800b 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -1,6 +1,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::trait_ref_of_method; use itertools::Itertools; +use rustc_ast::visit::{try_visit, walk_list}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::Applicability; use rustc_hir::FnRetTy::Return; @@ -11,8 +12,8 @@ use rustc_hir::intravisit::{ }; use rustc_hir::{ BareFnTy, BodyId, FnDecl, FnSig, GenericArg, GenericArgs, GenericBound, GenericParam, GenericParamKind, Generics, - Impl, ImplItem, ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, LifetimeParamKind, Node, PolyTraitRef, - PredicateOrigin, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate, lang_items, + HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, LifetimeParamKind, Node, PolyTraitRef, + PredicateOrigin, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WhereBoundPredicate, WherePredicate, lang_items, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::map::Map; @@ -483,6 +484,7 @@ fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, generics: &'tcx Generics<'_ struct Usage { lifetime: Lifetime, in_where_predicate: bool, + in_bounded_ty: bool, in_generics_arg: bool, } @@ -490,11 +492,15 @@ struct LifetimeChecker<'cx, 'tcx, F> { cx: &'cx LateContext<'tcx>, map: FxIndexMap>, where_predicate_depth: usize, + bounded_ty_depth: usize, generic_args_depth: usize, phantom: std::marker::PhantomData, } -impl<'cx, 'tcx, F> LifetimeChecker<'cx, 'tcx, F> { +impl<'cx, 'tcx, F> LifetimeChecker<'cx, 'tcx, F> +where + F: NestedFilter<'tcx>, +{ fn new(cx: &'cx LateContext<'tcx>, generics: &'tcx Generics<'_>) -> LifetimeChecker<'cx, 'tcx, F> { let map = generics .params @@ -510,10 +516,30 @@ impl<'cx, 'tcx, F> LifetimeChecker<'cx, 'tcx, F> { cx, map, where_predicate_depth: 0, + bounded_ty_depth: 0, generic_args_depth: 0, phantom: std::marker::PhantomData, } } + + // `visit_where_bound_predicate` is based on: + // https://github.com/rust-lang/rust/blob/864cee3ea383cc8254ba394ba355e648faa9cfa5/compiler/rustc_hir/src/intravisit.rs#L936-L939 + fn visit_where_bound_predicate( + &mut self, + hir_id: HirId, + bounded_ty: &'tcx Ty<'tcx>, + bounds: &'tcx [GenericBound<'tcx>], + bound_generic_params: &'tcx [GenericParam<'tcx>], + ) { + try_visit!(self.visit_id(hir_id)); + + self.bounded_ty_depth += 1; + try_visit!(self.visit_ty(bounded_ty)); + self.bounded_ty_depth -= 1; + + walk_list!(self, visit_param_bound, bounds); + walk_list!(self, visit_generic_param, bound_generic_params); + } } impl<'tcx, F> Visitor<'tcx> for LifetimeChecker<'_, 'tcx, F> @@ -531,6 +557,7 @@ where usages.push(Usage { lifetime: *lifetime, in_where_predicate: self.where_predicate_depth != 0, + in_bounded_ty: self.bounded_ty_depth != 0, in_generics_arg: self.generic_args_depth != 0, }); } @@ -538,7 +565,19 @@ where fn visit_where_predicate(&mut self, predicate: &'tcx WherePredicate<'tcx>) { self.where_predicate_depth += 1; - walk_where_predicate(self, predicate); + if let &WherePredicate::BoundPredicate(WhereBoundPredicate { + hir_id, + bounded_ty, + bounds, + bound_generic_params, + origin: _, + span: _, + }) = predicate + { + self.visit_where_bound_predicate(hir_id, bounded_ty, bounds, bound_generic_params); + } else { + walk_where_predicate(self, predicate); + } self.where_predicate_depth -= 1; } @@ -562,7 +601,7 @@ fn report_extra_lifetimes<'tcx>(cx: &LateContext<'tcx>, func: &'tcx FnDecl<'_>, for (def_id, usages) in checker.map { if usages .iter() - .all(|usage| usage.in_where_predicate && !usage.in_generics_arg) + .all(|usage| usage.in_where_predicate && !usage.in_bounded_ty && !usage.in_generics_arg) { span_lint( cx, @@ -589,7 +628,7 @@ fn report_extra_impl_lifetimes<'tcx>(cx: &LateContext<'tcx>, impl_: &'tcx Impl<' for (&def_id, usages) in &checker.map { if usages .iter() - .all(|usage| usage.in_where_predicate && !usage.in_generics_arg) + .all(|usage| usage.in_where_predicate && !usage.in_bounded_ty && !usage.in_generics_arg) { span_lint( cx, @@ -605,8 +644,8 @@ fn report_extra_impl_lifetimes<'tcx>(cx: &LateContext<'tcx>, impl_: &'tcx Impl<' // An `impl` lifetime is elidable if it satisfies the following conditions: // - It is used exactly once. -// - That single use is not in `GenericArgs` in a `WherePredicate`. (Note that `GenericArgs` are -// different from `GenericParam`s.) +// - That single use is not in a bounded type or `GenericArgs` in a `WherePredicate`. (Note that +// `GenericArgs` are different from `GenericParam`s.) fn report_elidable_impl_lifetimes<'tcx>( cx: &LateContext<'tcx>, impl_: &'tcx Impl<'_>, @@ -623,6 +662,7 @@ fn report_elidable_impl_lifetimes<'tcx>( } | Usage { lifetime, + in_bounded_ty: false, in_generics_arg: false, .. }, diff --git a/tests/ui/extra_unused_lifetimes.rs b/tests/ui/extra_unused_lifetimes.rs index 17d2ed9f50c..aa964af3fc2 100644 --- a/tests/ui/extra_unused_lifetimes.rs +++ b/tests/ui/extra_unused_lifetimes.rs @@ -134,4 +134,11 @@ struct Human<'a> { pub name: &'a str, } +// https://github.com/rust-lang/rust-clippy/issues/13578 +mod issue_13578 { + pub trait Foo {} + + impl<'a, T: 'a> Foo for Option where &'a T: Foo {} +} + fn main() {} From 66715532ab313f506f77897567b5ad823f7c4266 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Fri, 15 Nov 2024 21:06:17 +0100 Subject: [PATCH 19/45] Add `cargo dev sync` subcommand Currently this only provides the feature to auto-update the nightly version in the `rust-toolchain` file and the `clippy_utils/README.md` file. The actual sync to and from the Rust repo will be added with the move to Josh. --- clippy_dev/Cargo.toml | 1 + clippy_dev/src/lib.rs | 1 + clippy_dev/src/main.rs | 20 +++++++++++++++++++- clippy_dev/src/sync.rs | 33 +++++++++++++++++++++++++++++++++ rust-toolchain | 2 ++ 5 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 clippy_dev/src/sync.rs diff --git a/clippy_dev/Cargo.toml b/clippy_dev/Cargo.toml index 952a8711fb4..d3a103eaf4c 100644 --- a/clippy_dev/Cargo.toml +++ b/clippy_dev/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" [dependencies] aho-corasick = "1.0" +chrono = { version = "0.4.38", default-features = false, features = ["clock"] } clap = { version = "4.4", features = ["derive"] } indoc = "1.0" itertools = "0.12" diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs index d96b79ec26c..6505b33d345 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -20,5 +20,6 @@ pub mod lint; pub mod new_lint; pub mod serve; pub mod setup; +pub mod sync; pub mod update_lints; pub mod utils; diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index f5055b42912..541ce50b6e0 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -3,7 +3,7 @@ #![warn(rust_2018_idioms, unused_lifetimes)] use clap::{Args, Parser, Subcommand}; -use clippy_dev::{dogfood, fmt, lint, new_lint, serve, setup, update_lints, utils}; +use clippy_dev::{dogfood, fmt, lint, new_lint, serve, setup, sync, update_lints, utils}; use std::convert::Infallible; fn main() { @@ -75,6 +75,9 @@ fn main() { uplift, } => update_lints::rename(&old_name, new_name.as_ref().unwrap_or(&old_name), uplift), DevCommand::Deprecate { name, reason } => update_lints::deprecate(&name, &reason), + DevCommand::Sync(SyncCommand { subcommand }) => match subcommand { + SyncSubcommand::UpdateNightly => sync::update_nightly(), + }, } } @@ -225,6 +228,8 @@ enum DevCommand { /// The reason for deprecation reason: String, }, + /// Sync between the rust repo and the Clippy repo + Sync(SyncCommand), } #[derive(Args)] @@ -291,3 +296,16 @@ enum RemoveSubcommand { /// Remove the tasks added with 'cargo dev setup vscode-tasks' VscodeTasks, } + +#[derive(Args)] +struct SyncCommand { + #[command(subcommand)] + subcommand: SyncSubcommand, +} + +#[derive(Subcommand)] +enum SyncSubcommand { + #[command(name = "update_nightly")] + /// Update nightly version in rust-toolchain and `clippy_utils` + UpdateNightly, +} diff --git a/clippy_dev/src/sync.rs b/clippy_dev/src/sync.rs new file mode 100644 index 00000000000..3522d182e90 --- /dev/null +++ b/clippy_dev/src/sync.rs @@ -0,0 +1,33 @@ +use std::fmt::Write; +use std::path::Path; + +use chrono::offset::Utc; + +use crate::utils::{UpdateMode, replace_region_in_file}; + +pub fn update_nightly() { + // Update rust-toolchain nightly version + let date = Utc::now().format("%Y-%m-%d").to_string(); + replace_region_in_file( + UpdateMode::Change, + Path::new("rust-toolchain"), + "# begin autogenerated nightly\n", + "# end autogenerated nightly", + |res| { + writeln!(res, "channel = \"nightly-{date}\"").unwrap(); + }, + ); + + // Update clippy_utils nightly version + replace_region_in_file( + UpdateMode::Change, + Path::new("clippy_utils/README.md"), + "\n", + "", + |res| { + writeln!(res, "```").unwrap(); + writeln!(res, "nightly-{date}").unwrap(); + writeln!(res, "```").unwrap(); + }, + ); +} diff --git a/rust-toolchain b/rust-toolchain index e32e0cb3604..0a2e9d89b6e 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,6 @@ [toolchain] +# begin autogenerated nightly channel = "nightly-2024-11-14" +# end autogenerated nightly components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] profile = "minimal" From 93d5ccdba7ce49525a43fd0c05b707aedbf8aa12 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Fri, 15 Nov 2024 21:12:30 +0100 Subject: [PATCH 20/45] Add `cargo dev release` subcommand Currently this only provides the feature to auto-update the versions in the `Cargo.toml` files. With the move to Josh, a command to get beta and stable release commits will be added. --- Cargo.toml | 2 ++ clippy_config/Cargo.toml | 2 ++ clippy_dev/src/lib.rs | 1 + clippy_dev/src/main.rs | 20 +++++++++++++++++++- clippy_dev/src/release.rs | 27 +++++++++++++++++++++++++++ clippy_lints/Cargo.toml | 2 ++ clippy_utils/Cargo.toml | 2 ++ 7 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 clippy_dev/src/release.rs diff --git a/Cargo.toml b/Cargo.toml index ee9c57ab835..79b9af7b0bf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,8 @@ [package] name = "clippy" +# begin autogenerated version version = "0.1.84" +# end autogenerated version 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_config/Cargo.toml b/clippy_config/Cargo.toml index 0cd0cabc3a6..d1158b48e92 100644 --- a/clippy_config/Cargo.toml +++ b/clippy_config/Cargo.toml @@ -1,6 +1,8 @@ [package] name = "clippy_config" +# begin autogenerated version version = "0.1.84" +# end autogenerated version edition = "2021" publish = false diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs index 6505b33d345..9280369c23b 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -18,6 +18,7 @@ pub mod dogfood; pub mod fmt; pub mod lint; pub mod new_lint; +pub mod release; pub mod serve; pub mod setup; pub mod sync; diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index 541ce50b6e0..56ed60256f1 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -3,7 +3,7 @@ #![warn(rust_2018_idioms, unused_lifetimes)] use clap::{Args, Parser, Subcommand}; -use clippy_dev::{dogfood, fmt, lint, new_lint, serve, setup, sync, update_lints, utils}; +use clippy_dev::{dogfood, fmt, lint, new_lint, release, serve, setup, sync, update_lints, utils}; use std::convert::Infallible; fn main() { @@ -78,6 +78,9 @@ fn main() { DevCommand::Sync(SyncCommand { subcommand }) => match subcommand { SyncSubcommand::UpdateNightly => sync::update_nightly(), }, + DevCommand::Release(ReleaseCommand { subcommand }) => match subcommand { + ReleaseSubcommand::BumpVersion => release::bump_version(), + }, } } @@ -230,6 +233,8 @@ enum DevCommand { }, /// Sync between the rust repo and the Clippy repo Sync(SyncCommand), + /// Manage Clippy releases + Release(ReleaseCommand), } #[derive(Args)] @@ -309,3 +314,16 @@ enum SyncSubcommand { /// Update nightly version in rust-toolchain and `clippy_utils` UpdateNightly, } + +#[derive(Args)] +struct ReleaseCommand { + #[command(subcommand)] + subcommand: ReleaseSubcommand, +} + +#[derive(Subcommand)] +enum ReleaseSubcommand { + #[command(name = "bump_version")] + /// Bump the version in the Cargo.toml files + BumpVersion, +} diff --git a/clippy_dev/src/release.rs b/clippy_dev/src/release.rs new file mode 100644 index 00000000000..ac755168701 --- /dev/null +++ b/clippy_dev/src/release.rs @@ -0,0 +1,27 @@ +use std::fmt::Write; +use std::path::Path; + +use crate::utils::{UpdateMode, clippy_version, replace_region_in_file}; + +const CARGO_TOML_FILES: [&str; 4] = [ + "clippy_config/Cargo.toml", + "clippy_lints/Cargo.toml", + "clippy_utils/Cargo.toml", + "Cargo.toml", +]; + +pub fn bump_version() { + let (minor, mut patch) = clippy_version(); + patch += 1; + for file in &CARGO_TOML_FILES { + replace_region_in_file( + UpdateMode::Change, + Path::new(file), + "# begin autogenerated version\n", + "# end autogenerated version", + |res| { + writeln!(res, "version = \"0.{minor}.{patch}\"").unwrap(); + }, + ); + } +} diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index 63ea6faf60d..be99dcc2c7c 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -1,6 +1,8 @@ [package] name = "clippy_lints" +# begin autogenerated version version = "0.1.84" +# end autogenerated version 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 fb2acf700ab..4f95889a53a 100644 --- a/clippy_utils/Cargo.toml +++ b/clippy_utils/Cargo.toml @@ -1,6 +1,8 @@ [package] name = "clippy_utils" +# begin autogenerated version version = "0.1.84" +# end autogenerated version edition = "2021" description = "Helpful tools for writing lints, provided as they are used in Clippy" repository = "https://github.com/rust-lang/rust-clippy" From 809b420e16d462e925399be8c7289fb18bac8689 Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 19 Nov 2024 16:13:55 +0100 Subject: [PATCH 21/45] move `fn is_item_raw` to `TypingEnv` --- clippy_lints/src/casts/ptr_as_ptr.rs | 2 +- clippy_lints/src/dereference.rs | 2 +- clippy_lints/src/functions/must_use.rs | 2 +- clippy_lints/src/let_if_seq.rs | 2 +- clippy_lints/src/methods/manual_inspect.rs | 6 +++--- clippy_lints/src/mut_mut.rs | 2 +- clippy_lints/src/needless_pass_by_value.rs | 2 +- clippy_lints/src/question_mark.rs | 2 +- clippy_lints/src/transmute/transmute_ptr_to_ptr.rs | 2 +- clippy_lints/src/transmute/transmute_undefined_repr.rs | 4 ++-- clippy_lints/src/types/redundant_allocation.rs | 2 +- clippy_lints/src/types/vec_box.rs | 2 +- clippy_lints/src/unnecessary_box_returns.rs | 2 +- clippy_utils/src/ty.rs | 2 +- 14 files changed, 17 insertions(+), 17 deletions(-) diff --git a/clippy_lints/src/casts/ptr_as_ptr.rs b/clippy_lints/src/casts/ptr_as_ptr.rs index 86c5f6b9f0b..46d67e615c7 100644 --- a/clippy_lints/src/casts/ptr_as_ptr.rs +++ b/clippy_lints/src/casts/ptr_as_ptr.rs @@ -39,7 +39,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Msrv) { (Mutability::Not, Mutability::Not) | (Mutability::Mut, Mutability::Mut)) // The `U` in `pointer::cast` have to be `Sized` // as explained here: https://github.com/rust-lang/rust/issues/60602. - && to_pointee_ty.is_sized(cx.tcx, cx.param_env) + && to_pointee_ty.is_sized(cx.tcx, cx.typing_env()) { let mut app = Applicability::MachineApplicable; let turbofish = match &cast_to_hir_ty.kind { diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index f864b7a5a8a..9049739dddb 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -1028,7 +1028,7 @@ fn report<'tcx>( State::ExplicitDeref { mutability } => { if is_block_like(expr) && let ty::Ref(_, ty, _) = data.adjusted_ty.kind() - && ty.is_sized(cx.tcx, cx.param_env) + && ty.is_sized(cx.tcx, cx.typing_env()) { // Rustc bug: auto deref doesn't work on block expression when targeting sized types. return; diff --git a/clippy_lints/src/functions/must_use.rs b/clippy_lints/src/functions/must_use.rs index c74ba088b78..175d92d2d79 100644 --- a/clippy_lints/src/functions/must_use.rs +++ b/clippy_lints/src/functions/must_use.rs @@ -198,7 +198,7 @@ fn is_mutable_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, tys: &mut DefIdSet) // primitive types are never mutable ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => false, ty::Adt(adt, args) => { - tys.insert(adt.did()) && !ty.is_freeze(cx.tcx, cx.param_env) + tys.insert(adt.did()) && !ty.is_freeze(cx.tcx, cx.typing_env()) || matches!(cx.tcx.get_diagnostic_name(adt.did()), Some(sym::Rc | sym::Arc)) && args.types().any(|ty| is_mutable_ty(cx, ty, tys)) }, diff --git a/clippy_lints/src/let_if_seq.rs b/clippy_lints/src/let_if_seq.rs index 0e488cee6b7..5db28e9ae9b 100644 --- a/clippy_lints/src/let_if_seq.rs +++ b/clippy_lints/src/let_if_seq.rs @@ -80,7 +80,7 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq { let has_interior_mutability = !cx .typeck_results() .node_type(canonical_id) - .is_freeze(cx.tcx, cx.param_env); + .is_freeze(cx.tcx, cx.typing_env()); if has_interior_mutability { return; } diff --git a/clippy_lints/src/methods/manual_inspect.rs b/clippy_lints/src/methods/manual_inspect.rs index 223b0630bfd..7aa13d8d5b6 100644 --- a/clippy_lints/src/methods/manual_inspect.rs +++ b/clippy_lints/src/methods/manual_inspect.rs @@ -148,7 +148,7 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: _ => {}, } } - requires_copy |= !ty.is_copy_modulo_regions(cx.tcx, cx.param_env); + requires_copy |= !ty.is_copy_modulo_regions(cx.tcx, cx.typing_env()); break; } }, @@ -158,9 +158,9 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: } if can_lint - && (!requires_copy || arg_ty.is_copy_modulo_regions(cx.tcx, cx.param_env)) + && (!requires_copy || arg_ty.is_copy_modulo_regions(cx.tcx, cx.typing_env())) // This case could be handled, but a fair bit of care would need to be taken. - && (!requires_deref || arg_ty.is_freeze(cx.tcx, cx.param_env)) + && (!requires_deref || arg_ty.is_freeze(cx.tcx, cx.typing_env())) { if requires_deref { edits.push((param.span.shrink_to_lo(), "&".into())); diff --git a/clippy_lints/src/mut_mut.rs b/clippy_lints/src/mut_mut.rs index 6cddd7ea813..e2ab5e98504 100644 --- a/clippy_lints/src/mut_mut.rs +++ b/clippy_lints/src/mut_mut.rs @@ -80,7 +80,7 @@ impl<'tcx> intravisit::Visitor<'tcx> for MutVisitor<'_, 'tcx> { "generally you want to avoid `&mut &mut _` if possible", ); } else if let ty::Ref(_, ty, hir::Mutability::Mut) = self.cx.typeck_results().expr_ty(e).kind() { - if ty.peel_refs().is_sized(self.cx.tcx, self.cx.param_env) { + if ty.peel_refs().is_sized(self.cx.tcx, self.cx.typing_env()) { span_lint_hir( self.cx, MUT_MUT, diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 0775d7abdbb..ad0ab148530 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -180,7 +180,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { if !is_self(arg) && !ty.is_mutable_ptr() && !is_copy(cx, ty) - && ty.is_sized(cx.tcx, cx.param_env) + && ty.is_sized(cx.tcx, cx.typing_env()) && !allowed_traits.iter().any(|&t| { implements_trait_with_env_from_iter(cx.tcx, cx.param_env, ty, t, None, [Option::< ty::GenericArg<'tcx>, diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index a00fd01a62e..f69cb9be4ca 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -251,7 +251,7 @@ fn check_is_none_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: &Ex { let mut applicability = Applicability::MachineApplicable; let receiver_str = snippet_with_applicability(cx, caller.span, "..", &mut applicability); - let by_ref = !caller_ty.is_copy_modulo_regions(cx.tcx, cx.param_env) + let by_ref = !caller_ty.is_copy_modulo_regions(cx.tcx, cx.typing_env()) && !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)) { diff --git a/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs b/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs index 0772b284968..bf6700b1b6b 100644 --- a/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs +++ b/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs @@ -27,7 +27,7 @@ pub(super) fn check<'tcx>( |diag| { if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) { if from_mutbl == to_mutbl - && to_pointee_ty.is_sized(cx.tcx, cx.param_env) + && to_pointee_ty.is_sized(cx.tcx, cx.typing_env()) && msrv.meets(msrvs::POINTER_CAST) { diag.span_suggestion_verbose( diff --git a/clippy_lints/src/transmute/transmute_undefined_repr.rs b/clippy_lints/src/transmute/transmute_undefined_repr.rs index 4dc1290e8b1..48d65eb15d9 100644 --- a/clippy_lints/src/transmute/transmute_undefined_repr.rs +++ b/clippy_lints/src/transmute/transmute_undefined_repr.rs @@ -206,12 +206,12 @@ fn reduce_refs<'tcx>(cx: &LateContext<'tcx>, mut from_ty: Ty<'tcx>, mut to_ty: T continue; }, (&(ty::Ref(_, unsized_ty, _) | ty::RawPtr(unsized_ty, _)), _) - if !unsized_ty.is_sized(cx.tcx, cx.param_env) => + if !unsized_ty.is_sized(cx.tcx, cx.typing_env()) => { (true, false) }, (_, &(ty::Ref(_, unsized_ty, _) | ty::RawPtr(unsized_ty, _))) - if !unsized_ty.is_sized(cx.tcx, cx.param_env) => + if !unsized_ty.is_sized(cx.tcx, cx.typing_env()) => { (false, true) }, diff --git a/clippy_lints/src/types/redundant_allocation.rs b/clippy_lints/src/types/redundant_allocation.rs index 1a656088b17..de3456a8ba5 100644 --- a/clippy_lints/src/types/redundant_allocation.rs +++ b/clippy_lints/src/types/redundant_allocation.rs @@ -60,7 +60,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>, qpath: // here because `mod.rs` guarantees this lint is only run on types outside of bodies and // is not run on locals. let ty = lower_ty(cx.tcx, hir_ty); - if ty.has_escaping_bound_vars() || !ty.is_sized(cx.tcx, cx.param_env) { + if ty.has_escaping_bound_vars() || !ty.is_sized(cx.tcx, cx.typing_env()) { return false; } hir_ty.span diff --git a/clippy_lints/src/types/vec_box.rs b/clippy_lints/src/types/vec_box.rs index 230239335c6..9b236d3bda5 100644 --- a/clippy_lints/src/types/vec_box.rs +++ b/clippy_lints/src/types/vec_box.rs @@ -37,7 +37,7 @@ pub(super) fn check<'tcx>( && let boxed_alloc_ty = last.args.get(1) && let ty_ty = lower_ty(cx.tcx, boxed_ty) && !ty_ty.has_escaping_bound_vars() - && ty_ty.is_sized(cx.tcx, cx.param_env) + && ty_ty.is_sized(cx.tcx, cx.typing_env()) && let Ok(ty_ty_size) = cx.layout_of(ty_ty).map(|l| l.size.bytes()) && ty_ty_size < box_size_threshold // https://github.com/rust-lang/rust-clippy/issues/7114 diff --git a/clippy_lints/src/unnecessary_box_returns.rs b/clippy_lints/src/unnecessary_box_returns.rs index 14f4aa6676b..34df1d5560a 100644 --- a/clippy_lints/src/unnecessary_box_returns.rs +++ b/clippy_lints/src/unnecessary_box_returns.rs @@ -82,7 +82,7 @@ impl UnnecessaryBoxReturns { // It's sometimes useful to return Box if T is unsized, so don't lint those. // Also, don't lint if we know that T is very large, in which case returning // a Box may be beneficial. - if boxed_ty.is_sized(cx.tcx, cx.param_env) && approx_ty_size(cx, boxed_ty) <= self.maximum_size { + if boxed_ty.is_sized(cx.tcx, cx.typing_env()) && approx_ty_size(cx, boxed_ty) <= self.maximum_size { span_lint_and_then( cx, UNNECESSARY_BOX_RETURNS, diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 2aad867dc0d..fff516b730d 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -38,7 +38,7 @@ pub use type_certainty::expr_type_is_certain; /// Checks if the given type implements copy. pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { - ty.is_copy_modulo_regions(cx.tcx, cx.param_env) + ty.is_copy_modulo_regions(cx.tcx, cx.typing_env()) } /// This checks whether a given type is known to implement Debug. From d8e5f7ad8a10824a0de614d6f1276ebe2d84322e Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 19 Nov 2024 19:31:02 +0100 Subject: [PATCH 22/45] remove `TypingMode::from_param_env` in clippy --- clippy_lints/src/dereference.rs | 15 +++--- clippy_lints/src/derive.rs | 14 +++-- clippy_lints/src/loops/explicit_iter_loop.rs | 8 +-- .../src/needless_borrows_for_generic_args.rs | 6 +-- clippy_lints/src/needless_pass_by_value.rs | 11 ++-- clippy_utils/src/lib.rs | 54 ++++++++++--------- clippy_utils/src/ty.rs | 37 +++++-------- 7 files changed, 77 insertions(+), 68 deletions(-) diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 9049739dddb..fce7f9985ea 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -15,6 +15,7 @@ use rustc_hir::{ self as hir, BindingMode, Body, BodyId, BorrowKind, Expr, ExprKind, HirId, MatchSource, Mutability, Node, Pat, PatKind, Path, QPath, TyKind, UnOp, }; +use rustc_hir::def_id::DefId; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, TypeckResults}; @@ -753,11 +754,10 @@ impl TyCoercionStability { fn for_defined_ty<'tcx>(cx: &LateContext<'tcx>, ty: DefinedTy<'tcx>, for_return: bool) -> Self { match ty { DefinedTy::Hir(ty) => Self::for_hir_ty(ty), - DefinedTy::Mir(ty) => Self::for_mir_ty( + DefinedTy::Mir { def_site_def_id, ty } => Self::for_mir_ty( cx.tcx, - // FIXME(#132279): convert `DefinedTy` to use `TypingEnv` instead. - ty::TypingEnv::from_param_env(ty.param_env), - cx.tcx.instantiate_bound_regions_with_erased(ty.value), + def_site_def_id, + cx.tcx.instantiate_bound_regions_with_erased(ty), for_return, ), } @@ -824,12 +824,15 @@ impl TyCoercionStability { } } - fn for_mir_ty<'tcx>(tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>, ty: Ty<'tcx>, for_return: bool) -> Self { + fn for_mir_ty<'tcx>(tcx: TyCtxt<'tcx>, def_site_def_id: Option, ty: Ty<'tcx>, for_return: bool) -> Self { let ty::Ref(_, mut ty, _) = *ty.kind() else { return Self::None; }; - ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty); + if let Some(def_id) = def_site_def_id { + let typing_env = ty::TypingEnv::non_body_analysis(tcx, def_id); + ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty); + } loop { break match *ty.kind() { ty::Ref(_, ref_ty, _) => { diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index 0db6a822ec0..3b6b3c89858 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -454,13 +454,13 @@ fn check_partial_eq_without_eq<'tcx>(cx: &LateContext<'tcx>, span: Span, trait_r && cx.tcx.is_diagnostic_item(sym::PartialEq, def_id) && !has_non_exhaustive_attr(cx.tcx, *adt) && !ty_implements_eq_trait(cx.tcx, ty, eq_trait_def_id) - && let param_env = param_env_for_derived_eq(cx.tcx, adt.did(), eq_trait_def_id) + && let typing_env = typing_env_env_for_derived_eq(cx.tcx, adt.did(), eq_trait_def_id) && let Some(local_def_id) = adt.did().as_local() // If all of our fields implement `Eq`, we can implement `Eq` too && adt .all_fields() .map(|f| f.ty(cx.tcx, args)) - .all(|ty| implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, None, &[])) + .all(|ty| implements_trait_with_env(cx.tcx, typing_env, ty, eq_trait_def_id, None, &[])) { span_lint_hir_and_then( cx, @@ -485,7 +485,7 @@ fn ty_implements_eq_trait<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, eq_trait_id: De } /// Creates the `ParamEnv` used for the give type's derived `Eq` impl. -fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) -> ParamEnv<'_> { +fn typing_env_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) -> ty::TypingEnv<'_> { // Initial map from generic index to param def. // Vec<(param_def, needs_eq)> let mut params = tcx @@ -506,7 +506,7 @@ fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) -> } } - ParamEnv::new( + let param_env = ParamEnv::new( tcx.mk_clauses_from_iter(ty_predicates.iter().map(|&(p, _)| p).chain( params.iter().filter(|&&(_, needs_eq)| needs_eq).map(|&(param, _)| { ClauseKind::Trait(TraitPredicate { @@ -517,5 +517,9 @@ fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) -> }), )), Reveal::UserFacing, - ) + ); + ty::TypingEnv { + typing_mode: ty::TypingMode::non_body_analysis(), + param_env, + } } diff --git a/clippy_lints/src/loops/explicit_iter_loop.rs b/clippy_lints/src/loops/explicit_iter_loop.rs index 48318682f33..d999e1a0585 100644 --- a/clippy_lints/src/loops/explicit_iter_loop.rs +++ b/clippy_lints/src/loops/explicit_iter_loop.rs @@ -115,11 +115,11 @@ fn is_ref_iterable<'tcx>( .tcx .liberate_late_bound_regions(fn_id, cx.tcx.fn_sig(fn_id).skip_binder()) && let &[req_self_ty, req_res_ty] = &**sig.inputs_and_output - && let param_env = cx.tcx.param_env(fn_id) - && implements_trait_with_env(cx.tcx, param_env, req_self_ty, trait_id, Some(fn_id), &[]) + && let typing_env = ty::TypingEnv::non_body_analysis(cx.tcx, fn_id) + && implements_trait_with_env(cx.tcx, typing_env, req_self_ty, trait_id, Some(fn_id), &[]) && let Some(into_iter_ty) = - make_normalized_projection_with_regions(cx.tcx, param_env, trait_id, sym!(IntoIter), [req_self_ty]) - && let req_res_ty = normalize_with_regions(cx.tcx, param_env, req_res_ty) + make_normalized_projection_with_regions(cx.tcx, typing_env, trait_id, sym!(IntoIter), [req_self_ty]) + && let req_res_ty = normalize_with_regions(cx.tcx, typing_env, req_res_ty) && into_iter_ty == req_res_ty { let adjustments = typeck.expr_adjustments(self_arg); diff --git a/clippy_lints/src/needless_borrows_for_generic_args.rs b/clippy_lints/src/needless_borrows_for_generic_args.rs index 43b885fbd2c..9ebef531bc5 100644 --- a/clippy_lints/src/needless_borrows_for_generic_args.rs +++ b/clippy_lints/src/needless_borrows_for_generic_args.rs @@ -85,8 +85,8 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowsForGenericArgs<'tcx> { && use_cx.same_ctxt && !use_cx.is_ty_unified && let use_node = use_cx.use_node(cx) - && let Some(DefinedTy::Mir(ty)) = use_node.defined_ty(cx) - && let ty::Param(ty) = *ty.value.skip_binder().kind() + && let Some(DefinedTy::Mir { def_site_def_id: _, ty }) = use_node.defined_ty(cx) + && let ty::Param(param_ty) = *ty.skip_binder().kind() && let Some((hir_id, fn_id, i)) = match use_node { ExprUseNode::MethodArg(_, _, 0) => None, ExprUseNode::MethodArg(hir_id, None, i) => cx @@ -112,7 +112,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowsForGenericArgs<'tcx> { fn_id, cx.typeck_results().node_args(hir_id), i, - ty, + param_ty, expr, &self.msrv, ) diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index ad0ab148530..b65ec8c3c48 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -182,9 +182,14 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { && !is_copy(cx, ty) && ty.is_sized(cx.tcx, cx.typing_env()) && !allowed_traits.iter().any(|&t| { - implements_trait_with_env_from_iter(cx.tcx, cx.param_env, ty, t, None, [Option::< - ty::GenericArg<'tcx>, - >::None]) + implements_trait_with_env_from_iter( + cx.tcx, + cx.typing_env(), + ty, + t, + None, + [None::>] + ) }) && !implements_borrow_trait && !all_borrowable_trait diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index f28e5c9ed0e..6408cc938cb 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -116,8 +116,8 @@ use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::{ - self as rustc_ty, Binder, BorrowKind, ClosureKind, EarlyBinder, FloatTy, GenericArgsRef, IntTy, ParamEnv, - ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt, UintTy, UpvarCapture, + self as rustc_ty, Binder, BorrowKind, ClosureKind, EarlyBinder, FloatTy, GenericArgsRef, IntTy, + Ty, TyCtxt, TypeVisitableExt, UintTy, UpvarCapture, }; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::SourceMap; @@ -2712,9 +2712,17 @@ pub fn walk_to_expr_usage<'tcx, T>( pub enum DefinedTy<'tcx> { // Used for locals and closures defined within the function. Hir(&'tcx hir::Ty<'tcx>), - /// Used for function signatures, and constant and static values. This includes the `ParamEnv` - /// from the definition site. - Mir(ParamEnvAnd<'tcx, Binder<'tcx, Ty<'tcx>>>), + /// Used for function signatures, and constant and static values. The type is + /// in the context of its definition site. We also track the `def_id` of its + /// definition site. + /// + /// WARNING: As the `ty` in in the scope of the definition, not of the function + /// using it, you must be very careful with how you use it. Using it in the wrong + /// scope easily results in ICEs. + Mir { + def_site_def_id: Option, + ty: Binder<'tcx, Ty<'tcx>>, + }, } /// The context an expressions value is used in. @@ -2833,10 +2841,10 @@ impl<'tcx> ExprUseNode<'tcx> { pub fn defined_ty(&self, cx: &LateContext<'tcx>) -> Option> { match *self { Self::LetStmt(LetStmt { ty: Some(ty), .. }) => Some(DefinedTy::Hir(ty)), - Self::ConstStatic(id) => Some(DefinedTy::Mir( - cx.param_env - .and(Binder::dummy(cx.tcx.type_of(id).instantiate_identity())), - )), + Self::ConstStatic(id) => Some(DefinedTy::Mir { + def_site_def_id: Some(id.def_id.to_def_id()), + ty: Binder::dummy(cx.tcx.type_of(id).instantiate_identity()), + }), Self::Return(id) => { if let Node::Expr(Expr { kind: ExprKind::Closure(c), @@ -2848,9 +2856,8 @@ impl<'tcx> ExprUseNode<'tcx> { FnRetTy::Return(ty) => Some(DefinedTy::Hir(ty)), } } else { - Some(DefinedTy::Mir( - cx.param_env.and(cx.tcx.fn_sig(id).instantiate_identity().output()), - )) + let ty = cx.tcx.fn_sig(id).instantiate_identity().output(); + Some(DefinedTy::Mir { def_site_def_id: Some(id.def_id.to_def_id()), ty }) } }, Self::Field(field) => match get_parent_expr_for_hir(cx, field.hir_id) { @@ -2866,12 +2873,9 @@ impl<'tcx> ExprUseNode<'tcx> { .find(|f| f.name == field.ident.name) .map(|f| (adt, f)) }) - .map(|(adt, field_def)| { - DefinedTy::Mir( - cx.tcx - .param_env(adt.did()) - .and(Binder::dummy(cx.tcx.type_of(field_def.did).instantiate_identity())), - ) + .map(|(adt, field_def)| DefinedTy::Mir { + def_site_def_id: Some(adt.did()), + ty: Binder::dummy(cx.tcx.type_of(field_def.did).instantiate_identity()), }), _ => None, }, @@ -2880,17 +2884,19 @@ impl<'tcx> ExprUseNode<'tcx> { let (hir_ty, ty) = sig.input_with_hir(i)?; Some(match hir_ty { Some(hir_ty) => DefinedTy::Hir(hir_ty), - None => DefinedTy::Mir( - sig.predicates_id() - .map_or(ParamEnv::empty(), |id| cx.tcx.param_env(id)) - .and(ty), - ), + None => DefinedTy::Mir { + def_site_def_id: sig.predicates_id(), + ty, + } }) }, Self::MethodArg(id, _, i) => { let id = cx.typeck_results().type_dependent_def_id(id)?; let sig = cx.tcx.fn_sig(id).skip_binder(); - Some(DefinedTy::Mir(cx.tcx.param_env(id).and(sig.input(i)))) + Some(DefinedTy::Mir { + def_site_def_id: Some(id), + ty: sig.input(i), + }) }, Self::LetStmt(_) | Self::FieldAccess(..) | Self::Callee | Self::Other | Self::AddrOf(..) => None, } diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index fff516b730d..3498606dfd3 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -19,7 +19,7 @@ use rustc_middle::ty::layout::ValidityRequirement; use rustc_middle::ty::{ self, AdtDef, AliasTy, AssocItem, AssocKind, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, GenericArgsRef, GenericParamDefKind, IntTy, ParamEnv, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, - TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, UintTy, Upcast, VariantDef, VariantDiscr, + TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr, }; use rustc_span::symbol::Ident; use rustc_span::{DUMMY_SP, Span, Symbol, sym}; @@ -226,7 +226,7 @@ pub fn implements_trait<'tcx>( trait_id: DefId, args: &[GenericArg<'tcx>], ) -> bool { - implements_trait_with_env_from_iter(cx.tcx, cx.param_env, ty, trait_id, None, args.iter().map(|&x| Some(x))) + implements_trait_with_env_from_iter(cx.tcx, cx.typing_env(), ty, trait_id, None, args.iter().map(|&x| Some(x))) } /// Same as `implements_trait` but allows using a `ParamEnv` different from the lint context. @@ -235,19 +235,19 @@ pub fn implements_trait<'tcx>( /// environment, used for checking const traits. pub fn implements_trait_with_env<'tcx>( tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, ty: Ty<'tcx>, trait_id: DefId, callee_id: Option, args: &[GenericArg<'tcx>], ) -> bool { - implements_trait_with_env_from_iter(tcx, param_env, ty, trait_id, callee_id, args.iter().map(|&x| Some(x))) + implements_trait_with_env_from_iter(tcx, typing_env, ty, trait_id, callee_id, args.iter().map(|&x| Some(x))) } /// Same as `implements_trait_from_env` but takes the arguments as an iterator. pub fn implements_trait_with_env_from_iter<'tcx>( tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, ty: Ty<'tcx>, trait_id: DefId, callee_id: Option, @@ -268,7 +268,7 @@ pub fn implements_trait_with_env_from_iter<'tcx>( return false; } - let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env)); + let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env); let args = args .into_iter() .map(|arg| arg.into().unwrap_or_else(|| infcx.next_ty_var(DUMMY_SP).into())) @@ -1239,12 +1239,12 @@ impl<'tcx> InteriorMut<'tcx> { pub fn make_normalized_projection_with_regions<'tcx>( tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, container_id: DefId, assoc_ty: Symbol, args: impl IntoIterator>>, ) -> Option> { - fn helper<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: AliasTy<'tcx>) -> Option> { + fn helper<'tcx>(tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>, ty: AliasTy<'tcx>) -> Option> { #[cfg(debug_assertions)] if let Some((i, arg)) = ty .args @@ -1261,10 +1261,8 @@ pub fn make_normalized_projection_with_regions<'tcx>( return None; } let cause = ObligationCause::dummy(); - match tcx - .infer_ctxt() - .build(TypingMode::from_param_env(param_env)) - .at(&cause, param_env) + let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env); + match infcx.at(&cause, param_env) .query_normalize(Ty::new_projection_from_args(tcx, ty.def_id, ty.args)) { Ok(ty) => Some(ty.value), @@ -1274,20 +1272,13 @@ pub fn make_normalized_projection_with_regions<'tcx>( }, } } - helper(tcx, param_env, make_projection(tcx, container_id, assoc_ty, args)?) + helper(tcx, typing_env, make_projection(tcx, container_id, assoc_ty, args)?) } -pub fn normalize_with_regions<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { +pub fn normalize_with_regions<'tcx>(tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { let cause = ObligationCause::dummy(); - match tcx - .infer_ctxt() - .build(TypingMode::from_param_env(param_env)) - .at(&cause, param_env) - .query_normalize(ty) - { - Ok(ty) => ty.value, - Err(_) => ty, - } + let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env); + infcx.at(&cause, param_env).query_normalize(ty).map_or(ty, |ty| ty.value) } /// Checks if the type is `core::mem::ManuallyDrop<_>` From c783d1e387d0fbf35c19d76d5ea357c5d4a5d607 Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 19 Nov 2024 20:10:42 +0100 Subject: [PATCH 23/45] `InterpCx` store `TypingEnv` instead of a `ParamEnv` --- clippy_lints/src/non_copy_const.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 57fa4797c5e..5416e00fe0c 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -270,8 +270,8 @@ impl<'tcx> NonCopyConst<'tcx> { instance, promoted: None, }; - let param_env = cx.tcx.param_env(def_id).with_reveal_all_normalized(cx.tcx); - let result = cx.tcx.const_eval_global_id_for_typeck(param_env, cid, DUMMY_SP); + let typing_env = ty::TypingEnv::post_analysis(cx.tcx, def_id); + let result = cx.tcx.const_eval_global_id_for_typeck(typing_env, cid, DUMMY_SP); Self::is_value_unfrozen_raw(cx, result, ty) } @@ -294,7 +294,7 @@ impl<'tcx> NonCopyConst<'tcx> { instance, promoted: None, }; - tcx.const_eval_global_id_for_typeck(typing_env.param_env, cid, span) + tcx.const_eval_global_id_for_typeck(typing_env, cid, span) }, Ok(None) => Err(ErrorHandled::TooGeneric(span)), Err(err) => Err(ErrorHandled::Reported(err.into(), span)), From 425346a1bcbc54fa27109143dfc5338938d5ca93 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Tue, 19 Nov 2024 21:38:47 +0100 Subject: [PATCH 24/45] Use a better message for unnecessary_map_or lint Suggested by @smoelius. --- .../src/methods/unnecessary_map_or.rs | 2 +- tests/ui/unnecessary_map_or.stderr | 36 +++++++++---------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/clippy_lints/src/methods/unnecessary_map_or.rs b/clippy_lints/src/methods/unnecessary_map_or.rs index 74c0c35f9aa..1199d289761 100644 --- a/clippy_lints/src/methods/unnecessary_map_or.rs +++ b/clippy_lints/src/methods/unnecessary_map_or.rs @@ -135,7 +135,7 @@ pub(super) fn check<'a>( cx, UNNECESSARY_MAP_OR, expr.span, - "this `map_or` is redundant", + "this `map_or` can be simplified", format!("use {method} instead"), sugg, applicability, diff --git a/tests/ui/unnecessary_map_or.stderr b/tests/ui/unnecessary_map_or.stderr index 025eb24d465..890abb01228 100644 --- a/tests/ui/unnecessary_map_or.stderr +++ b/tests/ui/unnecessary_map_or.stderr @@ -1,4 +1,4 @@ -error: this `map_or` is redundant +error: this `map_or` can be simplified --> tests/ui/unnecessary_map_or.rs:12:13 | LL | let _ = Some(5).map_or(false, |n| n == 5); @@ -7,13 +7,13 @@ LL | let _ = Some(5).map_or(false, |n| n == 5); = note: `-D clippy::unnecessary-map-or` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::unnecessary_map_or)]` -error: this `map_or` is redundant +error: this `map_or` can be simplified --> tests/ui/unnecessary_map_or.rs:13:13 | LL | let _ = Some(5).map_or(true, |n| n != 5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(Some(5) != Some(5))` -error: this `map_or` is redundant +error: this `map_or` can be simplified --> tests/ui/unnecessary_map_or.rs:14:13 | LL | let _ = Some(5).map_or(false, |n| { @@ -23,7 +23,7 @@ LL | | n == 5 LL | | }); | |______^ help: use a standard comparison instead: `(Some(5) == Some(5))` -error: this `map_or` is redundant +error: this `map_or` can be simplified --> tests/ui/unnecessary_map_or.rs:18:13 | LL | let _ = Some(5).map_or(false, |n| { @@ -41,85 +41,85 @@ LL + 6 >= 5 LL ~ }); | -error: this `map_or` is redundant +error: this `map_or` can be simplified --> tests/ui/unnecessary_map_or.rs:22:13 | LL | let _ = Some(vec![5]).map_or(false, |n| n == [5]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_some_and instead: `Some(vec![5]).is_some_and(|n| n == [5])` -error: this `map_or` is redundant +error: this `map_or` can be simplified --> tests/ui/unnecessary_map_or.rs:23:13 | LL | let _ = Some(vec![1]).map_or(false, |n| vec![2] == n); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_some_and instead: `Some(vec![1]).is_some_and(|n| vec![2] == n)` -error: this `map_or` is redundant +error: this `map_or` can be simplified --> tests/ui/unnecessary_map_or.rs:24:13 | LL | let _ = Some(5).map_or(false, |n| n == n); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_some_and instead: `Some(5).is_some_and(|n| n == n)` -error: this `map_or` is redundant +error: this `map_or` can be simplified --> tests/ui/unnecessary_map_or.rs:25:13 | LL | let _ = Some(5).map_or(false, |n| n == if 2 > 1 { n } else { 0 }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_some_and instead: `Some(5).is_some_and(|n| n == if 2 > 1 { n } else { 0 })` -error: this `map_or` is redundant +error: this `map_or` can be simplified --> tests/ui/unnecessary_map_or.rs:26:13 | LL | let _ = Ok::, i32>(vec![5]).map_or(false, |n| n == [5]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_ok_and instead: `Ok::, i32>(vec![5]).is_ok_and(|n| n == [5])` -error: this `map_or` is redundant +error: this `map_or` can be simplified --> tests/ui/unnecessary_map_or.rs:27:13 | LL | let _ = Ok::(5).map_or(false, |n| n == 5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(Ok::(5) == Ok(5))` -error: this `map_or` is redundant +error: this `map_or` can be simplified --> tests/ui/unnecessary_map_or.rs:28:13 | LL | let _ = Some(5).map_or(false, |n| n == 5).then(|| 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(Some(5) == Some(5))` -error: this `map_or` is redundant +error: this `map_or` can be simplified --> tests/ui/unnecessary_map_or.rs:29:13 | LL | let _ = Some(5).map_or(true, |n| n == 5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_none_or instead: `Some(5).is_none_or(|n| n == 5)` -error: this `map_or` is redundant +error: this `map_or` can be simplified --> tests/ui/unnecessary_map_or.rs:30:13 | LL | let _ = Some(5).map_or(true, |n| 5 == n); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_none_or instead: `Some(5).is_none_or(|n| 5 == n)` -error: this `map_or` is redundant +error: this `map_or` can be simplified --> tests/ui/unnecessary_map_or.rs:54:13 | LL | let _ = r.map_or(false, |x| x == 7); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_ok_and instead: `r.is_ok_and(|x| x == 7)` -error: this `map_or` is redundant +error: this `map_or` can be simplified --> tests/ui/unnecessary_map_or.rs:59:13 | LL | let _ = r.map_or(false, func); | ^^^^^^^^^^^^^^^^^^^^^ help: use is_ok_and instead: `r.is_ok_and(func)` -error: this `map_or` is redundant +error: this `map_or` can be simplified --> tests/ui/unnecessary_map_or.rs:60:13 | LL | let _ = Some(5).map_or(false, func); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_some_and instead: `Some(5).is_some_and(func)` -error: this `map_or` is redundant +error: this `map_or` can be simplified --> tests/ui/unnecessary_map_or.rs:61:13 | LL | let _ = Some(5).map_or(true, func); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_none_or instead: `Some(5).is_none_or(func)` -error: this `map_or` is redundant +error: this `map_or` can be simplified --> tests/ui/unnecessary_map_or.rs:66:13 | LL | let _ = r.map_or(false, |x| x == 8); From ff6c4b731bc1df7f2a02c7dd6e94028371590db3 Mon Sep 17 00:00:00 2001 From: Ding Xiang Fei Date: Mon, 2 Sep 2024 01:13:07 +0800 Subject: [PATCH 25/45] reduce false positives of tail-expr-drop-order from consumed values take 2 open up coroutines tweak the wordings the lint works up until 2021 We were missing one case, for ADTs, which was causing `Result` to yield incorrect results. only include field spans with significant types deduplicate and eliminate field spans switch to emit spans to impl Drops Co-authored-by: Niko Matsakis collect drops instead of taking liveness diff apply some suggestions and add explantory notes small fix on the cache let the query recurse through coroutine new suggestion format with extracted variable name fine-tune the drop span and messages bugfix on runtime borrows tweak message wording filter out ecosystem types earlier apply suggestions clippy check lint level at session level further restrict applicability of the lint translate bid into nop for stable mir detect cycle in type structure --- 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 abadca71400..345c46f944a 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -233,6 +233,7 @@ fn check_statement<'tcx>( | StatementKind::PlaceMention(..) | StatementKind::Coverage(..) | StatementKind::ConstEvalCounter + | StatementKind::BackwardIncompatibleDropHint { .. } | StatementKind::Nop => Ok(()), } } From 78d0a2aaac61e404a86ba4656f5deefbb8a53fbc Mon Sep 17 00:00:00 2001 From: xFrednet Date: Thu, 21 Nov 2024 13:50:31 +0000 Subject: [PATCH 26/45] Update version attributes for 1.83 lints --- clippy_lints/src/manual_div_ceil.rs | 2 +- clippy_lints/src/manual_is_power_of_two.rs | 2 +- clippy_lints/src/misc.rs | 2 +- clippy_lints/src/non_zero_suggestions.rs | 2 +- clippy_lints/src/zombie_processes.rs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/manual_div_ceil.rs b/clippy_lints/src/manual_div_ceil.rs index 07af2ddb0de..bbb89bee835 100644 --- a/clippy_lints/src/manual_div_ceil.rs +++ b/clippy_lints/src/manual_div_ceil.rs @@ -35,7 +35,7 @@ declare_clippy_lint! { /// let y: i32 = 4; /// let div = x.div_ceil(y); /// ``` - #[clippy::version = "1.81.0"] + #[clippy::version = "1.83.0"] pub MANUAL_DIV_CEIL, complexity, "manually reimplementing `div_ceil`" diff --git a/clippy_lints/src/manual_is_power_of_two.rs b/clippy_lints/src/manual_is_power_of_two.rs index a11d3e4624c..4fee3bf7aa9 100644 --- a/clippy_lints/src/manual_is_power_of_two.rs +++ b/clippy_lints/src/manual_is_power_of_two.rs @@ -27,7 +27,7 @@ declare_clippy_lint! { /// let a: u32 = 4; /// let result = a.is_power_of_two(); /// ``` - #[clippy::version = "1.82.0"] + #[clippy::version = "1.83.0"] pub MANUAL_IS_POWER_OF_TWO, pedantic, "manually reimplementing `is_power_of_two`" diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 8aba650472b..b856c929cf6 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -114,7 +114,7 @@ declare_clippy_lint! { /// let _ = FooStruct{}; /// } /// ``` - #[clippy::version = "pre 1.29.0"] + #[clippy::version = "1.83.0"] pub USED_UNDERSCORE_ITEMS, pedantic, "using a item which is prefixed with an underscore" diff --git a/clippy_lints/src/non_zero_suggestions.rs b/clippy_lints/src/non_zero_suggestions.rs index aefb665b52e..f6ce1d1d586 100644 --- a/clippy_lints/src/non_zero_suggestions.rs +++ b/clippy_lints/src/non_zero_suggestions.rs @@ -39,7 +39,7 @@ declare_clippy_lint! { /// let r2 = x % NonZeroU64::from(y); /// } /// ``` - #[clippy::version = "1.81.0"] + #[clippy::version = "1.83.0"] pub NON_ZERO_SUGGESTIONS, restriction, "suggests using `NonZero#` from `u#` or `i#` for more efficient and type-safe conversions" diff --git a/clippy_lints/src/zombie_processes.rs b/clippy_lints/src/zombie_processes.rs index 8d9241cc7d9..4a13c10166f 100644 --- a/clippy_lints/src/zombie_processes.rs +++ b/clippy_lints/src/zombie_processes.rs @@ -35,7 +35,7 @@ declare_clippy_lint! { /// let mut child = Command::new("ls").spawn().expect("failed to execute child"); /// child.wait().expect("failed to wait on child"); /// ``` - #[clippy::version = "1.74.0"] + #[clippy::version = "1.83.0"] pub ZOMBIE_PROCESSES, suspicious, "not waiting on a spawned child process" From 404e47aa84b16cab60008cb74eead08475e83960 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 29 Oct 2024 17:53:40 +0100 Subject: [PATCH 27/45] Add new lint `doc_include_without_cfg` --- CHANGELOG.md | 1 + README.md | 2 +- book/src/README.md | 2 +- clippy_config/src/conf.rs | 2 +- clippy_lints/src/declared_lints.rs | 1 + .../src/doc/include_in_doc_without_cfg.rs | 45 +++++++++++++++++++ clippy_lints/src/doc/mod.rs | 28 ++++++++++++ tests/ui/doc/doc_include_without_cfg.fixed | 40 +++++++++++++++++ tests/ui/doc/doc_include_without_cfg.rs | 40 +++++++++++++++++ tests/ui/doc/doc_include_without_cfg.stderr | 17 +++++++ tests/ui/missing_doc_crate.rs | 1 + 11 files changed, 176 insertions(+), 3 deletions(-) create mode 100644 clippy_lints/src/doc/include_in_doc_without_cfg.rs create mode 100644 tests/ui/doc/doc_include_without_cfg.fixed create mode 100644 tests/ui/doc/doc_include_without_cfg.rs create mode 100644 tests/ui/doc/doc_include_without_cfg.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 4bdbc91db93..1af7f349b8d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5440,6 +5440,7 @@ Released 2018-09-13 [`disallowed_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_type [`disallowed_types`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_types [`diverging_sub_expression`]: https://rust-lang.github.io/rust-clippy/master/index.html#diverging_sub_expression +[`doc_include_without_cfg`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_include_without_cfg [`doc_lazy_continuation`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_lazy_continuation [`doc_link_with_quotes`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_link_with_quotes [`doc_markdown`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown diff --git a/README.md b/README.md index ec76a6dfb08..1690e2beb16 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are over 700 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are over 750 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) Lints are divided into categories, each with a default [lint level](https://doc.rust-lang.org/rustc/lints/levels.html). You can choose how much Clippy is supposed to ~~annoy~~ help you by changing the lint level by category. diff --git a/book/src/README.md b/book/src/README.md index 7bdfb97c3ac..23527ba896a 100644 --- a/book/src/README.md +++ b/book/src/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are over 700 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are over 750 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) Lints are divided into categories, each with a default [lint level](https://doc.rust-lang.org/rustc/lints/levels.html). You can choose how diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index b0faac6d2a8..263637aacd2 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -154,7 +154,7 @@ macro_rules! define_Conf { )*) => { /// Clippy lint configuration pub struct Conf { - $($(#[doc = $doc])+ pub $name: $ty,)* + $($(#[cfg_attr(doc, doc = $doc)])+ pub $name: $ty,)* } mod defaults { diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index d8918d37afa..fdb778d3ac0 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -134,6 +134,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::disallowed_names::DISALLOWED_NAMES_INFO, crate::disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS_INFO, crate::disallowed_types::DISALLOWED_TYPES_INFO, + crate::doc::DOC_INCLUDE_WITHOUT_CFG_INFO, crate::doc::DOC_LAZY_CONTINUATION_INFO, crate::doc::DOC_LINK_WITH_QUOTES_INFO, crate::doc::DOC_MARKDOWN_INFO, diff --git a/clippy_lints/src/doc/include_in_doc_without_cfg.rs b/clippy_lints/src/doc/include_in_doc_without_cfg.rs new file mode 100644 index 00000000000..49978d4a655 --- /dev/null +++ b/clippy_lints/src/doc/include_in_doc_without_cfg.rs @@ -0,0 +1,45 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_opt; +use rustc_ast::{AttrArgs, AttrArgsEq, AttrKind, AttrStyle, Attribute}; +use rustc_errors::Applicability; +use rustc_lint::LateContext; +use rustc_span::sym; + +use super::DOC_INCLUDE_WITHOUT_CFG; + +pub fn check(cx: &LateContext<'_>, attrs: &[Attribute]) { + for attr in attrs { + if !attr.span.from_expansion() + && let AttrKind::Normal(ref normal) = attr.kind + && normal.item.path == sym::doc + && let AttrArgs::Eq(_, AttrArgsEq::Hir(ref meta)) = normal.item.args + && !attr.span.contains(meta.span) + // Since the `include_str` is already expanded at this point, we can only take the + // whole attribute snippet and then modify for our suggestion. + && let Some(snippet) = snippet_opt(cx, attr.span) + // We cannot remove this because a `#[doc = include_str!("...")]` attribute can occupy + // several lines. + && let Some(start) = snippet.find('[') + && let Some(end) = snippet.rfind(']') + && let snippet = &snippet[start + 1..end] + // We check that the expansion actually comes from `include_str!` and not just from + // another macro. + && let Some(sub_snippet) = snippet.trim().strip_prefix("doc") + && let Some(sub_snippet) = sub_snippet.trim().strip_prefix("=") + && sub_snippet.trim().starts_with("include_str!") + { + span_lint_and_sugg( + cx, + DOC_INCLUDE_WITHOUT_CFG, + attr.span, + "included a file in documentation unconditionally", + "use `cfg_attr(doc, doc = \"...\")`", + format!( + "#{}[cfg_attr(doc, {snippet})]", + if attr.style == AttrStyle::Inner { "!" } else { "" } + ), + Applicability::MachineApplicable, + ); + } + } +} diff --git a/clippy_lints/src/doc/mod.rs b/clippy_lints/src/doc/mod.rs index df7c37a192a..dae7fab47df 100644 --- a/clippy_lints/src/doc/mod.rs +++ b/clippy_lints/src/doc/mod.rs @@ -1,3 +1,5 @@ +#![allow(clippy::lint_without_lint_pass)] + mod lazy_continuation; mod too_long_first_doc_paragraph; @@ -33,6 +35,7 @@ use std::ops::Range; use url::Url; mod empty_line_after; +mod include_in_doc_without_cfg; mod link_with_quotes; mod markdown; mod missing_headers; @@ -532,6 +535,29 @@ declare_clippy_lint! { "empty line after doc comments" } +declare_clippy_lint! { + /// ### What it does + /// Checks if included files in doc comments are included only for `cfg(doc)`. + /// + /// ### Why is this bad? + /// These files are not useful for compilation but will still be included. + /// Also, if any of these non-source code file is updated, it will trigger a + /// recompilation. + /// + /// ### Example + /// ```ignore + /// #![doc = include_str!("some_file.md")] + /// ``` + /// Use instead: + /// ```no_run + /// #![cfg_attr(doc, doc = include_str!("some_file.md"))] + /// ``` + #[clippy::version = "1.84.0"] + pub DOC_INCLUDE_WITHOUT_CFG, + pedantic, + "check if files included in documentation are behind `cfg(doc)`" +} + pub struct Documentation { valid_idents: FxHashSet, check_private_items: bool, @@ -561,6 +587,7 @@ impl_lint_pass!(Documentation => [ EMPTY_LINE_AFTER_OUTER_ATTR, EMPTY_LINE_AFTER_DOC_COMMENTS, TOO_LONG_FIRST_DOC_PARAGRAPH, + DOC_INCLUDE_WITHOUT_CFG, ]); impl<'tcx> LateLintPass<'tcx> for Documentation { @@ -690,6 +717,7 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet, attrs: &[ Some(("fake".into(), "fake".into())) } + include_in_doc_without_cfg::check(cx, attrs); if suspicious_doc_comments::check(cx, attrs) || empty_line_after::check(cx, attrs) || is_doc_hidden(attrs) { return None; } diff --git a/tests/ui/doc/doc_include_without_cfg.fixed b/tests/ui/doc/doc_include_without_cfg.fixed new file mode 100644 index 00000000000..d4ae810d738 --- /dev/null +++ b/tests/ui/doc/doc_include_without_cfg.fixed @@ -0,0 +1,40 @@ +#![warn(clippy::doc_include_without_cfg)] +// Should not lint. +#![doc(html_playground_url = "https://playground.example.com/")] +#![cfg_attr(doc, doc = include_str!("../approx_const.rs"))] //~ doc_include_without_cfg +// Should not lint. +#![cfg_attr(feature = "whatever", doc = include_str!("../approx_const.rs"))] +#![cfg_attr(doc, doc = include_str!("../approx_const.rs"))] +#![doc = "some doc"] +//! more doc + +macro_rules! man_link { + ($a:literal, $b:literal) => { + concat!($a, $b) + }; +} + +// Should not lint! +macro_rules! tst { + ($(#[$attr:meta])*) => { + $(#[$attr])* + fn blue() { + println!("Hello, world!"); + } + } +} + +tst! { + /// This is a test with no included file +} + +#[cfg_attr(doc, doc = include_str!("../approx_const.rs"))] //~ doc_include_without_cfg +// Should not lint. +#[doc = man_link!("bla", "blob")] +#[cfg_attr(feature = "whatever", doc = include_str!("../approx_const.rs"))] +#[cfg_attr(doc, doc = include_str!("../approx_const.rs"))] +#[doc = "some doc"] +/// more doc +fn main() { + // test code goes here +} diff --git a/tests/ui/doc/doc_include_without_cfg.rs b/tests/ui/doc/doc_include_without_cfg.rs new file mode 100644 index 00000000000..c82f6bf2035 --- /dev/null +++ b/tests/ui/doc/doc_include_without_cfg.rs @@ -0,0 +1,40 @@ +#![warn(clippy::doc_include_without_cfg)] +// Should not lint. +#![doc(html_playground_url = "https://playground.example.com/")] +#![doc = include_str!("../approx_const.rs")] //~ doc_include_without_cfg +// Should not lint. +#![cfg_attr(feature = "whatever", doc = include_str!("../approx_const.rs"))] +#![cfg_attr(doc, doc = include_str!("../approx_const.rs"))] +#![doc = "some doc"] +//! more doc + +macro_rules! man_link { + ($a:literal, $b:literal) => { + concat!($a, $b) + }; +} + +// Should not lint! +macro_rules! tst { + ($(#[$attr:meta])*) => { + $(#[$attr])* + fn blue() { + println!("Hello, world!"); + } + } +} + +tst! { + /// This is a test with no included file +} + +#[doc = include_str!("../approx_const.rs")] //~ doc_include_without_cfg +// Should not lint. +#[doc = man_link!("bla", "blob")] +#[cfg_attr(feature = "whatever", doc = include_str!("../approx_const.rs"))] +#[cfg_attr(doc, doc = include_str!("../approx_const.rs"))] +#[doc = "some doc"] +/// more doc +fn main() { + // test code goes here +} diff --git a/tests/ui/doc/doc_include_without_cfg.stderr b/tests/ui/doc/doc_include_without_cfg.stderr new file mode 100644 index 00000000000..17ea53c7c31 --- /dev/null +++ b/tests/ui/doc/doc_include_without_cfg.stderr @@ -0,0 +1,17 @@ +error: included a file in documentation unconditionally + --> tests/ui/doc/doc_include_without_cfg.rs:4:1 + | +LL | #![doc = include_str!("../approx_const.rs")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `cfg_attr(doc, doc = "...")`: `#![cfg_attr(doc, doc = include_str!("../approx_const.rs"))]` + | + = note: `-D clippy::doc-include-without-cfg` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::doc_include_without_cfg)]` + +error: included a file in documentation unconditionally + --> tests/ui/doc/doc_include_without_cfg.rs:31:1 + | +LL | #[doc = include_str!("../approx_const.rs")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `cfg_attr(doc, doc = "...")`: `#[cfg_attr(doc, doc = include_str!("../approx_const.rs"))]` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/missing_doc_crate.rs b/tests/ui/missing_doc_crate.rs index e00c7fbfed1..fdb23af279d 100644 --- a/tests/ui/missing_doc_crate.rs +++ b/tests/ui/missing_doc_crate.rs @@ -1,4 +1,5 @@ #![warn(clippy::missing_docs_in_private_items)] +#![allow(clippy::doc_include_without_cfg)] #![doc = include_str!("../../README.md")] fn main() {} From 70d53bb364ced275c2e893763a1d6f8772ea1cdb Mon Sep 17 00:00:00 2001 From: xFrednet Date: Thu, 21 Nov 2024 13:59:05 +0000 Subject: [PATCH 28/45] Changelog for Clippy 1.83 :robot: --- CHANGELOG.md | 49 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd3124ee9a3..1fefd3e37e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,11 +6,56 @@ document. ## Unreleased / Beta / In Rust Nightly -[0f8eabd6...master](https://github.com/rust-lang/rust-clippy/compare/0f8eabd6...master) +[aa0d5513...master](https://github.com/rust-lang/rust-clippy/compare/aa0d5513...master) + +## Rust 1.83 + +Current stable, released 2024-11-28 + +[View all 64 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2024-08-25T09%3A59%3A01Z..2024-10-03T13%3A42%3A56Z+base%3Amaster) + +### Important Change + +* Removed the implicit `cargo-clippy` feature set by Clippy as announced here: + + [#13246](https://github.com/rust-lang/rust-clippy/pull/13246) + +### New Lints + +* Added [`unused_trait_names`] to `restriction` + [#13322](https://github.com/rust-lang/rust-clippy/pull/13322) +* Added [`unnecessary_first_then_check`] to `complexity` + [#13421](https://github.com/rust-lang/rust-clippy/pull/13421) +* Added [`non_zero_suggestions`] to `restriction` + [#13167](https://github.com/rust-lang/rust-clippy/pull/13167) +* Added [`manual_is_power_of_two`] to `pedantic` + [#13327](https://github.com/rust-lang/rust-clippy/pull/13327) +* Added [`manual_div_ceil`] to `complexity` + [#12987](https://github.com/rust-lang/rust-clippy/pull/12987) +* Added [`zombie_processes`] to `suspicious` + [#11476](https://github.com/rust-lang/rust-clippy/pull/11476) +* Added [`used_underscore_items`] to `pedantic` + [#13294](https://github.com/rust-lang/rust-clippy/pull/13294) + +### Moves and Deprecations + +* Moved [`ref_option`] to `pedantic` (From `nursery`) + [#13469](https://github.com/rust-lang/rust-clippy/pull/13469) +* Moved [`manual_c_str_literals`] to `complexity` (From `pedantic` now warn-by-default) + [#13263](https://github.com/rust-lang/rust-clippy/pull/13263) +* Moved [`empty_line_after_doc_comments`] to `suspicious` (From `nursery` now warn-by-default) + [#13091](https://github.com/rust-lang/rust-clippy/pull/13091) +* Moved [`empty_line_after_outer_attr`] to `suspicious` (From `nursery` now warn-by-default) + [#13091](https://github.com/rust-lang/rust-clippy/pull/13091) + +### Enhancements + +* [`missing_panics_doc`]: No longer lints in const environments + [#13382](https://github.com/rust-lang/rust-clippy/pull/13382) ## Rust 1.82 -Current stable, released 2024-10-17 +Released 2024-10-17 [View all 108 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2024-07-11T20%3A12%3A07Z..2024-08-24T20%3A55%3A35Z+base%3Amaster) From 9f7fb41272647ee9db7038a9588aa5a70e38405e Mon Sep 17 00:00:00 2001 From: Scott Gerring Date: Fri, 22 Nov 2024 14:17:45 +0100 Subject: [PATCH 29/45] fix: multipart suggestions for derivable_impls --- clippy_lints/src/derivable_impls.rs | 48 +++-- tests/ui/derivable_impls.fixed | 295 ++++++++++++++++++++++++++++ tests/ui/derivable_impls.rs | 2 - tests/ui/derivable_impls.stderr | 60 +++--- 4 files changed, 343 insertions(+), 62 deletions(-) create mode 100644 tests/ui/derivable_impls.fixed diff --git a/clippy_lints/src/derivable_impls.rs b/clippy_lints/src/derivable_impls.rs index 2b264421322..9569081ad08 100644 --- a/clippy_lints/src/derivable_impls.rs +++ b/clippy_lints/src/derivable_impls.rs @@ -132,17 +132,15 @@ fn check_struct<'tcx>( if should_emit { let struct_span = cx.tcx.def_span(adt_def.did()); + let suggestions = vec![ + (item.span, String::new()), // Remove the manual implementation + (struct_span.shrink_to_lo(), "#[derive(Default)]\n".to_string()), // Add the derive attribute + ]; + span_lint_and_then(cx, DERIVABLE_IMPLS, item.span, "this `impl` can be derived", |diag| { - diag.span_suggestion_hidden( - item.span, - "remove the manual implementation...", - String::new(), - Applicability::MachineApplicable, - ); - diag.span_suggestion( - struct_span.shrink_to_lo(), - "...and instead derive it", - "#[derive(Default)]\n".to_string(), + diag.multipart_suggestion( + "replace the manual implementation with a derive attribute", + suggestions, Applicability::MachineApplicable, ); }); @@ -161,23 +159,23 @@ fn check_enum<'tcx>(cx: &LateContext<'tcx>, item: &'tcx Item<'_>, func_expr: &Ex let indent_enum = indent_of(cx, enum_span).unwrap_or(0); let variant_span = cx.tcx.def_span(variant_def.def_id); let indent_variant = indent_of(cx, variant_span).unwrap_or(0); - span_lint_and_then(cx, DERIVABLE_IMPLS, item.span, "this `impl` can be derived", |diag| { - diag.span_suggestion_hidden( - item.span, - "remove the manual implementation...", - String::new(), - Applicability::MachineApplicable, - ); - diag.span_suggestion( + + let suggestions = vec![ + (item.span, String::new()), // Remove the manual implementation + ( enum_span.shrink_to_lo(), - "...and instead derive it...", - format!("#[derive(Default)]\n{indent}", indent = " ".repeat(indent_enum),), - Applicability::MachineApplicable, - ); - diag.span_suggestion( + format!("#[derive(Default)]\n{}", " ".repeat(indent_enum)), + ), // Add the derive attribute + ( variant_span.shrink_to_lo(), - "...and mark the default variant", - format!("#[default]\n{indent}", indent = " ".repeat(indent_variant),), + format!("#[default]\n{}", " ".repeat(indent_variant)), + ), // Mark the default variant + ]; + + span_lint_and_then(cx, DERIVABLE_IMPLS, item.span, "this `impl` can be derived", |diag| { + diag.multipart_suggestion( + "replace the manual implementation with a derive attribute and mark the default variant", + suggestions, Applicability::MachineApplicable, ); }); diff --git a/tests/ui/derivable_impls.fixed b/tests/ui/derivable_impls.fixed new file mode 100644 index 00000000000..c85f384fd6e --- /dev/null +++ b/tests/ui/derivable_impls.fixed @@ -0,0 +1,295 @@ +#![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) + } +} + +#[derive(Default)] +pub enum SimpleEnum { + Foo, + #[default] + Bar, +} + + +pub enum NonExhaustiveEnum { + Foo, + #[non_exhaustive] + Bar, +} + +impl Default for NonExhaustiveEnum { + fn default() -> Self { + NonExhaustiveEnum::Bar + } +} + +// https://github.com/rust-lang/rust-clippy/issues/10396 + +#[derive(Default)] +struct DefaultType; + +struct GenericType { + t: T, +} + +impl Default for GenericType { + fn default() -> Self { + Self { t: Default::default() } + } +} + +struct InnerGenericType { + t: T, +} + +impl Default for InnerGenericType { + fn default() -> Self { + Self { t: Default::default() } + } +} + +struct OtherGenericType { + inner: InnerGenericType, +} + +impl Default for OtherGenericType { + fn default() -> Self { + Self { + inner: Default::default(), + } + } +} + +mod issue10158 { + pub trait T {} + + #[derive(Default)] + pub struct S {} + impl T for S {} + + pub struct Outer { + pub inner: Box, + } + + impl Default for Outer { + fn default() -> Self { + Outer { + // Box::::default() adjusts to Box + inner: Box::::default(), + } + } + } +} + +mod issue11368 { + pub struct A { + a: u32, + } + + impl Default for A { + #[track_caller] + fn default() -> Self { + Self { a: 0 } + } + } +} + +fn main() {} diff --git a/tests/ui/derivable_impls.rs b/tests/ui/derivable_impls.rs index 58f7771b627..21d73ba8b77 100644 --- a/tests/ui/derivable_impls.rs +++ b/tests/ui/derivable_impls.rs @@ -1,7 +1,5 @@ #![allow(dead_code)] -//@no-rustfix: need to change the suggestion to a multipart suggestion - use std::collections::HashMap; struct FooDefault<'a> { diff --git a/tests/ui/derivable_impls.stderr b/tests/ui/derivable_impls.stderr index d3adfa60e10..c22569145bd 100644 --- a/tests/ui/derivable_impls.stderr +++ b/tests/ui/derivable_impls.stderr @@ -1,5 +1,5 @@ error: this `impl` can be derived - --> tests/ui/derivable_impls.rs:22:1 + --> tests/ui/derivable_impls.rs:20:1 | LL | / impl std::default::Default for FooDefault<'_> { LL | | fn default() -> Self { @@ -12,15 +12,14 @@ LL | | } | = note: `-D clippy::derivable-impls` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::derivable_impls)]` - = help: remove the manual implementation... -help: ...and instead derive it +help: replace the manual implementation with a derive attribute | LL + #[derive(Default)] -LL | struct FooDefault<'a> { +LL ~ struct FooDefault<'a> { | error: this `impl` can be derived - --> tests/ui/derivable_impls.rs:43:1 + --> tests/ui/derivable_impls.rs:41:1 | LL | / impl std::default::Default for TupleDefault { LL | | fn default() -> Self { @@ -29,15 +28,14 @@ LL | | } LL | | } | |_^ | - = help: remove the manual implementation... -help: ...and instead derive it +help: replace the manual implementation with a derive attribute | LL + #[derive(Default)] -LL | struct TupleDefault(bool, i32, u64); +LL ~ struct TupleDefault(bool, i32, u64); | error: this `impl` can be derived - --> tests/ui/derivable_impls.rs:95:1 + --> tests/ui/derivable_impls.rs:93:1 | LL | / impl Default for StrDefault<'_> { LL | | fn default() -> Self { @@ -46,15 +44,14 @@ LL | | } LL | | } | |_^ | - = help: remove the manual implementation... -help: ...and instead derive it +help: replace the manual implementation with a derive attribute | LL + #[derive(Default)] -LL | struct StrDefault<'a>(&'a str); +LL ~ struct StrDefault<'a>(&'a str); | error: this `impl` can be derived - --> tests/ui/derivable_impls.rs:121:1 + --> tests/ui/derivable_impls.rs:119:1 | LL | / impl Default for Y { LL | | fn default() -> Self { @@ -63,15 +60,14 @@ LL | | } LL | | } | |_^ | - = help: remove the manual implementation... -help: ...and instead derive it +help: replace the manual implementation with a derive attribute | LL + #[derive(Default)] -LL | struct Y(u32); +LL ~ struct Y(u32); | error: this `impl` can be derived - --> tests/ui/derivable_impls.rs:160:1 + --> tests/ui/derivable_impls.rs:158:1 | LL | / impl Default for WithoutSelfCurly { LL | | fn default() -> Self { @@ -80,15 +76,14 @@ LL | | } LL | | } | |_^ | - = help: remove the manual implementation... -help: ...and instead derive it +help: replace the manual implementation with a derive attribute | LL + #[derive(Default)] -LL | struct WithoutSelfCurly { +LL ~ struct WithoutSelfCurly { | error: this `impl` can be derived - --> tests/ui/derivable_impls.rs:168:1 + --> tests/ui/derivable_impls.rs:166:1 | LL | / impl Default for WithoutSelfParan { LL | | fn default() -> Self { @@ -97,15 +92,14 @@ LL | | } LL | | } | |_^ | - = help: remove the manual implementation... -help: ...and instead derive it +help: replace the manual implementation with a derive attribute | LL + #[derive(Default)] -LL | struct WithoutSelfParan(bool); +LL ~ struct WithoutSelfParan(bool); | error: this `impl` can be derived - --> tests/ui/derivable_impls.rs:218:1 + --> tests/ui/derivable_impls.rs:216:1 | LL | / impl Default for RepeatDefault1 { LL | | fn default() -> Self { @@ -114,15 +108,14 @@ LL | | } LL | | } | |_^ | - = help: remove the manual implementation... -help: ...and instead derive it +help: replace the manual implementation with a derive attribute | LL + #[derive(Default)] -LL | pub struct RepeatDefault1 { +LL ~ pub struct RepeatDefault1 { | error: this `impl` can be derived - --> tests/ui/derivable_impls.rs:252:1 + --> tests/ui/derivable_impls.rs:250:1 | LL | / impl Default for SimpleEnum { LL | | fn default() -> Self { @@ -131,14 +124,11 @@ LL | | } LL | | } | |_^ | - = help: remove the manual implementation... -help: ...and instead derive it... +help: replace the manual implementation with a derive attribute and mark the default variant | LL + #[derive(Default)] -LL | pub enum SimpleEnum { - | -help: ...and mark the default variant - | +LL ~ pub enum SimpleEnum { +LL | Foo, LL ~ #[default] LL ~ Bar, | From f0bb475f80f39da2ba9c7919c8729eaa9a7bc76d Mon Sep 17 00:00:00 2001 From: boyned//Kampfkarren <3190756+Kampfkarren@users.noreply.github.com> Date: Fri, 22 Nov 2024 10:16:46 -0800 Subject: [PATCH 30/45] Remove incorrect "no default" text from trivial_copy_size_limit --- clippy_config/src/conf.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index 9eef3d9e4fc..41b56b45d9a 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -678,7 +678,7 @@ define_Conf! { #[lints(arbitrary_source_item_ordering)] trait_assoc_item_kinds_order: SourceItemOrderingTraitAssocItemKinds = DEFAULT_TRAIT_ASSOC_ITEM_KINDS_ORDER.into(), /// The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by - /// reference. By default there is no limit + /// reference. #[default_text = "target_pointer_width * 2"] #[lints(trivially_copy_pass_by_ref)] trivial_copy_size_limit: Option = None, From 45e1a3a6f413801519ccd0f1829ce51ecc836a44 Mon Sep 17 00:00:00 2001 From: Fridtjof Stoldt Date: Fri, 22 Nov 2024 20:47:47 +0000 Subject: [PATCH 31/45] Update CHANGELOG.md Co-authored-by: Philipp Krones --- CHANGELOG.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1fefd3e37e0..e9c8d222c55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,11 +41,11 @@ Current stable, released 2024-11-28 * Moved [`ref_option`] to `pedantic` (From `nursery`) [#13469](https://github.com/rust-lang/rust-clippy/pull/13469) -* Moved [`manual_c_str_literals`] to `complexity` (From `pedantic` now warn-by-default) +* Moved [`manual_c_str_literals`] to `complexity` (From `pedantic`, now warn-by-default) [#13263](https://github.com/rust-lang/rust-clippy/pull/13263) -* Moved [`empty_line_after_doc_comments`] to `suspicious` (From `nursery` now warn-by-default) +* Moved [`empty_line_after_doc_comments`] to `suspicious` (From `nursery`, now warn-by-default) [#13091](https://github.com/rust-lang/rust-clippy/pull/13091) -* Moved [`empty_line_after_outer_attr`] to `suspicious` (From `nursery` now warn-by-default) +* Moved [`empty_line_after_outer_attr`] to `suspicious` (From `nursery`, now warn-by-default) [#13091](https://github.com/rust-lang/rust-clippy/pull/13091) ### Enhancements From 1931fb825bb18a4bf6f2af6e0249dcf72119c263 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 Nov 2024 08:05:19 +0100 Subject: [PATCH 32/45] remove is_trivially_const_drop --- clippy_utils/src/qualify_min_const_fn.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index 345c46f944a..3c9ea4bfaf4 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -404,12 +404,11 @@ fn is_ty_const_destruct<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, body: &Body<'tcx> // FIXME(const_trait_impl, fee1-dead) revert to const destruct once it works again #[expect(unused)] fn is_ty_const_destruct_unused<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, body: &Body<'tcx>) -> bool { - // Avoid selecting for simple cases, such as builtin types. - if ty::util::is_trivially_const_drop(ty) { - return true; + // If this doesn't need drop at all, then don't select `~const Destruct`. + if !ty.needs_drop(tcx, body.typing_env(tcx)) { + return false; } - let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(body.typing_env(tcx)); // FIXME(const_trait_impl) constness From 78fa111a48001abf372911b50d7d7ed25424d489 Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 20 Nov 2024 11:31:49 +0100 Subject: [PATCH 33/45] no more Reveal :( --- clippy_lints/src/derive.rs | 2 -- clippy_utils/src/ty.rs | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index 3b6b3c89858..1a34b87e42a 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -11,7 +11,6 @@ use rustc_hir::{ }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; -use rustc_middle::traits::Reveal; use rustc_middle::ty::{ self, ClauseKind, GenericArgKind, GenericParamDefKind, ParamEnv, TraitPredicate, Ty, TyCtxt, Upcast, }; @@ -516,7 +515,6 @@ fn typing_env_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId .upcast(tcx) }), )), - Reveal::UserFacing, ); ty::TypingEnv { typing_mode: ty::TypingMode::non_body_analysis(), diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 3498606dfd3..03e1a814a86 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -575,7 +575,7 @@ pub fn same_type_and_consts<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { /// Checks if a given type looks safe to be uninitialized. pub fn is_uninit_value_valid_for_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { - let typing_env = cx.typing_env().with_reveal_all_normalized(cx.tcx); + let typing_env = cx.typing_env().with_post_analysis_normalized(cx.tcx); cx.tcx .check_validity_requirement((ValidityRequirement::Uninit, typing_env.as_query_input(ty))) .unwrap_or_else(|_| is_uninit_value_valid_for_ty_fallback(cx, ty)) From 80df2c4cede1ac58eac55c3d50b72f34dae6c65f Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Sat, 23 Nov 2024 19:38:44 +0100 Subject: [PATCH 34/45] Use a better description of an internal function --- 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 c73ab4bfa68..205c921f7cf 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -732,7 +732,7 @@ pub fn over(left: &[X], right: &[X], mut eq_fn: impl FnMut(&X, &X) -> bool) - left.len() == right.len() && left.iter().zip(right).all(|(x, y)| eq_fn(x, y)) } -/// Counts how many elements of the slices are equal as per `eq_fn`. +/// Counts how many elements at the beginning of the slices are equal as per `eq_fn`. pub fn count_eq( left: &mut dyn Iterator, right: &mut dyn Iterator, From 9fd8e99d91f7029016b9097d1311c1045f35667f Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Sat, 23 Nov 2024 19:22:01 +0100 Subject: [PATCH 35/45] Prevent ICE in case of a bound constraint on generic argument --- clippy_utils/src/hir_utils.rs | 11 ++++++----- tests/ui/trait_duplication_in_bounds.fixed | 17 ++++++++++++++++- tests/ui/trait_duplication_in_bounds.rs | 17 ++++++++++++++++- 3 files changed, 38 insertions(+), 7 deletions(-) diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index c73ab4bfa68..7bc70836651 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -603,11 +603,7 @@ impl HirEqInterExpr<'_, '_, '_> { } fn eq_assoc_type_binding(&mut self, left: &AssocItemConstraint<'_>, right: &AssocItemConstraint<'_>) -> bool { - left.ident.name == right.ident.name - && self.eq_ty( - left.ty().expect("expected assoc type binding"), - right.ty().expect("expected assoc type binding"), - ) + left.ident.name == right.ident.name && both_some_and(left.ty(), right.ty(), |l, r| self.eq_ty(l, r)) } fn check_ctxt(&mut self, left: SyntaxContext, right: SyntaxContext) -> bool { @@ -727,6 +723,11 @@ pub fn both(l: Option<&X>, r: Option<&X>, mut eq_fn: impl FnMut(&X, &X) -> bo .map_or_else(|| r.is_none(), |x| r.as_ref().is_some_and(|y| eq_fn(x, y))) } +/// Checks if the two `Option`s are both `Some` and pass the predicate function. +pub fn both_some_and(l: Option, r: Option, mut pred: impl FnMut(X, Y) -> bool) -> bool { + l.is_some_and(|l| r.is_some_and(|r| pred(l, r))) +} + /// Checks if two slices are equal as per `eq_fn`. pub fn over(left: &[X], right: &[X], mut eq_fn: impl FnMut(&X, &X) -> bool) -> bool { left.len() == right.len() && left.iter().zip(right).all(|(x, y)| eq_fn(x, y)) diff --git a/tests/ui/trait_duplication_in_bounds.fixed b/tests/ui/trait_duplication_in_bounds.fixed index 779431303ae..e57c79553c3 100644 --- a/tests/ui/trait_duplication_in_bounds.fixed +++ b/tests/ui/trait_duplication_in_bounds.fixed @@ -1,6 +1,6 @@ #![deny(clippy::trait_duplication_in_bounds)] #![allow(unused)] -#![feature(const_trait_impl)] +#![feature(associated_const_equality, const_trait_impl)] use std::any::Any; @@ -179,3 +179,18 @@ fn main() { let _x: fn(_) = f::<()>; let _x: fn(_) = f::; } + +// #13706 +fn assoc_tys_bounds() +where + T: Iterator + Iterator, +{ +} +trait AssocConstTrait { + const ASSOC: usize; +} +fn assoc_const_args() +where + T: AssocConstTrait + AssocConstTrait, +{ +} diff --git a/tests/ui/trait_duplication_in_bounds.rs b/tests/ui/trait_duplication_in_bounds.rs index 3e974dc0a8f..ee84d3c3011 100644 --- a/tests/ui/trait_duplication_in_bounds.rs +++ b/tests/ui/trait_duplication_in_bounds.rs @@ -1,6 +1,6 @@ #![deny(clippy::trait_duplication_in_bounds)] #![allow(unused)] -#![feature(const_trait_impl)] +#![feature(associated_const_equality, const_trait_impl)] use std::any::Any; @@ -179,3 +179,18 @@ fn main() { let _x: fn(_) = f::<()>; let _x: fn(_) = f::; } + +// #13706 +fn assoc_tys_bounds() +where + T: Iterator + Iterator, +{ +} +trait AssocConstTrait { + const ASSOC: usize; +} +fn assoc_const_args() +where + T: AssocConstTrait + AssocConstTrait, +{ +} From 943c3bc3db590b8549f76eee814bef58b68a37f8 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sat, 23 Nov 2024 17:10:08 -0700 Subject: [PATCH 36/45] Add note about caveat for `cfg(doc)` For example, we definitely wouldn't want to do this in libcore. --- clippy_lints/src/doc/mod.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/doc/mod.rs b/clippy_lints/src/doc/mod.rs index fd6ae21a5f8..993335e8248 100644 --- a/clippy_lints/src/doc/mod.rs +++ b/clippy_lints/src/doc/mod.rs @@ -539,11 +539,15 @@ declare_clippy_lint! { /// ### What it does /// Checks if included files in doc comments are included only for `cfg(doc)`. /// - /// ### Why is this bad? + /// ### Why restrict this? /// These files are not useful for compilation but will still be included. /// Also, if any of these non-source code file is updated, it will trigger a /// recompilation. /// + /// Excluding this will currently result in the file being left out if + /// the item's docs are inlined from another crate. This may be fixed in a + /// future version of rustdoc. + /// /// ### Example /// ```ignore /// #![doc = include_str!("some_file.md")] @@ -554,7 +558,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.84.0"] pub DOC_INCLUDE_WITHOUT_CFG, - pedantic, + restriction, "check if files included in documentation are behind `cfg(doc)`" } From 418dfb2257c3a2c516b648695b92367dde2a9cd3 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sun, 24 Nov 2024 11:23:14 -0700 Subject: [PATCH 37/45] Add Known problems section --- clippy_lints/src/doc/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/clippy_lints/src/doc/mod.rs b/clippy_lints/src/doc/mod.rs index 993335e8248..88ac871acf6 100644 --- a/clippy_lints/src/doc/mod.rs +++ b/clippy_lints/src/doc/mod.rs @@ -544,6 +544,8 @@ declare_clippy_lint! { /// Also, if any of these non-source code file is updated, it will trigger a /// recompilation. /// + /// ### Known problems + /// /// Excluding this will currently result in the file being left out if /// the item's docs are inlined from another crate. This may be fixed in a /// future version of rustdoc. From 671183a41f57f3a9932ce4d762c7fb30f4cbdd16 Mon Sep 17 00:00:00 2001 From: Kampfkarren Date: Sun, 24 Nov 2024 23:16:27 -0800 Subject: [PATCH 38/45] Bless --- book/src/lint_configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index 670b5cbef82..275d125096e 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -895,7 +895,7 @@ The order of associated items in traits. ## `trivial-copy-size-limit` The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by -reference. By default there is no limit +reference. **Default Value:** `target_pointer_width * 2` From 945ccbd0634b727f2b872f0ffd2872f8b9d7d173 Mon Sep 17 00:00:00 2001 From: Frank King Date: Mon, 25 Nov 2024 16:38:35 +0800 Subject: [PATCH 39/45] Refactor `where` predicates, and reserve for attributes support --- .../src/extra_unused_type_parameters.rs | 7 +++--- clippy_lints/src/implied_bounds_in_impls.rs | 4 ++-- clippy_lints/src/lifetimes.rs | 10 ++++----- clippy_lints/src/multiple_bound_locations.rs | 10 ++++----- clippy_lints/src/needless_maybe_sized.rs | 4 ++-- clippy_lints/src/trait_bounds.rs | 22 +++++++++---------- clippy_utils/src/ast_utils.rs | 4 ++-- 7 files changed, 31 insertions(+), 30 deletions(-) diff --git a/clippy_lints/src/extra_unused_type_parameters.rs b/clippy_lints/src/extra_unused_type_parameters.rs index 6ad879b9fe7..81152da8c85 100644 --- a/clippy_lints/src/extra_unused_type_parameters.rs +++ b/clippy_lints/src/extra_unused_type_parameters.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::intravisit::{Visitor, walk_impl_item, walk_item, walk_param_bound, walk_ty}; use rustc_hir::{ BodyId, ExprKind, GenericBound, GenericParam, GenericParamKind, Generics, ImplItem, ImplItemKind, Item, ItemKind, - PredicateOrigin, Ty, WherePredicate, + PredicateOrigin, Ty, WherePredicate, WherePredicateKind }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::nested_filter; @@ -205,12 +205,13 @@ impl<'tcx> Visitor<'tcx> for TypeWalker<'_, 'tcx> { } fn visit_where_predicate(&mut self, predicate: &'tcx WherePredicate<'tcx>) { - if let WherePredicate::BoundPredicate(predicate) = predicate { + let span = predicate.span; + if let WherePredicateKind::BoundPredicate(predicate) = predicate.kind { // Collect spans for any bounds on type parameters. if let Some((def_id, _)) = predicate.bounded_ty.peel_refs().as_generic_param() { match predicate.origin { PredicateOrigin::GenericParam => { - self.inline_bounds.insert(def_id, predicate.span); + self.inline_bounds.insert(def_id, span); }, PredicateOrigin::WhereClause => { self.where_bounds.insert(def_id); diff --git a/clippy_lints/src/implied_bounds_in_impls.rs b/clippy_lints/src/implied_bounds_in_impls.rs index 65fdc93e0ed..4427edb752e 100644 --- a/clippy_lints/src/implied_bounds_in_impls.rs +++ b/clippy_lints/src/implied_bounds_in_impls.rs @@ -4,7 +4,7 @@ use rustc_errors::{Applicability, SuggestionStyle}; use rustc_hir::def_id::DefId; use rustc_hir::{ AssocItemConstraint, GenericArg, GenericBound, GenericBounds, PredicateOrigin, TraitBoundModifiers, TyKind, - WherePredicate, + WherePredicateKind, }; use rustc_hir_analysis::lower_ty; use rustc_lint::{LateContext, LateLintPass}; @@ -324,7 +324,7 @@ fn check<'tcx>(cx: &LateContext<'tcx>, bounds: GenericBounds<'tcx>) { impl<'tcx> LateLintPass<'tcx> for ImpliedBoundsInImpls { fn check_generics(&mut self, cx: &LateContext<'tcx>, generics: &rustc_hir::Generics<'tcx>) { for predicate in generics.predicates { - if let WherePredicate::BoundPredicate(predicate) = predicate + if let WherePredicateKind::BoundPredicate(predicate) = predicate.kind // In theory, the origin doesn't really matter, // we *could* also lint on explicit where clauses written out by the user, // not just impl trait desugared ones, but that contradicts with the lint name... diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index ce0e1a24a7b..6ff1a1e5ec7 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -12,7 +12,7 @@ use rustc_hir::intravisit::{ use rustc_hir::{ BareFnTy, BodyId, FnDecl, FnSig, GenericArg, GenericArgs, GenericBound, GenericParam, GenericParamKind, Generics, Impl, ImplItem, ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, LifetimeParamKind, Node, PolyTraitRef, - PredicateOrigin, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate, lang_items, + PredicateOrigin, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate, WherePredicateKind, lang_items, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::map::Map; @@ -442,9 +442,9 @@ impl<'tcx> Visitor<'tcx> for RefVisitor<'_, 'tcx> { /// reason about elision. fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, generics: &'tcx Generics<'_>) -> bool { for predicate in generics.predicates { - match *predicate { - WherePredicate::RegionPredicate(..) => return true, - WherePredicate::BoundPredicate(ref pred) => { + match *predicate.kind { + WherePredicateKind::RegionPredicate(..) => return true, + WherePredicateKind::BoundPredicate(ref pred) => { // a predicate like F: Trait or F: for<'a> Trait<'a> let mut visitor = RefVisitor::new(cx); // walk the type F, it may not contain LT refs @@ -467,7 +467,7 @@ fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, generics: &'tcx Generics<'_ } } }, - WherePredicate::EqPredicate(ref pred) => { + WherePredicateKind::EqPredicate(ref pred) => { let mut visitor = RefVisitor::new(cx); walk_ty(&mut visitor, pred.lhs_ty); walk_ty(&mut visitor, pred.rhs_ty); diff --git a/clippy_lints/src/multiple_bound_locations.rs b/clippy_lints/src/multiple_bound_locations.rs index d276e29bace..882ab2dda7a 100644 --- a/clippy_lints/src/multiple_bound_locations.rs +++ b/clippy_lints/src/multiple_bound_locations.rs @@ -1,5 +1,5 @@ use rustc_ast::visit::FnKind; -use rustc_ast::{NodeId, WherePredicate}; +use rustc_ast::{NodeId, WherePredicateKind}; use rustc_data_structures::fx::FxHashMap; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::declare_lint_pass; @@ -51,8 +51,8 @@ impl EarlyLintPass for MultipleBoundLocations { } } for clause in &generics.where_clause.predicates { - match clause { - WherePredicate::BoundPredicate(pred) => { + match &clause.kind { + WherePredicateKind::BoundPredicate(pred) => { if (!pred.bound_generic_params.is_empty() || !pred.bounds.is_empty()) && let Some(Some(bound_span)) = pred .bounded_ty @@ -62,14 +62,14 @@ impl EarlyLintPass for MultipleBoundLocations { emit_lint(cx, *bound_span, pred.bounded_ty.span); } }, - WherePredicate::RegionPredicate(pred) => { + WherePredicateKind::RegionPredicate(pred) => { if !pred.bounds.is_empty() && let Some(bound_span) = generic_params_with_bounds.get(&pred.lifetime.ident.name.as_str()) { emit_lint(cx, *bound_span, pred.lifetime.ident.span); } }, - WherePredicate::EqPredicate(_) => {}, + WherePredicateKind::EqPredicate(_) => {}, } } } diff --git a/clippy_lints/src/needless_maybe_sized.rs b/clippy_lints/src/needless_maybe_sized.rs index 852a0ce8c6d..ad6313e391b 100644 --- a/clippy_lints/src/needless_maybe_sized.rs +++ b/clippy_lints/src/needless_maybe_sized.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use rustc_errors::Applicability; use rustc_hir::def_id::{DefId, DefIdMap}; -use rustc_hir::{BoundPolarity, GenericBound, Generics, PolyTraitRef, TraitBoundModifiers, WherePredicate}; +use rustc_hir::{BoundPolarity, GenericBound, Generics, PolyTraitRef, TraitBoundModifiers, WherePredicateKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{ClauseKind, PredicatePolarity}; use rustc_session::declare_lint_pass; @@ -52,7 +52,7 @@ fn type_param_bounds<'tcx>(generics: &'tcx Generics<'tcx>) -> impl Iterator LateLintPass<'tcx> for TraitBounds { let mut self_bounds_map = FxHashMap::default(); for predicate in item.generics.predicates { - if let WherePredicate::BoundPredicate(bound_predicate) = predicate + if let WherePredicateKind::BoundPredicate(bound_predicate) = predicate.kind && bound_predicate.origin != PredicateOrigin::ImplTrait - && !bound_predicate.span.from_expansion() + && !predicate.span.from_expansion() && let TyKind::Path(QPath::Resolved(_, Path { segments, .. })) = bound_predicate.bounded_ty.kind && let Some(PathSegment { res: Res::SelfTyParam { trait_: def_id }, @@ -268,10 +268,10 @@ impl TraitBounds { let mut map: UnhashMap, Vec<&GenericBound<'_>>> = UnhashMap::default(); let mut applicability = Applicability::MaybeIncorrect; for bound in generics.predicates { - if let WherePredicate::BoundPredicate(p) = bound + if let WherePredicateKind::BoundPredicate(p) = bound.kind && p.origin != PredicateOrigin::ImplTrait && p.bounds.len() as u64 <= self.max_trait_bounds - && !p.span.from_expansion() + && !bound.span.from_expansion() && let bounds = p .bounds .iter() @@ -295,7 +295,7 @@ impl TraitBounds { span_lint_and_help( cx, TYPE_REPETITION_IN_BOUNDS, - p.span, + bound.span, "this type has already been used as a bound predicate", None, hint_string, @@ -322,8 +322,8 @@ fn check_trait_bound_duplication<'tcx>(cx: &LateContext<'tcx>, generics: &'_ Gen .predicates .iter() .filter_map(|pred| { - if pred.in_where_clause() - && let WherePredicate::BoundPredicate(bound_predicate) = pred + if pred.kind.in_where_clause() + && let WherePredicateKind::BoundPredicate(bound_predicate) = pred.kind && let TyKind::Path(QPath::Resolved(_, path)) = bound_predicate.bounded_ty.kind { return Some( @@ -347,10 +347,10 @@ fn check_trait_bound_duplication<'tcx>(cx: &LateContext<'tcx>, generics: &'_ Gen // | // compare trait bounds keyed by generic name and comparable trait to collected where // predicates eg. (T, Clone) - for predicate in generics.predicates.iter().filter(|pred| !pred.in_where_clause()) { - if let WherePredicate::BoundPredicate(bound_predicate) = predicate + for predicate in generics.predicates.iter().filter(|pred| !pred.kind.in_where_clause()) { + if let WherePredicateKind::BoundPredicate(bound_predicate) = predicate.kind && bound_predicate.origin != PredicateOrigin::ImplTrait - && !bound_predicate.span.from_expansion() + && !predicate.span.from_expansion() && let TyKind::Path(QPath::Resolved(_, path)) = bound_predicate.bounded_ty.kind { let traits = rollup_traits(cx, bound_predicate.bounds, "these bounds contain repeated elements"); diff --git a/clippy_utils/src/ast_utils.rs b/clippy_utils/src/ast_utils.rs index 0be6dc15a8e..c90f4a6ebfe 100644 --- a/clippy_utils/src/ast_utils.rs +++ b/clippy_utils/src/ast_utils.rs @@ -661,8 +661,8 @@ pub fn eq_generics(l: &Generics, r: &Generics) -> bool { } pub fn eq_where_predicate(l: &WherePredicate, r: &WherePredicate) -> bool { - use WherePredicate::*; - match (l, r) { + use WherePredicateKind::*; + match (&l.kind, &r.kind) { (BoundPredicate(l), BoundPredicate(r)) => { over(&l.bound_generic_params, &r.bound_generic_params, |l, r| { eq_generic_param(l, r) From 2bf03f19e2722f5254555eaa8c96510de6d3ec66 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Sat, 23 Nov 2024 21:02:27 +0100 Subject: [PATCH 40/45] Handle repetition of associated constant constraint as well --- clippy_utils/src/hir_utils.rs | 11 ++++++++--- tests/ui/trait_duplication_in_bounds.fixed | 3 ++- tests/ui/trait_duplication_in_bounds.rs | 1 + tests/ui/trait_duplication_in_bounds.stderr | 8 +++++++- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index 5c93a9948b8..5c5d84cb381 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -545,7 +545,7 @@ impl HirEqInterExpr<'_, '_, '_> { fn eq_path_parameters(&mut self, left: &GenericArgs<'_>, right: &GenericArgs<'_>) -> bool { if left.parenthesized == right.parenthesized { over(left.args, right.args, |l, r| self.eq_generic_arg(l, r)) // FIXME(flip1995): may not work - && over(left.constraints, right.constraints, |l, r| self.eq_assoc_type_binding(l, r)) + && over(left.constraints, right.constraints, |l, r| self.eq_assoc_eq_constraint(l, r)) } else { false } @@ -602,8 +602,13 @@ impl HirEqInterExpr<'_, '_, '_> { } } - fn eq_assoc_type_binding(&mut self, left: &AssocItemConstraint<'_>, right: &AssocItemConstraint<'_>) -> bool { - left.ident.name == right.ident.name && both_some_and(left.ty(), right.ty(), |l, r| self.eq_ty(l, r)) + /// Checks whether two constraints designate the same equality constraint (same name, and same + /// type or const). + fn eq_assoc_eq_constraint(&mut self, left: &AssocItemConstraint<'_>, right: &AssocItemConstraint<'_>) -> bool { + // TODO: this could be extended to check for identical associated item bound constraints + left.ident.name == right.ident.name + && (both_some_and(left.ty(), right.ty(), |l, r| self.eq_ty(l, r)) + || both_some_and(left.ct(), right.ct(), |l, r| self.eq_const_arg(l, r))) } fn check_ctxt(&mut self, left: SyntaxContext, right: SyntaxContext) -> bool { diff --git a/tests/ui/trait_duplication_in_bounds.fixed b/tests/ui/trait_duplication_in_bounds.fixed index e57c79553c3..708512793d5 100644 --- a/tests/ui/trait_duplication_in_bounds.fixed +++ b/tests/ui/trait_duplication_in_bounds.fixed @@ -191,6 +191,7 @@ trait AssocConstTrait { } fn assoc_const_args() where - T: AssocConstTrait + AssocConstTrait, + T: AssocConstTrait, + //~^ trait_duplication_in_bounds { } diff --git a/tests/ui/trait_duplication_in_bounds.rs b/tests/ui/trait_duplication_in_bounds.rs index ee84d3c3011..12db6b65a7a 100644 --- a/tests/ui/trait_duplication_in_bounds.rs +++ b/tests/ui/trait_duplication_in_bounds.rs @@ -192,5 +192,6 @@ trait AssocConstTrait { fn assoc_const_args() where T: AssocConstTrait + AssocConstTrait, + //~^ trait_duplication_in_bounds { } diff --git a/tests/ui/trait_duplication_in_bounds.stderr b/tests/ui/trait_duplication_in_bounds.stderr index 0dd508e4745..83c06eaccd4 100644 --- a/tests/ui/trait_duplication_in_bounds.stderr +++ b/tests/ui/trait_duplication_in_bounds.stderr @@ -70,5 +70,11 @@ error: these where clauses contain repeated elements LL | T: IntoIterator + IntoIterator, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `IntoIterator` -error: aborting due to 11 previous errors +error: these where clauses contain repeated elements + --> tests/ui/trait_duplication_in_bounds.rs:194:8 + | +LL | T: AssocConstTrait + AssocConstTrait, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `AssocConstTrait` + +error: aborting due to 12 previous errors From 6dcac6e2bfbabc9f9552da40c7cc58996452dbe3 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Tue, 26 Nov 2024 10:55:13 +0100 Subject: [PATCH 41/45] unnecessary_map_or: fix version for lint addition --- clippy_lints/src/methods/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 2e9f6ea4731..7d1d5d69c99 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -4129,7 +4129,7 @@ declare_clippy_lint! { /// ) /// } /// ``` - #[clippy::version = "1.75.0"] + #[clippy::version = "1.84.0"] pub UNNECESSARY_MAP_OR, style, "reduce unnecessary calls to `.map_or(bool, …)`" From 17fb5adf58bda51c03d9a8794ecd622b8b221cb5 Mon Sep 17 00:00:00 2001 From: blyxyas Date: Tue, 26 Nov 2024 17:36:12 +0100 Subject: [PATCH 42/45] [] Fix FP on proc macros --- clippy_lints/src/operators/bit_mask.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/operators/bit_mask.rs b/clippy_lints/src/operators/bit_mask.rs index 4414056a467..e87cfd103c3 100644 --- a/clippy_lints/src/operators/bit_mask.rs +++ b/clippy_lints/src/operators/bit_mask.rs @@ -1,5 +1,6 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint; +use clippy_utils::is_from_proc_macro; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; use rustc_span::Span; @@ -35,9 +36,9 @@ fn invert_cmp(cmp: BinOpKind) -> BinOpKind { } } -fn check_compare(cx: &LateContext<'_>, bit_op: &Expr<'_>, cmp_op: BinOpKind, cmp_value: u128, span: Span) { +fn check_compare<'a>(cx: &LateContext<'a>, bit_op: &Expr<'a>, cmp_op: BinOpKind, cmp_value: u128, span: Span) { if let ExprKind::Binary(op, left, right) = &bit_op.kind { - if op.node != BinOpKind::BitAnd && op.node != BinOpKind::BitOr { + if op.node != BinOpKind::BitAnd && op.node != BinOpKind::BitOr || is_from_proc_macro(cx, bit_op) { return; } if let Some(mask) = fetch_int_literal(cx, right).or_else(|| fetch_int_literal(cx, left)) { From 3c9daca1d159930adada5ac843b00b24e7bd0d24 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 28 Nov 2024 18:57:00 +0100 Subject: [PATCH 43/45] Bump nightly version -> 2024-11-28 --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 0a2e9d89b6e..fb159ca2ae0 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,6 +1,6 @@ [toolchain] # begin autogenerated nightly -channel = "nightly-2024-11-14" +channel = "nightly-2024-11-28" # end autogenerated nightly components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] profile = "minimal" From 5fb924f3340cdacb4e67ff3e6e0ab42857c0ab5f Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 28 Nov 2024 18:57:52 +0100 Subject: [PATCH 44/45] Bump Clippy version -> 0.1.85 --- Cargo.toml | 4 ++-- clippy_config/Cargo.toml | 2 +- clippy_lints/Cargo.toml | 2 +- clippy_utils/Cargo.toml | 2 +- clippy_utils/README.md | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 79b9af7b0bf..bb259c77ee3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "clippy" # begin autogenerated version -version = "0.1.84" +version = "0.1.85" # end autogenerated version description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" @@ -29,7 +29,7 @@ rustc_tools_util = "0.4.0" tempfile = { version = "3.3", optional = true } termize = "0.1" color-print = "0.3.4" -anstream = "0.6.0" +anstream = "0.6.18" [dev-dependencies] cargo_metadata = "0.18.1" diff --git a/clippy_config/Cargo.toml b/clippy_config/Cargo.toml index d1158b48e92..3f18a0bc7d2 100644 --- a/clippy_config/Cargo.toml +++ b/clippy_config/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "clippy_config" # begin autogenerated version -version = "0.1.84" +version = "0.1.85" # end autogenerated version edition = "2021" publish = false diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index be99dcc2c7c..c1f8e82f698 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "clippy_lints" # begin autogenerated version -version = "0.1.84" +version = "0.1.85" # end autogenerated version description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" diff --git a/clippy_utils/Cargo.toml b/clippy_utils/Cargo.toml index 4f95889a53a..945827c98c1 100644 --- a/clippy_utils/Cargo.toml +++ b/clippy_utils/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "clippy_utils" # begin autogenerated version -version = "0.1.84" +version = "0.1.85" # end autogenerated version edition = "2021" description = "Helpful tools for writing lints, provided as they are used in Clippy" diff --git a/clippy_utils/README.md b/clippy_utils/README.md index fb1a3f13f8c..61476a82ba0 100644 --- a/clippy_utils/README.md +++ b/clippy_utils/README.md @@ -8,7 +8,7 @@ This crate is only guaranteed to build with this `nightly` toolchain: ``` -nightly-2024-11-14 +nightly-2024-11-28 ``` From 315b47ece33ed7c05e021f9cdf66b0431335f310 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 28 Nov 2024 19:39:15 +0100 Subject: [PATCH 45/45] Update Cargo.lock --- Cargo.lock | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 29176a3ae8e..a5fdcba0e63 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -536,7 +536,7 @@ checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" [[package]] name = "clippy" -version = "0.1.84" +version = "0.1.85" dependencies = [ "anstream", "cargo_metadata", @@ -567,8 +567,9 @@ dependencies = [ [[package]] name = "clippy_config" -version = "0.1.84" +version = "0.1.85" dependencies = [ + "clippy_utils", "itertools", "serde", "toml 0.7.8", @@ -580,6 +581,7 @@ name = "clippy_dev" version = "0.0.1" dependencies = [ "aho-corasick", + "chrono", "clap", "indoc", "itertools", @@ -590,7 +592,7 @@ dependencies = [ [[package]] name = "clippy_lints" -version = "0.1.84" +version = "0.1.85" dependencies = [ "arrayvec", "cargo_metadata", @@ -613,12 +615,12 @@ dependencies = [ [[package]] name = "clippy_utils" -version = "0.1.84" +version = "0.1.85" dependencies = [ "arrayvec", - "clippy_config", "itertools", "rustc_apfloat", + "serde", ] [[package]]