diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-07 05:48:48 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-07 05:48:48 +0000 |
commit | ef24de24a82fe681581cc130f342363c47c0969a (patch) | |
tree | 0d494f7e1a38b95c92426f58fe6eaa877303a86c /src/tools/clippy/clippy_lints | |
parent | Releasing progress-linux version 1.74.1+dfsg1-1~progress7.99u1. (diff) | |
download | rustc-ef24de24a82fe681581cc130f342363c47c0969a.tar.xz rustc-ef24de24a82fe681581cc130f342363c47c0969a.zip |
Merging upstream version 1.75.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/tools/clippy/clippy_lints')
371 files changed, 4741 insertions, 4360 deletions
diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml index dcd9a4adc..4bc27fd48 100644 --- a/src/tools/clippy/clippy_lints/Cargo.toml +++ b/src/tools/clippy/clippy_lints/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_lints" -version = "0.1.74" +version = "0.1.75" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" @@ -11,6 +11,7 @@ edition = "2021" [dependencies] arrayvec = { version = "0.7", default-features = false } cargo_metadata = "0.15.3" +clippy_config = { path = "../clippy_config" } clippy_utils = { path = "../clippy_utils" } declare_clippy_lint = { path = "../declare_clippy_lint" } if_chain = "1.0" @@ -28,10 +29,13 @@ semver = "1.0" rustc-semver = "1.1" url = "2.2" +[dev-dependencies] +walkdir = "2.3" + [features] -deny-warnings = ["clippy_utils/deny-warnings"] +deny-warnings = ["clippy_config/deny-warnings", "clippy_utils/deny-warnings"] # build clippy with internal lints enabled, off by default -internal = ["clippy_utils/internal", "serde_json", "tempfile", "regex"] +internal = ["serde_json", "tempfile", "regex"] [package.metadata.rust-analyzer] # This crate uses #[feature(rustc_private)] diff --git a/src/tools/clippy/clippy_lints/src/absolute_paths.rs b/src/tools/clippy/clippy_lints/src/absolute_paths.rs index 04417c4c4..582423603 100644 --- a/src/tools/clippy/clippy_lints/src/absolute_paths.rs +++ b/src/tools/clippy/clippy_lints/src/absolute_paths.rs @@ -24,11 +24,11 @@ declare_clippy_lint! { /// using absolute paths is the proper way of referencing items in one. /// /// ### Example - /// ```rust + /// ```no_run /// let x = std::f64::consts::PI; /// ``` /// Use any of the below instead, or anything else: - /// ```rust + /// ```no_run /// use std::f64; /// use std::f64::consts; /// use std::f64::consts::PI; diff --git a/src/tools/clippy/clippy_lints/src/allow_attributes.rs b/src/tools/clippy/clippy_lints/src/allow_attributes.rs index e1ef514ed..e3f4cf79d 100644 --- a/src/tools/clippy/clippy_lints/src/allow_attributes.rs +++ b/src/tools/clippy/clippy_lints/src/allow_attributes.rs @@ -8,6 +8,7 @@ use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { + /// ### What it does /// Checks for usage of the `#[allow]` attribute and suggests replacing it with /// the `#[expect]` (See [RFC 2383](https://rust-lang.github.io/rfcs/2383-lint-reasons.html)) /// @@ -19,7 +20,6 @@ declare_clippy_lint! { /// (`#![allow]`) are usually used to enable or disable lints on a global scale. /// /// ### Why is this bad? - /// /// `#[expect]` attributes suppress the lint emission, but emit a warning, if /// the expectation is unfulfilled. This can be useful to be notified when the /// lint is no longer triggered. diff --git a/src/tools/clippy/clippy_lints/src/almost_complete_range.rs b/src/tools/clippy/clippy_lints/src/almost_complete_range.rs index 32d80f42e..e85878eb5 100644 --- a/src/tools/clippy/clippy_lints/src/almost_complete_range.rs +++ b/src/tools/clippy/clippy_lints/src/almost_complete_range.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::{trim_span, walk_span_to_context}; use rustc_ast::ast::{Expr, ExprKind, LitKind, Pat, PatKind, RangeEnd, RangeLimits}; use rustc_errors::Applicability; @@ -17,11 +17,11 @@ declare_clippy_lint! { /// This (`'a'..'z'`) is almost certainly a typo meant to include all letters. /// /// ### Example - /// ```rust + /// ```no_run /// let _ = 'a'..'z'; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let _ = 'a'..='z'; /// ``` #[clippy::version = "1.68.0"] @@ -82,33 +82,20 @@ fn check_range(cx: &EarlyContext<'_>, span: Span, start: &Expr, end: &Expr, sugg ( Ok(LitKind::Byte(b'a') | LitKind::Char('a')), Ok(LitKind::Byte(b'z') | LitKind::Char('z')) - ) - | ( + ) | ( Ok(LitKind::Byte(b'A') | LitKind::Char('A')), Ok(LitKind::Byte(b'Z') | LitKind::Char('Z')), - ) - | ( + ) | ( Ok(LitKind::Byte(b'0') | LitKind::Char('0')), Ok(LitKind::Byte(b'9') | LitKind::Char('9')), ) ) && !in_external_macro(cx.sess(), span) { - span_lint_and_then( - cx, - ALMOST_COMPLETE_RANGE, - span, - "almost complete ascii range", - |diag| { - if let Some((span, sugg)) = sugg { - diag.span_suggestion( - span, - "use an inclusive range", - sugg, - Applicability::MaybeIncorrect, - ); - } + span_lint_and_then(cx, ALMOST_COMPLETE_RANGE, span, "almost complete ascii range", |diag| { + if let Some((span, sugg)) = sugg { + diag.span_suggestion(span, "use an inclusive range", sugg, Applicability::MaybeIncorrect); } - ); + }); } } diff --git a/src/tools/clippy/clippy_lints/src/approx_const.rs b/src/tools/clippy/clippy_lints/src/approx_const.rs index ccf82f132..b4f778f12 100644 --- a/src/tools/clippy/clippy_lints/src/approx_const.rs +++ b/src/tools/clippy/clippy_lints/src/approx_const.rs @@ -1,5 +1,5 @@ +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}; @@ -24,12 +24,12 @@ declare_clippy_lint! { /// issue](https://github.com/rust-lang/rust/issues). /// /// ### Example - /// ```rust + /// ```no_run /// let x = 3.14; /// let y = 1_f64 / x; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let x = std::f32::consts::PI; /// let y = std::f64::consts::FRAC_1_PI; /// ``` diff --git a/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs b/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs index 35a04b5e4..192bc7d9d 100644 --- a/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs +++ b/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs @@ -18,7 +18,7 @@ declare_clippy_lint! { /// either `T` should be made `Send + Sync` or an `Rc` should be used instead of an `Arc` /// /// ### Example - /// ```rust + /// ```no_run /// # use std::cell::RefCell; /// # use std::sync::Arc; /// @@ -62,19 +62,21 @@ impl<'tcx> LateLintPass<'tcx> for ArcWithNonSendSync { ARC_WITH_NON_SEND_SYNC, expr.span, "usage of an `Arc` that is not `Send` or `Sync`", - |diag| with_forced_trimmed_paths!({ - if !is_send { - diag.note(format!("the trait `Send` is not implemented for `{arg_ty}`")); - } - if !is_sync { - diag.note(format!("the trait `Sync` is not implemented for `{arg_ty}`")); - } + |diag| { + with_forced_trimmed_paths!({ + if !is_send { + diag.note(format!("the trait `Send` is not implemented for `{arg_ty}`")); + } + if !is_sync { + diag.note(format!("the trait `Sync` is not implemented for `{arg_ty}`")); + } - diag.note(format!("required for `{ty}` to implement `Send` and `Sync`")); + diag.note(format!("required for `{ty}` to implement `Send` and `Sync`")); - diag.help("consider using an `Rc` instead or wrapping the inner type with a `Mutex`"); - } - )); + diag.help("consider using an `Rc` instead or wrapping the inner type with a `Mutex`"); + }); + }, + ); } } } diff --git a/src/tools/clippy/clippy_lints/src/as_conversions.rs b/src/tools/clippy/clippy_lints/src/as_conversions.rs index b9dda49ca..2de205d80 100644 --- a/src/tools/clippy/clippy_lints/src/as_conversions.rs +++ b/src/tools/clippy/clippy_lints/src/as_conversions.rs @@ -48,11 +48,10 @@ declare_lint_pass!(AsConversions => [AS_CONVERSIONS]); impl<'tcx> LateLintPass<'tcx> for AsConversions { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { - if in_external_macro(cx.sess(), expr.span) || is_from_proc_macro(cx, expr) { - return; - } - - if let ExprKind::Cast(_, _) = expr.kind { + if let ExprKind::Cast(_, _) = expr.kind + && !in_external_macro(cx.sess(), expr.span) + && !is_from_proc_macro(cx, expr) + { span_lint_and_help( cx, AS_CONVERSIONS, diff --git a/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs b/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs index 2980c9d6d..71ec87a88 100644 --- a/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs +++ b/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs @@ -58,7 +58,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates { return; } } - let semicolon = if is_expr_final_block_expr(cx.tcx, e) {";"} else {""}; + let semicolon = if is_expr_final_block_expr(cx.tcx, e) { ";" } else { "" }; let mut app = Applicability::MachineApplicable; match method_segment.ident.as_str() { "is_ok" if type_suitable_to_unwrap(cx, args.type_at(1)) => { @@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates { ), app, ); - } + }, "is_err" if type_suitable_to_unwrap(cx, args.type_at(0)) => { span_lint_and_sugg( cx, @@ -88,7 +88,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates { ), app, ); - } + }, _ => (), }; } diff --git a/src/tools/clippy/clippy_lints/src/async_yields_async.rs b/src/tools/clippy/clippy_lints/src/async_yields_async.rs index 9464694a3..ec2447dae 100644 --- a/src/tools/clippy/clippy_lints/src/async_yields_async.rs +++ b/src/tools/clippy/clippy_lints/src/async_yields_async.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::source::snippet; use clippy_utils::ty::implements_trait; use rustc_errors::Applicability; -use rustc_hir::{AsyncGeneratorKind, Body, BodyId, ExprKind, GeneratorKind, QPath}; +use rustc_hir::{Body, BodyId, CoroutineKind, CoroutineSource, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -15,7 +15,7 @@ declare_clippy_lint! { /// An await is likely missing. /// /// ### Example - /// ```rust + /// ```no_run /// async fn foo() {} /// /// fn bar() { @@ -26,7 +26,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// async fn foo() {} /// /// fn bar() { @@ -45,10 +45,10 @@ declare_lint_pass!(AsyncYieldsAsync => [ASYNC_YIELDS_ASYNC]); impl<'tcx> LateLintPass<'tcx> for AsyncYieldsAsync { fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) { - use AsyncGeneratorKind::{Block, Closure}; + use CoroutineSource::{Block, Closure}; // For functions, with explicitly defined types, don't warn. // XXXkhuey maybe we should? - if let Some(GeneratorKind::Async(Block | Closure)) = body.generator_kind { + if let Some(CoroutineKind::Async(Block | Closure)) = body.coroutine_kind { if let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() { let body_id = BodyId { hir_id: body.value.hir_id, diff --git a/src/tools/clippy/clippy_lints/src/attrs.rs b/src/tools/clippy/clippy_lints/src/attrs.rs index 0546807ba..38364af27 100644 --- a/src/tools/clippy/clippy_lints/src/attrs.rs +++ b/src/tools/clippy/clippy_lints/src/attrs.rs @@ -1,9 +1,9 @@ //! checks for attributes +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::is_from_proc_macro; use clippy_utils::macros::{is_panic, macro_backtrace}; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::{first_line_of_span, is_present_in_source, snippet_opt, without_block_comments}; use if_chain::if_chain; use rustc_ast::token::{Token, TokenKind}; @@ -19,9 +19,8 @@ use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass}; -use rustc_span::source_map::Span; use rustc_span::symbol::Symbol; -use rustc_span::{sym, DUMMY_SP}; +use rustc_span::{sym, DUMMY_SP, Span}; use semver::Version; static UNIX_SYSTEMS: &[&str] = &[ @@ -129,7 +128,7 @@ declare_clippy_lint! { /// a valid semver. Failing that, the contained information is useless. /// /// ### Example - /// ```rust + /// ```no_run /// #[deprecated(since = "forever")] /// fn something_else() { /* ... */ } /// ``` @@ -156,14 +155,14 @@ declare_clippy_lint! { /// currently works for basic cases but is not perfect. /// /// ### Example - /// ```rust + /// ```no_run /// #[allow(dead_code)] /// /// fn not_quite_good_code() { } /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// // Good (as inner attribute) /// #![allow(dead_code)] /// @@ -183,7 +182,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for empty lines after documenation comments. + /// Checks for empty lines after documentation comments. /// /// ### Why is this bad? /// The documentation comment was most likely meant to be an inner attribute or regular comment. @@ -198,25 +197,25 @@ declare_clippy_lint! { /// Does not detect empty lines after doc attributes (e.g. `#[doc = ""]`). /// /// ### Example - /// ```rust + /// ```no_run /// /// Some doc comment with a blank line after it. /// /// fn not_quite_good_code() { } /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// /// Good (no blank line) /// fn this_is_fine() { } /// ``` /// - /// ```rust + /// ```no_run /// // Good (convert to a regular comment) /// /// fn this_is_fine_too() { } /// ``` /// - /// ```rust + /// ```no_run /// //! Good (convert to a comment on an inner attribute) /// /// fn this_is_fine_as_well() { } @@ -236,12 +235,12 @@ declare_clippy_lint! { /// These lints should only be enabled on a lint-by-lint basis and with careful consideration. /// /// ### Example - /// ```rust + /// ```no_run /// #![deny(clippy::restriction)] /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// #![deny(clippy::as_conversions)] /// ``` #[clippy::version = "1.47.0"] @@ -265,13 +264,13 @@ declare_clippy_lint! { /// [#3123](https://github.com/rust-lang/rust-clippy/pull/3123#issuecomment-422321765) /// /// ### Example - /// ```rust + /// ```no_run /// #[cfg_attr(rustfmt, rustfmt_skip)] /// fn main() { } /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// #[rustfmt::skip] /// fn main() { } /// ``` @@ -290,13 +289,13 @@ declare_clippy_lint! { /// by the conditional compilation engine. /// /// ### Example - /// ```rust + /// ```no_run /// #[cfg(linux)] /// fn conditional() { } /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # mod hidden { /// #[cfg(target_os = "linux")] /// fn conditional() { } @@ -325,14 +324,14 @@ declare_clippy_lint! { /// ensure that others understand the reasoning /// /// ### Example - /// ```rust + /// ```no_run /// #![feature(lint_reasons)] /// /// #![allow(clippy::some_lint)] /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// #![feature(lint_reasons)] /// /// #![allow(clippy::some_lint, reason = "False positive rust-lang/rust-clippy#1002020")] @@ -352,7 +351,7 @@ declare_clippy_lint! { /// panicking with the expected message, and not another unrelated panic. /// /// ### Example - /// ```rust + /// ```no_run /// fn random() -> i32 { 0 } /// /// #[should_panic] @@ -363,7 +362,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// fn random() -> i32 { 0 } /// /// #[should_panic = "attempt to divide by zero"] @@ -386,13 +385,13 @@ declare_clippy_lint! { /// If there is only one condition, no need to wrap it into `any` or `all` combinators. /// /// ### Example - /// ```rust + /// ```no_run /// #[cfg(any(unix))] /// pub struct Bar; /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// #[cfg(unix)] /// pub struct Bar; /// ``` @@ -409,16 +408,16 @@ declare_clippy_lint! { /// /// ### Why is this bad? /// Misspelling `feature` as `features` can be sometimes hard to spot. It - /// may cause conditional compilation not work quitely. + /// may cause conditional compilation not work quietly. /// /// ### Example - /// ```rust + /// ```no_run /// #[cfg(features = "some-feature")] /// fn conditional() { } /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// #[cfg(feature = "some-feature")] /// fn conditional() { } /// ``` @@ -602,9 +601,26 @@ fn check_should_panic_reason(cx: &LateContext<'_>, attr: &Attribute) { if let AttrArgs::Delimited(args) = &normal_attr.item.args && let mut tt_iter = args.tokens.trees() - && let Some(TokenTree::Token(Token { kind: TokenKind::Ident(sym::expected, _), .. }, _)) = tt_iter.next() - && let Some(TokenTree::Token(Token { kind: TokenKind::Eq, .. }, _)) = tt_iter.next() - && let Some(TokenTree::Token(Token { kind: TokenKind::Literal(_), .. }, _)) = tt_iter.next() + && let Some(TokenTree::Token( + Token { + kind: TokenKind::Ident(sym::expected, _), + .. + }, + _, + )) = tt_iter.next() + && let Some(TokenTree::Token( + Token { + kind: TokenKind::Eq, .. + }, + _, + )) = tt_iter.next() + && let Some(TokenTree::Token( + Token { + kind: TokenKind::Literal(_), + .. + }, + _, + )) = tt_iter.next() { // `#[should_panic(expected = "..")]` found, good return; @@ -795,7 +811,7 @@ impl EarlyLintPass for EarlyAttributes { /// Check for empty lines after outer attributes. /// -/// Attributes and documenation comments are both considered outer attributes +/// Attributes and documentation comments are both considered outer attributes /// by the AST. However, the average user likely considers them to be different. /// Checking for empty lines after each of these attributes is split into two different /// lints but can share the same logic. @@ -914,7 +930,9 @@ fn check_nested_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) { fn check_nested_misused_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) { for item in items { if let NestedMetaItem::MetaItem(meta) = item { - if meta.has_name(sym!(features)) && let Some(val) = meta.value_str() { + if meta.has_name(sym!(features)) + && let Some(val) = meta.value_str() + { span_lint_and_sugg( cx, MAYBE_MISUSED_CFG, @@ -933,16 +951,16 @@ fn check_nested_misused_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) { } fn check_minimal_cfg_condition(cx: &EarlyContext<'_>, attr: &Attribute) { - if attr.has_name(sym::cfg) && - let Some(items) = attr.meta_item_list() + if attr.has_name(sym::cfg) + && let Some(items) = attr.meta_item_list() { check_nested_cfg(cx, &items); } } fn check_misused_cfg(cx: &EarlyContext<'_>, attr: &Attribute) { - if attr.has_name(sym::cfg) && - let Some(items) = attr.meta_item_list() + if attr.has_name(sym::cfg) + && let Some(items) = attr.meta_item_list() { check_nested_misused_cfg(cx, &items); } diff --git a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs index 7dd808a7b..06b74b972 100644 --- a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs +++ b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs @@ -1,15 +1,14 @@ +use clippy_config::types::DisallowedPath; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::{match_def_path, paths}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::DefId; -use rustc_hir::{AsyncGeneratorKind, Body, GeneratorKind}; +use rustc_hir::{Body, CoroutineKind, CoroutineSource}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::mir::GeneratorLayout; +use rustc_middle::mir::CoroutineLayout; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{sym, Span}; -use crate::utils::conf::DisallowedPath; - declare_clippy_lint! { /// ### What it does /// Checks for calls to await while holding a non-async-aware MutexGuard. @@ -29,7 +28,7 @@ declare_clippy_lint! { /// to wrap the `.lock()` call in a block instead of explicitly dropping the guard. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::sync::Mutex; /// # async fn baz() {} /// async fn foo(x: &Mutex<u32>) { @@ -47,7 +46,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # use std::sync::Mutex; /// # async fn baz() {} /// async fn foo(x: &Mutex<u32>) { @@ -87,7 +86,7 @@ declare_clippy_lint! { /// to wrap the `.borrow[_mut]()` call in a block instead of explicitly dropping the ref. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::cell::RefCell; /// # async fn baz() {} /// async fn foo(x: &RefCell<u32>) { @@ -105,7 +104,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # use std::cell::RefCell; /// # async fn baz() {} /// async fn foo(x: &RefCell<u32>) { @@ -151,7 +150,7 @@ declare_clippy_lint! { /// ] /// ``` /// - /// ```rust + /// ```no_run /// # async fn baz() {} /// struct CustomLockType; /// struct OtherCustomLockType; @@ -195,26 +194,26 @@ impl LateLintPass<'_> for AwaitHolding { } fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) { - use AsyncGeneratorKind::{Block, Closure, Fn}; - if let Some(GeneratorKind::Async(Block | Closure | Fn)) = body.generator_kind { + use CoroutineSource::{Block, Closure, Fn}; + if let Some(CoroutineKind::Async(Block | Closure | Fn)) = body.coroutine_kind { let def_id = cx.tcx.hir().body_owner_def_id(body.id()); - if let Some(generator_layout) = cx.tcx.mir_generator_witnesses(def_id) { - self.check_interior_types(cx, generator_layout); + if let Some(coroutine_layout) = cx.tcx.mir_coroutine_witnesses(def_id) { + self.check_interior_types(cx, coroutine_layout); } } } } impl AwaitHolding { - fn check_interior_types(&self, cx: &LateContext<'_>, generator: &GeneratorLayout<'_>) { - for (ty_index, ty_cause) in generator.field_tys.iter_enumerated() { + fn check_interior_types(&self, cx: &LateContext<'_>, coroutine: &CoroutineLayout<'_>) { + for (ty_index, ty_cause) in coroutine.field_tys.iter_enumerated() { if let rustc_middle::ty::Adt(adt, _) = ty_cause.ty.kind() { let await_points = || { - generator + coroutine .variant_source_info .iter_enumerated() .filter_map(|(variant, source_info)| { - generator.variant_fields[variant] + coroutine.variant_fields[variant] .raw .contains(&ty_index) .then_some(source_info.span) @@ -287,5 +286,8 @@ fn is_mutex_guard(cx: &LateContext<'_>, def_id: DefId) -> bool { } fn is_refcell_ref(cx: &LateContext<'_>, def_id: DefId) -> bool { - match_def_path(cx, def_id, &paths::REFCELL_REF) || match_def_path(cx, def_id, &paths::REFCELL_REFMUT) + matches!( + cx.tcx.get_diagnostic_name(def_id), + Some(sym::RefCellRef | sym::RefCellRefMut) + ) } diff --git a/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs b/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs index 1593d7b0f..04bf541a5 100644 --- a/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs +++ b/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs @@ -21,7 +21,7 @@ declare_clippy_lint! { /// Style, using blocks in the condition makes it hard to read. /// /// ### Examples - /// ```rust + /// ```no_run /// # fn somefunc() -> bool { true }; /// if { true } { /* ... */ } /// @@ -29,7 +29,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # fn somefunc() -> bool { true }; /// if true { /* ... */ } /// diff --git a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs index 450359771..665dbd6f7 100644 --- a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs +++ b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs @@ -18,13 +18,13 @@ declare_clippy_lint! { /// It is shorter to use the equivalent. /// /// ### Example - /// ```rust + /// ```no_run /// assert_eq!("a".is_empty(), false); /// assert_ne!("a".is_empty(), true); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// assert!(!"a".is_empty()); /// ``` #[clippy::version = "1.53.0"] diff --git a/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs b/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs index 1828dd651..156cb34df 100644 --- a/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs +++ b/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs @@ -21,7 +21,7 @@ declare_clippy_lint! { /// See https://doc.rust-lang.org/std/primitive.bool.html#impl-From%3Cbool%3E /// /// ### Example - /// ```rust + /// ```no_run /// # let condition = false; /// if condition { /// 1_i64 @@ -30,12 +30,12 @@ declare_clippy_lint! { /// }; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # let condition = false; /// i64::from(condition); /// ``` /// or - /// ```rust + /// ```no_run /// # let condition = false; /// condition as i64; /// ``` @@ -55,7 +55,11 @@ impl<'tcx> LateLintPass<'tcx> for BoolToIntWithIf { } fn check_if_else<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) { - if let Some(If { cond, then, r#else: Some(r#else) }) = If::hir(expr) + if let Some(If { + cond, + then, + r#else: Some(r#else), + }) = If::hir(expr) && let Some(then_lit) = int_literal(then) && let Some(else_lit) = int_literal(r#else) { @@ -90,19 +94,18 @@ fn check_if_else<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx> let into_snippet = snippet.clone().maybe_par(); let as_snippet = snippet.as_ty(ty); - span_lint_and_then(cx, + span_lint_and_then( + cx, BOOL_TO_INT_WITH_IF, expr.span, "boolean to int conversion using if", |diag| { - diag.span_suggestion( - expr.span, - "replace with from", - suggestion, - applicability, - ); - diag.note(format!("`{as_snippet}` or `{into_snippet}.into()` can also be valid options")); - }); + diag.span_suggestion(expr.span, "replace with from", suggestion, applicability); + diag.note(format!( + "`{as_snippet}` or `{into_snippet}.into()` can also be valid options" + )); + }, + ); }; } @@ -110,7 +113,7 @@ fn check_if_else<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx> fn int_literal<'tcx>(expr: &'tcx rustc_hir::Expr<'tcx>) -> Option<&'tcx rustc_hir::Expr<'tcx>> { if let ExprKind::Block(block, _) = expr.kind && let Block { - stmts: [], // Shouldn't lint if statements with side effects + stmts: [], // Shouldn't lint if statements with side effects expr: Some(expr), .. } = block diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs index 04cca9e31..0e0d229e8 100644 --- a/src/tools/clippy/clippy_lints/src/booleans.rs +++ b/src/tools/clippy/clippy_lints/src/booleans.rs @@ -10,8 +10,7 @@ use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, UnOp}; use rustc_lint::{LateContext, LateLintPass, Level}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::def_id::LocalDefId; -use rustc_span::source_map::Span; -use rustc_span::sym; +use rustc_span::{sym, Span}; declare_clippy_lint! { /// ### What it does @@ -472,8 +471,9 @@ impl<'a, 'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'a, 'tcx> { self.bool_expr(e); }, ExprKind::Unary(UnOp::Not, inner) => { - if let ExprKind::Unary(UnOp::Not, ex) = inner.kind && - !self.cx.typeck_results().node_types()[ex.hir_id].is_bool() { + if let ExprKind::Unary(UnOp::Not, ex) = inner.kind + && !self.cx.typeck_results().node_types()[ex.hir_id].is_bool() + { return; } if self.cx.typeck_results().node_types()[inner.hir_id].is_bool() { @@ -500,10 +500,10 @@ struct NotSimplificationVisitor<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for NotSimplificationVisitor<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { - if let ExprKind::Unary(UnOp::Not, inner) = &expr.kind && - !inner.span.from_expansion() && - let Some(suggestion) = simplify_not(self.cx, inner) - && self.cx.tcx.lint_level_at_node(NONMINIMAL_BOOL, expr.hir_id).0 != Level::Allow + if let ExprKind::Unary(UnOp::Not, inner) = &expr.kind + && !inner.span.from_expansion() + && let Some(suggestion) = simplify_not(self.cx, inner) + && self.cx.tcx.lint_level_at_node(NONMINIMAL_BOOL, expr.hir_id).0 != Level::Allow { span_lint_and_sugg( self.cx, diff --git a/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs b/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs index b3dbbb08f..a38269083 100644 --- a/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs +++ b/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs @@ -19,7 +19,7 @@ declare_clippy_lint! { /// /// ### Known problems /// False negative on such code: - /// ``` + /// ```no_run /// let x = &12; /// let addr_x = &x as *const _ as usize; /// let addr_y = &&*x as *const _ as usize; // assert ok now, and lint triggered. @@ -28,14 +28,14 @@ declare_clippy_lint! { /// ``` /// /// ### Example - /// ```rust + /// ```no_run /// let s = &String::new(); /// /// let a: &String = &* s; /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let s = &String::new(); /// let a: &String = s; /// ``` @@ -49,69 +49,64 @@ declare_lint_pass!(BorrowDerefRef => [BORROW_DEREF_REF]); impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &rustc_hir::Expr<'tcx>) { - if_chain! { - if !e.span.from_expansion(); - if let ExprKind::AddrOf(_, Mutability::Not, addrof_target) = e.kind; - if !addrof_target.span.from_expansion(); - if let ExprKind::Unary(UnOp::Deref, deref_target) = addrof_target.kind; - if !deref_target.span.from_expansion(); - if !matches!(deref_target.kind, ExprKind::Unary(UnOp::Deref, ..) ); - let ref_ty = cx.typeck_results().expr_ty(deref_target); - if let ty::Ref(_, inner_ty, Mutability::Not) = ref_ty.kind(); - if !is_from_proc_macro(cx, e); - then{ - - if let Some(parent_expr) = get_parent_expr(cx, e){ - if matches!(parent_expr.kind, ExprKind::Unary(UnOp::Deref, ..)) && - !is_lint_allowed(cx, DEREF_ADDROF, parent_expr.hir_id) { - return; - } + if !e.span.from_expansion() + && let ExprKind::AddrOf(_, Mutability::Not, addrof_target) = e.kind + && !addrof_target.span.from_expansion() + && let ExprKind::Unary(UnOp::Deref, deref_target) = addrof_target.kind + && !deref_target.span.from_expansion() + && !matches!(deref_target.kind, ExprKind::Unary(UnOp::Deref, ..)) + && let ref_ty = cx.typeck_results().expr_ty(deref_target) + && let ty::Ref(_, inner_ty, Mutability::Not) = ref_ty.kind() + { + if let Some(parent_expr) = get_parent_expr(cx, e) { + if matches!(parent_expr.kind, ExprKind::Unary(UnOp::Deref, ..)) + && !is_lint_allowed(cx, DEREF_ADDROF, parent_expr.hir_id) + { + return; + } - // modification to `&mut &*x` is different from `&mut x` - if matches!(deref_target.kind, ExprKind::Path(..) - | ExprKind::Field(..) - | ExprKind::Index(..) - | ExprKind::Unary(UnOp::Deref, ..)) - && matches!(parent_expr.kind, ExprKind::AddrOf(_, Mutability::Mut, _)) { - return; - } + // modification to `&mut &*x` is different from `&mut x` + if matches!( + deref_target.kind, + ExprKind::Path(..) | ExprKind::Field(..) | ExprKind::Index(..) | ExprKind::Unary(UnOp::Deref, ..) + ) && matches!(parent_expr.kind, ExprKind::AddrOf(_, Mutability::Mut, _)) + { + return; } + } + if is_from_proc_macro(cx, e) { + return; + } - span_lint_and_then( - cx, - BORROW_DEREF_REF, - e.span, - "deref on an immutable reference", - |diag| { - diag.span_suggestion( - e.span, - "if you would like to reborrow, try removing `&*`", - snippet_opt(cx, deref_target.span).unwrap(), - Applicability::MachineApplicable - ); + span_lint_and_then( + cx, + BORROW_DEREF_REF, + e.span, + "deref on an immutable reference", + |diag| { + diag.span_suggestion( + e.span, + "if you would like to reborrow, try removing `&*`", + snippet_opt(cx, deref_target.span).unwrap(), + Applicability::MachineApplicable, + ); - // has deref trait -> give 2 help - // doesn't have deref trait -> give 1 help - if let Some(deref_trait_id) = cx.tcx.lang_items().deref_trait(){ - if !implements_trait(cx, *inner_ty, deref_trait_id, &[]) { - return; - } + // has deref trait -> give 2 help + // doesn't have deref trait -> give 1 help + if let Some(deref_trait_id) = cx.tcx.lang_items().deref_trait() { + if !implements_trait(cx, *inner_ty, deref_trait_id, &[]) { + return; } - - diag.span_suggestion( - e.span, - "if you would like to deref, try using `&**`", - format!( - "&**{}", - &snippet_opt(cx, deref_target.span).unwrap(), - ), - Applicability::MaybeIncorrect - ); - } - ); - } + diag.span_suggestion( + e.span, + "if you would like to deref, try using `&**`", + format!("&**{}", &snippet_opt(cx, deref_target.span).unwrap()), + Applicability::MaybeIncorrect, + ); + }, + ); } } } diff --git a/src/tools/clippy/clippy_lints/src/box_default.rs b/src/tools/clippy/clippy_lints/src/box_default.rs index fa9c525fc..9c78c6e53 100644 --- a/src/tools/clippy/clippy_lints/src/box_default.rs +++ b/src/tools/clippy/clippy_lints/src/box_default.rs @@ -1,8 +1,9 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::macros::macro_backtrace; use clippy_utils::ty::expr_sig; -use clippy_utils::{get_parent_node, is_default_equivalent, match_path, path_def_id, paths}; +use clippy_utils::{get_parent_node, is_default_equivalent, path_def_id}; use rustc_errors::Applicability; +use rustc_hir::def::Res; use rustc_hir::intravisit::{walk_ty, Visitor}; use rustc_hir::{Block, Expr, ExprKind, Local, Node, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -23,11 +24,11 @@ declare_clippy_lint! { /// [in certain cases](https://nnethercote.github.io/perf-book/standard-library-types.html#box). /// /// ### Example - /// ```rust + /// ```no_run /// let x: Box<String> = Box::new(Default::default()); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let x: Box<String> = Box::default(); /// ``` #[clippy::version = "1.66.0"] @@ -55,24 +56,26 @@ impl LateLintPass<'_> for BoxDefault { expr.span, "`Box::new(_)` of default value", "try", - if is_plain_default(arg_path) || given_type(cx, expr) { + if is_plain_default(cx, arg_path) || given_type(cx, expr) { "Box::default()".into() } else if let Some(arg_ty) = cx.typeck_results().expr_ty(arg).make_suggestable(cx.tcx, true) { with_forced_trimmed_paths!(format!("Box::<{arg_ty}>::default()")) } else { - return + return; }, - Applicability::MachineApplicable + Applicability::MachineApplicable, ); } } } -fn is_plain_default(arg_path: &Expr<'_>) -> bool { +fn is_plain_default(cx: &LateContext<'_>, arg_path: &Expr<'_>) -> bool { // we need to match the actual path so we don't match e.g. "u8::default" - if let ExprKind::Path(QPath::Resolved(None, path)) = &arg_path.kind { + if let ExprKind::Path(QPath::Resolved(None, path)) = &arg_path.kind + && let Res::Def(_, def_id) = path.res + { // avoid generic parameters - match_path(path, &paths::DEFAULT_TRAIT_METHOD) && path.segments.iter().all(|seg| seg.args.is_none()) + cx.tcx.is_diagnostic_item(sym::default_fn, def_id) && path.segments.iter().all(|seg| seg.args.is_none()) } else { false } @@ -107,7 +110,8 @@ fn given_type(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { Node::Expr(Expr { kind: ExprKind::Call(path, args), .. - }) | Node::Block(Block { + }) + | Node::Block(Block { expr: Some(Expr { kind: ExprKind::Call(path, args), @@ -116,10 +120,10 @@ fn given_type(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { .. }), ) => { - if let Some(index) = args.iter().position(|arg| arg.hir_id == expr.hir_id) && - let Some(sig) = expr_sig(cx, path) && - let Some(input) = sig.input(index) && - !cx.typeck_results().expr_ty_adjusted(expr).boxed_ty().is_trait() + if let Some(index) = args.iter().position(|arg| arg.hir_id == expr.hir_id) + && let Some(sig) = expr_sig(cx, path) + && let Some(input) = sig.input(index) + && !cx.typeck_results().expr_ty_adjusted(expr).boxed_ty().is_trait() { input.no_bound_vars().is_some() } else { diff --git a/src/tools/clippy/clippy_lints/src/cargo/common_metadata.rs b/src/tools/clippy/clippy_lints/src/cargo/common_metadata.rs index 805121bcc..99fe6c1e7 100644 --- a/src/tools/clippy/clippy_lints/src/cargo/common_metadata.rs +++ b/src/tools/clippy/clippy_lints/src/cargo/common_metadata.rs @@ -3,7 +3,7 @@ use cargo_metadata::Metadata; use clippy_utils::diagnostics::span_lint; use rustc_lint::LateContext; -use rustc_span::source_map::DUMMY_SP; +use rustc_span::DUMMY_SP; use super::CARGO_COMMON_METADATA; diff --git a/src/tools/clippy/clippy_lints/src/cargo/feature_name.rs b/src/tools/clippy/clippy_lints/src/cargo/feature_name.rs index 37c169dbd..9e69919c7 100644 --- a/src/tools/clippy/clippy_lints/src/cargo/feature_name.rs +++ b/src/tools/clippy/clippy_lints/src/cargo/feature_name.rs @@ -1,7 +1,7 @@ use cargo_metadata::Metadata; use clippy_utils::diagnostics::span_lint_and_help; use rustc_lint::LateContext; -use rustc_span::source_map::DUMMY_SP; +use rustc_span::DUMMY_SP; use super::{NEGATIVE_FEATURE_NAMES, REDUNDANT_FEATURE_NAMES}; diff --git a/src/tools/clippy/clippy_lints/src/cargo/multiple_crate_versions.rs b/src/tools/clippy/clippy_lints/src/cargo/multiple_crate_versions.rs index f9b17d45e..f7a5b1857 100644 --- a/src/tools/clippy/clippy_lints/src/cargo/multiple_crate_versions.rs +++ b/src/tools/clippy/clippy_lints/src/cargo/multiple_crate_versions.rs @@ -6,7 +6,7 @@ use if_chain::if_chain; use itertools::Itertools; use rustc_hir::def_id::LOCAL_CRATE; use rustc_lint::LateContext; -use rustc_span::source_map::DUMMY_SP; +use rustc_span::DUMMY_SP; use super::MULTIPLE_CRATE_VERSIONS; diff --git a/src/tools/clippy/clippy_lints/src/cargo/wildcard_dependencies.rs b/src/tools/clippy/clippy_lints/src/cargo/wildcard_dependencies.rs index 7fa6acbf5..4dcc9cbe3 100644 --- a/src/tools/clippy/clippy_lints/src/cargo/wildcard_dependencies.rs +++ b/src/tools/clippy/clippy_lints/src/cargo/wildcard_dependencies.rs @@ -2,7 +2,7 @@ use cargo_metadata::Metadata; use clippy_utils::diagnostics::span_lint; use if_chain::if_chain; use rustc_lint::LateContext; -use rustc_span::source_map::DUMMY_SP; +use rustc_span::DUMMY_SP; use super::WILDCARD_DEPENDENCIES; diff --git a/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs b/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs index 1e56ed5f4..55294f5f3 100644 --- a/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs +++ b/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs @@ -9,12 +9,19 @@ use rustc_middle::ty::{self, Ty, TypeAndMut}; use super::AS_PTR_CAST_MUT; pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_to: Ty<'_>) { - if let ty::RawPtr(ptrty @ TypeAndMut { mutbl: Mutability::Mut, .. }) = cast_to.kind() - && let ty::RawPtr(TypeAndMut { mutbl: Mutability::Not, .. }) = - cx.typeck_results().node_type(cast_expr.hir_id).kind() + if let ty::RawPtr( + ptrty @ TypeAndMut { + mutbl: Mutability::Mut, .. + }, + ) = cast_to.kind() + && let ty::RawPtr(TypeAndMut { + mutbl: Mutability::Not, .. + }) = cx.typeck_results().node_type(cast_expr.hir_id).kind() && let ExprKind::MethodCall(method_name, receiver, [], _) = cast_expr.peel_blocks().kind && method_name.ident.name == rustc_span::sym::as_ptr - && let Some(as_ptr_did) = cx.typeck_results().type_dependent_def_id(cast_expr.peel_blocks().hir_id) + && let Some(as_ptr_did) = cx + .typeck_results() + .type_dependent_def_id(cast_expr.peel_blocks().hir_id) && let as_ptr_sig = cx.tcx.fn_sig(as_ptr_did).instantiate_identity() && let Some(first_param_ty) = as_ptr_sig.skip_binder().inputs().iter().next() && let ty::Ref(_, _, Mutability::Not) = first_param_ty.kind() @@ -30,7 +37,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, &format!("casting the result of `as_ptr` to *{ptrty}"), "replace with", format!("{recv}.as_mut_ptr()"), - applicability + applicability, ); } } diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs b/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs index 442262983..c16633483 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs +++ b/src/tools/clippy/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/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs b/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs index c586b572b..fe2455f4b 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs @@ -1,6 +1,6 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::in_constant; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_opt; use clippy_utils::ty::is_isize_or_usize; use rustc_errors::Applicability; diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs index 1de691221..f12f03fbe 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::is_c_void; -use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant, match_any_def_paths, paths}; +use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant}; use rustc_hir::{Expr, ExprKind, GenericArg}; use rustc_lint::LateContext; use rustc_middle::ty::layout::LayoutOf; @@ -26,8 +26,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { // There probably is no obvious reason to do this, just to be consistent with `as` cases. && !is_hir_ty_cfg_dependant(cx, cast_to) { - let (cast_from, cast_to) = - (cx.typeck_results().expr_ty(self_arg), cx.typeck_results().expr_ty(expr)); + let (cast_from, cast_to) = (cx.typeck_results().expr_ty(self_arg), cx.typeck_results().expr_ty(expr)); lint_cast_ptr_alignment(cx, expr, cast_from, cast_to); } } @@ -75,16 +74,17 @@ fn is_used_as_unaligned(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { } }, ExprKind::Call(func, [arg, ..]) if arg.hir_id == e.hir_id => { - static PATHS: &[&[&str]] = &[ - paths::PTR_READ_UNALIGNED.as_slice(), - paths::PTR_UNALIGNED_VOLATILE_LOAD.as_slice(), - paths::PTR_UNALIGNED_VOLATILE_STORE.as_slice(), - ]; - if let ExprKind::Path(path) = &func.kind && let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id() - && (match_any_def_paths(cx, def_id, PATHS).is_some() - || cx.tcx.is_diagnostic_item(sym::ptr_write_unaligned, def_id)) + && matches!( + cx.tcx.get_diagnostic_name(def_id), + Some( + sym::ptr_write_unaligned + | sym::ptr_read_unaligned + | sym::intrinsics_unaligned_volatile_load + | sym::intrinsics_unaligned_volatile_store + ) + ) { true } else { diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs b/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs index 4d9cc4cac..d14104029 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs +++ b/src/tools/clippy/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 if_chain::if_chain; use rustc_ast::Mutability; diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs b/src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs index 5e0123842..badadf2c9 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs @@ -1,13 +1,13 @@ +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::{match_def_path, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; +use rustc_span::sym; use super::CAST_SLICE_FROM_RAW_PARTS; @@ -17,12 +17,10 @@ enum RawPartsKind { } fn raw_parts_kind(cx: &LateContext<'_>, did: DefId) -> Option<RawPartsKind> { - if match_def_path(cx, did, &paths::SLICE_FROM_RAW_PARTS) { - Some(RawPartsKind::Immutable) - } else if match_def_path(cx, did, &paths::SLICE_FROM_RAW_PARTS_MUT) { - Some(RawPartsKind::Mutable) - } else { - None + match cx.tcx.get_diagnostic_name(did)? { + sym::slice_from_raw_parts => Some(RawPartsKind::Immutable), + sym::slice_from_raw_parts_mut => Some(RawPartsKind::Mutable), + _ => None, } } diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs index b00130ffd..49a90a2f3 100644 --- a/src/tools/clippy/clippy_lints/src/casts/mod.rs +++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs @@ -22,8 +22,8 @@ mod unnecessary_cast; mod utils; mod zero_ptr; +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; @@ -45,7 +45,7 @@ declare_clippy_lint! { /// those places in the code. /// /// ### Example - /// ```rust + /// ```no_run /// let x = u64::MAX; /// x as f64; /// ``` @@ -67,7 +67,7 @@ declare_clippy_lint! { /// as a one-time check to see where numerical wrapping can arise. /// /// ### Example - /// ```rust + /// ```no_run /// let y: i8 = -1; /// y as u128; // will return 18446744073709551615 /// ``` @@ -90,13 +90,13 @@ declare_clippy_lint! { /// checks could be beneficial. /// /// ### Example - /// ```rust + /// ```no_run /// fn as_u8(x: u64) -> u8 { /// x as u8 /// } /// ``` /// Use instead: - /// ``` + /// ```no_run /// fn as_u8(x: u64) -> u8 { /// if let Ok(x) = u8::try_from(x) { /// x @@ -132,7 +132,7 @@ declare_clippy_lint! { /// example below. /// /// ### Example - /// ```rust + /// ```no_run /// u32::MAX as i32; // will yield a value of `-1` /// ``` #[clippy::version = "pre 1.29.0"] @@ -155,7 +155,7 @@ declare_clippy_lint! { /// people reading the code to know that the conversion is lossless. /// /// ### Example - /// ```rust + /// ```no_run /// fn as_u64(x: u8) -> u64 { /// x as u64 /// } @@ -163,7 +163,7 @@ declare_clippy_lint! { /// /// Using `::from` would look like this: /// - /// ```rust + /// ```no_run /// fn as_u64(x: u8) -> u64 { /// u64::from(x) /// } @@ -191,14 +191,14 @@ declare_clippy_lint! { /// intermediate references, raw pointers and trait objects may or may not work. /// /// ### Example - /// ```rust + /// ```no_run /// let _ = 2i32 as i32; /// let _ = 0.5 as f32; /// ``` /// /// Better: /// - /// ```rust + /// ```no_run /// let _ = 2_i32; /// let _ = 0.5_f32; /// ``` @@ -223,7 +223,7 @@ declare_clippy_lint! { /// u64-> u8 -> u16 can be fine. Miri is able to do a more in-depth analysis. /// /// ### Example - /// ```rust + /// ```no_run /// let _ = (&1u8 as *const u8) as *const u16; /// let _ = (&mut 1u8 as *mut u8) as *mut u16; /// @@ -249,13 +249,13 @@ declare_clippy_lint! { /// Casting to isize also doesn't make sense since there are no signed addresses. /// /// ### Example - /// ```rust + /// ```no_run /// fn fun() -> i32 { 1 } /// let _ = fun as i64; /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # fn fun() -> i32 { 1 } /// let _ = fun as usize; /// ``` @@ -276,7 +276,7 @@ declare_clippy_lint! { /// a comment) to perform the truncation. /// /// ### Example - /// ```rust + /// ```no_run /// fn fn1() -> i16 { /// 1 /// }; @@ -284,7 +284,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// // Cast to usize first, then comment with the reason for the truncation /// fn fn1() -> i16 { /// 1 @@ -310,7 +310,7 @@ declare_clippy_lint! { /// pointer casts in your code. /// /// ### Example - /// ```rust + /// ```no_run /// // fn1 is cast as `usize` /// fn fn1() -> u16 { /// 1 @@ -319,7 +319,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// // maybe you intended to call the function? /// fn fn2() -> u16 { /// 1 @@ -378,14 +378,14 @@ declare_clippy_lint! { /// it cannot accidentally change the pointer's mutability nor cast the pointer to other types like `usize`. /// /// ### Example - /// ```rust + /// ```no_run /// let ptr: *const u32 = &42_u32; /// let mut_ptr: *mut u32 = &mut 42_u32; /// let _ = ptr as *const i32; /// let _ = mut_ptr as *mut i32; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let ptr: *const u32 = &42_u32; /// let mut_ptr: *mut u32 = &mut 42_u32; /// let _ = ptr.cast::<i32>(); @@ -408,13 +408,13 @@ declare_clippy_lint! { /// type. /// /// ### Example - /// ```rust + /// ```no_run /// let ptr: *const u32 = &42_u32; /// let mut_ptr = ptr as *mut u32; /// let ptr = mut_ptr as *const u32; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let ptr: *const u32 = &42_u32; /// let mut_ptr = ptr.cast_mut(); /// let ptr = mut_ptr.cast_const(); @@ -434,7 +434,7 @@ declare_clippy_lint! { /// The resulting integral value will not match the value of the variant it came from. /// /// ### Example - /// ```rust + /// ```no_run /// enum E { X = 256 }; /// let _ = E::X as u8; /// ``` @@ -457,7 +457,7 @@ declare_clippy_lint! { /// /// ### Example /// // Missing data - /// ```rust + /// ```no_run /// let a = [1_i32, 2, 3, 4]; /// let p = &a as *const [i32] as *const [u8]; /// unsafe { @@ -465,7 +465,7 @@ declare_clippy_lint! { /// } /// ``` /// // Undefined Behavior (note: also potential alignment issues) - /// ```rust + /// ```no_run /// let a = [1_u8, 2, 3, 4]; /// let p = &a as *const [u8] as *const [u32]; /// unsafe { @@ -473,7 +473,7 @@ declare_clippy_lint! { /// } /// ``` /// Instead use `ptr::slice_from_raw_parts` to construct a slice from a data pointer and the correct length - /// ```rust + /// ```no_run /// let a = [1_i32, 2, 3, 4]; /// let old_ptr = &a as *const [i32]; /// // The data pointer is cast to a pointer to the target `u8` not `[u8]` @@ -497,7 +497,7 @@ declare_clippy_lint! { /// The cast is easily confused with casting a c-like enum value to an integer. /// /// ### Example - /// ```rust + /// ```no_run /// enum E { X(i32) }; /// let _ = E::X as usize; /// ``` @@ -515,12 +515,12 @@ declare_clippy_lint! { /// The `unsigned_abs()` method avoids panic when called on the MIN value. /// /// ### Example - /// ```rust + /// ```no_run /// let x: i32 = -42; /// let y: u32 = x.abs() as u32; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let x: i32 = -42; /// let y: u32 = x.unsigned_abs(); /// ``` @@ -541,13 +541,13 @@ declare_clippy_lint! { /// The lint is allowed by default as using `_` is less wordy than always specifying the type. /// /// ### Example - /// ```rust + /// ```no_run /// fn foo(n: usize) {} /// let n: u16 = 256; /// foo(n as _); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn foo(n: usize) {} /// let n: u16 = 256; /// foo(n as usize); @@ -570,7 +570,7 @@ declare_clippy_lint! { /// Read the `ptr::addr_of` docs for more information. /// /// ### Example - /// ```rust + /// ```no_run /// let val = 1; /// let p = &val as *const i32; /// @@ -578,7 +578,7 @@ declare_clippy_lint! { /// let p_mut = &mut val_mut as *mut i32; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let val = 1; /// let p = std::ptr::addr_of!(val); /// @@ -627,13 +627,13 @@ declare_clippy_lint! { /// mutability is used, making it unlikely that having it as a mutable pointer is correct. /// /// ### Example - /// ```rust + /// ```no_run /// let mut vec = Vec::<u8>::with_capacity(1); /// let ptr = vec.as_ptr() as *mut u8; /// unsafe { ptr.write(4) }; // UNDEFINED BEHAVIOUR /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let mut vec = Vec::<u8>::with_capacity(1); /// let ptr = vec.as_mut_ptr(); /// unsafe { ptr.write(4) }; @@ -675,12 +675,12 @@ declare_clippy_lint! { /// {`std`, `core`}`::ptr::`{`null`, `null_mut`}. /// /// ### Example - /// ```rust + /// ```no_run /// let a = 0 as *const u32; /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let a = std::ptr::null::<u32>(); /// ``` #[clippy::version = "pre 1.29.0"] diff --git a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs index 181dbcf6e..0c555c1ac 100644 --- a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs +++ b/src/tools/clippy/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/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs b/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs index ce1ab1091..0172e9336 100644 --- a/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs +++ b/src/tools/clippy/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::{Msrv, POINTER_CAST_CONSTNESS}; use clippy_utils::sugg::Sugg; use if_chain::if_chain; use rustc_errors::Applicability; @@ -18,7 +18,7 @@ pub(super) fn check<'tcx>( msrv: &Msrv, ) { if_chain! { - if msrv.meets(POINTER_CAST_CONSTNESS); + if msrv.meets(msrvs::POINTER_CAST_CONSTNESS); if let ty::RawPtr(TypeAndMut { mutbl: from_mutbl, ty: from_ty }) = cast_from.kind(); if let ty::RawPtr(TypeAndMut { mutbl: to_mutbl, ty: to_ty }) = cast_to.kind(); if matches!((from_mutbl, to_mutbl), diff --git a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs index 86057bb74..61bfce07e 100644 --- a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs +++ b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs @@ -97,7 +97,9 @@ pub(super) fn check<'tcx>( } // skip cast of fn call that returns type alias - if let ExprKind::Cast(inner, ..) = expr.kind && is_cast_from_ty_alias(cx, inner, cast_from) { + if let ExprKind::Cast(inner, ..) = expr.kind + && is_cast_from_ty_alias(cx, inner, cast_from) + { return false; } @@ -189,11 +191,10 @@ fn lint_unnecessary_cast( let sugg = if let Some(parent_expr) = get_parent_expr(cx, expr) && let ExprKind::MethodCall(..) = parent_expr.kind && literal_str.starts_with('-') - { - format!("({literal_str}_{cast_to})") - - } else { - format!("{literal_str}_{cast_to}") + { + format!("({literal_str}_{cast_to})") + } else { + format!("{literal_str}_{cast_to}") }; span_lint_and_sugg( @@ -269,7 +270,9 @@ fn is_cast_from_ty_alias<'tcx>(cx: &LateContext<'tcx>, expr: impl Visitable<'tcx && let Some(parent) = get_parent_node(cx.tcx, hir_id) && let Node::Local(l) = parent { - if let Some(e) = l.init && is_cast_from_ty_alias(cx, e, cast_from) { + if let Some(e) = l.init + && is_cast_from_ty_alias(cx, e, cast_from) + { return ControlFlow::Break::<()>(()); } diff --git a/src/tools/clippy/clippy_lints/src/checked_conversions.rs b/src/tools/clippy/clippy_lints/src/checked_conversions.rs index 9102a89e3..d31c2268a 100644 --- a/src/tools/clippy/clippy_lints/src/checked_conversions.rs +++ b/src/tools/clippy/clippy_lints/src/checked_conversions.rs @@ -1,7 +1,7 @@ //! lint on manually implemented checked conversions that could be transformed into `try_from` +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::{in_constant, is_integer_literal, SpanlessEq}; use if_chain::if_chain; @@ -19,13 +19,13 @@ declare_clippy_lint! { /// Reduces the readability of statements & is error prone. /// /// ### Example - /// ```rust + /// ```no_run /// # let foo: u32 = 5; /// foo <= i32::MAX as u32; /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let foo = 1; /// # #[allow(unused)] /// i32::try_from(foo).is_ok(); diff --git a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs index a8926b29a..74ecaa60c 100644 --- a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs +++ b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs @@ -12,8 +12,7 @@ use rustc_hir::{Body, Expr, ExprKind, FnDecl}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::def_id::LocalDefId; -use rustc_span::source_map::Span; -use rustc_span::{sym, BytePos}; +use rustc_span::{sym, BytePos, Span}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/collapsible_if.rs b/src/tools/clippy/clippy_lints/src/collapsible_if.rs index b38e09dc0..d21ef195d 100644 --- a/src/tools/clippy/clippy_lints/src/collapsible_if.rs +++ b/src/tools/clippy/clippy_lints/src/collapsible_if.rs @@ -32,7 +32,7 @@ declare_clippy_lint! { /// makes code look more complex than it really is. /// /// ### Example - /// ```rust + /// ```no_run /// # let (x, y) = (true, true); /// if x { /// if y { @@ -42,7 +42,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let (x, y) = (true, true); /// if x && y { /// // … diff --git a/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs b/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs index ac5ac542c..1dfc2e251 100644 --- a/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs +++ b/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs @@ -20,7 +20,7 @@ declare_clippy_lint! { /// instead. /// /// ### Example - /// ```rust + /// ```no_run /// # let samples = vec![3, 1, 2]; /// let mut sorted_samples = samples.clone(); /// sorted_samples.sort(); @@ -29,7 +29,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # let samples = vec![3, 1, 2]; /// let mut sorted_samples = samples.clone(); /// sorted_samples.sort(); diff --git a/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs b/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs index 726674d88..a2005638d 100644 --- a/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs +++ b/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs @@ -18,7 +18,7 @@ declare_clippy_lint! { /// https://doc.rust-lang.org/reference/macros-by-example.html#hygiene /// /// ### Example - /// ```rust + /// ```no_run /// #[macro_export] /// macro_rules! print_message { /// () => { @@ -28,7 +28,7 @@ declare_clippy_lint! { /// pub const MESSAGE: &str = "Hello!"; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// #[macro_export] /// macro_rules! print_message { /// () => { diff --git a/src/tools/clippy/clippy_lints/src/create_dir.rs b/src/tools/clippy/clippy_lints/src/create_dir.rs index 878248a6b..2bca695c4 100644 --- a/src/tools/clippy/clippy_lints/src/create_dir.rs +++ b/src/tools/clippy/clippy_lints/src/create_dir.rs @@ -1,11 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; -use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -37,7 +37,7 @@ impl LateLintPass<'_> for CreateDir { if let ExprKind::Call(func, [arg, ..]) = expr.kind; if let ExprKind::Path(ref path) = func.kind; if let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id(); - if match_def_path(cx, def_id, &paths::STD_FS_CREATE_DIR); + if cx.tcx.is_diagnostic_item(sym::fs_create_dir, def_id); then { span_lint_and_sugg( cx, diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs index 4d1281ec1..1a646ba38 100644 --- a/src/tools/clippy/clippy_lints/src/declared_lints.rs +++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs @@ -6,8 +6,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ #[cfg(feature = "internal")] crate::utils::internal_lints::almost_standard_lint_formulation::ALMOST_STANDARD_LINT_FORMULATION_INFO, #[cfg(feature = "internal")] - crate::utils::internal_lints::clippy_lints_internal::CLIPPY_LINTS_INTERNAL_INFO, - #[cfg(feature = "internal")] crate::utils::internal_lints::collapsible_calls::COLLAPSIBLE_SPAN_LINT_CALLS_INFO, #[cfg(feature = "internal")] crate::utils::internal_lints::compiler_lint_functions::COMPILER_LINT_FUNCTIONS_INFO, @@ -30,6 +28,8 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ #[cfg(feature = "internal")] crate::utils::internal_lints::lint_without_lint_pass::MISSING_CLIPPY_VERSION_ATTRIBUTE_INFO, #[cfg(feature = "internal")] + crate::utils::internal_lints::metadata_collector::METADATA_COLLECTOR_INFO, + #[cfg(feature = "internal")] crate::utils::internal_lints::msrv_attr_impl::MISSING_MSRV_ATTR_IMPL_INFO, #[cfg(feature = "internal")] crate::utils::internal_lints::outer_expn_data_pass::OUTER_EXPN_EXPN_DATA_INFO, @@ -37,6 +37,8 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::utils::internal_lints::produce_ice::PRODUCE_ICE_INFO, #[cfg(feature = "internal")] crate::utils::internal_lints::unnecessary_def_path::UNNECESSARY_DEF_PATH_INFO, + #[cfg(feature = "internal")] + crate::utils::internal_lints::unsorted_clippy_utils_paths::UNSORTED_CLIPPY_UTILS_PATHS_INFO, crate::absolute_paths::ABSOLUTE_PATHS_INFO, crate::allow_attributes::ALLOW_ATTRIBUTES_INFO, crate::almost_complete_range::ALMOST_COMPLETE_RANGE_INFO, @@ -154,9 +156,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::endian_bytes::LITTLE_ENDIAN_BYTES_INFO, crate::entry::MAP_ENTRY_INFO, crate::enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT_INFO, - crate::enum_variants::ENUM_VARIANT_NAMES_INFO, - crate::enum_variants::MODULE_INCEPTION_INFO, - crate::enum_variants::MODULE_NAME_REPETITIONS_INFO, crate::equatable_if_let::EQUATABLE_IF_LET_INFO, crate::error_impl_error::ERROR_IMPL_ERROR_INFO, crate::escape::BOXED_LOCAL_INFO, @@ -226,9 +225,15 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::instant_subtraction::UNCHECKED_DURATION_SUBTRACTION_INFO, crate::int_plus_one::INT_PLUS_ONE_INFO, crate::invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS_INFO, + crate::item_name_repetitions::ENUM_VARIANT_NAMES_INFO, + crate::item_name_repetitions::MODULE_INCEPTION_INFO, + crate::item_name_repetitions::MODULE_NAME_REPETITIONS_INFO, + crate::item_name_repetitions::STRUCT_FIELD_NAMES_INFO, crate::items_after_statements::ITEMS_AFTER_STATEMENTS_INFO, crate::items_after_test_module::ITEMS_AFTER_TEST_MODULE_INFO, crate::iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR_INFO, + crate::iter_without_into_iter::INTO_ITER_WITHOUT_ITER_INFO, + crate::iter_without_into_iter::ITER_WITHOUT_INTO_ITER_INFO, crate::large_const_arrays::LARGE_CONST_ARRAYS_INFO, crate::large_enum_variant::LARGE_ENUM_VARIANT_INFO, crate::large_futures::LARGE_FUTURES_INFO, @@ -269,6 +274,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::loops::NEVER_LOOP_INFO, crate::loops::SAME_ITEM_PUSH_INFO, crate::loops::SINGLE_ELEMENT_LOOP_INFO, + crate::loops::UNUSED_ENUMERATE_INDEX_INFO, crate::loops::WHILE_IMMUTABLE_CONDITION_INFO, crate::loops::WHILE_LET_LOOP_INFO, crate::loops::WHILE_LET_ON_ITERATOR_INFO, @@ -280,6 +286,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::manual_clamp::MANUAL_CLAMP_INFO, crate::manual_float_methods::MANUAL_IS_FINITE_INFO, crate::manual_float_methods::MANUAL_IS_INFINITE_INFO, + crate::manual_hash_one::MANUAL_HASH_ONE_INFO, crate::manual_is_ascii_check::MANUAL_IS_ASCII_CHECK_INFO, crate::manual_let_else::MANUAL_LET_ELSE_INFO, crate::manual_main_separator_str::MANUAL_MAIN_SEPARATOR_STR_INFO, @@ -424,6 +431,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::TYPE_ID_ON_BOX_INFO, crate::methods::UNINIT_ASSUMED_INIT_INFO, crate::methods::UNIT_HASH_INFO, + crate::methods::UNNECESSARY_FALLIBLE_CONVERSIONS_INFO, crate::methods::UNNECESSARY_FILTER_MAP_INFO, crate::methods::UNNECESSARY_FIND_MAP_INFO, crate::methods::UNNECESSARY_FOLD_INFO, @@ -437,6 +445,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::USELESS_ASREF_INFO, crate::methods::VEC_RESIZE_TO_ZERO_INFO, crate::methods::VERBOSE_FILE_READS_INFO, + crate::methods::WAKER_CLONE_WAKE_INFO, crate::methods::WRONG_SELF_CONVENTION_INFO, crate::methods::ZST_OFFSET_INFO, crate::min_ident_chars::MIN_IDENT_CHARS_INFO, diff --git a/src/tools/clippy/clippy_lints/src/default.rs b/src/tools/clippy/clippy_lints/src/default.rs index 763ad0264..c74b2b883 100644 --- a/src/tools/clippy/clippy_lints/src/default.rs +++ b/src/tools/clippy/clippy_lints/src/default.rs @@ -1,9 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg}; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{has_drop, is_copy}; -use clippy_utils::{ - any_parent_is_automatically_derived, contains_name, get_parent_expr, is_from_proc_macro, match_def_path, paths, -}; +use clippy_utils::{any_parent_is_automatically_derived, contains_name, get_parent_expr, is_from_proc_macro}; use if_chain::if_chain; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; @@ -14,7 +12,7 @@ use rustc_middle::ty; use rustc_middle::ty::print::with_forced_trimmed_paths; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::symbol::{Ident, Symbol}; -use rustc_span::Span; +use rustc_span::{sym, Span}; declare_clippy_lint! { /// ### What it does @@ -25,12 +23,12 @@ declare_clippy_lint! { /// generic `Default`. /// /// ### Example - /// ```rust + /// ```no_run /// let s: String = Default::default(); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let s = String::default(); /// ``` #[clippy::version = "pre 1.29.0"] @@ -51,7 +49,7 @@ declare_clippy_lint! { /// Assignments to patterns that are of tuple type are not linted. /// /// ### Example - /// ``` + /// ```no_run /// # #[derive(Default)] /// # struct A { i: i32 } /// let mut a: A = Default::default(); @@ -59,7 +57,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ``` + /// ```no_run /// # #[derive(Default)] /// # struct A { i: i32 } /// let a = A { @@ -91,7 +89,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { if !any_parent_is_automatically_derived(cx.tcx, expr.hir_id); if let ExprKind::Path(ref qpath) = path.kind; if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id(); - if match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD); + if cx.tcx.is_diagnostic_item(sym::default_fn, def_id); if !is_update_syntax_base(cx, expr); // Detect and ignore <Foo as Default>::default() because these calls do explicitly name the type. if let QPath::Resolved(None, _path) = qpath; @@ -268,7 +266,7 @@ fn is_expr_default<'tcx>(expr: &'tcx Expr<'tcx>, cx: &LateContext<'tcx>) -> bool if let Res::Def(_, def_id) = cx.qpath_res(qpath, fn_expr.hir_id); then { // right hand side of assignment is `Default::default` - match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD) + cx.tcx.is_diagnostic_item(sym::default_fn, def_id) } else { false } diff --git a/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs b/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs index a294c6937..bf070432e 100644 --- a/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs +++ b/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::{is_ty_alias, match_def_path, paths}; +use clippy_utils::is_ty_alias; use hir::def::Res; use hir::ExprKind; use rustc_errors::Applicability; @@ -7,6 +7,7 @@ use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -16,7 +17,7 @@ declare_clippy_lint! { /// This adds code complexity and an unnecessary function call. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::marker::PhantomData; /// #[derive(Default)] /// struct S<T> { @@ -28,7 +29,7 @@ declare_clippy_lint! { /// }; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # use std::marker::PhantomData; /// struct S<T> { /// _marker: PhantomData<T> @@ -63,7 +64,7 @@ impl LateLintPass<'_> for DefaultConstructedUnitStructs { // `<Foo as Bar>::Assoc` cannot be used as a constructor if !is_alias(*base); if let Res::Def(_, def_id) = cx.qpath_res(qpath, fn_expr.hir_id); - if match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD); + if cx.tcx.is_diagnostic_item(sym::default_fn, def_id); // make sure we have a struct with no fields (unit struct) if let ty::Adt(def, ..) = cx.typeck_results().expr_ty(expr).kind(); if def.is_struct(); diff --git a/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs b/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs index 572990aab..553b670fd 100644 --- a/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs +++ b/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs @@ -1,11 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::last_path_segment; use clippy_utils::source::snippet_with_context; -use clippy_utils::{last_path_segment, match_def_path, paths}; use rustc_errors::Applicability; use rustc_hir::{def, Expr, ExprKind, GenericArg, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::SyntaxContext; +use rustc_span::{sym, SyntaxContext}; declare_clippy_lint! { /// ### What it does @@ -14,12 +14,12 @@ declare_clippy_lint! { /// ### Why is this bad? /// `std::iter::empty()` is the more idiomatic way. /// ### Example - /// ```rust + /// ```no_run /// let _ = std::iter::Empty::<usize>::default(); /// let iter: std::iter::Empty<usize> = std::iter::Empty::default(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let _ = std::iter::empty::<usize>(); /// let iter: std::iter::Empty<usize> = std::iter::empty(); /// ``` @@ -37,7 +37,7 @@ impl<'tcx> LateLintPass<'tcx> for DefaultIterEmpty { && let TyKind::Path(ty_path) = &ty.kind && let QPath::Resolved(None, path) = ty_path && let def::Res::Def(_, def_id) = &path.res - && match_def_path(cx, *def_id, &paths::ITER_EMPTY) + && cx.tcx.is_diagnostic_item(sym::IterEmpty, *def_id) && let ctxt = expr.span.ctxt() && ty.span.ctxt() == ctxt { @@ -68,7 +68,10 @@ fn make_sugg( _ => None, }) { - format!("std::iter::empty::<{}>()", snippet_with_context(cx, iter_ty.span, ctxt, "..", applicability).0) + format!( + "std::iter::empty::<{}>()", + snippet_with_context(cx, iter_ty.span, ctxt, "..", applicability).0 + ) } else { "std::iter::empty()".to_owned() } diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs index d09428dbc..b296ea20f 100644 --- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs +++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs @@ -31,13 +31,13 @@ declare_clippy_lint! { /// This lint can only be allowed at the function level or above. /// /// ### Example - /// ```rust + /// ```no_run /// let i = 10; /// let f = 1.23; /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let i = 10i32; /// let f = 1.23f64; /// ``` diff --git a/src/tools/clippy/clippy_lints/src/default_union_representation.rs b/src/tools/clippy/clippy_lints/src/default_union_representation.rs index 63ec81950..8c6749a95 100644 --- a/src/tools/clippy/clippy_lints/src/default_union_representation.rs +++ b/src/tools/clippy/clippy_lints/src/default_union_representation.rs @@ -17,7 +17,7 @@ declare_clippy_lint! { /// specified layout. These cases may lead to undefined behavior in unsafe blocks. /// /// ### Example - /// ```rust + /// ```no_run /// union Foo { /// a: i32, /// b: u32, @@ -30,7 +30,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// #[repr(C)] /// union Foo { /// a: i32, diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index 148773856..6c109a51f 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -29,14 +29,14 @@ declare_clippy_lint! { /// when not part of a method chain. /// /// ### Example - /// ```rust + /// ```no_run /// use std::ops::Deref; /// let a: &mut String = &mut String::from("foo"); /// let b: &str = a.deref(); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let a: &mut String = &mut String::from("foo"); /// let b = &*a; /// ``` @@ -68,7 +68,7 @@ declare_clippy_lint! { /// in such a case can change the semantics of the code. /// /// ### Example - /// ```rust + /// ```no_run /// fn fun(_a: &i32) {} /// /// let x: &i32 = &&&&&&5; @@ -76,7 +76,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # fn fun(_a: &i32) {} /// let x: &i32 = &5; /// fun(x); @@ -95,7 +95,7 @@ declare_clippy_lint! { /// The address-of operator at the use site is clearer about the need for a reference. /// /// ### Example - /// ```rust + /// ```no_run /// let x = Some(""); /// if let Some(ref x) = x { /// // use `x` here @@ -103,7 +103,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let x = Some(""); /// if let Some(x) = x { /// // use `&x` here @@ -123,12 +123,12 @@ declare_clippy_lint! { /// This unnecessarily complicates the code. /// /// ### Example - /// ```rust + /// ```no_run /// let x = String::new(); /// let y: &str = &*x; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let x = String::new(); /// let y: &str = &x; /// ``` @@ -353,23 +353,26 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { // priority. if let Some(fn_id) = typeck.type_dependent_def_id(hir_id) && let Some(trait_id) = cx.tcx.trait_of_item(fn_id) - && let arg_ty - = cx.tcx.erase_regions(use_cx.adjustments.last().map_or(expr_ty, |a| a.target)) + && let arg_ty = cx + .tcx + .erase_regions(use_cx.adjustments.last().map_or(expr_ty, |a| a.target)) && let ty::Ref(_, sub_ty, _) = *arg_ty.kind() && let args = cx .typeck_results() - .node_args_opt(hir_id).map(|args| &args[1..]).unwrap_or_default() - && let impl_ty = if cx.tcx.fn_sig(fn_id) - .instantiate_identity() - .skip_binder() - .inputs()[0].is_ref() - { - // Trait methods taking `&self` - sub_ty - } else { - // Trait methods taking `self` - arg_ty - } && impl_ty.is_ref() + .node_args_opt(hir_id) + .map(|args| &args[1..]) + .unwrap_or_default() + && let impl_ty = + if cx.tcx.fn_sig(fn_id).instantiate_identity().skip_binder().inputs()[0] + .is_ref() + { + // Trait methods taking `&self` + sub_ty + } else { + // Trait methods taking `self` + arg_ty + } + && impl_ty.is_ref() && implements_trait( cx, impl_ty, @@ -414,9 +417,9 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { let (required_refs, msg) = if can_auto_borrow { (1, if deref_count == 1 { borrow_msg } else { deref_msg }) } else if let Some(&Adjustment { - kind: Adjust::Borrow(AutoBorrow::Ref(_, mutability)), - .. - }) = next_adjust + kind: Adjust::Borrow(AutoBorrow::Ref(_, mutability)), + .. + }) = next_adjust && matches!(mutability, AutoBorrowMutability::Mut { .. }) && !stability.is_reborrow_stable() { @@ -701,13 +704,15 @@ fn deref_method_same_type<'tcx>(result_ty: Ty<'tcx>, arg_ty: Ty<'tcx>) -> bool { fn in_postfix_position<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> bool { if let Some(parent) = get_parent_expr(cx, e) - && parent.span.ctxt() == e.span.ctxt() + && parent.span.eq_ctxt(e.span) { match parent.kind { ExprKind::Call(child, _) | ExprKind::MethodCall(_, child, _, _) | ExprKind::Index(child, _, _) - if child.hir_id == e.hir_id => true, - ExprKind::Match(.., MatchSource::TryDesugar(_) | MatchSource::AwaitDesugar) - | ExprKind::Field(_, _) => true, + if child.hir_id == e.hir_id => + { + true + }, + ExprKind::Match(.., MatchSource::TryDesugar(_) | MatchSource::AwaitDesugar) | ExprKind::Field(_, _) => true, _ => false, } } else { @@ -842,8 +847,8 @@ impl TyCoercionStability { | ty::Adt(..) | ty::Foreign(_) | ty::FnDef(..) - | ty::Generator(..) - | ty::GeneratorWitness(..) + | ty::Coroutine(..) + | ty::CoroutineWitness(..) | ty::Closure(..) | ty::Never | ty::Tuple(_) diff --git a/src/tools/clippy/clippy_lints/src/derivable_impls.rs b/src/tools/clippy/clippy_lints/src/derivable_impls.rs index d2bfc4f8e..a450becc6 100644 --- a/src/tools/clippy/clippy_lints/src/derivable_impls.rs +++ b/src/tools/clippy/clippy_lints/src/derivable_impls.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::indent_of; use clippy_utils::{is_default_equivalent, peel_blocks}; use rustc_errors::Applicability; @@ -21,7 +21,7 @@ declare_clippy_lint! { /// It is less concise. /// /// ### Example - /// ```rust + /// ```no_run /// struct Foo { /// bar: bool /// } @@ -36,7 +36,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// #[derive(Default)] /// struct Foo { /// bar: bool diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs index 2bdac1352..3a331564d 100644 --- a/src/tools/clippy/clippy_lints/src/derive.rs +++ b/src/tools/clippy/clippy_lints/src/derive.rs @@ -17,8 +17,7 @@ use rustc_middle::ty::{ }; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::def_id::LocalDefId; -use rustc_span::source_map::Span; -use rustc_span::sym; +use rustc_span::{sym, Span}; declare_clippy_lint! { /// ### What it does @@ -173,7 +172,7 @@ declare_clippy_lint! { /// `Eq` themselves. /// /// ### Example - /// ```rust + /// ```no_run /// #[derive(PartialEq)] /// struct Foo { /// i_am_eq: i32, @@ -181,7 +180,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// #[derive(PartialEq, Eq)] /// struct Foo { /// i_am_eq: i32, diff --git a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs index 7469f813e..324b5e079 100644 --- a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs +++ b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs @@ -1,3 +1,4 @@ +use clippy_config::types::DisallowedPath; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::macro_backtrace; use rustc_ast::Attribute; @@ -8,8 +9,6 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{ExpnId, Span}; -use crate::utils::conf; - declare_clippy_lint! { /// ### What it does /// Denies the configured macros in clippy.toml @@ -35,7 +34,7 @@ declare_clippy_lint! { /// { path = "serde::Serialize", reason = "no serializing" }, /// ] /// ``` - /// ``` + /// ```no_run /// use serde::Serialize; /// /// // Example code where clippy issues a warning @@ -55,13 +54,13 @@ declare_clippy_lint! { } pub struct DisallowedMacros { - conf_disallowed: Vec<conf::DisallowedPath>, + conf_disallowed: Vec<DisallowedPath>, disallowed: DefIdMap<usize>, seen: FxHashSet<ExpnId>, } impl DisallowedMacros { - pub fn new(conf_disallowed: Vec<conf::DisallowedPath>) -> Self { + pub fn new(conf_disallowed: Vec<DisallowedPath>) -> Self { Self { conf_disallowed, disallowed: DefIdMap::default(), diff --git a/src/tools/clippy/clippy_lints/src/disallowed_methods.rs b/src/tools/clippy/clippy_lints/src/disallowed_methods.rs index 95d3f7547..d23aeebb5 100644 --- a/src/tools/clippy/clippy_lints/src/disallowed_methods.rs +++ b/src/tools/clippy/clippy_lints/src/disallowed_methods.rs @@ -1,13 +1,11 @@ +use clippy_config::types::DisallowedPath; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::{fn_def_id, get_parent_expr, path_def_id}; - use rustc_hir::def_id::DefIdMap; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use crate::utils::conf; - declare_clippy_lint! { /// ### What it does /// Denies the configured methods and functions in clippy.toml @@ -59,12 +57,12 @@ declare_clippy_lint! { #[derive(Clone, Debug)] pub struct DisallowedMethods { - conf_disallowed: Vec<conf::DisallowedPath>, + conf_disallowed: Vec<DisallowedPath>, disallowed: DefIdMap<usize>, } impl DisallowedMethods { - pub fn new(conf_disallowed: Vec<conf::DisallowedPath>) -> Self { + pub fn new(conf_disallowed: Vec<DisallowedPath>) -> Self { Self { conf_disallowed, disallowed: DefIdMap::default(), diff --git a/src/tools/clippy/clippy_lints/src/disallowed_names.rs b/src/tools/clippy/clippy_lints/src/disallowed_names.rs index 04c2d4413..5e46b29b6 100644 --- a/src/tools/clippy/clippy_lints/src/disallowed_names.rs +++ b/src/tools/clippy/clippy_lints/src/disallowed_names.rs @@ -15,7 +15,7 @@ declare_clippy_lint! { /// avoided. /// /// ### Example - /// ```rust + /// ```no_run /// let foo = 3.14; /// ``` #[clippy::version = "pre 1.29.0"] diff --git a/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs b/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs index c9fad98e4..96a7f0e4f 100644 --- a/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs +++ b/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs @@ -30,7 +30,7 @@ declare_clippy_lint! { /// [`non_ascii_idents`]: https://doc.rust-lang.org/rustc/lints/listing/allowed-by-default.html#non-ascii-idents /// /// ### Example - /// ```rust + /// ```no_run /// // Assuming that `clippy.toml` contains the following line: /// // allowed-scripts = ["Latin", "Cyrillic"] /// let counter = 10; // OK, latin is allowed. diff --git a/src/tools/clippy/clippy_lints/src/disallowed_types.rs b/src/tools/clippy/clippy_lints/src/disallowed_types.rs index 1f56d0118..3578fb640 100644 --- a/src/tools/clippy/clippy_lints/src/disallowed_types.rs +++ b/src/tools/clippy/clippy_lints/src/disallowed_types.rs @@ -1,5 +1,5 @@ +use clippy_config::types::DisallowedPath; use clippy_utils::diagnostics::span_lint_and_then; - use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::Res; use rustc_hir::def_id::DefId; @@ -8,8 +8,6 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::Span; -use crate::utils::conf; - declare_clippy_lint! { /// ### What it does /// Denies the configured types in clippy.toml. @@ -50,15 +48,16 @@ declare_clippy_lint! { style, "use of disallowed types" } + #[derive(Clone, Debug)] pub struct DisallowedTypes { - conf_disallowed: Vec<conf::DisallowedPath>, + conf_disallowed: Vec<DisallowedPath>, def_ids: FxHashMap<DefId, usize>, prim_tys: FxHashMap<PrimTy, usize>, } impl DisallowedTypes { - pub fn new(conf_disallowed: Vec<conf::DisallowedPath>) -> Self { + pub fn new(conf_disallowed: Vec<DisallowedPath>) -> Self { Self { conf_disallowed, def_ids: FxHashMap::default(), @@ -123,7 +122,7 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedTypes { } } -fn emit(cx: &LateContext<'_>, name: &str, span: Span, conf: &conf::DisallowedPath) { +fn emit(cx: &LateContext<'_>, name: &str, span: Span, conf: &DisallowedPath) { span_lint_and_then( cx, DISALLOWED_TYPES, diff --git a/src/tools/clippy/clippy_lints/src/doc.rs b/src/tools/clippy/clippy_lints/src/doc.rs index e789e0da6..8982fca6e 100644 --- a/src/tools/clippy/clippy_lints/src/doc.rs +++ b/src/tools/clippy/clippy_lints/src/doc.rs @@ -30,8 +30,8 @@ use rustc_resolve::rustdoc::{ use rustc_session::parse::ParseSess; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::edition::Edition; -use rustc_span::source_map::{BytePos, FilePathMapping, SourceMap, Span}; -use rustc_span::{sym, FileName, Pos}; +use rustc_span::{sym, BytePos, FileName, Pos, Span}; +use rustc_span::source_map::{FilePathMapping, SourceMap}; use std::ops::Range; use std::{io, thread}; use url::Url; @@ -58,14 +58,14 @@ declare_clippy_lint! { /// would fail. /// /// ### Examples - /// ```rust + /// ```no_run /// /// Do something with the foo_bar parameter. See also /// /// that::other::module::foo. /// // ^ `foo_bar` and `that::other::module::foo` should be ticked. /// fn doit(foo_bar: usize) {} /// ``` /// - /// ```rust + /// ```no_run /// // Link text with `[]` brackets should be written as following: /// /// Consume the array and return the inner /// /// [`SmallVec<[T; INLINE_CAPACITY]>`][SmallVec]. @@ -88,7 +88,7 @@ declare_clippy_lint! { /// preconditions, so that users can be sure they are using them safely. /// /// ### Examples - /// ```rust + /// ```no_run ///# type Universe = (); /// /// This function should really be documented /// pub unsafe fn start_apocalypse(u: &mut Universe) { @@ -98,7 +98,7 @@ declare_clippy_lint! { /// /// At least write a line about safety: /// - /// ```rust + /// ```no_run ///# type Universe = (); /// /// # Safety /// /// @@ -126,7 +126,7 @@ declare_clippy_lint! { /// Since the following function returns a `Result` it has an `# Errors` section in /// its doc comment: /// - /// ```rust + /// ```no_run ///# use std::io; /// /// # Errors /// /// @@ -155,7 +155,7 @@ declare_clippy_lint! { /// Since the following function may panic it has a `# Panics` section in /// its doc comment: /// - /// ```rust + /// ```no_run /// /// # Panics /// /// /// /// Will panic if y is 0 @@ -182,7 +182,7 @@ declare_clippy_lint! { /// if the `fn main()` is left implicit. /// /// ### Examples - /// ```rust + /// ```no_run /// /// An example of a doctest with a `main()` function /// /// /// /// # Examples @@ -210,12 +210,12 @@ declare_clippy_lint! { /// It is likely a typo when defining an intra-doc link /// /// ### Example - /// ```rust + /// ```no_run /// /// See also: ['foo'] /// fn bar() {} /// ``` /// Use instead: - /// ```rust + /// ```no_run /// /// See also: [`foo`] /// fn bar() {} /// ``` @@ -235,7 +235,7 @@ declare_clippy_lint! { /// need to describe safety preconditions that users are required to uphold. /// /// ### Examples - /// ```rust + /// ```no_run ///# type Universe = (); /// /// # Safety /// /// @@ -248,7 +248,7 @@ declare_clippy_lint! { /// The function is safe, so there shouldn't be any preconditions /// that have to be explained for safety reasons. /// - /// ```rust + /// ```no_run ///# type Universe = (); /// /// This function should really be documented /// pub fn start_apocalypse(u: &mut Universe) { @@ -436,8 +436,8 @@ fn lint_for_missing_headers( let body = cx.tcx.hir().body(body_id); let ret_ty = typeck.expr_ty(body.value); if implements_trait(cx, ret_ty, future, &[]); - if let ty::Generator(_, subs, _) = ret_ty.kind(); - if is_type_diagnostic_item(cx, subs.as_generator().return_ty(), sym::Result); + if let ty::Coroutine(_, subs, _) = ret_ty.kind(); + if is_type_diagnostic_item(cx, subs.as_coroutine().return_ty(), sym::Result); then { span_lint( cx, @@ -569,9 +569,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize if let End(Heading(_, _, _)) = event { in_heading = false; } - if ticks_unbalanced - && let Some(span) = fragments.span(cx, paragraph_range.clone()) - { + if ticks_unbalanced && let Some(span) = fragments.span(cx, paragraph_range.clone()) { span_lint_and_help( cx, DOC_MARKDOWN, @@ -617,8 +615,9 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize check_link_quotes(cx, trimmed_text, range.clone(), fragments); } if let Some(link) = in_link.as_ref() - && let Ok(url) = Url::parse(link) - && (url.scheme() == "https" || url.scheme() == "http") { + && let Ok(url) = Url::parse(link) + && (url.scheme() == "https" || url.scheme() == "http") + { // Don't check the text associated with external URLs continue; } @@ -716,7 +715,9 @@ fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, range: Range<u // Because of the global session, we need to create a new session in a different thread with // the edition we need. let text = text.to_owned(); - if thread::spawn(move || has_needless_main(text, edition)).join().expect("thread::spawn failed") + if thread::spawn(move || has_needless_main(text, edition)) + .join() + .expect("thread::spawn failed") && let Some(span) = fragments.span(cx, range.start..range.end - trailing_whitespace) { span_lint(cx, NEEDLESS_DOCTEST_MAIN, span, "needless `fn main` in doctest"); @@ -756,11 +757,12 @@ fn check_text(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, text: &str } fn check_word(cx: &LateContext<'_>, word: &str, span: Span) { - /// Checks if a string is camel-case, i.e., contains at least two uppercase - /// letters (`Clippy` is ok) and one lower-case letter (`NASA` is ok). + /// Checks if a string is upper-camel-case, i.e., starts with an uppercase and + /// contains at least two uppercase letters (`Clippy` is ok) and one lower-case + /// letter (`NASA` is ok). /// Plurals are also excluded (`IDs` is ok). fn is_camel_case(s: &str) -> bool { - if s.starts_with(|c: char| c.is_ascii_digit()) { + if s.starts_with(|c: char| c.is_ascii_digit() | c.is_ascii_lowercase()) { return false; } diff --git a/src/tools/clippy/clippy_lints/src/double_parens.rs b/src/tools/clippy/clippy_lints/src/double_parens.rs index 29425b2e5..63f32173b 100644 --- a/src/tools/clippy/clippy_lints/src/double_parens.rs +++ b/src/tools/clippy/clippy_lints/src/double_parens.rs @@ -12,7 +12,7 @@ declare_clippy_lint! { /// mistake. /// /// ### Example - /// ```rust + /// ```no_run /// fn simple_double_parens() -> i32 { /// ((0)) /// } @@ -22,7 +22,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// fn simple_no_parens() -> i32 { /// 0 /// } diff --git a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs index 14122abbf..177e04dfa 100644 --- a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs +++ b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs @@ -16,7 +16,7 @@ declare_clippy_lint! { /// have been intended. /// /// ### Example - /// ```rust + /// ```no_run /// struct Foo; /// let x = Foo; /// std::mem::drop(x); @@ -36,7 +36,7 @@ declare_clippy_lint! { /// have been intended. /// /// ### Example - /// ```rust + /// ```no_run /// struct Foo; /// let x = Foo; /// std::mem::forget(x); @@ -57,7 +57,7 @@ declare_clippy_lint! { /// destructor, possibly causing leaks. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::mem; /// # use std::rc::Rc; /// mem::forget(Rc::new(55)) @@ -90,7 +90,8 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef { let is_copy = is_copy(cx, arg_ty); let drop_is_single_call_in_arm = is_single_call_in_arm(cx, arg, expr); let (lint, msg, note_span) = match fn_name { - // early return for uplifted lints: dropping_references, dropping_copy_types, forgetting_references, forgetting_copy_types + // early return for uplifted lints: dropping_references, dropping_copy_types, forgetting_references, + // forgetting_copy_types sym::mem_drop if arg_ty.is_ref() && !drop_is_single_call_in_arm => return, sym::mem_forget if arg_ty.is_ref() => return, sym::mem_drop if is_copy && !drop_is_single_call_in_arm => return, @@ -100,8 +101,7 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef { if !(arg_ty.needs_drop(cx.tcx, cx.param_env) || is_must_use_func_call(cx, arg) || is_must_use_ty(cx, arg_ty) - || drop_is_single_call_in_arm - ) => + || drop_is_single_call_in_arm) => { (DROP_NON_DROP, DROP_NON_DROP_SUMMARY.into(), Some(arg.span)) }, @@ -122,7 +122,7 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef { } else { (FORGET_NON_DROP, FORGET_NON_DROP_SUMMARY.into(), Some(arg.span)) } - } + }, _ => return, }; span_lint_and_note( diff --git a/src/tools/clippy/clippy_lints/src/else_if_without_else.rs b/src/tools/clippy/clippy_lints/src/else_if_without_else.rs index bf4488570..61db1c1ab 100644 --- a/src/tools/clippy/clippy_lints/src/else_if_without_else.rs +++ b/src/tools/clippy/clippy_lints/src/else_if_without_else.rs @@ -15,7 +15,7 @@ declare_clippy_lint! { /// Some coding guidelines require this (e.g., MISRA-C:2004 Rule 14.10). /// /// ### Example - /// ```rust + /// ```no_run /// # fn a() {} /// # fn b() {} /// # let x: i32 = 1; @@ -28,7 +28,7 @@ declare_clippy_lint! { /// /// Use instead: /// - /// ```rust + /// ```no_run /// # fn a() {} /// # fn b() {} /// # let x: i32 = 1; diff --git a/src/tools/clippy/clippy_lints/src/empty_drop.rs b/src/tools/clippy/clippy_lints/src/empty_drop.rs index 209fb66fa..5fcdca7cf 100644 --- a/src/tools/clippy/clippy_lints/src/empty_drop.rs +++ b/src/tools/clippy/clippy_lints/src/empty_drop.rs @@ -16,7 +16,7 @@ declare_clippy_lint! { /// destructured, which might be the intention behind adding the implementation as a marker. /// /// ### Example - /// ```rust + /// ```no_run /// struct S; /// /// impl Drop for S { @@ -24,7 +24,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// struct S; /// ``` #[clippy::version = "1.62.0"] diff --git a/src/tools/clippy/clippy_lints/src/empty_enum.rs b/src/tools/clippy/clippy_lints/src/empty_enum.rs index 1701d0611..a5699727b 100644 --- a/src/tools/clippy/clippy_lints/src/empty_enum.rs +++ b/src/tools/clippy/clippy_lints/src/empty_enum.rs @@ -23,12 +23,12 @@ declare_clippy_lint! { /// /// /// ### Example - /// ```rust + /// ```no_run /// enum Test {} /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// #![feature(never_type)] /// /// struct Test(!); diff --git a/src/tools/clippy/clippy_lints/src/empty_structs_with_brackets.rs b/src/tools/clippy/clippy_lints/src/empty_structs_with_brackets.rs index 282157181..4e2a8b73c 100644 --- a/src/tools/clippy/clippy_lints/src/empty_structs_with_brackets.rs +++ b/src/tools/clippy/clippy_lints/src/empty_structs_with_brackets.rs @@ -15,11 +15,11 @@ declare_clippy_lint! { /// Empty brackets after a struct declaration can be omitted. /// /// ### Example - /// ```rust + /// ```no_run /// struct Cookie {} /// ``` /// Use instead: - /// ```rust + /// ```no_run /// struct Cookie; /// ``` #[clippy::version = "1.62.0"] @@ -35,7 +35,8 @@ impl EarlyLintPass for EmptyStructsWithBrackets { if let ItemKind::Struct(var_data, _) = &item.kind && has_brackets(var_data) - && has_no_fields(cx, var_data, span_after_ident) { + && has_no_fields(cx, var_data, span_after_ident) + { span_lint_and_then( cx, EMPTY_STRUCTS_WITH_BRACKETS, @@ -46,8 +47,9 @@ impl EarlyLintPass for EmptyStructsWithBrackets { span_after_ident, "remove the brackets", ";", - Applicability::Unspecified); - }, + Applicability::Unspecified, + ); + }, ); } } diff --git a/src/tools/clippy/clippy_lints/src/entry.rs b/src/tools/clippy/clippy_lints/src/entry.rs index 6197b5b19..3e3c62e85 100644 --- a/src/tools/clippy/clippy_lints/src/entry.rs +++ b/src/tools/clippy/clippy_lints/src/entry.rs @@ -23,7 +23,7 @@ declare_clippy_lint! { /// /// ### Known problems /// The suggestion may have type inference errors in some cases. e.g. - /// ```rust + /// ```no_run /// let mut map = std::collections::HashMap::new(); /// let _ = if !map.contains_key(&0) { /// map.insert(0, 0) @@ -33,7 +33,7 @@ declare_clippy_lint! { /// ``` /// /// ### Example - /// ```rust + /// ```no_run /// # use std::collections::HashMap; /// # let mut map = HashMap::new(); /// # let k = 1; @@ -43,7 +43,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # use std::collections::HashMap; /// # let mut map = HashMap::new(); /// # let k = 1; @@ -241,7 +241,7 @@ fn try_parse_contains<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Optio }, ], _, - ) if key_span.ctxt() == expr.span.ctxt() => { + ) if key_span.eq_ctxt(expr.span) => { let id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?; let expr = ContainsExpr { negated, diff --git a/src/tools/clippy/clippy_lints/src/enum_clike.rs b/src/tools/clippy/clippy_lints/src/enum_clike.rs index 3f60e5a7c..003b5fc72 100644 --- a/src/tools/clippy/clippy_lints/src/enum_clike.rs +++ b/src/tools/clippy/clippy_lints/src/enum_clike.rs @@ -1,7 +1,7 @@ //! lint on C-like enums that are `repr(isize/usize)` and have values that //! don't fit into an `i32` -use clippy_utils::consts::{miri_to_const, Constant}; +use clippy_utils::consts::{mir_to_const, Constant}; use clippy_utils::diagnostics::span_lint; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -19,7 +19,7 @@ declare_clippy_lint! { /// architectures, but works fine on 64 bit. /// /// ### Example - /// ```rust + /// ```no_run /// # #[cfg(target_pointer_width = "64")] /// #[repr(usize)] /// enum NonPortable { @@ -51,7 +51,7 @@ impl<'tcx> LateLintPass<'tcx> for UnportableVariant { .const_eval_poly(def_id.to_def_id()) .ok() .map(|val| rustc_middle::mir::Const::from_value(val, ty)); - if let Some(Constant::Int(val)) = constant.and_then(|c| miri_to_const(cx, c)) { + if let Some(Constant::Int(val)) = constant.and_then(|c| mir_to_const(cx, c)) { if let ty::Adt(adt, _) = ty.kind() { if adt.is_enum() { ty = adt.repr().discr_type().to_ty(cx.tcx); diff --git a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs index c691e6c54..575fead5b 100644 --- a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs +++ b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs @@ -68,7 +68,8 @@ impl<'tcx> LateLintPass<'tcx> for PatternEquality { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if !in_external_macro(cx.sess(), expr.span) && let ExprKind::Let(let_expr) = expr.kind - && unary_pattern(let_expr.pat) { + && unary_pattern(let_expr.pat) + { let exp_ty = cx.typeck_results().expr_ty(let_expr.init); let pat_ty = cx.typeck_results().pat_ty(let_expr.pat); let mut applicability = Applicability::MachineApplicable; @@ -79,7 +80,9 @@ impl<'tcx> LateLintPass<'tcx> for PatternEquality { "({})", snippet_with_context(cx, let_expr.pat.span, expr.span.ctxt(), "..", &mut applicability).0, ), - _ => snippet_with_context(cx, let_expr.pat.span, expr.span.ctxt(), "..", &mut applicability).0.to_string(), + _ => snippet_with_context(cx, let_expr.pat.span, expr.span.ctxt(), "..", &mut applicability) + .0 + .to_string(), }; span_lint_and_sugg( cx, diff --git a/src/tools/clippy/clippy_lints/src/error_impl_error.rs b/src/tools/clippy/clippy_lints/src/error_impl_error.rs index f24577c73..bc878555c 100644 --- a/src/tools/clippy/clippy_lints/src/error_impl_error.rs +++ b/src/tools/clippy/clippy_lints/src/error_impl_error.rs @@ -27,7 +27,7 @@ declare_clippy_lint! { /// /// impl std::error::Error for Error { ... } /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub ERROR_IMPL_ERROR, restriction, "exported types named `Error` that implement `Error`" @@ -41,10 +41,11 @@ impl<'tcx> LateLintPass<'tcx> for ErrorImplError { }; match item.kind { - ItemKind::TyAlias(..) if item.ident.name == sym::Error - && is_visible_outside_module(cx, item.owner_id.def_id) - && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity() - && implements_trait(cx, ty, error_def_id, &[]) => + ItemKind::TyAlias(..) + if item.ident.name == sym::Error + && is_visible_outside_module(cx, item.owner_id.def_id) + && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity() + && implements_trait(cx, ty, error_def_id, &[]) => { span_lint( cx, @@ -53,13 +54,14 @@ impl<'tcx> LateLintPass<'tcx> for ErrorImplError { "exported type alias named `Error` that implements `Error`", ); }, - ItemKind::Impl(imp) if let Some(trait_def_id) = imp.of_trait.and_then(|t| t.trait_def_id()) - && error_def_id == trait_def_id - && let Some(def_id) = path_res(cx, imp.self_ty).opt_def_id().and_then(DefId::as_local) - && let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id) - && let Some(ident) = cx.tcx.opt_item_ident(def_id.to_def_id()) - && ident.name == sym::Error - && is_visible_outside_module(cx, def_id) => + ItemKind::Impl(imp) + if let Some(trait_def_id) = imp.of_trait.and_then(|t| t.trait_def_id()) + && error_def_id == trait_def_id + && let Some(def_id) = path_res(cx, imp.self_ty).opt_def_id().and_then(DefId::as_local) + && let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id) + && let Some(ident) = cx.tcx.opt_item_ident(def_id.to_def_id()) + && ident.name == sym::Error + && is_visible_outside_module(cx, def_id) => { span_lint_hir_and_then( cx, @@ -69,9 +71,9 @@ impl<'tcx> LateLintPass<'tcx> for ErrorImplError { "exported type named `Error` that implements `Error`", |diag| { diag.span_note(item.span, "`Error` was implemented here"); - } + }, ); - } + }, _ => {}, } } diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs index dbe3453e7..3d0ddca19 100644 --- a/src/tools/clippy/clippy_lints/src/escape.rs +++ b/src/tools/clippy/clippy_lints/src/escape.rs @@ -8,7 +8,7 @@ use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, TraitRef, Ty}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::def_id::LocalDefId; -use rustc_span::source_map::Span; +use rustc_span::Span; use rustc_span::symbol::kw; use rustc_target::spec::abi::Abi; @@ -28,12 +28,12 @@ declare_clippy_lint! { /// into something. /// /// ### Example - /// ```rust + /// ```no_run /// fn foo(x: Box<u32>) {} /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// fn foo(x: u32) {} /// ``` #[clippy::version = "pre 1.29.0"] diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs index 38066503c..fad8fbf04 100644 --- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs +++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs @@ -119,19 +119,21 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction { match body.value.kind { ExprKind::Call(callee, args) - if matches!(callee.kind, ExprKind::Path(QPath::Resolved(..) | QPath::TypeRelative(..))) => + if matches!( + callee.kind, + ExprKind::Path(QPath::Resolved(..) | QPath::TypeRelative(..)) + ) => { let callee_ty = typeck.expr_ty(callee).peel_refs(); - if matches!( - type_diagnostic_name(cx, callee_ty), - Some(sym::Arc | sym::Rc) - ) || !check_inputs(typeck, body.params, None, args) { + if matches!(type_diagnostic_name(cx, callee_ty), Some(sym::Arc | sym::Rc)) + || !check_inputs(typeck, body.params, None, args) + { return; } - let callee_ty_adjusted = typeck.expr_adjustments(callee).last().map_or( - callee_ty, - |a| a.target.peel_refs(), - ); + let callee_ty_adjusted = typeck + .expr_adjustments(callee) + .last() + .map_or(callee_ty, |a| a.target.peel_refs()); let sig = match callee_ty_adjusted.kind() { ty::FnDef(def, _) => cx.tcx.fn_sig(def).skip_binder().skip_binder(), @@ -160,36 +162,26 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction { // For now ignore all callee types which reference a type parameter. && !generic_args.types().any(|t| matches!(t.kind(), ty::Param(_))) { - span_lint_and_then( - cx, - REDUNDANT_CLOSURE, - expr.span, - "redundant closure", - |diag| { - if let Some(mut snippet) = snippet_opt(cx, callee.span) { - if let Ok((ClosureKind::FnMut, _)) - = cx.tcx.infer_ctxt().build().type_implements_fn_trait( - cx.param_env, - Binder::bind_with_vars(callee_ty_adjusted, List::empty()), - ImplPolarity::Positive, - ) && path_to_local(callee) - .map_or( - false, - |l| local_used_in(cx, l, args) || local_used_after_expr(cx, l, expr), - ) - { - // Mutable closure is used after current expr; we cannot consume it. - snippet = format!("&mut {snippet}"); - } - diag.span_suggestion( - expr.span, - "replace the closure with the function itself", - snippet, - Applicability::MachineApplicable, - ); + span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure", |diag| { + if let Some(mut snippet) = snippet_opt(cx, callee.span) { + if let Ok((ClosureKind::FnMut, _)) = cx.tcx.infer_ctxt().build().type_implements_fn_trait( + cx.param_env, + Binder::bind_with_vars(callee_ty_adjusted, List::empty()), + ImplPolarity::Positive, + ) && path_to_local(callee).map_or(false, |l| { + local_used_in(cx, l, args) || local_used_after_expr(cx, l, expr) + }) { + // Mutable closure is used after current expr; we cannot consume it. + snippet = format!("&mut {snippet}"); } + diag.span_suggestion( + expr.span, + "replace the closure with the function itself", + snippet, + Applicability::MachineApplicable, + ); } - ); + }); } }, ExprKind::MethodCall(path, self_, args, _) if check_inputs(typeck, body.params, Some(self_), args) => { diff --git a/src/tools/clippy/clippy_lints/src/excessive_bools.rs b/src/tools/clippy/clippy_lints/src/excessive_bools.rs index aef2db385..1d18e194d 100644 --- a/src/tools/clippy/clippy_lints/src/excessive_bools.rs +++ b/src/tools/clippy/clippy_lints/src/excessive_bools.rs @@ -22,7 +22,7 @@ declare_clippy_lint! { /// readability and API. /// /// ### Example - /// ```rust + /// ```no_run /// struct S { /// is_pending: bool, /// is_processing: bool, @@ -31,7 +31,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// enum S { /// Pending, /// Processing, @@ -157,7 +157,7 @@ impl<'tcx> LateLintPass<'tcx> for ExcessiveBools { // functions with a body are already checked by `check_fn` if let TraitItemKind::Fn(fn_sig, TraitFn::Required(_)) = &trait_item.kind && fn_sig.header.abi == Abi::Rust - { + { self.check_fn_sig(cx, fn_sig.decl, fn_sig.span); } } @@ -174,11 +174,8 @@ impl<'tcx> LateLintPass<'tcx> for ExcessiveBools { let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id); if let Some(fn_header) = fn_kind.header() && fn_header.abi == Abi::Rust - && get_parent_as_impl(cx.tcx, hir_id) - .map_or(true, - |impl_item| impl_item.of_trait.is_none() - ) - { + && get_parent_as_impl(cx.tcx, hir_id).map_or(true, |impl_item| impl_item.of_trait.is_none()) + { self.check_fn_sig(cx, fn_decl, span); } } diff --git a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs index 9fd13084d..f976cfd3f 100644 --- a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs +++ b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs @@ -17,14 +17,14 @@ declare_clippy_lint! { /// disable them by default. /// /// ### Example - /// ```rust + /// ```no_run /// enum Foo { /// Bar, /// Baz /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// #[non_exhaustive] /// enum Foo { /// Bar, @@ -47,14 +47,14 @@ declare_clippy_lint! { /// disable them by default. /// /// ### Example - /// ```rust + /// ```no_run /// struct Foo { /// bar: u8, /// baz: String, /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// #[non_exhaustive] /// struct Foo { /// bar: u8, diff --git a/src/tools/clippy/clippy_lints/src/exit.rs b/src/tools/clippy/clippy_lints/src/exit.rs index 8ba6a9e48..e14b1c556 100644 --- a/src/tools/clippy/clippy_lints/src/exit.rs +++ b/src/tools/clippy/clippy_lints/src/exit.rs @@ -1,9 +1,10 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::{is_entrypoint_fn, match_def_path, paths}; +use clippy_utils::is_entrypoint_fn; use if_chain::if_chain; use rustc_hir::{Expr, ExprKind, Item, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -16,7 +17,7 @@ declare_clippy_lint! { /// the main function. /// /// ### Example - /// ``` + /// ```no_run /// std::process::exit(0) /// ``` /// @@ -45,7 +46,7 @@ impl<'tcx> LateLintPass<'tcx> for Exit { if let ExprKind::Call(path_expr, _args) = e.kind; if let ExprKind::Path(ref path) = path_expr.kind; if let Some(def_id) = cx.qpath_res(path, path_expr.hir_id).opt_def_id(); - if match_def_path(cx, def_id, &paths::EXIT); + if cx.tcx.is_diagnostic_item(sym::process_exit, def_id); let parent = cx.tcx.hir().get_parent_item(e.hir_id).def_id; if let Some(Node::Item(Item{kind: ItemKind::Fn(..), ..})) = cx.tcx.hir().find_by_def_id(parent); // If the next item up is a function we check if it is an entry point diff --git a/src/tools/clippy/clippy_lints/src/explicit_write.rs b/src/tools/clippy/clippy_lints/src/explicit_write.rs index b612cc00b..4b5bcb06a 100644 --- a/src/tools/clippy/clippy_lints/src/explicit_write.rs +++ b/src/tools/clippy/clippy_lints/src/explicit_write.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::macros::{find_format_args, format_args_inputs_span}; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{is_expn_of, match_function_call, paths}; +use clippy_utils::{is_expn_of, path_def_id}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def::Res; @@ -19,7 +19,7 @@ declare_clippy_lint! { /// Using `(e)println! is clearer and more concise /// /// ### Example - /// ```rust + /// ```no_run /// # use std::io::Write; /// # let bar = "furchtbar"; /// writeln!(&mut std::io::stderr(), "foo: {:?}", bar).unwrap(); @@ -27,7 +27,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # use std::io::Write; /// # let bar = "furchtbar"; /// eprintln!("foo: {:?}", bar); @@ -47,18 +47,21 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { if let ExprKind::MethodCall(unwrap_fun, write_call, [], _) = expr.kind && unwrap_fun.ident.name == sym::unwrap // match call to write_fmt - && let ExprKind::MethodCall(write_fun, write_recv, [write_arg], _) = look_in_block(cx, &write_call.kind) + && let ExprKind::MethodCall(write_fun, write_recv, [write_arg], _) = *look_in_block(cx, &write_call.kind) + && let ExprKind::Call(write_recv_path, _) = write_recv.kind && write_fun.ident.name == sym!(write_fmt) - // match calls to std::io::stdout() / std::io::stderr () - && let Some(dest_name) = if match_function_call(cx, write_recv, &paths::STDOUT).is_some() { - Some("stdout") - } else if match_function_call(cx, write_recv, &paths::STDERR).is_some() { - Some("stderr") - } else { - None - } - && let Some(format_args) = find_format_args(cx, write_arg, ExpnId::root()) + && let Some(def_id) = path_def_id(cx, write_recv_path) { + // match calls to std::io::stdout() / std::io::stderr () + let (dest_name, prefix) = match cx.tcx.get_diagnostic_name(def_id) { + Some(sym::io_stdout) => ("stdout", ""), + Some(sym::io_stderr) => ("stderr", "e"), + _ => return, + }; + let Some(format_args) = find_format_args(cx, write_arg, ExpnId::root()) else { + return; + }; + // ordering is important here, since `writeln!` uses `write!` internally let calling_macro = if is_expn_of(write_call.span, "writeln").is_some() { Some("writeln") @@ -67,11 +70,6 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { } else { None }; - let prefix = if dest_name == "stderr" { - "e" - } else { - "" - }; // We need to remove the last trailing newline from the string because the // underlying `fmt::write` function doesn't know whether `println!` or `print!` was @@ -82,18 +80,11 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { macro_name.replace("write", "print"), ) } else { - ( - format!("{dest_name}().write_fmt(...)"), - "print".into(), - ) + (format!("{dest_name}().write_fmt(...)"), "print".into()) }; let mut applicability = Applicability::MachineApplicable; - let inputs_snippet = snippet_with_applicability( - cx, - format_args_inputs_span(&format_args), - "..", - &mut applicability, - ); + let inputs_snippet = + snippet_with_applicability(cx, format_args_inputs_span(&format_args), "..", &mut applicability); span_lint_and_sugg( cx, EXPLICIT_WRITE, diff --git a/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs b/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs index 0a885984a..d6c746901 100644 --- a/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs +++ b/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs @@ -23,13 +23,13 @@ declare_clippy_lint! { /// requires using a turbofish, which serves no purpose but to satisfy the compiler. /// /// ### Example - /// ```rust + /// ```no_run /// fn unused_ty<T>(x: u8) { /// // .. /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn no_unused_ty(x: u8) { /// // .. /// } @@ -177,20 +177,22 @@ impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> { .iter() .rev() .map(|(idx, param)| { - if let Some(next) = explicit_params.get(idx + 1) && end != Some(next.def_id) { - // Extend the current span forward, up until the next param in the list. - param.span.until(next.span) - } else { - // Extend the current span back to include the comma following the previous - // param. If the span of the next param in the list has already been - // extended, we continue the chain. This is why we're iterating in reverse. - end = Some(param.def_id); + if let Some(next) = explicit_params.get(idx + 1) + && end != Some(next.def_id) + { + // Extend the current span forward, up until the next param in the list. + param.span.until(next.span) + } else { + // Extend the current span back to include the comma following the previous + // param. If the span of the next param in the list has already been + // extended, we continue the chain. This is why we're iterating in reverse. + end = Some(param.def_id); - // idx will never be 0, else we'd be removing the entire list of generics - let prev = explicit_params[idx - 1]; - let prev_span = self.get_bound_span(prev); - self.get_bound_span(param).with_lo(prev_span.hi()) - } + // idx will never be 0, else we'd be removing the entire list of generics + let prev = explicit_params[idx - 1]; + let prev_span = self.get_bound_span(prev); + self.get_bound_span(param).with_lo(prev_span.hi()) + } }) .collect() }; diff --git a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs index 2ef547526..efb69476b 100644 --- a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs +++ b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs @@ -17,7 +17,7 @@ declare_clippy_lint! { /// `TryFrom` should be used if there's a possibility of failure. /// /// ### Example - /// ```rust + /// ```no_run /// struct Foo(i32); /// /// impl From<String> for Foo { @@ -28,7 +28,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// struct Foo(i32); /// /// impl TryFrom<String> for Foo { diff --git a/src/tools/clippy/clippy_lints/src/float_literal.rs b/src/tools/clippy/clippy_lints/src/float_literal.rs index d182bb621..506a11917 100644 --- a/src/tools/clippy/clippy_lints/src/float_literal.rs +++ b/src/tools/clippy/clippy_lints/src/float_literal.rs @@ -18,13 +18,13 @@ declare_clippy_lint! { /// Rust will truncate the literal silently. /// /// ### Example - /// ```rust + /// ```no_run /// let v: f32 = 0.123_456_789_9; /// println!("{}", v); // 0.123_456_789 /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let v: f64 = 0.123_456_789_9; /// println!("{}", v); // 0.123_456_789_9 /// ``` @@ -44,12 +44,12 @@ declare_clippy_lint! { /// conversion to a float. /// /// ### Example - /// ```rust + /// ```no_run /// let _: f32 = 16_777_217.0; // 16_777_216.0 /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let _: f32 = 16_777_216.0; /// let _: f64 = 16_777_217.0; /// ``` diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs index 29e5315f8..09a9d9924 100644 --- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs @@ -27,7 +27,7 @@ declare_clippy_lint! { /// Negatively impacts accuracy. /// /// ### Example - /// ```rust + /// ```no_run /// let a = 3f32; /// let _ = a.powf(1.0 / 3.0); /// let _ = (1.0 + a).ln(); @@ -35,7 +35,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let a = 3f32; /// let _ = a.cbrt(); /// let _ = a.ln_1p(); @@ -57,7 +57,7 @@ declare_clippy_lint! { /// Negatively impacts accuracy and performance. /// /// ### Example - /// ```rust + /// ```no_run /// use std::f32::consts::E; /// /// let a = 3f32; @@ -83,7 +83,7 @@ declare_clippy_lint! { /// /// is better expressed as /// - /// ```rust + /// ```no_run /// use std::f32::consts::E; /// /// let a = 3f32; @@ -323,9 +323,9 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: let maybe_neg_sugg = |expr, hir_id| { let sugg = Sugg::hir(cx, expr, ".."); if matches!(op, BinOpKind::Sub) && hir_id == rhs.hir_id { - format!("-{}", sugg.maybe_par()) + -sugg } else { - sugg.to_string() + sugg } }; @@ -470,25 +470,13 @@ fn check_mul_add(cx: &LateContext<'_>, expr: &Expr<'_>) { let maybe_neg_sugg = |expr| { let sugg = Sugg::hir(cx, expr, ".."); - if let BinOpKind::Sub = op { - format!("-{sugg}") - } else { - sugg.to_string() - } + if let BinOpKind::Sub = op { -sugg } else { sugg } }; let (recv, arg1, arg2) = if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, lhs) { - ( - inner_lhs, - Sugg::hir(cx, inner_rhs, "..").to_string(), - maybe_neg_sugg(rhs), - ) + (inner_lhs, Sugg::hir(cx, inner_rhs, ".."), maybe_neg_sugg(rhs)) } else if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, rhs) { - ( - inner_lhs, - maybe_neg_sugg(inner_rhs), - Sugg::hir(cx, lhs, "..").to_string(), - ) + (inner_lhs, maybe_neg_sugg(inner_rhs), Sugg::hir(cx, lhs, "..")) } else { return; }; diff --git a/src/tools/clippy/clippy_lints/src/format.rs b/src/tools/clippy/clippy_lints/src/format.rs index b748d3293..18ed05c1c 100644 --- a/src/tools/clippy/clippy_lints/src/format.rs +++ b/src/tools/clippy/clippy_lints/src/format.rs @@ -23,13 +23,13 @@ declare_clippy_lint! { /// if `foo: &str`. /// /// ### Examples - /// ```rust + /// ```no_run /// let foo = "foo"; /// format!("{}", foo); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let foo = "foo"; /// foo.to_owned(); /// ``` @@ -54,7 +54,9 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat { ([], []) => span_useless_format_empty(cx, call_site, "String::new()".to_owned(), applicability), ([], [_]) => { // Simulate macro expansion, converting {{ and }} to { and }. - let Some(snippet) = snippet_opt(cx, format_args.span) else { return }; + let Some(snippet) = snippet_opt(cx, format_args.span) else { + return; + }; let s_expand = snippet.replace("{{", "{").replace("}}", "}"); let sugg = format!("{s_expand}.to_string()"); span_useless_format(cx, call_site, sugg, applicability); @@ -76,13 +78,14 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat { _ => false, }; let sugg = if is_new_string { - snippet_with_context(cx, value.span, call_site.ctxt(), "..", &mut applicability).0.into_owned() + snippet_with_context(cx, value.span, call_site.ctxt(), "..", &mut applicability) + .0 + .into_owned() } else { let sugg = Sugg::hir_with_context(cx, value, call_site.ctxt(), "<arg>", &mut applicability); format!("{}.to_string()", sugg.maybe_par()) }; span_useless_format(cx, call_site, sugg, applicability); - } }, _ => {}, diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs index 39abf5c2d..3c1f2d9d5 100644 --- a/src/tools/clippy/clippy_lints/src/format_args.rs +++ b/src/tools/clippy/clippy_lints/src/format_args.rs @@ -1,11 +1,11 @@ use arrayvec::ArrayVec; +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::{ find_format_arg_expr, find_format_args, format_arg_removal_span, format_placeholder_format_span, is_assert_macro, is_format_macro, is_panic, root_macro_call, root_macro_call_first_node, FormatParamUsage, }; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_opt; use clippy_utils::ty::{implements_trait, is_type_lang_item}; use if_chain::if_chain; @@ -35,12 +35,12 @@ declare_clippy_lint! { /// The recommended code is both shorter and avoids a temporary allocation. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::panic::Location; /// println!("error: {}", format!("something failed at {}", Location::caller())); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # use std::panic::Location; /// println!("error: something failed at {}", Location::caller()); /// ``` @@ -61,12 +61,12 @@ declare_clippy_lint! { /// unnecessary. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::panic::Location; /// println!("error: something failed at {}", Location::caller().to_string()); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # use std::panic::Location; /// println!("error: something failed at {}", Location::caller()); /// ``` @@ -87,7 +87,7 @@ declare_clippy_lint! { /// The inlined syntax, where allowed, is simpler. /// /// ### Example - /// ```rust + /// ```no_run /// # let var = 42; /// # let width = 1; /// # let prec = 2; @@ -98,7 +98,7 @@ declare_clippy_lint! { /// format!("{:.*}", prec, var); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # let var = 42; /// # let width = 1; /// # let prec = 2; @@ -111,12 +111,12 @@ declare_clippy_lint! { /// /// If allow-mixed-uninlined-format-args is set to false in clippy.toml, /// the following code will also trigger the lint: - /// ```rust + /// ```no_run /// # let var = 42; /// format!("{} {}", var, 1+2); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # let var = 42; /// format!("{var} {}", 1+2); /// ``` @@ -141,13 +141,13 @@ declare_clippy_lint! { /// an expected formatting operation such as adding padding isn't happening. /// /// ### Example - /// ```rust + /// ```no_run /// println!("{:.}", 1.0); /// /// println!("not padded: {:5}", format_args!("...")); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// println!("{}", 1.0); /// /// println!("not padded: {}", format_args!("...")); @@ -370,7 +370,7 @@ fn check_one_arg( }; fixes.push((pos_span, replacement)); fixes.push((arg_span, String::new())); - true // successful inlining, continue checking + true // successful inlining, continue checking } else { // Do not continue inlining (return false) in case // * if we can't inline a numbered argument, e.g. `print!("{0} ...", foo.bar, ...)` diff --git a/src/tools/clippy/clippy_lints/src/format_impl.rs b/src/tools/clippy/clippy_lints/src/format_impl.rs index 1d2f7cb71..08ee7032c 100644 --- a/src/tools/clippy/clippy_lints/src/format_impl.rs +++ b/src/tools/clippy/clippy_lints/src/format_impl.rs @@ -21,7 +21,7 @@ declare_clippy_lint! { /// /// ### Example /// - /// ```rust + /// ```no_run /// use std::fmt; /// /// struct Structure(i32); @@ -33,7 +33,7 @@ declare_clippy_lint! { /// /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::fmt; /// /// struct Structure(i32); @@ -59,7 +59,7 @@ declare_clippy_lint! { /// should write to the `Formatter`, not stdout/stderr. /// /// ### Example - /// ```rust + /// ```no_run /// use std::fmt::{Display, Error, Formatter}; /// /// struct S; @@ -72,7 +72,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::fmt::{Display, Error, Formatter}; /// /// struct S; diff --git a/src/tools/clippy/clippy_lints/src/format_push_string.rs b/src/tools/clippy/clippy_lints/src/format_push_string.rs index 45f67020c..ac45f5aed 100644 --- a/src/tools/clippy/clippy_lints/src/format_push_string.rs +++ b/src/tools/clippy/clippy_lints/src/format_push_string.rs @@ -21,13 +21,13 @@ declare_clippy_lint! { /// While using `write!` in the suggested way should never fail, this isn't necessarily clear to the programmer. /// /// ### Example - /// ```rust + /// ```no_run /// let mut s = String::new(); /// s += &format!("0x{:X}", 1024); /// s.push_str(&format!("0x{:X}", 1024)); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::fmt::Write as _; // import without risk of name clashing /// /// let mut s = String::new(); @@ -58,7 +58,7 @@ fn is_format(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { arms.iter().any(|arm| is_format(cx, arm.body)) }, Some(higher::IfLetOrMatch::IfLet(_, _, then, r#else)) => { - is_format(cx, then) ||r#else.is_some_and(|e| is_format(cx, e)) + is_format(cx, then) || r#else.is_some_and(|e| is_format(cx, e)) }, _ => false, } @@ -69,17 +69,15 @@ impl<'tcx> LateLintPass<'tcx> for FormatPushString { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { let arg = match expr.kind { ExprKind::MethodCall(_, _, [arg], _) => { - if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) && - match_def_path(cx, fn_def_id, &paths::PUSH_STR) { + if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) + && match_def_path(cx, fn_def_id, &paths::PUSH_STR) + { arg } else { return; } - } - ExprKind::AssignOp(op, left, arg) - if op.node == BinOpKind::Add && is_string(cx, left) => { - arg }, + ExprKind::AssignOp(op, left, arg) if op.node == BinOpKind::Add && is_string(cx, left) => arg, _ => return, }; if is_format(cx, arg) { diff --git a/src/tools/clippy/clippy_lints/src/formatting.rs b/src/tools/clippy/clippy_lints/src/formatting.rs index d03480c21..2c9c43d3e 100644 --- a/src/tools/clippy/clippy_lints/src/formatting.rs +++ b/src/tools/clippy/clippy_lints/src/formatting.rs @@ -6,7 +6,7 @@ use rustc_ast::ast::{BinOpKind, Block, Expr, ExprKind, StmtKind, UnOp}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::Span; +use rustc_span::Span; declare_clippy_lint! { /// ### What it does @@ -37,7 +37,7 @@ declare_clippy_lint! { /// This is either a typo in the binary operator or confusing. /// /// ### Example - /// ```rust + /// ```no_run /// # let foo = true; /// # let bar = false; /// // &&! looks like a different operator @@ -45,7 +45,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let foo = true; /// # let bar = false; /// if foo && !bar {} @@ -274,7 +274,7 @@ fn check_array(cx: &EarlyContext<'_>, expr: &Expr) { for element in array { if_chain! { if let ExprKind::Binary(ref op, ref lhs, _) = element.kind; - if has_unary_equivalent(op.node) && lhs.span.ctxt() == op.span.ctxt(); + if has_unary_equivalent(op.node) && lhs.span.eq_ctxt(op.span); let space_span = lhs.span.between(op.span); if let Some(space_snippet) = snippet_opt(cx, space_span); let lint_span = lhs.span.with_lo(lhs.span.hi()); diff --git a/src/tools/clippy/clippy_lints/src/four_forward_slashes.rs b/src/tools/clippy/clippy_lints/src/four_forward_slashes.rs index 419c77343..69bc0b726 100644 --- a/src/tools/clippy/clippy_lints/src/four_forward_slashes.rs +++ b/src/tools/clippy/clippy_lints/src/four_forward_slashes.rs @@ -14,7 +14,7 @@ declare_clippy_lint! { /// comment. /// /// ### Example - /// ```rust + /// ```no_run /// //// My amazing data structure /// pub struct Foo { /// // ... @@ -22,13 +22,13 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// /// My amazing data structure /// pub struct Foo { /// // ... /// } /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub FOUR_FORWARD_SLASHES, suspicious, "comments with 4 forward slashes (`////`) likely intended to be doc comments (`///`)" diff --git a/src/tools/clippy/clippy_lints/src/from_over_into.rs b/src/tools/clippy/clippy_lints/src/from_over_into.rs index 2b899e21e..5477532bb 100644 --- a/src/tools/clippy/clippy_lints/src/from_over_into.rs +++ b/src/tools/clippy/clippy_lints/src/from_over_into.rs @@ -1,6 +1,6 @@ +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::snippet_opt; use rustc_errors::Applicability; @@ -24,7 +24,7 @@ declare_clippy_lint! { /// According the std docs implementing `From<..>` is preferred since it gives you `Into<..>` for free where the reverse isn't true. /// /// ### Example - /// ```rust + /// ```no_run /// struct StringWrapper(String); /// /// impl Into<StringWrapper> for String { @@ -34,7 +34,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// struct StringWrapper(String); /// /// impl From<String> for StringWrapper { @@ -88,7 +88,8 @@ impl<'tcx> LateLintPass<'tcx> for FromOverInto { cx.tcx.sess.source_map().guess_head_span(item.span), "an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true", |diag| { - // If the target type is likely foreign mention the orphan rules as it's a common source of confusion + // 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()) { diag.help( "`impl From<Local> for Foreign` is allowed by the orphan rules, for more information see\n\ @@ -96,7 +97,10 @@ impl<'tcx> LateLintPass<'tcx> for FromOverInto { ); } - let message = format!("replace the `Into` implementation with `From<{}>`", middle_trait_ref.self_ty()); + let message = format!( + "replace the `Into` implementation with `From<{}>`", + middle_trait_ref.self_ty() + ); if let Some(suggestions) = convert_to_from(cx, into_trait_seg, target_ty, self_ty, impl_item_ref) { diag.multipart_suggestion(message, suggestions, Applicability::MachineApplicable); } else { @@ -110,12 +114,12 @@ impl<'tcx> LateLintPass<'tcx> for FromOverInto { extract_msrv_attr!(LateContext); } -/// Finds the occurences of `Self` and `self` +/// Finds the occurrences of `Self` and `self` struct SelfFinder<'a, 'tcx> { cx: &'a LateContext<'tcx>, - /// Occurences of `Self` + /// Occurrences of `Self` upper: Vec<Span>, - /// Occurences of `self` + /// Occurrences of `self` lower: Vec<Span>, /// If any of the `self`/`Self` usages were from an expansion, or the body contained a binding /// already named `val` diff --git a/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs b/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs index 5e859d97c..d9138d48b 100644 --- a/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs +++ b/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::path_def_id; use clippy_utils::ty::is_c_void; -use clippy_utils::{match_def_path, path_def_id, paths}; use rustc_hir::def_id::DefId; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; @@ -18,13 +18,13 @@ declare_clippy_lint! { /// For this to be safe, `c_void` would need to have the same memory layout as the original type, which is often not the case. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::ffi::c_void; /// let ptr = Box::into_raw(Box::new(42usize)) as *mut c_void; /// let _ = unsafe { Box::from_raw(ptr) }; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # use std::ffi::c_void; /// # let ptr = Box::into_raw(Box::new(42usize)) as *mut c_void; /// let _ = unsafe { Box::from_raw(ptr as *mut usize) }; @@ -40,14 +40,22 @@ declare_lint_pass!(FromRawWithVoidPtr => [FROM_RAW_WITH_VOID_PTR]); impl LateLintPass<'_> for FromRawWithVoidPtr { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { if let ExprKind::Call(box_from_raw, [arg]) = expr.kind - && let ExprKind::Path(QPath::TypeRelative(ty, seg)) = box_from_raw.kind - && seg.ident.name == sym!(from_raw) - && let Some(type_str) = path_def_id(cx, ty).and_then(|id| def_id_matches_type(cx, id)) - && let arg_kind = cx.typeck_results().expr_ty(arg).kind() - && let RawPtr(TypeAndMut { ty, .. }) = arg_kind - && is_c_void(cx, *ty) { + && let ExprKind::Path(QPath::TypeRelative(ty, seg)) = box_from_raw.kind + && seg.ident.name == sym!(from_raw) + && let Some(type_str) = path_def_id(cx, ty).and_then(|id| def_id_matches_type(cx, id)) + && let arg_kind = cx.typeck_results().expr_ty(arg).kind() + && let RawPtr(TypeAndMut { ty, .. }) = arg_kind + && is_c_void(cx, *ty) + { let msg = format!("creating a `{type_str}` from a void raw pointer"); - span_lint_and_help(cx, FROM_RAW_WITH_VOID_PTR, expr.span, &msg, Some(arg.span), "cast this to a pointer of the appropriate type"); + span_lint_and_help( + cx, + FROM_RAW_WITH_VOID_PTR, + expr.span, + &msg, + Some(arg.span), + "cast this to a pointer of the appropriate type", + ); } } } @@ -68,7 +76,7 @@ fn def_id_matches_type(cx: &LateContext<'_>, def_id: DefId) -> Option<&'static s } } - if match_def_path(cx, def_id, &paths::WEAK_RC) || match_def_path(cx, def_id, &paths::WEAK_ARC) { + if matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::RcWeak | sym::ArcWeak)) { Some("Weak") } else { None diff --git a/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs b/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs index 597fca888..ee66c841e 100644 --- a/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs +++ b/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs @@ -1,50 +1,104 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_in_test_function; +use rustc_hir as hir; use rustc_hir::intravisit::FnKind; -use rustc_hir::{Body, HirId}; +use rustc_hir::{Body, GenericParam, Generics, HirId, ImplItem, ImplItemKind, TraitItem, TraitItemKind}; use rustc_lint::LateContext; -use rustc_span::Span; +use rustc_span::symbol::Ident; +use rustc_span::{BytePos, Span}; use super::IMPL_TRAIT_IN_PARAMS; +fn report( + cx: &LateContext<'_>, + param: &GenericParam<'_>, + ident: &Ident, + generics: &Generics<'_>, + first_param_span: Span, +) { + // No generics with nested generics, and no generics like FnMut(x) + span_lint_and_then( + cx, + IMPL_TRAIT_IN_PARAMS, + param.span, + "`impl Trait` used as a function parameter", + |diag| { + if let Some(gen_span) = generics.span_for_param_suggestion() { + // If there's already a generic param with the same bound, do not lint **this** suggestion. + diag.span_suggestion_with_style( + gen_span, + "add a type parameter", + format!(", {{ /* Generic name */ }}: {}", ¶m.name.ident().as_str()[5..]), + rustc_errors::Applicability::HasPlaceholders, + rustc_errors::SuggestionStyle::ShowAlways, + ); + } else { + diag.span_suggestion_with_style( + Span::new( + first_param_span.lo() - rustc_span::BytePos(1), + ident.span.hi(), + ident.span.ctxt(), + ident.span.parent(), + ), + "add a type parameter", + format!("<{{ /* Generic name */ }}: {}>", ¶m.name.ident().as_str()[5..]), + rustc_errors::Applicability::HasPlaceholders, + rustc_errors::SuggestionStyle::ShowAlways, + ); + } + }, + ); +} + pub(super) fn check_fn<'tcx>(cx: &LateContext<'_>, kind: &'tcx FnKind<'_>, body: &'tcx Body<'_>, hir_id: HirId) { - if cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public() && !is_in_test_function(cx.tcx, hir_id) - { - if let FnKind::ItemFn(ident, generics, _) = kind { + if_chain! { + if let FnKind::ItemFn(ident, generics, _) = kind; + if cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public(); + if !is_in_test_function(cx.tcx, hir_id); + then { for param in generics.params { if param.is_impl_trait() { - // No generics with nested generics, and no generics like FnMut(x) - span_lint_and_then( - cx, - IMPL_TRAIT_IN_PARAMS, - param.span, - "'`impl Trait` used as a function parameter'", - |diag| { - if let Some(gen_span) = generics.span_for_param_suggestion() { - diag.span_suggestion_with_style( - gen_span, - "add a type parameter", - format!(", {{ /* Generic name */ }}: {}", ¶m.name.ident().as_str()[5..]), - rustc_errors::Applicability::HasPlaceholders, - rustc_errors::SuggestionStyle::ShowAlways, - ); - } else { - diag.span_suggestion_with_style( - Span::new( - body.params[0].span.lo() - rustc_span::BytePos(1), - ident.span.hi(), - ident.span.ctxt(), - ident.span.parent(), - ), - "add a type parameter", - format!("<{{ /* Generic name */ }}: {}>", ¶m.name.ident().as_str()[5..]), - rustc_errors::Applicability::HasPlaceholders, - rustc_errors::SuggestionStyle::ShowAlways, - ); - } - }, - ); + report(cx, param, ident, generics, body.params[0].span); + }; + } + } + } +} + +pub(super) fn check_impl_item(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) { + if_chain! { + if let ImplItemKind::Fn(_, body_id) = impl_item.kind; + if let hir::Node::Item(item) = cx.tcx.hir().get_parent(impl_item.hir_id()); + if let hir::ItemKind::Impl(impl_) = item.kind; + if let hir::Impl { of_trait, .. } = *impl_; + if of_trait.is_none(); + let body = cx.tcx.hir().body(body_id); + if cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public(); + if !is_in_test_function(cx.tcx, impl_item.hir_id()); + then { + for param in impl_item.generics.params { + if param.is_impl_trait() { + report(cx, param, &impl_item.ident, impl_item.generics, body.params[0].span); + } + } + } + } +} + +pub(super) fn check_trait_item(cx: &LateContext<'_>, trait_item: &TraitItem<'_>, avoid_breaking_exported_api: bool) { + if_chain! { + if !avoid_breaking_exported_api; + if let TraitItemKind::Fn(_, _) = trait_item.kind; + if let hir::Node::Item(item) = cx.tcx.hir().get_parent(trait_item.hir_id()); + // ^^ (Will always be a trait) + if !item.vis_span.is_empty(); // Is public + if !is_in_test_function(cx.tcx, trait_item.hir_id()); + then { + for param in trait_item.generics.params { + if param.is_impl_trait() { + let sp = trait_item.ident.span.with_hi(trait_item.ident.span.hi() + BytePos(1)); + report(cx, param, &trait_item.ident, trait_item.generics, sp.shrink_to_hi()); } } } diff --git a/src/tools/clippy/clippy_lints/src/functions/mod.rs b/src/tools/clippy/clippy_lints/src/functions/mod.rs index ee10334c6..3f5cceec7 100644 --- a/src/tools/clippy/clippy_lints/src/functions/mod.rs +++ b/src/tools/clippy/clippy_lints/src/functions/mod.rs @@ -23,7 +23,7 @@ declare_clippy_lint! { /// grouping some parameters into a new type. /// /// ### Example - /// ```rust + /// ```no_run /// # struct Color; /// fn foo(x: u32, y: u32, name: &str, c: Color, w: f32, h: f32, a: f32, b: f32) { /// // .. @@ -46,7 +46,7 @@ declare_clippy_lint! { /// multiple functions. /// /// ### Example - /// ```rust + /// ```no_run /// fn im_too_long() { /// println!(""); /// // ... 100 more LoC @@ -129,7 +129,7 @@ declare_clippy_lint! { /// a remnant of a refactoring that removed the return type. /// /// ### Examples - /// ```rust + /// ```no_run /// #[must_use] /// fn useless() { } /// ``` @@ -151,7 +151,7 @@ declare_clippy_lint! { /// attribute to improve the lint message. /// /// ### Examples - /// ```rust + /// ```no_run /// #[must_use] /// fn double_must_use() -> Result<(), ()> { /// unimplemented!(); @@ -183,7 +183,7 @@ declare_clippy_lint! { /// `#[must_use]`. /// /// ### Examples - /// ```rust + /// ```no_run /// // this could be annotated with `#[must_use]`. /// pub fn id<T>(t: T) -> T { t } /// ``` @@ -211,7 +211,7 @@ declare_clippy_lint! { /// instead. /// /// ### Examples - /// ```rust + /// ```no_run /// pub fn read_u8() -> Result<u8, ()> { Err(()) } /// ``` /// should become @@ -262,7 +262,7 @@ declare_clippy_lint! { /// The size determined by Clippy is platform-dependent. /// /// ### Examples - /// ```rust + /// ```no_run /// pub enum ParseError { /// UnparsedBytes([u8; 512]), /// UnexpectedEof, @@ -274,7 +274,7 @@ declare_clippy_lint! { /// } /// ``` /// should be - /// ``` + /// ```no_run /// pub enum ParseError { /// UnparsedBytes(Box<[u8; 512]>), /// UnexpectedEof, @@ -301,7 +301,7 @@ declare_clippy_lint! { /// /// ### Example - /// ```rust + /// ```no_run /// struct A { /// a: String, /// b: String, @@ -315,7 +315,7 @@ declare_clippy_lint! { /// ``` /// Use instead: - /// ```rust + /// ```no_run /// struct A { /// a: String, /// b: String, @@ -340,14 +340,14 @@ declare_clippy_lint! { /// Turbofish syntax (`::<>`) cannot be used when `impl Trait` is being used, making `impl Trait` less powerful. Readability may also be a factor. /// /// ### Example - /// ```rust + /// ```no_run /// trait MyTrait {} /// fn foo(a: impl MyTrait) { /// // [...] /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// trait MyTrait {} /// fn foo<T: MyTrait>(a: T) { /// // [...] @@ -360,18 +360,26 @@ declare_clippy_lint! { } #[derive(Copy, Clone)] +#[allow(clippy::struct_field_names)] pub struct Functions { too_many_arguments_threshold: u64, too_many_lines_threshold: u64, large_error_threshold: u64, + avoid_breaking_exported_api: bool, } impl Functions { - pub fn new(too_many_arguments_threshold: u64, too_many_lines_threshold: u64, large_error_threshold: u64) -> Self { + pub fn new( + too_many_arguments_threshold: u64, + too_many_lines_threshold: u64, + large_error_threshold: u64, + avoid_breaking_exported_api: bool, + ) -> Self { Self { too_many_arguments_threshold, too_many_lines_threshold, large_error_threshold, + avoid_breaking_exported_api, } } } @@ -415,6 +423,7 @@ impl<'tcx> LateLintPass<'tcx> for Functions { fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) { must_use::check_impl_item(cx, item); result::check_impl_item(cx, item, self.large_error_threshold); + impl_trait_in_params::check_impl_item(cx, item); } fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) { @@ -422,5 +431,6 @@ impl<'tcx> LateLintPass<'tcx> for Functions { not_unsafe_ptr_arg_deref::check_trait_item(cx, item); must_use::check_trait_item(cx, item); result::check_trait_item(cx, item, self.large_error_threshold); + impl_trait_in_params::check_trait_item(cx, item, self.avoid_breaking_exported_api); } } diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs index 57df5683c..3aaf63ce3 100644 --- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs +++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs @@ -118,9 +118,10 @@ fn check_needless_must_use( if sig.header.is_async() { let infcx = cx.tcx.infer_ctxt().build(); if let Some(future_ty) = infcx.get_impl_future_output_ty(return_ty(cx, item_id)) - && !is_must_use_ty(cx, future_ty) { - return; - } + && !is_must_use_ty(cx, future_ty) + { + return; + } } span_lint_and_help( diff --git a/src/tools/clippy/clippy_lints/src/functions/result.rs b/src/tools/clippy/clippy_lints/src/functions/result.rs index 90fc0d4f6..485235514 100644 --- a/src/tools/clippy/clippy_lints/src/functions/result.rs +++ b/src/tools/clippy/clippy_lints/src/functions/result.rs @@ -21,7 +21,9 @@ fn result_err_ty<'tcx>( ) -> Option<(&'tcx hir::Ty<'tcx>, Ty<'tcx>)> { if !in_external_macro(cx.sess(), item_span) && let hir::FnRetTy::Return(hir_ty) = decl.output - && let ty = cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).instantiate_identity().output()) + && let ty = cx + .tcx + .erase_late_bound_regions(cx.tcx.fn_sig(id).instantiate_identity().output()) && is_type_diagnostic_item(cx, ty, sym::Result) && let ty::Adt(_, args) = ty.kind() { diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs index 621415c88..eee5b7540 100644 --- a/src/tools/clippy/clippy_lints/src/future_not_send.rs +++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs @@ -34,11 +34,11 @@ declare_clippy_lint! { /// produced. /// /// ### Example - /// ```rust + /// ```no_run /// async fn not_send(bytes: std::rc::Rc<[u8]>) {} /// ``` /// Use instead: - /// ```rust + /// ```no_run /// async fn is_send(bytes: std::sync::Arc<[u8]>) {} /// ``` #[clippy::version = "1.44.0"] diff --git a/src/tools/clippy/clippy_lints/src/if_not_else.rs b/src/tools/clippy/clippy_lints/src/if_not_else.rs index 3d59b7833..cae561f78 100644 --- a/src/tools/clippy/clippy_lints/src/if_not_else.rs +++ b/src/tools/clippy/clippy_lints/src/if_not_else.rs @@ -1,6 +1,7 @@ //! lint on if branches that could be swapped so no `!` operation is necessary //! on the condition +use clippy_utils::consts::{constant_simple, Constant}; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::is_else_clause; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; @@ -16,7 +17,7 @@ declare_clippy_lint! { /// Negations reduce the readability of statements. /// /// ### Example - /// ```rust + /// ```no_run /// # let v: Vec<usize> = vec![]; /// # fn a() {} /// # fn b() {} @@ -29,7 +30,7 @@ declare_clippy_lint! { /// /// Could be written: /// - /// ```rust + /// ```no_run /// # let v: Vec<usize> = vec![]; /// # fn a() {} /// # fn b() {} @@ -47,6 +48,13 @@ declare_clippy_lint! { declare_lint_pass!(IfNotElse => [IF_NOT_ELSE]); +fn is_zero_const(expr: &Expr<'_>, cx: &LateContext<'_>) -> bool { + if let Some(value) = constant_simple(cx, cx.typeck_results(), expr) { + return Constant::Int(0) == value; + } + false +} + impl LateLintPass<'_> for IfNotElse { fn check_expr(&mut self, cx: &LateContext<'_>, item: &Expr<'_>) { // While loops will be desugared to ExprKind::If. This will cause the lint to fire. @@ -72,7 +80,9 @@ impl LateLintPass<'_> for IfNotElse { "remove the `!` and swap the blocks of the `if`/`else`", ); }, - ExprKind::Binary(ref kind, _, _) if kind.node == BinOpKind::Ne => { + ExprKind::Binary(ref kind, _, lhs) if kind.node == BinOpKind::Ne && !is_zero_const(lhs, cx) => { + // Disable firing the lint on `… != 0`, as these are likely to be bit tests. + // For example, `if foo & 0x0F00 != 0 { … } else { … }` already is in the "proper" order. span_lint_and_help( cx, IF_NOT_ELSE, diff --git a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs index e2d19e245..66c10ab22 100644 --- a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs +++ b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs @@ -1,6 +1,6 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_help; 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::{contains_return, higher, is_else_clause, is_res_lang_ctor, path_res, peel_blocks}; @@ -21,7 +21,7 @@ declare_clippy_lint! { /// in comparison to `bool::then`. /// /// ### Example - /// ```rust + /// ```no_run /// # let v = vec![0]; /// let a = if v.is_empty() { /// println!("true!"); @@ -33,7 +33,7 @@ declare_clippy_lint! { /// /// Could be written: /// - /// ```rust + /// ```no_run /// # let v = vec![0]; /// let a = v.is_empty().then(|| { /// println!("true!"); @@ -76,7 +76,11 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { let ctxt = expr.span.ctxt(); - if let Some(higher::If { cond, then, r#else: Some(els) }) = higher::If::hir(expr) + if let Some(higher::If { + cond, + then, + r#else: Some(els), + }) = higher::If::hir(expr) && let ExprKind::Block(then_block, _) = then.kind && let Some(then_expr) = then_block.expr && let ExprKind::Call(then_call, [then_arg]) = then_expr.kind @@ -86,7 +90,9 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { && !contains_return(then_block.stmts) { let mut app = Applicability::Unspecified; - let cond_snip = Sugg::hir_with_context(cx, cond, expr.span.ctxt(), "[condition]", &mut app).maybe_par().to_string(); + let cond_snip = Sugg::hir_with_context(cx, cond, expr.span.ctxt(), "[condition]", &mut app) + .maybe_par() + .to_string(); let arg_snip = snippet_with_context(cx, then_arg.span, ctxt, "[body]", &mut app).0; let mut method_body = if then_block.stmts.is_empty() { arg_snip.into_owned() @@ -100,9 +106,8 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { "then" }; - let help = format!( - "consider using `bool::{method_name}` like: `{cond_snip}.{method_name}({method_body})`", - ); + let help = + format!("consider using `bool::{method_name}` like: `{cond_snip}.{method_name}({method_body})`",); span_lint_and_help( cx, IF_THEN_SOME_ELSE_NONE, diff --git a/src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs b/src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs index d8ead1c9d..76bdfb94e 100644 --- a/src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs @@ -15,14 +15,14 @@ declare_clippy_lint! { /// would detect a type change that `_` would ignore. /// /// ### Example - /// ```rust + /// ```no_run /// match std::fs::create_dir("tmp-work-dir") { /// Ok(_) => println!("Working directory created"), /// Err(s) => eprintln!("Could not create directory: {s}"), /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// match std::fs::create_dir("tmp-work-dir") { /// Ok(()) => println!("Working directory created"), /// Err(s) => eprintln!("Could not create directory: {s}"), @@ -37,6 +37,10 @@ declare_lint_pass!(IgnoredUnitPatterns => [IGNORED_UNIT_PATTERNS]); impl<'tcx> LateLintPass<'tcx> for IgnoredUnitPatterns { fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx hir::Pat<'tcx>) { + if pat.span.from_expansion() { + return; + } + match cx.tcx.hir().get_parent(pat.hir_id) { Node::Param(param) if matches!(cx.tcx.hir().get_parent(param.hir_id), Node::Item(_)) => { // Ignore function parameters @@ -48,7 +52,7 @@ impl<'tcx> LateLintPass<'tcx> for IgnoredUnitPatterns { }, _ => {}, } - if matches!(pat.kind, PatKind::Wild) && cx.typeck_results().pat_ty(pat).is_unit() { + if matches!(pat.kind, PatKind::Wild) && cx.typeck_results().pat_ty(pat).peel_refs().is_unit() { span_lint_and_sugg( cx, IGNORED_UNIT_PATTERNS, diff --git a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs index 64a4a3fa7..eaf80de38 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs @@ -6,12 +6,11 @@ use rustc_hir as hir; use rustc_hir::intravisit::{walk_body, walk_expr, walk_inf, walk_ty, Visitor}; use rustc_hir::{Body, Expr, ExprKind, GenericArg, Item, ItemKind, QPath, TyKind}; use rustc_hir_analysis::hir_ty_to_ty; -use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; -use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{Ty, TypeckResults}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::Span; +use rustc_span::Span; use rustc_span::symbol::sym; use if_chain::if_chain; @@ -36,7 +35,7 @@ declare_clippy_lint! { /// pieces of code, possibly including external crates. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::collections::HashMap; /// # use std::hash::{Hash, BuildHasher}; /// # trait Serialize {}; @@ -45,7 +44,7 @@ declare_clippy_lint! { /// pub fn foo(map: &mut HashMap<i32, i32>) { } /// ``` /// could be rewritten as - /// ```rust + /// ```no_run /// # use std::collections::HashMap; /// # use std::hash::{Hash, BuildHasher}; /// # trait Serialize {}; @@ -162,7 +161,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher { vis.visit_ty(ty); for target in &vis.found { - if in_external_macro(cx.sess(), generics.span) { + if generics.span.from_expansion() { continue; } let generics_suggestion_span = generics.span.substitute_dummy({ diff --git a/src/tools/clippy/clippy_lints/src/implicit_return.rs b/src/tools/clippy/clippy_lints/src/implicit_return.rs index a6b035d51..c6bcf3ba4 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_return.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_return.rs @@ -24,13 +24,13 @@ declare_clippy_lint! { /// corresponding statements. /// /// ### Example - /// ```rust + /// ```no_run /// fn foo(x: usize) -> usize { /// x /// } /// ``` /// add return - /// ```rust + /// ```no_run /// fn foo(x: usize) -> usize { /// return x; /// } diff --git a/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs b/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs index ee7973b82..24f62490f 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs @@ -18,7 +18,7 @@ declare_clippy_lint! { /// The built-in function is more readable and may be faster. /// /// ### Example - /// ```rust + /// ```no_run ///let mut u:u32 = 7000; /// /// if u != u32::MAX { @@ -26,7 +26,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run ///let mut u:u32 = 7000; /// /// u = u.saturating_add(1); @@ -82,18 +82,18 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingAdd { fn get_int_max(ty: Ty<'_>) -> Option<u128> { match ty.peel_refs().kind() { - Int(IntTy::I8) => i8::max_value().try_into().ok(), - Int(IntTy::I16) => i16::max_value().try_into().ok(), - Int(IntTy::I32) => i32::max_value().try_into().ok(), - Int(IntTy::I64) => i64::max_value().try_into().ok(), - Int(IntTy::I128) => i128::max_value().try_into().ok(), - Int(IntTy::Isize) => isize::max_value().try_into().ok(), - Uint(UintTy::U8) => u8::max_value().try_into().ok(), - Uint(UintTy::U16) => u16::max_value().try_into().ok(), - Uint(UintTy::U32) => u32::max_value().try_into().ok(), - Uint(UintTy::U64) => u64::max_value().try_into().ok(), - Uint(UintTy::U128) => Some(u128::max_value()), - Uint(UintTy::Usize) => usize::max_value().try_into().ok(), + Int(IntTy::I8) => i8::MAX.try_into().ok(), + Int(IntTy::I16) => i16::MAX.try_into().ok(), + Int(IntTy::I32) => i32::MAX.try_into().ok(), + Int(IntTy::I64) => i64::MAX.try_into().ok(), + Int(IntTy::I128) => i128::MAX.try_into().ok(), + Int(IntTy::Isize) => isize::MAX.try_into().ok(), + Uint(UintTy::U8) => Some(u8::MAX.into()), + Uint(UintTy::U16) => Some(u16::MAX.into()), + Uint(UintTy::U32) => Some(u32::MAX.into()), + Uint(UintTy::U64) => Some(u64::MAX.into()), + Uint(UintTy::U128) => Some(u128::MAX), + Uint(UintTy::Usize) => usize::MAX.try_into().ok(), _ => None, } } diff --git a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs index b99d45446..859404289 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs @@ -15,7 +15,7 @@ declare_clippy_lint! { /// Simplicity and readability. Instead we can easily use an builtin function. /// /// ### Example - /// ```rust + /// ```no_run /// # let end: u32 = 10; /// # let start: u32 = 5; /// let mut i: u32 = end - start; @@ -26,7 +26,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let end: u32 = 10; /// # let start: u32 = 5; /// let mut i: u32 = end - start; diff --git a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs index ec9044bba..ff27a5d66 100644 --- a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs +++ b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs @@ -29,7 +29,7 @@ declare_clippy_lint! { /// (e.g. `trait A {} trait B: A {} trait C: B {}`, then having an `fn() -> impl A + C`) /// /// ### Example - /// ```rust + /// ```no_run /// # use std::ops::{Deref,DerefMut}; /// fn f() -> impl Deref<Target = i32> + DerefMut<Target = i32> { /// // ^^^^^^^^^^^^^^^^^^^ unnecessary bound, already implied by the `DerefMut` trait bound @@ -37,7 +37,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # use std::ops::{Deref,DerefMut}; /// fn f() -> impl DerefMut<Target = i32> { /// Box::new(123) @@ -230,19 +230,24 @@ fn check(cx: &LateContext<'_>, decl: &FnDecl<'_>) { // Example: // `impl Deref<Target = i32> + DerefMut<Target = u32>` is not allowed. // `DerefMut::Target` needs to match `Deref::Target`. - let implied_bounds: Vec<_> = opaque_ty.bounds.iter().filter_map(|bound| { - if let GenericBound::Trait(poly_trait, TraitBoundModifier::None) = bound - && let [.., path] = poly_trait.trait_ref.path.segments - && poly_trait.bound_generic_params.is_empty() - && let Some(trait_def_id) = path.res.opt_def_id() - && let predicates = cx.tcx.super_predicates_of(trait_def_id).predicates - && !predicates.is_empty() // If the trait has no supertrait, there is nothing to add. - { - Some((bound.span(), path, predicates, trait_def_id)) - } else { - None - } - }).collect(); + let implied_bounds: Vec<_> = opaque_ty + .bounds + .iter() + .filter_map(|bound| { + if let GenericBound::Trait(poly_trait, TraitBoundModifier::None) = bound + && let [.., path] = poly_trait.trait_ref.path.segments + && poly_trait.bound_generic_params.is_empty() + && let Some(trait_def_id) = path.res.opt_def_id() + && let predicates = cx.tcx.super_predicates_of(trait_def_id).predicates + && !predicates.is_empty() + // If the trait has no supertrait, there is nothing to add. + { + Some((bound.span(), path, predicates, trait_def_id)) + } else { + None + } + }) + .collect(); // Lint all bounds in the `impl Trait` type that are also in the `implied_bounds` vec. // This involves some extra logic when generic arguments are present, since @@ -253,30 +258,31 @@ fn check(cx: &LateContext<'_>, decl: &FnDecl<'_>) { && let implied_args = path.args.map_or([].as_slice(), |a| a.args) && let implied_bindings = path.args.map_or([].as_slice(), |a| a.bindings) && let Some(def_id) = poly_trait.trait_ref.path.res.opt_def_id() - && let Some((implied_by_span, implied_by_args, implied_by_bindings)) = implied_bounds - .iter() - .find_map(|&(span, implied_by_path, preds, implied_by_def_id)| { - let implied_by_args = implied_by_path.args.map_or([].as_slice(), |a| a.args); - let implied_by_bindings = implied_by_path.args.map_or([].as_slice(), |a| a.bindings); + && let Some((implied_by_span, implied_by_args, implied_by_bindings)) = + implied_bounds + .iter() + .find_map(|&(span, implied_by_path, preds, implied_by_def_id)| { + let implied_by_args = implied_by_path.args.map_or([].as_slice(), |a| a.args); + let implied_by_bindings = implied_by_path.args.map_or([].as_slice(), |a| a.bindings); - preds.iter().find_map(|(clause, _)| { - if let ClauseKind::Trait(tr) = clause.kind().skip_binder() - && tr.def_id() == def_id - && is_same_generics( - cx.tcx, - tr.trait_ref.args, - implied_by_args, - implied_args, - implied_by_def_id, - def_id, - ) - { - Some((span, implied_by_args, implied_by_bindings)) - } else { - None - } + preds.iter().find_map(|(clause, _)| { + if let ClauseKind::Trait(tr) = clause.kind().skip_binder() + && tr.def_id() == def_id + && is_same_generics( + cx.tcx, + tr.trait_ref.args, + implied_by_args, + implied_args, + implied_by_def_id, + def_id, + ) + { + Some((span, implied_by_args, implied_by_bindings)) + } else { + None + } + }) }) - }) { emit_lint( cx, @@ -286,7 +292,7 @@ fn check(cx: &LateContext<'_>, decl: &FnDecl<'_>) { implied_bindings, implied_by_bindings, implied_by_args, - implied_by_span + implied_by_span, ); } } diff --git a/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs b/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs index 1ad886f2c..a84f7351a 100644 --- a/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs +++ b/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs @@ -19,7 +19,7 @@ declare_clippy_lint! { /// Since the order of fields in a constructor doesn't affect the /// resulted instance as the below example indicates, /// - /// ```rust + /// ```no_run /// #[derive(Debug, PartialEq, Eq)] /// struct Foo { /// x: i32, @@ -35,7 +35,7 @@ declare_clippy_lint! { /// inconsistent order can be confusing and decreases readability and consistency. /// /// ### Example - /// ```rust + /// ```no_run /// struct Foo { /// x: i32, /// y: i32, @@ -47,7 +47,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # struct Foo { /// # x: i32, /// # y: i32, diff --git a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs index f507f45d5..c2f1f18e3 100644 --- a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs +++ b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs @@ -1,7 +1,7 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{constant, 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 if_chain::if_chain; @@ -31,7 +31,7 @@ declare_clippy_lint! { /// patterns. /// /// ### Example - /// ```rust + /// ```no_run /// let slice: Option<&[u32]> = Some(&[1, 2, 3]); /// /// if let Some(slice) = slice { @@ -39,7 +39,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let slice: Option<&[u32]> = Some(&[1, 2, 3]); /// /// if let Some(&[first, ..]) = slice { diff --git a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs index 4f4f57177..1ce7d85d3 100644 --- a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs +++ b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs @@ -26,7 +26,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let x = [1, 2, 3, 4]; /// // Index within bounds /// @@ -65,7 +65,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # #![allow(unused)] /// /// # let x = vec![0; 5]; diff --git a/src/tools/clippy/clippy_lints/src/infinite_iter.rs b/src/tools/clippy/clippy_lints/src/infinite_iter.rs index fe28c526b..e9c53671a 100644 --- a/src/tools/clippy/clippy_lints/src/infinite_iter.rs +++ b/src/tools/clippy/clippy_lints/src/infinite_iter.rs @@ -39,7 +39,7 @@ declare_clippy_lint! { /// this lint is not clever enough to analyze it. /// /// ### Example - /// ```rust + /// ```no_run /// let infinite_iter = 0..; /// # #[allow(unused)] /// [0..].iter().zip(infinite_iter.take_while(|x| *x > 5)); diff --git a/src/tools/clippy/clippy_lints/src/inherent_impl.rs b/src/tools/clippy/clippy_lints/src/inherent_impl.rs index 3d1113ff9..a61a64161 100644 --- a/src/tools/clippy/clippy_lints/src/inherent_impl.rs +++ b/src/tools/clippy/clippy_lints/src/inherent_impl.rs @@ -18,7 +18,7 @@ declare_clippy_lint! { /// Splitting the implementation of a type makes the code harder to navigate. /// /// ### Example - /// ```rust + /// ```no_run /// struct X; /// impl X { /// fn one() {} @@ -30,7 +30,7 @@ declare_clippy_lint! { /// /// Could be written: /// - /// ```rust + /// ```no_run /// struct X; /// impl X { /// fn one() {} diff --git a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs index bc4ec33b7..fe5eb5cca 100644 --- a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs +++ b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs @@ -15,7 +15,7 @@ declare_clippy_lint! { /// This method is also implicitly defined if a type implements the `Display` trait. As the functionality of `Display` is much more versatile, it should be preferred. /// /// ### Example - /// ```rust + /// ```no_run /// pub struct A; /// /// impl A { @@ -26,7 +26,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// use std::fmt; /// /// pub struct A; @@ -51,7 +51,7 @@ declare_clippy_lint! { /// This method is also implicitly defined if a type implements the `Display` trait. The less versatile inherent method will then shadow the implementation introduced by `Display`. /// /// ### Example - /// ```rust + /// ```no_run /// use std::fmt; /// /// pub struct A; @@ -70,7 +70,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// use std::fmt; /// /// pub struct A; diff --git a/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs b/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs index f95d2c2ed..269311a67 100644 --- a/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs +++ b/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs @@ -20,7 +20,7 @@ declare_clippy_lint! { /// benefit as opposed to tuple initializers /// /// ### Example - /// ```rust + /// ```no_run /// struct TupleStruct(u8, u16); /// /// let _ = TupleStruct { diff --git a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs index d609a5ca4..899126565 100644 --- a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs +++ b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs @@ -18,7 +18,7 @@ declare_clippy_lint! { /// The inline attribute is ignored for trait methods without bodies. /// /// ### Example - /// ```rust + /// ```no_run /// trait Animal { /// #[inline] /// fn name(&self) -> &'static str; diff --git a/src/tools/clippy/clippy_lints/src/instant_subtraction.rs b/src/tools/clippy/clippy_lints/src/instant_subtraction.rs index 8df7dfb8b..32b2cb438 100644 --- a/src/tools/clippy/clippy_lints/src/instant_subtraction.rs +++ b/src/tools/clippy/clippy_lints/src/instant_subtraction.rs @@ -1,5 +1,5 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{self, 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; @@ -21,13 +21,13 @@ declare_clippy_lint! { /// `prev_instant.elapsed()` also more clearly signals intention. /// /// ### Example - /// ```rust + /// ```no_run /// use std::time::Instant; /// let prev_instant = Instant::now(); /// let duration = Instant::now() - prev_instant; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::time::Instant; /// let prev_instant = Instant::now(); /// let duration = prev_instant.elapsed(); @@ -47,13 +47,13 @@ declare_clippy_lint! { /// unintentional panics. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::time::{Instant, Duration}; /// let time_passed = Instant::now() - Duration::from_secs(5); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # use std::time::{Instant, Duration}; /// let time_passed = Instant::now().checked_sub(Duration::from_secs(5)); /// ``` @@ -130,11 +130,7 @@ fn is_instant_now_call(cx: &LateContext<'_>, expr_block: &'_ Expr<'_>) -> bool { fn is_an_instant(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { let expr_ty = cx.typeck_results().expr_ty(expr); - - match expr_ty.kind() { - rustc_middle::ty::Adt(def, _) => clippy_utils::match_def_path(cx, def.did(), &clippy_utils::paths::INSTANT), - _ => false, - } + ty::is_type_diagnostic_item(cx, expr_ty, sym::Instant) } fn is_a_duration(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { diff --git a/src/tools/clippy/clippy_lints/src/int_plus_one.rs b/src/tools/clippy/clippy_lints/src/int_plus_one.rs index 1b14e525d..9ffcee07d 100644 --- a/src/tools/clippy/clippy_lints/src/int_plus_one.rs +++ b/src/tools/clippy/clippy_lints/src/int_plus_one.rs @@ -16,14 +16,14 @@ declare_clippy_lint! { /// Readability -- better to use `> y` instead of `>= y + 1`. /// /// ### Example - /// ```rust + /// ```no_run /// # let x = 1; /// # let y = 1; /// if x >= y + 1 {} /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let x = 1; /// # let y = 1; /// if x > y {} diff --git a/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs b/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs index 6ea637412..de82935e6 100644 --- a/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs +++ b/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs @@ -26,7 +26,7 @@ declare_clippy_lint! { /// https://github.com/rust-lang/rust-clippy/issues/886 /// /// ### Example - /// ```rust + /// ```no_run /// let x: u8 = 1; /// (x as u32) > 300; /// ``` diff --git a/src/tools/clippy/clippy_lints/src/enum_variants.rs b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs index e332f681b..90048d96c 100644 --- a/src/tools/clippy/clippy_lints/src/enum_variants.rs +++ b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs @@ -1,12 +1,13 @@ //! lint on enum variants that are prefixed or suffixed by the same characters use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_hir}; +use clippy_utils::macros::span_is_local; use clippy_utils::source::is_present_in_source; -use clippy_utils::str_utils::{camel_case_split, count_match_end, count_match_start}; -use rustc_hir::{EnumDef, Item, ItemKind, OwnerId, Variant}; +use clippy_utils::str_utils::{camel_case_split, count_match_end, count_match_start, to_camel_case, to_snake_case}; +use rustc_hir::{EnumDef, FieldDef, Item, ItemKind, OwnerId, Variant, VariantData}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::source_map::Span; +use rustc_span::Span; use rustc_span::symbol::Symbol; declare_clippy_lint! { @@ -25,7 +26,7 @@ declare_clippy_lint! { /// (the prefixes are `Foo1` and `Foo2` respectively), as also `Bar螃`, `Bar蟹` /// /// ### Example - /// ```rust + /// ```no_run /// enum Cake { /// BlackForestCake, /// HummingbirdCake, @@ -33,7 +34,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// enum Cake { /// BlackForest, /// Hummingbird, @@ -55,14 +56,14 @@ declare_clippy_lint! { /// It requires the user to type the module name twice. /// /// ### Example - /// ```rust + /// ```no_run /// mod cake { /// struct BlackForestCake; /// } /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// mod cake { /// struct BlackForest; /// } @@ -103,32 +104,184 @@ declare_clippy_lint! { style, "modules that have the same name as their parent module" } +declare_clippy_lint! { + /// ### What it does + /// Detects struct fields that are prefixed or suffixed + /// by the same characters or the name of the struct itself. + /// + /// ### Why is this bad? + /// Information common to all struct fields is better represented in the struct name. + /// + /// ### Limitations + /// Characters with no casing will be considered when comparing prefixes/suffixes + /// This applies to numbers and non-ascii characters without casing + /// e.g. `foo1` and `foo2` is considered to have different prefixes + /// (the prefixes are `foo1` and `foo2` respectively), as also `bar螃`, `bar蟹` + /// + /// ### Example + /// ```no_run + /// struct Cake { + /// cake_sugar: u8, + /// cake_flour: u8, + /// cake_eggs: u8 + /// } + /// ``` + /// Use instead: + /// ```no_run + /// struct Cake { + /// sugar: u8, + /// flour: u8, + /// eggs: u8 + /// } + /// ``` + #[clippy::version = "1.75.0"] + pub STRUCT_FIELD_NAMES, + pedantic, + "structs where all fields share a prefix/postfix or contain the name of the struct" +} -pub struct EnumVariantNames { +pub struct ItemNameRepetitions { modules: Vec<(Symbol, String, OwnerId)>, - threshold: u64, + enum_threshold: u64, + struct_threshold: u64, avoid_breaking_exported_api: bool, allow_private_module_inception: bool, } -impl EnumVariantNames { +impl ItemNameRepetitions { #[must_use] - pub fn new(threshold: u64, avoid_breaking_exported_api: bool, allow_private_module_inception: bool) -> Self { + pub fn new( + enum_threshold: u64, + struct_threshold: u64, + avoid_breaking_exported_api: bool, + allow_private_module_inception: bool, + ) -> Self { Self { modules: Vec::new(), - threshold, + enum_threshold, + struct_threshold, avoid_breaking_exported_api, allow_private_module_inception, } } } -impl_lint_pass!(EnumVariantNames => [ +impl_lint_pass!(ItemNameRepetitions => [ ENUM_VARIANT_NAMES, + STRUCT_FIELD_NAMES, MODULE_NAME_REPETITIONS, MODULE_INCEPTION ]); +#[must_use] +fn have_no_extra_prefix(prefixes: &[&str]) -> bool { + prefixes.iter().all(|p| p == &"" || p == &"_") +} + +fn check_fields(cx: &LateContext<'_>, threshold: u64, item: &Item<'_>, fields: &[FieldDef<'_>]) { + if (fields.len() as u64) < threshold { + return; + } + + check_struct_name_repetition(cx, item, fields); + + // if the SyntaxContext of the identifiers of the fields and struct differ dont lint them. + // this prevents linting in macros in which the location of the field identifier names differ + if !fields.iter().all(|field| item.ident.span.eq_ctxt(field.ident.span)) { + return; + } + + let mut pre: Vec<&str> = match fields.first() { + Some(first_field) => first_field.ident.name.as_str().split('_').collect(), + None => return, + }; + let mut post = pre.clone(); + post.reverse(); + for field in fields { + let field_split: Vec<&str> = field.ident.name.as_str().split('_').collect(); + if field_split.len() == 1 { + return; + } + + pre = pre + .into_iter() + .zip(field_split.iter()) + .take_while(|(a, b)| &a == b) + .map(|e| e.0) + .collect(); + post = post + .into_iter() + .zip(field_split.iter().rev()) + .take_while(|(a, b)| &a == b) + .map(|e| e.0) + .collect(); + } + let prefix = pre.join("_"); + post.reverse(); + let postfix = match post.last() { + Some(&"") => post.join("_") + "_", + Some(_) | None => post.join("_"), + }; + if fields.len() > 1 { + let (what, value) = match ( + prefix.is_empty() || prefix.chars().all(|c| c == '_'), + postfix.is_empty(), + ) { + (true, true) => return, + (false, _) => ("pre", prefix), + (true, false) => ("post", postfix), + }; + span_lint_and_help( + cx, + STRUCT_FIELD_NAMES, + item.span, + &format!("all fields have the same {what}fix: `{value}`"), + None, + &format!("remove the {what}fixes"), + ); + } +} + +fn check_struct_name_repetition(cx: &LateContext<'_>, item: &Item<'_>, fields: &[FieldDef<'_>]) { + let snake_name = to_snake_case(item.ident.name.as_str()); + let item_name_words: Vec<&str> = snake_name.split('_').collect(); + for field in fields { + if field.ident.span.eq_ctxt(item.ident.span) { + //consider linting only if the field identifier has the same SyntaxContext as the item(struct) + let field_words: Vec<&str> = field.ident.name.as_str().split('_').collect(); + if field_words.len() >= item_name_words.len() { + // if the field name is shorter than the struct name it cannot contain it + if field_words.iter().zip(item_name_words.iter()).all(|(a, b)| a == b) { + span_lint_hir( + cx, + STRUCT_FIELD_NAMES, + field.hir_id, + field.span, + "field name starts with the struct's name", + ); + } + if field_words.len() > item_name_words.len() { + // lint only if the end is not covered by the start + if field_words + .iter() + .rev() + .zip(item_name_words.iter().rev()) + .all(|(a, b)| a == b) + { + span_lint_hir( + cx, + STRUCT_FIELD_NAMES, + field.hir_id, + field.span, + "field name ends with the struct's name", + ); + } + } + } + } + } +} + fn check_enum_start(cx: &LateContext<'_>, item_name: &str, variant: &Variant<'_>) { let name = variant.ident.name.as_str(); let item_name_chars = item_name.chars().count(); @@ -167,6 +320,11 @@ fn check_variant(cx: &LateContext<'_>, threshold: u64, def: &EnumDef<'_>, item_n return; } + for var in def.variants { + check_enum_start(cx, item_name, var); + check_enum_end(cx, item_name, var); + } + let first = match def.variants.first() { Some(variant) => variant.ident.name.as_str(), None => return, @@ -175,8 +333,6 @@ fn check_variant(cx: &LateContext<'_>, threshold: u64, def: &EnumDef<'_>, item_n let mut post = pre.clone(); post.reverse(); for var in def.variants { - check_enum_start(cx, item_name, var); - check_enum_end(cx, item_name, var); let name = var.ident.name.as_str(); let variant_split = camel_case_split(name); @@ -218,35 +374,7 @@ fn check_variant(cx: &LateContext<'_>, threshold: u64, def: &EnumDef<'_>, item_n ); } -#[must_use] -fn have_no_extra_prefix(prefixes: &[&str]) -> bool { - prefixes.iter().all(|p| p == &"" || p == &"_") -} - -#[must_use] -fn to_camel_case(item_name: &str) -> String { - let mut s = String::new(); - let mut up = true; - for c in item_name.chars() { - if c.is_uppercase() { - // we only turn snake case text into CamelCase - return item_name.to_string(); - } - if c == '_' { - up = true; - continue; - } - if up { - up = false; - s.extend(c.to_uppercase()); - } else { - s.push(c); - } - } - s -} - -impl LateLintPass<'_> for EnumVariantNames { +impl LateLintPass<'_> for ItemNameRepetitions { fn check_item_post(&mut self, _cx: &LateContext<'_>, _item: &Item<'_>) { let last = self.modules.pop(); assert!(last.is_some()); @@ -303,9 +431,15 @@ impl LateLintPass<'_> for EnumVariantNames { } } } - if let ItemKind::Enum(ref def, _) = item.kind { - if !(self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(item.owner_id.def_id)) { - check_variant(cx, self.threshold, def, item_name, item.span); + if !(self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(item.owner_id.def_id)) + && span_is_local(item.span) + { + match item.kind { + ItemKind::Enum(def, _) => check_variant(cx, self.enum_threshold, &def, item_name, item.span), + ItemKind::Struct(VariantData::Struct(fields, _), _) => { + check_fields(cx, self.struct_threshold, item, fields); + }, + _ => (), } } self.modules.push((item.ident.name, item_camel, item.owner_id)); diff --git a/src/tools/clippy/clippy_lints/src/items_after_statements.rs b/src/tools/clippy/clippy_lints/src/items_after_statements.rs index a7ec57e28..9605d76fb 100644 --- a/src/tools/clippy/clippy_lints/src/items_after_statements.rs +++ b/src/tools/clippy/clippy_lints/src/items_after_statements.rs @@ -16,7 +16,7 @@ declare_clippy_lint! { /// it's hard to figure out which item is meant in a statement. /// /// ### Example - /// ```rust + /// ```no_run /// fn foo() { /// println!("cake"); /// } @@ -31,7 +31,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// fn foo() { /// println!("cake"); /// } diff --git a/src/tools/clippy/clippy_lints/src/items_after_test_module.rs b/src/tools/clippy/clippy_lints/src/items_after_test_module.rs index 55a43e915..35e01862c 100644 --- a/src/tools/clippy/clippy_lints/src/items_after_test_module.rs +++ b/src/tools/clippy/clippy_lints/src/items_after_test_module.rs @@ -1,10 +1,12 @@ -use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::{is_from_proc_macro, is_in_cfg_test}; -use rustc_hir::{HirId, ItemId, ItemKind, Mod}; -use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; +use clippy_utils::diagnostics::span_lint_hir_and_then; +use clippy_utils::source::snippet_opt; +use clippy_utils::{fulfill_or_allowed, is_cfg_test, is_from_proc_macro}; +use rustc_errors::{Applicability, SuggestionStyle}; +use rustc_hir::{HirId, Item, ItemKind, Mod}; +use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::{sym, Span}; +use rustc_span::hygiene::AstPass; +use rustc_span::{sym, ExpnKind}; declare_clippy_lint! { /// ### What it does @@ -12,7 +14,7 @@ declare_clippy_lint! { /// ### Why is this bad? /// Having items declared after the testing module is confusing and may lead to bad test coverage. /// ### Example - /// ```rust + /// ```no_run /// #[cfg(test)] /// mod tests { /// // [...] @@ -23,7 +25,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn my_function() { /// // [...] /// } @@ -41,46 +43,67 @@ declare_clippy_lint! { declare_lint_pass!(ItemsAfterTestModule => [ITEMS_AFTER_TEST_MODULE]); -impl LateLintPass<'_> for ItemsAfterTestModule { - fn check_mod(&mut self, cx: &LateContext<'_>, _: &Mod<'_>, _: HirId) { - let mut was_test_mod_visited = false; - let mut test_mod_span: Option<Span> = None; +fn cfg_test_module<'tcx>(cx: &LateContext<'tcx>, item: &Item<'tcx>) -> bool { + if let ItemKind::Mod(test_mod) = item.kind + && item.span.hi() == test_mod.spans.inner_span.hi() + && is_cfg_test(cx.tcx, item.hir_id()) + && !item.span.from_expansion() + && !is_from_proc_macro(cx, item) + { + true + } else { + false + } +} - let hir = cx.tcx.hir(); - let items = hir.items().collect::<Vec<ItemId>>(); +impl LateLintPass<'_> for ItemsAfterTestModule { + fn check_mod(&mut self, cx: &LateContext<'_>, module: &Mod<'_>, _: HirId) { + let mut items = module.item_ids.iter().map(|&id| cx.tcx.hir().item(id)); - for (i, itid) in items.iter().enumerate() { - let item = hir.item(*itid); + let Some((mod_pos, test_mod)) = items.by_ref().enumerate().find(|(_, item)| cfg_test_module(cx, item)) else { + return; + }; - if_chain! { - if was_test_mod_visited; - if i == (items.len() - 3 /* Weird magic number (HIR-translation behaviour) */); - if cx.sess().source_map().lookup_char_pos(item.span.lo()).file.name_hash - == cx.sess().source_map().lookup_char_pos(test_mod_span.unwrap().lo()).file.name_hash; // Will never fail - if !matches!(item.kind, ItemKind::Mod(_)); - if !is_in_cfg_test(cx.tcx, itid.hir_id()); // The item isn't in the testing module itself - if !in_external_macro(cx.sess(), item.span); - if !is_from_proc_macro(cx, item); + let after: Vec<_> = items + .filter(|item| { + // Ignore the generated test main function + !(item.ident.name == sym::main + && item.span.ctxt().outer_expn_data().kind == ExpnKind::AstPass(AstPass::TestHarness)) + }) + .collect(); - then { - span_lint_and_help(cx, ITEMS_AFTER_TEST_MODULE, test_mod_span.unwrap().with_hi(item.span.hi()), "items were found after the testing module", None, "move the items to before the testing module was defined"); - }}; + if let Some(last) = after.last() + && after.iter().all(|&item| { + !matches!(item.kind, ItemKind::Mod(_)) && !item.span.from_expansion() && !is_from_proc_macro(cx, item) + }) + && !fulfill_or_allowed(cx, ITEMS_AFTER_TEST_MODULE, after.iter().map(|item| item.hir_id())) + { + let def_spans: Vec<_> = std::iter::once(test_mod.owner_id) + .chain(after.iter().map(|item| item.owner_id)) + .map(|id| cx.tcx.def_span(id)) + .collect(); - if let ItemKind::Mod(module) = item.kind && item.span.hi() == module.spans.inner_span.hi() { - // Check that it works the same way, the only I way I've found for #10713 - for attr in cx.tcx.get_attrs(item.owner_id.to_def_id(), sym::cfg) { - if_chain! { - if attr.has_name(sym::cfg); - if let Some(mitems) = attr.meta_item_list(); - if let [mitem] = &*mitems; - if mitem.has_name(sym::test); - then { - was_test_mod_visited = true; - test_mod_span = Some(item.span); - } + span_lint_hir_and_then( + cx, + ITEMS_AFTER_TEST_MODULE, + test_mod.hir_id(), + def_spans, + "items after a test module", + |diag| { + if let Some(prev) = mod_pos.checked_sub(1) + && let prev = cx.tcx.hir().item(module.item_ids[prev]) + && let items_span = last.span.with_lo(test_mod.span.hi()) + && let Some(items) = snippet_opt(cx, items_span) + { + diag.multipart_suggestion_with_style( + "move the items to before the test module was defined", + vec![(prev.span.shrink_to_hi(), items), (items_span, String::new())], + Applicability::MachineApplicable, + SuggestionStyle::HideCodeAlways, + ); } - } - } + }, + ); } } } diff --git a/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs b/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs index 066d2c4b7..505aadd1a 100644 --- a/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs +++ b/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs @@ -15,7 +15,7 @@ declare_clippy_lint! { /// Methods named `iter` or `iter_mut` conventionally return an `Iterator`. /// /// ### Example - /// ```rust + /// ```no_run /// // `String` does not implement `Iterator` /// struct Data {} /// impl Data { @@ -25,7 +25,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::str::Chars; /// struct Data {} /// impl Data { diff --git a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs new file mode 100644 index 000000000..3c291f255 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs @@ -0,0 +1,295 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::get_parent_as_impl; +use clippy_utils::source::snippet; +use clippy_utils::ty::{implements_trait, make_normalized_projection}; +use rustc_ast::Mutability; +use rustc_errors::Applicability; +use rustc_hir::{FnRetTy, ImplItemKind, ImplicitSelfKind, ItemKind, TyKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::{self, Ty}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::{sym, Symbol}; +use std::iter; + +declare_clippy_lint! { + /// ### What it does + /// Looks for `iter` and `iter_mut` methods without an associated `IntoIterator for (&|&mut) Type` implementation. + /// + /// ### Why is this bad? + /// It's not bad, but having them is idiomatic and allows the type to be used in for loops directly + /// (`for val in &iter {}`), without having to first call `iter()` or `iter_mut()`. + /// + /// ### Limitations + /// This lint focuses on providing an idiomatic API. Therefore, it will only + /// lint on types which are accessible outside of the crate. For internal types, + /// the `IntoIterator` trait can be implemented on demand if it is actually needed. + /// + /// ### Example + /// ```no_run + /// struct MySlice<'a>(&'a [u8]); + /// impl<'a> MySlice<'a> { + /// pub fn iter(&self) -> std::slice::Iter<'a, u8> { + /// self.0.iter() + /// } + /// } + /// ``` + /// Use instead: + /// ```no_run + /// struct MySlice<'a>(&'a [u8]); + /// impl<'a> MySlice<'a> { + /// pub fn iter(&self) -> std::slice::Iter<'a, u8> { + /// self.0.iter() + /// } + /// } + /// impl<'a> IntoIterator for &MySlice<'a> { + /// type Item = &'a u8; + /// type IntoIter = std::slice::Iter<'a, u8>; + /// fn into_iter(self) -> Self::IntoIter { + /// self.iter() + /// } + /// } + /// ``` + #[clippy::version = "1.74.0"] + pub ITER_WITHOUT_INTO_ITER, + pedantic, + "implementing `iter(_mut)` without an associated `IntoIterator for (&|&mut) Type` impl" +} + +declare_clippy_lint! { + /// ### What it does + /// This is the opposite of the `iter_without_into_iter` lint. + /// It looks for `IntoIterator for (&|&mut) Type` implementations without an inherent `iter` or `iter_mut` method + /// on the type or on any of the types in its `Deref` chain. + /// + /// ### Why is this bad? + /// It's not bad, but having them is idiomatic and allows the type to be used in iterator chains + /// by just calling `.iter()`, instead of the more awkward `<&Type>::into_iter` or `(&val).into_iter()` syntax + /// in case of ambiguity with another `IntoIterator` impl. + /// + /// ### Limitations + /// This lint focuses on providing an idiomatic API. Therefore, it will only + /// lint on types which are accessible outside of the crate. For internal types, + /// these methods can be added on demand if they are actually needed. Otherwise, + /// it would trigger the [`dead_code`] lint for the unused method. + /// + /// [`dead_code`]: https://doc.rust-lang.org/rustc/lints/listing/warn-by-default.html#dead-code + /// + /// ### Example + /// ```no_run + /// struct MySlice<'a>(&'a [u8]); + /// impl<'a> IntoIterator for &MySlice<'a> { + /// type Item = &'a u8; + /// type IntoIter = std::slice::Iter<'a, u8>; + /// fn into_iter(self) -> Self::IntoIter { + /// self.0.iter() + /// } + /// } + /// ``` + /// Use instead: + /// ```no_run + /// struct MySlice<'a>(&'a [u8]); + /// impl<'a> MySlice<'a> { + /// pub fn iter(&self) -> std::slice::Iter<'a, u8> { + /// self.into_iter() + /// } + /// } + /// impl<'a> IntoIterator for &MySlice<'a> { + /// type Item = &'a u8; + /// type IntoIter = std::slice::Iter<'a, u8>; + /// fn into_iter(self) -> Self::IntoIter { + /// self.0.iter() + /// } + /// } + /// ``` + #[clippy::version = "1.74.0"] + pub INTO_ITER_WITHOUT_ITER, + pedantic, + "implementing `IntoIterator for (&|&mut) Type` without an inherent `iter(_mut)` method" +} + +declare_lint_pass!(IterWithoutIntoIter => [ITER_WITHOUT_INTO_ITER, INTO_ITER_WITHOUT_ITER]); + +/// Checks if a given type is nameable in a trait (impl). +/// RPIT is stable, but impl Trait in traits is not (yet), so when we have +/// a function such as `fn iter(&self) -> impl IntoIterator`, we can't +/// suggest `type IntoIter = impl IntoIterator`. +fn is_nameable_in_impl_trait(ty: &rustc_hir::Ty<'_>) -> bool { + !matches!(ty.kind, TyKind::OpaqueDef(..)) +} + +fn is_ty_exported(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { + ty.ty_adt_def() + .and_then(|adt| adt.did().as_local()) + .is_some_and(|did| cx.effective_visibilities.is_exported(did)) +} + +/// Returns the deref chain of a type, starting with the type itself. +fn deref_chain<'cx, 'tcx>(cx: &'cx LateContext<'tcx>, ty: Ty<'tcx>) -> impl Iterator<Item = Ty<'tcx>> + 'cx { + iter::successors(Some(ty), |&ty| { + 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]) + } else { + None + } + }) +} + +fn adt_has_inherent_method(cx: &LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> bool { + if let Some(ty_did) = ty.ty_adt_def().map(ty::AdtDef::did) { + cx.tcx.inherent_impls(ty_did).iter().any(|&did| { + cx.tcx + .associated_items(did) + .filter_by_name_unhygienic(method_name) + .next() + .is_some_and(|item| item.kind == ty::AssocKind::Fn) + }) + } else { + false + } +} + +impl LateLintPass<'_> for IterWithoutIntoIter { + fn check_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::Item<'_>) { + if let ItemKind::Impl(imp) = item.kind + && let TyKind::Ref(_, self_ty_without_ref) = &imp.self_ty.kind + && let Some(trait_ref) = imp.of_trait + && trait_ref + .trait_def_id() + .is_some_and(|did| cx.tcx.is_diagnostic_item(sym::IntoIterator, did)) + && let &ty::Ref(_, ty, mtbl) = cx.tcx.type_of(item.owner_id).instantiate_identity().kind() + && let expected_method_name = match mtbl { + Mutability::Mut => sym::iter_mut, + Mutability::Not => sym::iter, + } + && !deref_chain(cx, ty).any(|ty| { + // We can't check inherent impls for slices, but we know that they have an `iter(_mut)` method + ty.peel_refs().is_slice() || adt_has_inherent_method(cx, ty, expected_method_name) + }) + && let Some(iter_assoc_span) = imp.items.iter().find_map(|item| { + if item.ident.name == sym!(IntoIter) { + Some(cx.tcx.hir().impl_item(item.id).expect_type().span) + } else { + None + } + }) + && is_ty_exported(cx, ty) + { + span_lint_and_then( + cx, + INTO_ITER_WITHOUT_ITER, + item.span, + &format!("`IntoIterator` implemented for a reference type without an `{expected_method_name}` method"), + |diag| { + // The suggestion forwards to the `IntoIterator` impl and uses a form of UFCS + // to avoid name ambiguities, as there might be an inherent into_iter method + // that we don't want to call. + let sugg = format!( + " +impl {self_ty_without_ref} {{ + fn {expected_method_name}({ref_self}self) -> {iter_ty} {{ + <{ref_self}Self as IntoIterator>::into_iter(self) + }} +}} +", + self_ty_without_ref = snippet(cx, self_ty_without_ref.ty.span, ".."), + ref_self = mtbl.ref_prefix_str(), + iter_ty = snippet(cx, iter_assoc_span, ".."), + ); + + diag.span_suggestion_verbose( + item.span.shrink_to_lo(), + format!("consider implementing `{expected_method_name}`"), + sugg, + // Just like iter_without_into_iter, this suggestion is on a best effort basis + // and requires potentially adding lifetimes or moving them around. + Applicability::Unspecified, + ); + }, + ); + } + } + + fn check_impl_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::ImplItem<'_>) { + let item_did = item.owner_id.to_def_id(); + let (borrow_prefix, expected_implicit_self) = match item.ident.name { + sym::iter => ("&", ImplicitSelfKind::ImmRef), + sym::iter_mut => ("&mut ", ImplicitSelfKind::MutRef), + _ => return, + }; + + if let ImplItemKind::Fn(sig, _) = item.kind + && let FnRetTy::Return(ret) = sig.decl.output + && is_nameable_in_impl_trait(ret) + && cx.tcx.generics_of(item_did).params.is_empty() + && sig.decl.implicit_self == expected_implicit_self + && sig.decl.inputs.len() == 1 + && let Some(imp) = get_parent_as_impl(cx.tcx, item.hir_id()) + && imp.of_trait.is_none() + && let sig = cx.tcx.liberate_late_bound_regions( + item_did, + cx.tcx.fn_sig(item_did).instantiate_identity() + ) + && let ref_ty = sig.inputs()[0] + && let Some(into_iter_did) = cx.tcx.get_diagnostic_item(sym::IntoIterator) + && let Some(iterator_did) = cx.tcx.get_diagnostic_item(sym::Iterator) + && let ret_ty = sig.output() + // Order is important here, we need to check that the `fn iter` return type actually implements `IntoIterator` + // *before* normalizing `<_ as IntoIterator>::Item` (otherwise make_normalized_projection ICEs) + && implements_trait(cx, ret_ty, iterator_did, &[]) + && let Some(iter_ty) = make_normalized_projection( + cx.tcx, + cx.param_env, + iterator_did, + sym::Item, + [ret_ty], + ) + // Only lint if the `IntoIterator` impl doesn't actually exist + && !implements_trait(cx, ref_ty, into_iter_did, &[]) + && is_ty_exported(cx, ref_ty.peel_refs()) + { + let self_ty_snippet = format!("{borrow_prefix}{}", snippet(cx, imp.self_ty.span, "..")); + + span_lint_and_then( + cx, + ITER_WITHOUT_INTO_ITER, + item.span, + &format!( + "`{}` method without an `IntoIterator` impl for `{self_ty_snippet}`", + item.ident + ), + |diag| { + // Get the lower span of the `impl` block, and insert the suggestion right before it: + // impl X { + // ^ fn iter(&self) -> impl IntoIterator { ... } + // } + let span_behind_impl = cx + .tcx + .def_span(cx.tcx.hir().parent_id(item.hir_id()).owner.def_id) + .shrink_to_lo(); + + let sugg = format!( + " +impl IntoIterator for {self_ty_snippet} {{ + type IntoIter = {ret_ty}; + type Item = {iter_ty}; + fn into_iter(self) -> Self::IntoIter {{ + self.iter() + }} +}} +" + ); + diag.span_suggestion_verbose( + span_behind_impl, + format!("consider implementing `IntoIterator` for `{self_ty_snippet}`"), + sugg, + // Suggestion is on a best effort basis, might need some adjustments by the user + // such as adding some lifetimes in the associated types, or importing types. + Applicability::Unspecified, + ); + }, + ); + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs index b22b57a30..0bf9b8718 100644 --- a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs +++ b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs @@ -9,7 +9,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{Adt, Ty}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::source_map::Span; +use rustc_span::Span; declare_clippy_lint! { /// ### What it does @@ -38,7 +38,7 @@ declare_clippy_lint! { /// this may lead to a false positive. /// /// ### Example - /// ```rust + /// ```no_run /// enum Test { /// A(i32), /// B([i32; 8000]), @@ -46,7 +46,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// // Possibly better /// enum Test2 { /// A(i32), diff --git a/src/tools/clippy/clippy_lints/src/large_futures.rs b/src/tools/clippy/clippy_lints/src/large_futures.rs index 19f1e08b5..26a727852 100644 --- a/src/tools/clippy/clippy_lints/src/large_futures.rs +++ b/src/tools/clippy/clippy_lints/src/large_futures.rs @@ -12,11 +12,11 @@ declare_clippy_lint! { /// It checks for the size of a `Future` created by `async fn` or `async {}`. /// /// ### Why is this bad? - /// Due to the current [unideal implementation](https://github.com/rust-lang/rust/issues/69826) of `Generator`, + /// Due to the current [unideal implementation](https://github.com/rust-lang/rust/issues/69826) of `Coroutine`, /// large size of a `Future` may cause stack overflows. /// /// ### Example - /// ```rust + /// ```no_run /// async fn large_future(_x: [u8; 16 * 1024]) {} /// /// pub async fn trigger() { @@ -26,7 +26,7 @@ declare_clippy_lint! { /// /// `Box::pin` the big future instead. /// - /// ```rust + /// ```no_run /// async fn large_future(_x: [u8; 16 * 1024]) {} /// /// pub async fn trigger() { diff --git a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs index 0a5901bce..5e312ab72 100644 --- a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs +++ b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs @@ -39,27 +39,35 @@ impl_lint_pass!(LargeStackArrays => [LARGE_STACK_ARRAYS]); impl<'tcx> LateLintPass<'tcx> for LargeStackArrays { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { if let ExprKind::Repeat(_, _) | ExprKind::Array(_) = expr.kind - && let ty::Array(element_type, cst) = cx.typeck_results().expr_ty(expr).kind() - && let ConstKind::Value(ty::ValTree::Leaf(element_count)) = cst.kind() - && let Ok(element_count) = element_count.try_to_target_usize(cx.tcx) - && let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes()) - && !cx.tcx.hir().parent_iter(expr.hir_id) - .any(|(_, node)| matches!(node, Node::Item(Item { kind: ItemKind::Static(..), .. }))) - && self.maximum_allowed_size < u128::from(element_count) * u128::from(element_size) { - span_lint_and_help( - cx, - LARGE_STACK_ARRAYS, - expr.span, - &format!( - "allocating a local array larger than {} bytes", - self.maximum_allowed_size - ), - None, - &format!( - "consider allocating on the heap with `vec!{}.into_boxed_slice()`", - snippet(cx, expr.span, "[...]") - ), - ); - } + && let ty::Array(element_type, cst) = cx.typeck_results().expr_ty(expr).kind() + && let ConstKind::Value(ty::ValTree::Leaf(element_count)) = cst.kind() + && let Ok(element_count) = element_count.try_to_target_usize(cx.tcx) + && let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes()) + && !cx.tcx.hir().parent_iter(expr.hir_id).any(|(_, node)| { + matches!( + node, + Node::Item(Item { + kind: ItemKind::Static(..), + .. + }) + ) + }) + && self.maximum_allowed_size < u128::from(element_count) * u128::from(element_size) + { + span_lint_and_help( + cx, + LARGE_STACK_ARRAYS, + expr.span, + &format!( + "allocating a local array larger than {} bytes", + self.maximum_allowed_size + ), + None, + &format!( + "consider allocating on the heap with `vec!{}.into_boxed_slice()`", + snippet(cx, expr.span, "[...]") + ), + ); + } } } diff --git a/src/tools/clippy/clippy_lints/src/large_stack_frames.rs b/src/tools/clippy/clippy_lints/src/large_stack_frames.rs index 1d28d7dd0..33636eb68 100644 --- a/src/tools/clippy/clippy_lints/src/large_stack_frames.rs +++ b/src/tools/clippy/clippy_lints/src/large_stack_frames.rs @@ -49,7 +49,7 @@ declare_clippy_lint! { /// ### Example /// This function creates four 500 KB arrays on the stack. Quite big but just small enough to not trigger `large_stack_arrays`. /// However, looking at the function as a whole, it's clear that this uses a lot of stack space. - /// ```rust + /// ```no_run /// struct QuiteLargeType([u8; 500_000]); /// fn foo() { /// // ... some function that uses a lot of stack space ... @@ -62,7 +62,7 @@ declare_clippy_lint! { /// /// Instead of doing this, allocate the arrays on the heap. /// This currently requires going through a `Vec` first and then converting it to a `Box`: - /// ```rust + /// ```no_run /// struct NotSoLargeType(Box<[u8]>); /// /// fn foo() { diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs index c06b35ca0..0f17d2676 100644 --- a/src/tools/clippy/clippy_lints/src/len_zero.rs +++ b/src/tools/clippy/clippy_lints/src/len_zero.rs @@ -15,7 +15,8 @@ use rustc_hir::{ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, AssocKind, FnSig, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::{Span, Spanned, Symbol}; +use rustc_span::{Span, Symbol}; +use rustc_span::source_map::Spanned; use rustc_span::symbol::sym; declare_clippy_lint! { @@ -181,8 +182,7 @@ impl<'tcx> LateLintPass<'tcx> for LenZero { let mut applicability = Applicability::MachineApplicable; let lit1 = peel_ref_operators(cx, lt.init); - let lit_str = - Sugg::hir_with_context(cx, lit1, lt.span.ctxt(), "_", &mut applicability).maybe_par(); + let lit_str = Sugg::hir_with_context(cx, lit1, lt.span.ctxt(), "_", &mut applicability).maybe_par(); span_lint_and_sugg( cx, @@ -288,18 +288,26 @@ enum LenOutput { } fn extract_future_output<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<&'tcx PathSegment<'tcx>> { - if let ty::Alias(_, alias_ty) = ty.kind() && - let Some(Node::Item(item)) = cx.tcx.hir().get_if_local(alias_ty.def_id) && - let Item { kind: ItemKind::OpaqueTy(opaque), .. } = item && - opaque.bounds.len() == 1 && - let GenericBound::LangItemTrait(LangItem::Future, _, _, generic_args) = &opaque.bounds[0] && - generic_args.bindings.len() == 1 && - let TypeBindingKind::Equality { - term: rustc_hir::Term::Ty(rustc_hir::Ty {kind: TyKind::Path(QPath::Resolved(_, path)), .. }), - } = &generic_args.bindings[0].kind && - path.segments.len() == 1 { - return Some(&path.segments[0]); - } + if let ty::Alias(_, alias_ty) = ty.kind() + && let Some(Node::Item(item)) = cx.tcx.hir().get_if_local(alias_ty.def_id) + && let Item { + kind: ItemKind::OpaqueTy(opaque), + .. + } = item + && opaque.bounds.len() == 1 + && let GenericBound::LangItemTrait(LangItem::Future, _, _, generic_args) = &opaque.bounds[0] + && generic_args.bindings.len() == 1 + && let TypeBindingKind::Equality { + term: + rustc_hir::Term::Ty(rustc_hir::Ty { + kind: TyKind::Path(QPath::Resolved(_, path)), + .. + }), + } = &generic_args.bindings[0].kind + && path.segments.len() == 1 + { + return Some(&path.segments[0]); + } None } diff --git a/src/tools/clippy/clippy_lints/src/let_underscore.rs b/src/tools/clippy/clippy_lints/src/let_underscore.rs index e7c875ab3..04f23a213 100644 --- a/src/tools/clippy/clippy_lints/src/let_underscore.rs +++ b/src/tools/clippy/clippy_lints/src/let_underscore.rs @@ -17,7 +17,7 @@ declare_clippy_lint! { /// expr /// /// ### Example - /// ```rust + /// ```no_run /// fn f() -> Result<u32, u32> { /// Ok(0) /// } @@ -69,7 +69,7 @@ declare_clippy_lint! { /// and ignore the resulting value. /// /// ### Example - /// ```rust + /// ```no_run /// async fn foo() -> Result<(), ()> { /// Ok(()) /// } @@ -77,7 +77,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # async fn context() { /// async fn foo() -> Result<(), ()> { /// Ok(()) @@ -107,14 +107,14 @@ declare_clippy_lint! { /// lints. /// /// ### Example - /// ```rust + /// ```no_run /// fn foo() -> Result<u32, ()> { /// Ok(123) /// } /// let _ = foo(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn foo() -> Result<u32, ()> { /// Ok(123) /// } @@ -159,14 +159,15 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { binding or dropping explicitly with `std::mem::drop`", ); } else if let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() - && implements_trait(cx, cx.typeck_results().expr_ty(init), future_trait_def_id, &[]) { + && implements_trait(cx, cx.typeck_results().expr_ty(init), future_trait_def_id, &[]) + { span_lint_and_help( cx, LET_UNDERSCORE_FUTURE, local.span, "non-binding `let` on a future", None, - "consider awaiting the future or dropping explicitly with `std::mem::drop`" + "consider awaiting the future or dropping explicitly with `std::mem::drop`", ); } else if is_must_use_ty(cx, cx.typeck_results().expr_ty(init)) { span_lint_and_help( @@ -203,17 +204,17 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { return; } - span_lint_and_help( + span_lint_and_help( cx, LET_UNDERSCORE_UNTYPED, local.span, "non-binding `let` without a type annotation", - Some( - Span::new(local.pat.span.hi(), - local.pat.span.hi() + BytePos(1), - local.pat.span.ctxt(), - local.pat.span.parent() - )), + Some(Span::new( + local.pat.span.hi(), + local.pat.span.hi() + BytePos(1), + local.pat.span.ctxt(), + local.pat.span.parent(), + )), "consider adding a type annotation", ); } diff --git a/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs b/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs index 4e9d77ea1..79d728a02 100644 --- a/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs +++ b/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs @@ -31,7 +31,7 @@ impl LateLintPass<'_> for UnderscoreTyped { if !in_external_macro(cx.tcx.sess, local.span); if let Some(ty) = local.ty; // Ensure that it has a type defined if let TyKind::Infer = &ty.kind; // that type is '_' - if local.span.ctxt() == ty.span.ctxt(); + if local.span.eq_ctxt(ty.span); then { // NOTE: Using `is_from_proc_macro` on `init` will require that it's initialized, // this doesn't. Alternatively, `WithSearchPat` can be implemented for `Ty` diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index 1271be2fd..ab978a677 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -50,10 +50,6 @@ extern crate clippy_utils; #[macro_use] extern crate declare_clippy_lint; -use std::io; -use std::path::PathBuf; - -use clippy_utils::msrvs::Msrv; use rustc_data_structures::fx::FxHashSet; use rustc_lint::{Lint, LintId}; use rustc_session::Session; @@ -121,7 +117,6 @@ mod empty_structs_with_brackets; mod endian_bytes; mod entry; mod enum_clike; -mod enum_variants; mod equatable_if_let; mod error_impl_error; mod escape; @@ -166,9 +161,11 @@ mod inline_fn_without_body; mod instant_subtraction; mod int_plus_one; mod invalid_upcast_comparisons; +mod item_name_repetitions; mod items_after_statements; mod items_after_test_module; mod iter_not_returning_iterator; +mod iter_without_into_iter; mod large_const_arrays; mod large_enum_variant; mod large_futures; @@ -190,6 +187,7 @@ mod manual_async_fn; mod manual_bits; mod manual_clamp; mod manual_float_methods; +mod manual_hash_one; mod manual_is_ascii_check; mod manual_let_else; mod manual_main_separator_str; @@ -359,10 +357,7 @@ mod zero_div_zero; mod zero_sized_map_values; // end lints modules, do not remove this comment, it’s used in `update_lints` -use crate::utils::conf::metadata::get_configuration_metadata; -use crate::utils::conf::TryConf; -pub use crate::utils::conf::{lookup_conf_file, Conf}; -use crate::utils::FindAll; +use clippy_config::{get_configuration_metadata, Conf}; /// Register all pre expansion lints /// @@ -372,65 +367,13 @@ use crate::utils::FindAll; /// level (i.e `#![cfg_attr(...)]`) will still be expanded even when using a pre-expansion pass. /// /// Used in `./src/driver.rs`. -pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore, sess: &Session, conf: &Conf) { +pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { // NOTE: Do not add any more pre-expansion passes. These should be removed eventually. - let msrv = Msrv::read(&conf.msrv, sess); - let msrv = move || msrv.clone(); + let msrv = || conf.msrv.clone(); store.register_pre_expansion_pass(move || Box::new(attrs::EarlyAttributes { msrv: msrv() })); } -#[doc(hidden)] -pub fn read_conf(sess: &Session, path: &io::Result<(Option<PathBuf>, Vec<String>)>) -> Conf { - if let Ok((_, warnings)) = path { - for warning in warnings { - sess.warn(warning.clone()); - } - } - let file_name = match path { - Ok((Some(path), _)) => path, - Ok((None, _)) => return Conf::default(), - Err(error) => { - sess.err(format!("error finding Clippy's configuration file: {error}")); - return Conf::default(); - }, - }; - - let TryConf { conf, errors, warnings } = utils::conf::read(sess, file_name); - // all conf errors are non-fatal, we just use the default conf in case of error - for error in errors { - if let Some(span) = error.span { - sess.span_err( - span, - format!("error reading Clippy's configuration file: {}", error.message), - ); - } else { - sess.err(format!( - "error reading Clippy's configuration file `{}`: {}", - file_name.display(), - error.message - )); - } - } - - for warning in warnings { - if let Some(span) = warning.span { - sess.span_warn( - span, - format!("error reading Clippy's configuration file: {}", warning.message), - ); - } else { - sess.warn(format!( - "error reading Clippy's configuration file `{}`: {}", - file_name.display(), - warning.message - )); - } - } - - conf -} - #[derive(Default)] struct RegistrationGroups { all: Vec<LintId>, @@ -516,16 +459,13 @@ pub fn explain(name: &str) -> i32 { if let Some(info) = declared_lints::LINTS.iter().find(|info| info.lint.name == target) { println!("{}", info.explanation); // Check if the lint has configuration - let mdconf = get_configuration_metadata(); - if let Some(config_vec_positions) = mdconf - .iter() - .find_all(|cconf| cconf.lints.contains(&info.lint.name_lower()[8..].to_owned())) - { - // If it has, print it + let mut mdconf = get_configuration_metadata(); + let name = name.to_ascii_lowercase(); + mdconf.retain(|cconf| cconf.lints.contains(&name)); + if !mdconf.is_empty() { println!("### Configuration for {}:\n", info.lint.name_lower()); - for position in config_vec_positions { - let conf = &mdconf[position]; - println!(" - {}: {} (default: {})", conf.name, conf.doc, conf.default); + for conf in mdconf { + println!("{conf}"); } } 0 @@ -556,7 +496,7 @@ fn register_categories(store: &mut rustc_lint::LintStore) { /// /// Used in `./src/driver.rs`. #[expect(clippy::too_many_lines)] -pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &Conf) { +pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &'static Conf) { register_removed_non_tool_lints(store); register_categories(store); @@ -573,7 +513,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: // all the internal lints #[cfg(feature = "internal")] { - store.register_early_pass(|| Box::new(utils::internal_lints::clippy_lints_internal::ClippyLintsInternal)); + store.register_early_pass(|| { + Box::new(utils::internal_lints::unsorted_clippy_utils_paths::UnsortedClippyUtilsPaths) + }); store.register_early_pass(|| Box::new(utils::internal_lints::produce_ice::ProduceIce)); store.register_late_pass(|_| Box::new(utils::internal_lints::collapsible_calls::CollapsibleCalls)); store.register_late_pass(|_| { @@ -658,8 +600,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(non_octal_unix_permissions::NonOctalUnixPermissions)); store.register_early_pass(|| Box::new(unnecessary_self_imports::UnnecessarySelfImports)); - let msrv = Msrv::read(&conf.msrv, sess); - let msrv = move || msrv.clone(); + let msrv = || conf.msrv.clone(); let avoid_breaking_exported_api = conf.avoid_breaking_exported_api; let allow_expect_in_tests = conf.allow_expect_in_tests; let allow_unwrap_in_tests = conf.allow_unwrap_in_tests; @@ -760,6 +701,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: too_many_arguments_threshold, too_many_lines_threshold, large_error_threshold, + avoid_breaking_exported_api, )) }); let doc_valid_idents = conf.doc_valid_idents.iter().cloned().collect::<FxHashSet<_>>(); @@ -804,7 +746,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: suppress_restriction_lint_in_const, )) }); - store.register_late_pass(|_| Box::new(non_copy_const::NonCopyConst)); + let ignore_interior_mutability = conf.ignore_interior_mutability.clone(); + store.register_late_pass(move |_| Box::new(non_copy_const::NonCopyConst::new(ignore_interior_mutability.clone()))); store.register_late_pass(|_| Box::new(ptr_offset_with_cast::PtrOffsetWithCast)); store.register_late_pass(|_| Box::new(redundant_clone::RedundantClone)); store.register_late_pass(|_| Box::new(slow_vector_initialization::SlowVectorInit)); @@ -849,10 +792,12 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: )) }); let enum_variant_name_threshold = conf.enum_variant_name_threshold; + let struct_field_name_threshold = conf.struct_field_name_threshold; let allow_private_module_inception = conf.allow_private_module_inception; store.register_late_pass(move |_| { - Box::new(enum_variants::EnumVariantNames::new( + Box::new(item_name_repetitions::ItemNameRepetitions::new( enum_variant_name_threshold, + struct_field_name_threshold, avoid_breaking_exported_api, allow_private_module_inception, )) @@ -1119,6 +1064,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: msrv(), )) }); + store.register_late_pass(move |_| Box::new(manual_hash_one::ManualHashOne::new(msrv()))); + store.register_late_pass(|_| Box::new(iter_without_into_iter::IterWithoutIntoIter)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs index 0004a150d..7517003be 100644 --- a/src/tools/clippy/clippy_lints/src/lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs @@ -20,7 +20,7 @@ use rustc_middle::hir::nested_filter as middle_nested_filter; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::def_id::LocalDefId; -use rustc_span::source_map::Span; +use rustc_span::Span; use rustc_span::symbol::{kw, Ident, Symbol}; declare_clippy_lint! { @@ -38,7 +38,7 @@ declare_clippy_lint! { /// are mentioned due to potential false positives. /// /// ### Example - /// ```rust + /// ```no_run /// // Unnecessary lifetime annotations /// fn in_and_out<'a>(x: &'a u8, y: u8) -> &'a u8 { /// x @@ -46,7 +46,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// fn elided(x: &u8, y: u8) -> &u8 { /// x /// } @@ -69,7 +69,7 @@ declare_clippy_lint! { /// them leads to more readable code. /// /// ### Example - /// ```rust + /// ```no_run /// // unnecessary lifetimes /// fn unused_lifetime<'a>(x: u8) { /// // .. @@ -77,7 +77,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// fn no_lifetime(x: u8) { /// // ... /// } @@ -517,9 +517,11 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> { fn visit_poly_trait_ref(&mut self, poly_tref: &'tcx PolyTraitRef<'tcx>) { let trait_ref = &poly_tref.trait_ref; - if let Some(id) = trait_ref.trait_def_id() && lang_items::FN_TRAITS.iter().any(|&item| { - self.cx.tcx.lang_items().get(item) == Some(id) - }) { + if let Some(id) = trait_ref.trait_def_id() + && lang_items::FN_TRAITS + .iter() + .any(|&item| self.cx.tcx.lang_items().get(item) == Some(id)) + { let mut sub_visitor = RefVisitor::new(self.cx); sub_visitor.visit_trait_ref(trait_ref); self.nested_elision_site_lts.append(&mut sub_visitor.all_lts()); diff --git a/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs b/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs index 49425ff0a..0a5f5a80c 100644 --- a/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs +++ b/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::ty::match_type; +use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{is_diag_item_method, is_trait_method, match_def_path, path_to_local_id, paths}; use rustc_errors::Applicability; use rustc_hir::{Body, Closure, Expr, ExprKind}; @@ -34,7 +34,7 @@ declare_clippy_lint! { /// successful results, using `map_while()` would stop at the first error. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::{fs::File, io::{self, BufRead, BufReader}}; /// # let _ = || -> io::Result<()> { /// let mut lines = BufReader::new(File::open("some-path")?).lines().filter_map(Result::ok); @@ -43,7 +43,7 @@ declare_clippy_lint! { /// # Ok(()) }; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # use std::{fs::File, io::{self, BufRead, BufReader}}; /// # let _ = || -> io::Result<()> { /// let mut lines = BufReader::new(File::open("some-path")?).lines().map_while(Result::ok); @@ -59,41 +59,56 @@ declare_lint_pass!(LinesFilterMapOk => [LINES_FILTER_MAP_OK]); impl LateLintPass<'_> for LinesFilterMapOk { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { - if let ExprKind::MethodCall(fm_method, fm_receiver, [fm_arg], fm_span) = expr.kind && - is_trait_method(cx, expr, sym::Iterator) && - (fm_method.ident.as_str() == "filter_map" || fm_method.ident.as_str() == "flat_map") && - match_type(cx, cx.typeck_results().expr_ty_adjusted(fm_receiver), &paths::STD_IO_LINES) + if let ExprKind::MethodCall(fm_method, fm_receiver, [fm_arg], fm_span) = expr.kind + && is_trait_method(cx, expr, sym::Iterator) + && (fm_method.ident.as_str() == "filter_map" || fm_method.ident.as_str() == "flat_map") + && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty_adjusted(fm_receiver), sym::IoLines) { let lint = match &fm_arg.kind { // Detect `Result::ok` - ExprKind::Path(qpath) => - cx.qpath_res(qpath, fm_arg.hir_id).opt_def_id().map(|did| - match_def_path(cx, did, &paths::CORE_RESULT_OK_METHOD)).unwrap_or_default(), + ExprKind::Path(qpath) => cx + .qpath_res(qpath, fm_arg.hir_id) + .opt_def_id() + .map(|did| match_def_path(cx, did, &paths::CORE_RESULT_OK_METHOD)) + .unwrap_or_default(), // Detect `|x| x.ok()` - ExprKind::Closure(Closure { body, .. }) => - if let Body { params: [param], value, .. } = cx.tcx.hir().body(*body) && - let ExprKind::MethodCall(method, receiver, [], _) = value.kind && - path_to_local_id(receiver, param.pat.hir_id) && - let Some(method_did) = cx.typeck_results().type_dependent_def_id(value.hir_id) + ExprKind::Closure(Closure { body, .. }) => { + if let Body { + params: [param], value, .. + } = cx.tcx.hir().body(*body) + && let ExprKind::MethodCall(method, receiver, [], _) = value.kind + && path_to_local_id(receiver, param.pat.hir_id) + && let Some(method_did) = cx.typeck_results().type_dependent_def_id(value.hir_id) { is_diag_item_method(cx, method_did, sym::Result) && method.ident.as_str() == "ok" } else { false } + }, _ => false, }; if lint { - span_lint_and_then(cx, + span_lint_and_then( + cx, LINES_FILTER_MAP_OK, fm_span, - &format!("`{}()` will run forever if the iterator repeatedly produces an `Err`", fm_method.ident), + &format!( + "`{}()` will run forever if the iterator repeatedly produces an `Err`", + fm_method.ident + ), |diag| { diag.span_note( fm_receiver.span, "this expression returning a `std::io::Lines` may produce an infinite number of `Err` in case of a read error"); - diag.span_suggestion(fm_span, "replace with", "map_while(Result::ok)", Applicability::MaybeIncorrect); - }); - } + diag.span_suggestion( + fm_span, + "replace with", + "map_while(Result::ok)", + Applicability::MaybeIncorrect, + ); + }, + ); + } } } } diff --git a/src/tools/clippy/clippy_lints/src/literal_representation.rs b/src/tools/clippy/clippy_lints/src/literal_representation.rs index 09ca03173..2c14bb72a 100644 --- a/src/tools/clippy/clippy_lints/src/literal_representation.rs +++ b/src/tools/clippy/clippy_lints/src/literal_representation.rs @@ -23,14 +23,14 @@ declare_clippy_lint! { /// Reading long numbers is difficult without separators. /// /// ### Example - /// ```rust + /// ```no_run /// # let _: u64 = /// 61864918973511 /// # ; /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let _: u64 = /// 61_864_918_973_511 /// # ; @@ -73,14 +73,14 @@ declare_clippy_lint! { /// grouped digits. /// /// ### Example - /// ```rust + /// ```no_run /// # let _: u64 = /// 618_64_9189_73_511 /// # ; /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let _: u64 = /// 61_864_918_973_511 /// # ; @@ -100,7 +100,7 @@ declare_clippy_lint! { /// Negatively impacts readability. /// /// ### Example - /// ```rust + /// ```no_run /// let x: u32 = 0xFFF_FFF; /// let y: u8 = 0b01_011_101; /// ``` @@ -120,7 +120,7 @@ declare_clippy_lint! { /// Negatively impacts readability. /// /// ### Example - /// ```rust + /// ```no_run /// let x: u64 = 6186491_8973511; /// ``` #[clippy::version = "pre 1.29.0"] diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs index 6ab256ef0..1c2b7a169 100644 --- a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs +++ b/src/tools/clippy/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, make_normalized_projection, @@ -113,7 +113,9 @@ fn is_ref_iterable<'tcx>( let typeck = cx.typeck_results(); if let Some(trait_id) = cx.tcx.get_diagnostic_item(sym::IntoIterator) && let Some(fn_id) = typeck.type_dependent_def_id(call_expr.hir_id) - && let sig = cx.tcx.liberate_late_bound_regions(fn_id, cx.tcx.fn_sig(fn_id).skip_binder()) + && let sig = cx + .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, &[]) @@ -131,8 +133,9 @@ fn is_ref_iterable<'tcx>( return Some((AdjustKind::None, self_ty)); } - let res_ty = cx.tcx.erase_regions(EarlyBinder::bind(req_res_ty) - .instantiate(cx.tcx, typeck.node_args(call_expr.hir_id))); + let res_ty = cx + .tcx + .erase_regions(EarlyBinder::bind(req_res_ty).instantiate(cx.tcx, typeck.node_args(call_expr.hir_id))); let mutbl = if let ty::Ref(_, _, mutbl) = *req_self_ty.kind() { Some(mutbl) } else { @@ -157,7 +160,7 @@ fn is_ref_iterable<'tcx>( let self_ty = if mutbl.is_mut() { self_ty } else { - Ty::new_ref(cx.tcx,region, TypeAndMut { ty, mutbl }) + Ty::new_ref(cx.tcx, region, TypeAndMut { ty, mutbl }) }; if implements_trait(cx, self_ty, trait_id, &[]) && let Some(ty) = @@ -172,10 +175,7 @@ fn is_ref_iterable<'tcx>( && !self_ty.is_ref() { // Attempt to borrow - let self_ty = Ty::new_ref(cx.tcx,cx.tcx.lifetimes.re_erased, TypeAndMut { - ty: self_ty, - mutbl, - }); + let self_ty = Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, TypeAndMut { ty: 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]) && ty == res_ty @@ -187,12 +187,14 @@ fn is_ref_iterable<'tcx>( match adjustments { [] => Some((AdjustKind::None, self_ty)), &[ - Adjustment { kind: Adjust::Deref(_), ..}, + Adjustment { + kind: Adjust::Deref(_), .. + }, Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(_, mutbl)), target, }, - .. + .., ] => { if enforce_iter_loop_reborrow && target != self_ty @@ -205,8 +207,14 @@ fn is_ref_iterable<'tcx>( } else { None } - } - &[Adjustment { kind: Adjust::Deref(_), target }, ..] => { + }, + &[ + Adjustment { + kind: Adjust::Deref(_), + target, + }, + .., + ] => { if is_copy(cx, target) && implements_trait(cx, target, trait_id, &[]) && let Some(ty) = @@ -217,13 +225,13 @@ fn is_ref_iterable<'tcx>( } else { None } - } + }, &[ Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(_, mutbl)), target, }, - .. + .., ] => { if self_ty.is_ref() && implements_trait(cx, target, trait_id, &[]) @@ -235,7 +243,7 @@ fn is_ref_iterable<'tcx>( } else { None } - } + }, _ => None, } } else { diff --git a/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs b/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs index ed620460d..94c951fc1 100644 --- a/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs +++ b/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs @@ -1,9 +1,8 @@ use super::FOR_KV_MAP; use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; use clippy_utils::source::snippet; -use clippy_utils::sugg; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::visitors::is_local_used; +use clippy_utils::{pat_is_wild, sugg}; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Pat, PatKind}; use rustc_lint::LateContext; use rustc_middle::ty; @@ -55,12 +54,3 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, arg: &'tcx } } } - -/// Returns `true` if the pattern is a `PatWild` or an ident prefixed with `_`. -fn pat_is_wild<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx PatKind<'_>, body: &'tcx Expr<'_>) -> bool { - match *pat { - PatKind::Wild => true, - PatKind::Binding(_, id, ident, None) if ident.as_str().starts_with('_') => !is_local_used(cx, body, id), - _ => false, - } -} diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_find.rs b/src/tools/clippy/clippy_lints/src/loops/manual_find.rs index 0aaa66e6b..a9a9058c9 100644 --- a/src/tools/clippy/clippy_lints/src/loops/manual_find.rs +++ b/src/tools/clippy/clippy_lints/src/loops/manual_find.rs @@ -10,7 +10,7 @@ use rustc_hir::def::Res; use rustc_hir::lang_items::LangItem; use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Node, Pat, PatKind, Stmt, StmtKind}; use rustc_lint::LateContext; -use rustc_span::source_map::Span; +use rustc_span::Span; pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs b/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs index 559a2c03f..124a35f8f 100644 --- a/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs +++ b/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs @@ -9,7 +9,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Expr, Pat, PatKind}; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::source_map::Span; +use rustc_span::Span; /// Check for unnecessary `if let` usage in a for loop where only the `Some` or `Ok` variant of the /// iterator element is used. diff --git a/src/tools/clippy/clippy_lints/src/loops/mod.rs b/src/tools/clippy/clippy_lints/src/loops/mod.rs index 1fb16adad..67c80fb83 100644 --- a/src/tools/clippy/clippy_lints/src/loops/mod.rs +++ b/src/tools/clippy/clippy_lints/src/loops/mod.rs @@ -14,17 +14,18 @@ mod needless_range_loop; mod never_loop; mod same_item_push; mod single_element_loop; +mod unused_enumerate_index; mod utils; mod while_immutable_condition; mod while_let_loop; mod while_let_on_iterator; +use clippy_config::msrvs::Msrv; use clippy_utils::higher; -use clippy_utils::msrvs::Msrv; use rustc_hir::{Expr, ExprKind, LoopSource, Pat}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::source_map::Span; +use rustc_span::Span; use utils::{make_iterator_snippet, IncrementVisitor, InitializeVisitor}; declare_clippy_lint! { @@ -36,7 +37,7 @@ declare_clippy_lint! { /// It is not as fast as a memcpy. /// /// ### Example - /// ```rust + /// ```no_run /// # let src = vec![1]; /// # let mut dst = vec![0; 65]; /// for i in 0..src.len() { @@ -45,7 +46,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let src = vec![1]; /// # let mut dst = vec![0; 65]; /// dst[64..(src.len() + 64)].clone_from_slice(&src[..]); @@ -67,7 +68,7 @@ declare_clippy_lint! { /// the bounds check that is done when indexing. /// /// ### Example - /// ```rust + /// ```no_run /// let vec = vec!['a', 'b', 'c']; /// for i in 0..vec.len() { /// println!("{}", vec[i]); @@ -75,7 +76,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let vec = vec!['a', 'b', 'c']; /// for i in vec { /// println!("{}", i); @@ -100,7 +101,7 @@ declare_clippy_lint! { /// types. /// /// ### Example - /// ```rust + /// ```no_run /// // with `y` a `Vec` or slice: /// # let y = vec![1]; /// for x in y.iter() { @@ -109,7 +110,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let y = vec![1]; /// for x in &y { /// // .. @@ -130,7 +131,7 @@ declare_clippy_lint! { /// Readability. /// /// ### Example - /// ```rust + /// ```no_run /// # let y = vec![1]; /// // with `y` a `Vec` or slice: /// for x in y.into_iter() { @@ -138,7 +139,7 @@ declare_clippy_lint! { /// } /// ``` /// can be rewritten to - /// ```rust + /// ```no_run /// # let y = vec![1]; /// for x in y { /// // .. @@ -217,7 +218,7 @@ declare_clippy_lint! { /// declutters the code and may be faster in some instances. /// /// ### Example - /// ```rust + /// ```no_run /// # let v = vec![1]; /// # fn bar(bar: usize, baz: usize) {} /// let mut i = 0; @@ -228,7 +229,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let v = vec![1]; /// # fn bar(bar: usize, baz: usize) {} /// for (i, item) in v.iter().enumerate() { bar(i, *item); } @@ -339,7 +340,7 @@ declare_clippy_lint! { /// code. /// /// ### Example - /// ```rust + /// ```no_run /// loop { /// ..; /// break; @@ -362,7 +363,7 @@ declare_clippy_lint! { /// False positive when mutation is followed by a `break`, but the `break` is not immediately /// after the mutation: /// - /// ```rust + /// ```no_run /// let mut x = 5; /// for _ in 0..x { /// x += 1; // x is a range bound that is mutated @@ -374,7 +375,7 @@ declare_clippy_lint! { /// False positive on nested loops ([#6072](https://github.com/rust-lang/rust-clippy/issues/6072)) /// /// ### Example - /// ```rust + /// ```no_run /// let mut foo = 42; /// for i in 0..foo { /// foo -= 1; @@ -402,7 +403,7 @@ declare_clippy_lint! { /// in the condition and only `Upvar` `b` gets mutated in the body, the lint will not trigger. /// /// ### Example - /// ```rust + /// ```no_run /// let i = 0; /// while i > 10 { /// println!("let me loop forever!"); @@ -425,7 +426,7 @@ declare_clippy_lint! { /// have better performance. /// /// ### Example - /// ```rust + /// ```no_run /// let item1 = 2; /// let item2 = 3; /// let mut vec: Vec<u8> = Vec::new(); @@ -438,7 +439,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let item1 = 2; /// let item2 = 3; /// let mut vec: Vec<u8> = vec![item1; 20]; @@ -459,7 +460,7 @@ declare_clippy_lint! { /// single element. /// /// ### Example - /// ```rust + /// ```no_run /// let item1 = 2; /// for item in &[item1] { /// println!("{}", item); @@ -467,7 +468,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let item1 = 2; /// let item = &item1; /// println!("{}", item); @@ -489,7 +490,7 @@ declare_clippy_lint! { /// /// ### Example /// - /// ```rust + /// ```no_run /// let x = vec![Some(1), Some(2), Some(3)]; /// for n in x { /// if let Some(n) = n { @@ -498,7 +499,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let x = vec![Some(1), Some(2), Some(3)]; /// for n in x.into_iter().flatten() { /// println!("{}", n); @@ -555,7 +556,7 @@ declare_clippy_lint! { /// /// ### Example /// - /// ```rust + /// ```no_run /// fn example(arr: Vec<i32>) -> Option<i32> { /// for el in arr { /// if el == 1 { @@ -566,7 +567,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn example(arr: Vec<i32>) -> Option<i32> { /// arr.into_iter().find(|&el| el == 1) /// } @@ -579,6 +580,33 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does + /// Checks for uses of the `enumerate` method where the index is unused (`_`) + /// + /// ### Why is this bad? + /// The index from `.enumerate()` is immediately dropped. + /// + /// ### Example + /// ```rust + /// let v = vec![1, 2, 3, 4]; + /// for (_, x) in v.iter().enumerate() { + /// println!("{x}"); + /// } + /// ``` + /// Use instead: + /// ```rust + /// let v = vec![1, 2, 3, 4]; + /// for x in v.iter() { + /// println!("{x}"); + /// } + /// ``` + #[clippy::version = "1.75.0"] + pub UNUSED_ENUMERATE_INDEX, + style, + "using `.enumerate()` and immediately dropping the index" +} + +declare_clippy_lint! { + /// ### What it does /// Looks for loops that check for emptiness of a `Vec` in the condition and pop an element /// in the body as a separate operation. /// @@ -587,7 +615,7 @@ declare_clippy_lint! { /// pattern matching on the return value of `Vec::pop()`. /// /// ### Example - /// ```rust + /// ```no_run /// let mut numbers = vec![1, 2, 3, 4, 5]; /// while !numbers.is_empty() { /// let number = numbers.pop().unwrap(); @@ -595,7 +623,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let mut numbers = vec![1, 2, 3, 4, 5]; /// while let Some(number) = numbers.pop() { /// // use `number` @@ -619,6 +647,7 @@ impl Loops { } } } + impl_lint_pass!(Loops => [ MANUAL_MEMCPY, MANUAL_FLATTEN, @@ -638,7 +667,8 @@ impl_lint_pass!(Loops => [ SINGLE_ELEMENT_LOOP, MISSING_SPIN_LOOP, MANUAL_FIND, - MANUAL_WHILE_LET_SOME + MANUAL_WHILE_LET_SOME, + UNUSED_ENUMERATE_INDEX, ]); impl<'tcx> LateLintPass<'tcx> for Loops { @@ -717,6 +747,7 @@ impl Loops { same_item_push::check(cx, pat, arg, body, expr); manual_flatten::check(cx, pat, arg, body, span); manual_find::check(cx, pat, arg, body, span, expr); + unused_enumerate_index::check(cx, pat, arg, body); } fn check_for_loop_arg(&self, cx: &LateContext<'_>, _: &Pat<'_>, arg: &Expr<'_>) { diff --git a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs index b83d148b5..2c12d9582 100644 --- a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs +++ b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs @@ -9,7 +9,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty; -use rustc_span::source_map::Span; +use rustc_span::Span; pub(super) fn check(cx: &LateContext<'_>, arg: &Expr<'_>, body: &Expr<'_>) { if_chain! { diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs index 3d8a4cd94..cc054cb46 100644 --- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs @@ -271,9 +271,9 @@ fn never_loop_expr<'tcx>( NeverLoopResult::Normal } }); - if let NeverLoopResult::Diverging = result && - let Some(macro_call) = root_macro_call_first_node(cx, expr) && - let Some(sym::todo_macro) = cx.tcx.get_diagnostic_name(macro_call.def_id) + if let NeverLoopResult::Diverging = result + && let Some(macro_call) = root_macro_call_first_node(cx, expr) + && let Some(sym::todo_macro) = cx.tcx.get_diagnostic_name(macro_call.def_id) { // We return MayContinueMainLoop here because we treat `todo!()` // as potentially containing any code, including a continue of the main loop. diff --git a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs index f7b3b2358..5fffb27cd 100644 --- a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs +++ b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs @@ -185,7 +185,7 @@ fn get_vec_push<'tcx>( if let StmtKind::Semi(semi_stmt) = &stmt.kind; if let ExprKind::MethodCall(path, self_expr, args, _) = &semi_stmt.kind; // Figure out the parameters for the method call - if let Some(pushed_item) = args.get(0); + if let Some(pushed_item) = args.first(); // Check that the method being called is push() on a Vec if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym::Vec); if path.ident.name.as_str() == "push"; diff --git a/src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs b/src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs new file mode 100644 index 000000000..dd7fae79d --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs @@ -0,0 +1,62 @@ +use super::UNUSED_ENUMERATE_INDEX; +use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; +use clippy_utils::source::snippet; +use clippy_utils::{pat_is_wild, sugg}; +use rustc_hir::def::DefKind; +use rustc_hir::{Expr, ExprKind, Pat, PatKind}; +use rustc_lint::LateContext; +use rustc_middle::ty; + +/// Checks for the `UNUSED_ENUMERATE_INDEX` lint. +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, arg: &'tcx Expr<'_>, body: &'tcx Expr<'_>) { + let PatKind::Tuple([index, elem], _) = pat.kind else { + return; + }; + + let ExprKind::MethodCall(_method, self_arg, [], _) = arg.kind else { + return; + }; + + let ty = cx.typeck_results().expr_ty(arg); + + if !pat_is_wild(cx, &index.kind, body) { + return; + } + + let name = match *ty.kind() { + ty::Adt(base, _substs) => cx.tcx.def_path_str(base.did()), + _ => return, + }; + + if name != "std::iter::Enumerate" && name != "core::iter::Enumerate" { + return; + } + + let Some((DefKind::AssocFn, call_id)) = cx.typeck_results().type_dependent_def(arg.hir_id) else { + return; + }; + + let call_name = cx.tcx.def_path_str(call_id); + + if call_name != "std::iter::Iterator::enumerate" && call_name != "core::iter::Iterator::enumerate" { + return; + } + + span_lint_and_then( + cx, + UNUSED_ENUMERATE_INDEX, + arg.span, + "you seem to use `.enumerate()` and immediately discard the index", + |diag| { + let base_iter = sugg::Sugg::hir(cx, self_arg, "base iter"); + multispan_sugg( + diag, + "remove the `.enumerate()` call", + vec![ + (pat.span, snippet(cx, elem.span, "..").into_owned()), + (arg.span, base_iter.to_string()), + ], + ); + }, + ); +} diff --git a/src/tools/clippy/clippy_lints/src/manual_assert.rs b/src/tools/clippy/clippy_lints/src/manual_assert.rs index 45ea5aab4..9a3da975f 100644 --- a/src/tools/clippy/clippy_lints/src/manual_assert.rs +++ b/src/tools/clippy/clippy_lints/src/manual_assert.rs @@ -16,14 +16,14 @@ declare_clippy_lint! { /// `assert!` is simpler than `if`-then-`panic!`. /// /// ### Example - /// ```rust + /// ```no_run /// let sad_people: Vec<&str> = vec![]; /// if !sad_people.is_empty() { /// panic!("there are sad people: {:?}", sad_people); /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let sad_people: Vec<&str> = vec![]; /// assert!(sad_people.is_empty(), "there are sad people: {:?}", sad_people); /// ``` @@ -64,7 +64,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualAssert { }; let cond_sugg = sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_par(); let sugg = format!("assert!({not}{cond_sugg}, {format_args_snip});"); - // we show to the user the suggestion without the comments, but when applying the fix, include the comments in the block + // we show to the user the suggestion without the comments, but when applying the fix, include the + // comments in the block span_lint_and_then( cx, MANUAL_ASSERT, @@ -77,16 +78,11 @@ impl<'tcx> LateLintPass<'tcx> for ManualAssert { expr.span.shrink_to_lo(), "add comments back", comments, - applicability + applicability, ); } - diag.span_suggestion( - expr.span, - "try instead", - sugg, - applicability - ); - } + diag.span_suggestion(expr.span, "try instead", sugg, applicability); + }, ); } } diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs index 577bc1d66..998de38a9 100644 --- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs +++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs @@ -4,7 +4,7 @@ use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{ - AsyncGeneratorKind, Block, Body, Closure, Expr, ExprKind, FnDecl, FnRetTy, GeneratorKind, GenericArg, GenericBound, + Block, Body, Closure, CoroutineKind, CoroutineSource, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, GenericBound, ImplItem, Item, ItemKind, LifetimeName, Node, Term, TraitRef, Ty, TyKind, TypeBindingKind, }; use rustc_lint::{LateContext, LateLintPass}; @@ -20,13 +20,13 @@ declare_clippy_lint! { /// It's more idiomatic to use the dedicated syntax. /// /// ### Example - /// ```rust + /// ```no_run /// use std::future::Future; /// /// fn foo() -> impl Future<Output = i32> { async { 42 } } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// async fn foo() -> i32 { 42 } /// ``` #[clippy::version = "1.45.0"] @@ -188,7 +188,7 @@ fn desugared_async_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) .. } = block_expr; let closure_body = cx.tcx.hir().body(body); - if closure_body.generator_kind == Some(GeneratorKind::Async(AsyncGeneratorKind::Block)); + if closure_body.coroutine_kind == Some(CoroutineKind::Async(CoroutineSource::Block)); then { return Some(closure_body); } diff --git a/src/tools/clippy/clippy_lints/src/manual_bits.rs b/src/tools/clippy/clippy_lints/src/manual_bits.rs index 6c7c57ba1..cd614c895 100644 --- a/src/tools/clippy/clippy_lints/src/manual_bits.rs +++ b/src/tools/clippy/clippy_lints/src/manual_bits.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_with_context; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -20,11 +20,11 @@ declare_clippy_lint! { /// Can be written as the shorter `T::BITS`. /// /// ### Example - /// ```rust + /// ```no_run /// std::mem::size_of::<usize>() * 8; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// usize::BITS as usize; /// ``` #[clippy::version = "1.60.0"] @@ -103,9 +103,9 @@ fn get_size_of_ty<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option< if let ExprKind::Path(ref count_func_qpath) = count_func.kind; if let QPath::Resolved(_, count_func_path) = count_func_qpath; - if let Some(segment_zero) = count_func_path.segments.get(0); + if let Some(segment_zero) = count_func_path.segments.first(); if let Some(args) = segment_zero.args; - if let Some(GenericArg::Type(real_ty)) = args.args.get(0); + if let Some(GenericArg::Type(real_ty)) = args.args.first(); if let Some(def_id) = cx.qpath_res(count_func_qpath, count_func.hir_id).opt_def_id(); if cx.tcx.is_diagnostic_item(sym::mem_size_of, def_id); diff --git a/src/tools/clippy/clippy_lints/src/manual_clamp.rs b/src/tools/clippy/clippy_lints/src/manual_clamp.rs index e75666e61..09c90e38e 100644 --- a/src/tools/clippy/clippy_lints/src/manual_clamp.rs +++ b/src/tools/clippy/clippy_lints/src/manual_clamp.rs @@ -1,6 +1,6 @@ +use clippy_config::msrvs::{self, Msrv}; 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; @@ -38,7 +38,7 @@ declare_clippy_lint! { /// PR](https://github.com/rust-lang/rust-clippy/pull/9484#issuecomment-1278922613). /// /// ### Examples - /// ```rust + /// ```no_run /// # let (input, min, max) = (0, -2, 1); /// if input > max { /// max @@ -50,13 +50,13 @@ declare_clippy_lint! { /// # ; /// ``` /// - /// ```rust + /// ```no_run /// # let (input, min, max) = (0, -2, 1); /// input.max(min).min(max) /// # ; /// ``` /// - /// ```rust + /// ```no_run /// # let (input, min, max) = (0, -2, 1); /// match input { /// x if x > max => max, @@ -66,14 +66,14 @@ declare_clippy_lint! { /// # ; /// ``` /// - /// ```rust + /// ```no_run /// # let (input, min, max) = (0, -2, 1); /// let mut x = input; /// if x < min { x = min; } /// if x > max { x = max; } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # let (input, min, max) = (0, -2, 1); /// input.clamp(min, max) /// # ; @@ -207,7 +207,7 @@ impl TypeClampability { /// Targets patterns like /// -/// ``` +/// ```no_run /// # let (input, min, max) = (0, -3, 12); /// /// if input < min { @@ -225,11 +225,11 @@ fn is_if_elseif_else_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx then, r#else: Some(else_if), }) = If::hir(expr) - && let Some(If { - cond: else_if_cond, - then: else_if_then, - r#else: Some(else_body), - }) = If::hir(peel_blocks(else_if)) + && let Some(If { + cond: else_if_cond, + then: else_if_then, + r#else: Some(else_body), + }) = If::hir(peel_blocks(else_if)) { let params = is_clamp_meta_pattern( cx, @@ -256,7 +256,7 @@ fn is_if_elseif_else_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx /// Targets patterns like /// -/// ``` +/// ```no_run /// # let (input, min_value, max_value) = (0, -3, 12); /// /// input.max(min_value).min(max_value) @@ -275,7 +275,12 @@ fn is_max_min_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> O _ => return None, }; Some(ClampSuggestion { - params: InputMinMax { input, min, max, is_float }, + params: InputMinMax { + input, + min, + max, + is_float, + }, span: expr.span, make_assignment: None, hir_with_ignore_attr: None, @@ -287,7 +292,7 @@ fn is_max_min_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> O /// Targets patterns like /// -/// ``` +/// ```no_run /// # let (input, min_value, max_value) = (0, -3, 12); /// # use std::cmp::{max, min}; /// min(max(input, min_value), max_value) @@ -346,11 +351,16 @@ fn is_call_max_min_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) ("max", "min") => (inner_arg, outer_arg), _ => return None, } - } + }, _ => return None, }; Some(ClampSuggestion { - params: InputMinMax { input, min, max, is_float }, + params: InputMinMax { + input, + min, + max, + is_float, + }, span, make_assignment: None, hir_with_ignore_attr: None, @@ -369,7 +379,7 @@ fn is_call_max_min_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) /// Targets patterns like /// -/// ``` +/// ```no_run /// # let (input, min, max) = (0, -3, 12); /// /// match input { @@ -384,7 +394,8 @@ fn is_match_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Opt // Find possible min/max branches let minmax_values = |a: &'tcx Arm<'tcx>| { if let PatKind::Binding(_, var_hir_id, _, None) = &a.pat.kind - && let Some(Guard::If(e)) = a.guard { + && let Some(Guard::If(e)) = a.guard + { Some((e, var_hir_id, a.body)) } else { None @@ -428,7 +439,7 @@ fn is_match_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Opt /// Targets patterns like /// -/// ``` +/// ```no_run /// # let (input, min, max) = (0, -3, 12); /// /// let mut x = input; @@ -441,18 +452,20 @@ fn is_two_if_pattern<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) -> .filter_map(|(maybe_set_first, maybe_set_second)| { if let StmtKind::Expr(first_expr) = *maybe_set_first && let StmtKind::Expr(second_expr) = *maybe_set_second - && let Some(If { cond: first_cond, then: first_then, r#else: None }) = If::hir(first_expr) - && let Some(If { cond: second_cond, then: second_then, r#else: None }) = If::hir(second_expr) - && let ExprKind::Assign( - maybe_input_first_path, - maybe_min_max_first, - _ - ) = peel_blocks_with_stmt(first_then).kind - && let ExprKind::Assign( - maybe_input_second_path, - maybe_min_max_second, - _ - ) = peel_blocks_with_stmt(second_then).kind + && let Some(If { + cond: first_cond, + then: first_then, + r#else: None, + }) = If::hir(first_expr) + && let Some(If { + cond: second_cond, + then: second_then, + r#else: None, + }) = If::hir(second_expr) + && let ExprKind::Assign(maybe_input_first_path, maybe_min_max_first, _) = + peel_blocks_with_stmt(first_then).kind + && let ExprKind::Assign(maybe_input_second_path, maybe_min_max_second, _) = + peel_blocks_with_stmt(second_then).kind && eq_expr_value(cx, maybe_input_first_path, maybe_input_second_path) && let Some(first_bin) = BinaryOp::new(first_cond) && let Some(second_bin) = BinaryOp::new(second_cond) @@ -462,7 +475,7 @@ fn is_two_if_pattern<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) -> &second_bin, maybe_min_max_first, maybe_min_max_second, - None + None, ) { Some(ClampSuggestion { @@ -485,7 +498,7 @@ fn is_two_if_pattern<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) -> /// Targets patterns like /// -/// ``` +/// ```no_run /// # let (mut input, min, max) = (0, -3, 12); /// /// if input < min { @@ -505,16 +518,9 @@ fn is_if_elseif_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> then: else_if_then, r#else: None, }) = If::hir(peel_blocks(else_if)) - && let ExprKind::Assign( - maybe_input_first_path, - maybe_min_max_first, - _ - ) = peel_blocks_with_stmt(then).kind - && let ExprKind::Assign( - maybe_input_second_path, - maybe_min_max_second, - _ - ) = peel_blocks_with_stmt(else_if_then).kind + && let ExprKind::Assign(maybe_input_first_path, maybe_min_max_first, _) = peel_blocks_with_stmt(then).kind + && let ExprKind::Assign(maybe_input_second_path, maybe_min_max_second, _) = + peel_blocks_with_stmt(else_if_then).kind { let params = is_clamp_meta_pattern( cx, diff --git a/src/tools/clippy/clippy_lints/src/manual_float_methods.rs b/src/tools/clippy/clippy_lints/src/manual_float_methods.rs index 88db7ae6a..f923e0ac8 100644 --- a/src/tools/clippy/clippy_lints/src/manual_float_methods.rs +++ b/src/tools/clippy/clippy_lints/src/manual_float_methods.rs @@ -17,16 +17,16 @@ declare_clippy_lint! { /// The method `is_infinite` is shorter and more readable. /// /// ### Example - /// ```rust + /// ```no_run /// # let x = 1.0f32; /// if x == f32::INFINITY || x == f32::NEG_INFINITY {} /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # let x = 1.0f32; /// if x.is_infinite() {} /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub MANUAL_IS_INFINITE, style, "use dedicated method to check if a float is infinite" @@ -40,18 +40,18 @@ declare_clippy_lint! { /// The method `is_finite` is shorter and more readable. /// /// ### Example - /// ```rust + /// ```no_run /// # let x = 1.0f32; /// if x != f32::INFINITY && x != f32::NEG_INFINITY {} /// if x.abs() < f32::INFINITY {} /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # let x = 1.0f32; /// if x.is_finite() {} /// if x.is_finite() {} /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub MANUAL_IS_FINITE, style, "use dedicated method to check if a float is finite" @@ -85,7 +85,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods { if !in_external_macro(cx.sess(), expr.span) && ( matches!(cx.tcx.constness(cx.tcx.hir().enclosing_body_owner(expr.hir_id)), Constness::NotConst) - || cx.tcx.features().active(sym!(const_float_classify)) + || cx.tcx.features().declared(sym!(const_float_classify)) ) && let ExprKind::Binary(kind, lhs, rhs) = expr.kind && let ExprKind::Binary(lhs_kind, lhs_lhs, lhs_rhs) = lhs.kind && let ExprKind::Binary(rhs_kind, rhs_lhs, rhs_rhs) = rhs.kind @@ -105,7 +105,6 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods { // case somebody does that for some reason && (is_infinity(const_1) && is_neg_infinity(const_2) || is_neg_infinity(const_1) && is_infinity(const_2)) - && !is_from_proc_macro(cx, expr) && let Some(local_snippet) = snippet_opt(cx, first.span) { let variant = match (kind.node, lhs_kind.node, rhs_kind.node) { @@ -113,47 +112,44 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods { (BinOpKind::And, BinOpKind::Ne, BinOpKind::Ne) => Variant::ManualIsFinite, _ => return, }; + if is_from_proc_macro(cx, expr) { + return; + } - span_lint_and_then( - cx, - variant.lint(), - expr.span, - variant.msg(), - |diag| { - match variant { - Variant::ManualIsInfinite => { - diag.span_suggestion( - expr.span, - "use the dedicated method instead", - format!("{local_snippet}.is_infinite()"), - Applicability::MachineApplicable, - ); - }, - Variant::ManualIsFinite => { - // TODO: There's probably some better way to do this, i.e., create - // multiple suggestions with notes between each of them - diag.span_suggestion_verbose( - expr.span, - "use the dedicated method instead", - format!("{local_snippet}.is_finite()"), - Applicability::MaybeIncorrect, - ) - .span_suggestion_verbose( - expr.span, - "this will alter how it handles NaN; if that is a problem, use instead", - format!("{local_snippet}.is_finite() || {local_snippet}.is_nan()"), - Applicability::MaybeIncorrect, - ) - .span_suggestion_verbose( - expr.span, - "or, for conciseness", - format!("!{local_snippet}.is_infinite()"), - Applicability::MaybeIncorrect, - ); - }, - } - }, - ); + span_lint_and_then(cx, variant.lint(), expr.span, variant.msg(), |diag| { + match variant { + Variant::ManualIsInfinite => { + diag.span_suggestion( + expr.span, + "use the dedicated method instead", + format!("{local_snippet}.is_infinite()"), + Applicability::MachineApplicable, + ); + }, + Variant::ManualIsFinite => { + // TODO: There's probably some better way to do this, i.e., create + // multiple suggestions with notes between each of them + diag.span_suggestion_verbose( + expr.span, + "use the dedicated method instead", + format!("{local_snippet}.is_finite()"), + Applicability::MaybeIncorrect, + ) + .span_suggestion_verbose( + expr.span, + "this will alter how it handles NaN; if that is a problem, use instead", + format!("{local_snippet}.is_finite() || {local_snippet}.is_nan()"), + Applicability::MaybeIncorrect, + ) + .span_suggestion_verbose( + expr.span, + "or, for conciseness", + format!("!{local_snippet}.is_infinite()"), + Applicability::MaybeIncorrect, + ); + }, + } + }); } } } diff --git a/src/tools/clippy/clippy_lints/src/manual_hash_one.rs b/src/tools/clippy/clippy_lints/src/manual_hash_one.rs new file mode 100644 index 000000000..472b4eb90 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/manual_hash_one.rs @@ -0,0 +1,132 @@ +use clippy_config::msrvs::{self, Msrv}; +use clippy_utils::diagnostics::span_lint_hir_and_then; +use clippy_utils::source::snippet_opt; +use clippy_utils::visitors::{is_local_used, local_used_once}; +use clippy_utils::{is_trait_method, path_to_local_id}; +use rustc_errors::Applicability; +use rustc_hir::{BindingAnnotation, ExprKind, Local, Node, PatKind, StmtKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::sym; + +declare_clippy_lint! { + /// ### What it does + /// Checks for cases where [`BuildHasher::hash_one`] can be used. + /// + /// [`BuildHasher::hash_one`]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html#method.hash_one + /// + /// ### Why is this bad? + /// It is more concise to use the `hash_one` method. + /// + /// ### Example + /// ```no_run + /// use std::hash::{BuildHasher, Hash, Hasher}; + /// use std::collections::hash_map::RandomState; + /// + /// let s = RandomState::new(); + /// let value = vec![1, 2, 3]; + /// + /// let mut hasher = s.build_hasher(); + /// value.hash(&mut hasher); + /// let hash = hasher.finish(); + /// ``` + /// Use instead: + /// ```no_run + /// use std::hash::BuildHasher; + /// use std::collections::hash_map::RandomState; + /// + /// let s = RandomState::new(); + /// let value = vec![1, 2, 3]; + /// + /// let hash = s.hash_one(&value); + /// ``` + #[clippy::version = "1.74.0"] + pub MANUAL_HASH_ONE, + complexity, + "manual implementations of `BuildHasher::hash_one`" +} + +pub struct ManualHashOne { + msrv: Msrv, +} + +impl ManualHashOne { + #[must_use] + pub fn new(msrv: Msrv) -> Self { + Self { msrv } + } +} + +impl_lint_pass!(ManualHashOne => [MANUAL_HASH_ONE]); + +impl LateLintPass<'_> for ManualHashOne { + fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) { + // `let mut hasher = seg.build_hasher();` + if let PatKind::Binding(BindingAnnotation::MUT, hasher, _, None) = local.pat.kind + && let Some(init) = local.init + && !init.span.from_expansion() + && let ExprKind::MethodCall(seg, build_hasher, [], _) = init.kind + && seg.ident.name == sym!(build_hasher) + + && let Node::Stmt(local_stmt) = cx.tcx.hir().get_parent(local.hir_id) + && let Node::Block(block) = cx.tcx.hir().get_parent(local_stmt.hir_id) + + && let mut stmts = block.stmts.iter() + .skip_while(|stmt| stmt.hir_id != local_stmt.hir_id) + .skip(1) + .filter(|&stmt| is_local_used(cx, stmt, hasher)) + + // `hashed_value.hash(&mut hasher);` + && let Some(hash_stmt) = stmts.next() + && let StmtKind::Semi(hash_expr) = hash_stmt.kind + && !hash_expr.span.from_expansion() + && let ExprKind::MethodCall(seg, hashed_value, [ref_to_hasher], _) = hash_expr.kind + && seg.ident.name == sym::hash + && is_trait_method(cx, hash_expr, sym::Hash) + && path_to_local_id(ref_to_hasher.peel_borrows(), hasher) + + && let maybe_finish_stmt = stmts.next() + // There should be no more statements referencing `hasher` + && stmts.next().is_none() + + // `hasher.finish()`, may be anywhere in a statement or the trailing expr of the block + && let Some(path_expr) = local_used_once(cx, (maybe_finish_stmt, block.expr), hasher) + && let Node::Expr(finish_expr) = cx.tcx.hir().get_parent(path_expr.hir_id) + && !finish_expr.span.from_expansion() + && let ExprKind::MethodCall(seg, _, [], _) = finish_expr.kind + && seg.ident.name == sym!(finish) + + && self.msrv.meets(msrvs::BUILD_HASHER_HASH_ONE) + { + span_lint_hir_and_then( + cx, + MANUAL_HASH_ONE, + finish_expr.hir_id, + finish_expr.span, + "manual implementation of `BuildHasher::hash_one`", + |diag| { + if let Some(build_hasher) = snippet_opt(cx, build_hasher.span) + && let Some(hashed_value) = snippet_opt(cx, hashed_value.span) + { + diag.multipart_suggestion( + "try", + vec![ + (local_stmt.span, String::new()), + (hash_stmt.span, String::new()), + ( + finish_expr.span, + // `needless_borrows_for_generic_args` will take care of + // removing the `&` when it isn't needed + format!("{build_hasher}.hash_one(&{hashed_value})"), + ), + ], + Applicability::MachineApplicable, + ); + } + }, + ); + } + } + + extract_msrv_attr!(LateContext); +} diff --git a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs index f26442447..468f41707 100644 --- a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs +++ b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs @@ -1,6 +1,6 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::macros::root_macro_call; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::sugg::Sugg; use clippy_utils::{higher, in_constant}; use rustc_ast::ast::RangeLimits; @@ -15,19 +15,21 @@ use rustc_span::{sym, Span}; declare_clippy_lint! { /// ### What it does /// Suggests to use dedicated built-in methods, - /// `is_ascii_(lowercase|uppercase|digit)` for checking on corresponding ascii range + /// `is_ascii_(lowercase|uppercase|digit|hexdigit)` for checking on corresponding + /// ascii range /// /// ### Why is this bad? /// Using the built-in functions is more readable and makes it /// clear that it's not a specific subset of characters, but all - /// ASCII (lowercase|uppercase|digit) characters. + /// ASCII (lowercase|uppercase|digit|hexdigit) characters. /// ### Example - /// ```rust + /// ```no_run /// fn main() { /// assert!(matches!('x', 'a'..='z')); /// assert!(matches!(b'X', b'A'..=b'Z')); /// assert!(matches!('2', '0'..='9')); /// assert!(matches!('x', 'A'..='Z' | 'a'..='z')); + /// assert!(matches!('C', '0'..='9' | 'a'..='f' | 'A'..='F')); /// /// ('0'..='9').contains(&'0'); /// ('a'..='z').contains(&'a'); @@ -35,12 +37,13 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn main() { /// assert!('x'.is_ascii_lowercase()); /// assert!(b'X'.is_ascii_uppercase()); /// assert!('2'.is_ascii_digit()); /// assert!('x'.is_ascii_alphabetic()); + /// assert!('C'.is_ascii_hexdigit()); /// /// '0'.is_ascii_digit(); /// 'a'.is_ascii_lowercase(); @@ -75,6 +78,12 @@ enum CharRange { FullChar, /// '0..=9' Digit, + /// 'a..=f' + LowerHexLetter, + /// 'A..=F' + UpperHexLetter, + /// '0..=9' | 'a..=f' | 'A..=F' + HexDigit, Otherwise, } @@ -89,15 +98,20 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck { } if let Some(macro_call) = root_macro_call(expr.span) - && is_matches_macro(cx, macro_call.def_id) { + && is_matches_macro(cx, macro_call.def_id) + { if let ExprKind::Match(recv, [arm, ..], _) = expr.kind { let range = check_pat(&arm.pat.kind); check_is_ascii(cx, macro_call.span, recv, &range); } } else if let ExprKind::MethodCall(path, receiver, [arg], ..) = expr.kind && path.ident.name == sym!(contains) - && let Some(higher::Range { start: Some(start), end: Some(end), limits: RangeLimits::Closed }) - = higher::Range::hir(receiver) { + && let Some(higher::Range { + start: Some(start), + end: Some(end), + limits: RangeLimits::Closed, + }) = higher::Range::hir(receiver) + { let range = check_range(start, end); if let ExprKind::AddrOf(BorrowKind::Ref, _, e) = arg.kind { check_is_ascii(cx, expr.span, e, &range); @@ -116,7 +130,8 @@ fn check_is_ascii(cx: &LateContext<'_>, span: Span, recv: &Expr<'_>, range: &Cha CharRange::LowerChar => Some("is_ascii_lowercase"), CharRange::FullChar => Some("is_ascii_alphabetic"), CharRange::Digit => Some("is_ascii_digit"), - CharRange::Otherwise => None, + CharRange::HexDigit => Some("is_ascii_hexdigit"), + CharRange::Otherwise | CharRange::LowerHexLetter | CharRange::UpperHexLetter => None, } { let default_snip = ".."; let mut app = Applicability::MachineApplicable; @@ -141,6 +156,12 @@ fn check_pat(pat_kind: &PatKind<'_>) -> CharRange { if ranges.len() == 2 && ranges.contains(&CharRange::UpperChar) && ranges.contains(&CharRange::LowerChar) { CharRange::FullChar + } else if ranges.len() == 3 + && ranges.contains(&CharRange::Digit) + && ranges.contains(&CharRange::LowerHexLetter) + && ranges.contains(&CharRange::UpperHexLetter) + { + CharRange::HexDigit } else { CharRange::Otherwise } @@ -152,10 +173,13 @@ fn check_pat(pat_kind: &PatKind<'_>) -> CharRange { fn check_range(start: &Expr<'_>, end: &Expr<'_>) -> CharRange { if let ExprKind::Lit(start_lit) = &start.kind - && let ExprKind::Lit(end_lit) = &end.kind { + && let ExprKind::Lit(end_lit) = &end.kind + { match (&start_lit.node, &end_lit.node) { (Char('a'), Char('z')) | (Byte(b'a'), Byte(b'z')) => CharRange::LowerChar, (Char('A'), Char('Z')) | (Byte(b'A'), Byte(b'Z')) => CharRange::UpperChar, + (Char('a'), Char('f')) | (Byte(b'a'), Byte(b'f')) => CharRange::LowerHexLetter, + (Char('A'), Char('F')) | (Byte(b'A'), Byte(b'F')) => CharRange::UpperHexLetter, (Char('0'), Char('9')) | (Byte(b'0'), Byte(b'9')) => CharRange::Digit, _ => CharRange::Otherwise, } diff --git a/src/tools/clippy/clippy_lints/src/manual_let_else.rs b/src/tools/clippy/clippy_lints/src/manual_let_else.rs index c531137b7..170a040d4 100644 --- a/src/tools/clippy/clippy_lints/src/manual_let_else.rs +++ b/src/tools/clippy/clippy_lints/src/manual_let_else.rs @@ -1,10 +1,12 @@ use crate::question_mark::{QuestionMark, QUESTION_MARK}; +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::visitors::{Descend, Visitable}; -use clippy_utils::{is_lint_allowed, msrvs, pat_and_expr_can_be_question_mark, peel_blocks}; +use clippy_utils::{is_lint_allowed, pat_and_expr_can_be_question_mark, peel_blocks}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, Visitor}; @@ -14,7 +16,6 @@ use rustc_middle::lint::in_external_macro; use rustc_session::declare_tool_lint; use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; -use serde::Deserialize; use std::ops::ControlFlow; use std::slice; @@ -30,14 +31,14 @@ declare_clippy_lint! { /// /// ### Example /// - /// ```rust + /// ```no_run /// # let w = Some(0); /// let v = if let Some(v) = w { v } else { return }; /// ``` /// /// Could be written: /// - /// ```rust + /// ```no_run /// # fn main () { /// # let w = Some(0); /// let Some(v) = w else { return }; @@ -55,21 +56,20 @@ impl<'tcx> QuestionMark { return; } - if let StmtKind::Local(local) = stmt.kind && - let Some(init) = local.init && - local.els.is_none() && - local.ty.is_none() && - init.span.ctxt() == stmt.span.ctxt() && - let Some(if_let_or_match) = IfLetOrMatch::parse(cx, init) + if let StmtKind::Local(local) = stmt.kind + && let Some(init) = local.init + && local.els.is_none() + && local.ty.is_none() + && init.span.eq_ctxt(stmt.span) + && let Some(if_let_or_match) = IfLetOrMatch::parse(cx, init) { match if_let_or_match { IfLetOrMatch::IfLet(if_let_expr, let_pat, if_then, if_else) => { - if - let Some(ident_map) = expr_simple_identity_map(local.pat, let_pat, if_then) && - let Some(if_else) = if_else && - expr_diverges(cx, if_else) && - let qm_allowed = is_lint_allowed(cx, QUESTION_MARK, stmt.hir_id) && - (qm_allowed || pat_and_expr_can_be_question_mark(cx, let_pat, if_else).is_none()) + if let Some(ident_map) = expr_simple_identity_map(local.pat, let_pat, if_then) + && let Some(if_else) = if_else + && expr_diverges(cx, if_else) + && let qm_allowed = is_lint_allowed(cx, QUESTION_MARK, stmt.hir_id) + && (qm_allowed || pat_and_expr_can_be_question_mark(cx, let_pat, if_else).is_none()) { emit_manual_let_else(cx, stmt.span, if_let_expr, &ident_map, let_pat, if_else); } @@ -95,7 +95,9 @@ impl<'tcx> QuestionMark { .iter() .enumerate() .find(|(_, arm)| expr_diverges(cx, arm.body) && pat_allowed_for_else(cx, arm.pat, check_types)); - let Some((idx, diverging_arm)) = diverging_arm_opt else { return; }; + let Some((idx, diverging_arm)) = diverging_arm_opt else { + return; + }; // If the non-diverging arm is the first one, its pattern can be reused in a let/else statement. // However, if it arrives in second position, its pattern may cover some cases already covered // by the diverging one. @@ -105,7 +107,7 @@ impl<'tcx> QuestionMark { } let pat_arm = &arms[1 - idx]; let Some(ident_map) = expr_simple_identity_map(local.pat, pat_arm.pat, pat_arm.body) else { - return + return; }; emit_manual_let_else(cx, stmt.span, match_expr, &ident_map, pat_arm.pat, diverging_arm.body); @@ -136,9 +138,9 @@ fn emit_manual_let_else( // for this to be machine applicable. let mut app = Applicability::HasPlaceholders; let (sn_expr, _) = snippet_with_context(cx, expr.span, span.ctxt(), "", &mut app); - let (sn_else, _) = snippet_with_context(cx, else_body.span, span.ctxt(), "", &mut app); + let (sn_else, else_is_mac_call) = snippet_with_context(cx, else_body.span, span.ctxt(), "", &mut app); - let else_bl = if matches!(else_body.kind, ExprKind::Block(..)) { + let else_bl = if matches!(else_body.kind, ExprKind::Block(..)) && !else_is_mac_call { sn_else.into_owned() } else { format!("{{ {sn_else} }}") @@ -216,8 +218,8 @@ fn replace_in_pattern( let fields = fields .iter() .map(|fld| { - if let PatKind::Binding(_, _, name, None) = fld.pat.kind && - let Some(pat_to_put) = ident_map.get(&name.name) + if let PatKind::Binding(_, _, name, None) = fld.pat.kind + && let Some(pat_to_put) = ident_map.get(&name.name) { let (sn_fld_name, _) = snippet_with_context(cx, fld.ident.span, span.ctxt(), "", app); let (sn_ptp, _) = snippet_with_context(cx, pat_to_put.span, span.ctxt(), "", app); @@ -463,8 +465,8 @@ fn expr_simple_identity_map<'a, 'hir>( } let mut ident_map = FxHashMap::default(); for (sub_pat, path) in sub_pats.iter().zip(paths.iter()) { - if let ExprKind::Path(QPath::Resolved(_ty, path)) = path.kind && - let [path_seg] = path.segments + if let ExprKind::Path(QPath::Resolved(_ty, path)) = path.kind + && let [path_seg] = path.segments { let ident = path_seg.ident; if !pat_bindings.remove(&ident) { @@ -477,10 +479,3 @@ fn expr_simple_identity_map<'a, 'hir>( } Some(ident_map) } - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize)] -pub enum MatchLintBehaviour { - AllTypes, - WellKnownTypes, - Never, -} diff --git a/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs b/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs index c292bbe4e..23f47c86f 100644 --- a/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs +++ b/src/tools/clippy/clippy_lints/src/manual_main_separator_str.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::{is_trait_method, match_def_path, paths, peel_hir_expr_refs}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; @@ -19,11 +19,11 @@ declare_clippy_lint! { /// an extra memory allocation. /// /// ### Example - /// ```rust + /// ```no_run /// let s: &str = &std::path::MAIN_SEPARATOR.to_string(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let s: &str = std::path::MAIN_SEPARATOR_STR; /// ``` #[clippy::version = "1.70.0"] @@ -47,27 +47,27 @@ impl_lint_pass!(ManualMainSeparatorStr => [MANUAL_MAIN_SEPARATOR_STR]); impl LateLintPass<'_> for ManualMainSeparatorStr { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { - if self.msrv.meets(msrvs::PATH_MAIN_SEPARATOR_STR) && - let (target, _) = peel_hir_expr_refs(expr) && - is_trait_method(cx, target, sym::ToString) && - let ExprKind::MethodCall(path, receiver, &[], _) = target.kind && - path.ident.name == sym::to_string && - let ExprKind::Path(QPath::Resolved(None, path)) = receiver.kind && - let Res::Def(DefKind::Const, receiver_def_id) = path.res && - match_def_path(cx, receiver_def_id, &paths::PATH_MAIN_SEPARATOR) && - let ty::Ref(_, ty, Mutability::Not) = cx.typeck_results().expr_ty_adjusted(expr).kind() && - ty.is_str() - { - span_lint_and_sugg( - cx, - MANUAL_MAIN_SEPARATOR_STR, - expr.span, - "taking a reference on `std::path::MAIN_SEPARATOR` conversion to `String`", - "replace with", - "std::path::MAIN_SEPARATOR_STR".to_owned(), - Applicability::MachineApplicable, - ); - } + if self.msrv.meets(msrvs::PATH_MAIN_SEPARATOR_STR) + && let (target, _) = peel_hir_expr_refs(expr) + && is_trait_method(cx, target, sym::ToString) + && let ExprKind::MethodCall(path, receiver, &[], _) = target.kind + && path.ident.name == sym::to_string + && let ExprKind::Path(QPath::Resolved(None, path)) = receiver.kind + && let Res::Def(DefKind::Const, receiver_def_id) = path.res + && match_def_path(cx, receiver_def_id, &paths::PATH_MAIN_SEPARATOR) + && let ty::Ref(_, ty, Mutability::Not) = cx.typeck_results().expr_ty_adjusted(expr).kind() + && ty.is_str() + { + span_lint_and_sugg( + cx, + MANUAL_MAIN_SEPARATOR_STR, + expr.span, + "taking a reference on `std::path::MAIN_SEPARATOR` conversion to `String`", + "replace with", + "std::path::MAIN_SEPARATOR_STR".to_owned(), + Applicability::MachineApplicable, + ); + } } extract_msrv_attr!(LateContext); diff --git a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs index 0e22485db..fc8f23630 100644 --- a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs +++ b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs @@ -1,8 +1,9 @@ +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_opt; use rustc_ast::ast::{self, VisibilityKind}; +use rustc_ast::attr; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; @@ -21,7 +22,7 @@ declare_clippy_lint! { /// and allows possible optimizations when applied to enums. /// /// ### Example - /// ```rust + /// ```no_run /// struct S { /// pub a: i32, /// pub b: i32, @@ -38,7 +39,7 @@ declare_clippy_lint! { /// struct T(pub i32, pub i32, ()); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// #[non_exhaustive] /// struct S { /// pub a: i32, @@ -137,7 +138,7 @@ impl EarlyLintPass for ManualNonExhaustiveStruct { ); } diag.span_help(field.span, "remove this field"); - } + }, ); } } @@ -158,7 +159,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum { let mut iter = def.variants.iter().filter_map(|v| { (matches!(v.data, hir::VariantData::Unit(_, _)) && v.ident.as_str().starts_with('_') - && is_doc_hidden(cx.tcx.hir().attrs(v.hir_id))) + && is_doc_hidden(cx.tcx.hir().attrs(v.hir_id)) + && !attr::contains_name(cx.tcx.hir().attrs(item.hir_id()), sym::non_exhaustive)) .then_some((v.def_id, v.span)) }); if let Some((id, span)) = iter.next() @@ -198,16 +200,14 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum { enum_span, "this seems like a manual implementation of the non-exhaustive pattern", |diag| { - if !cx.tcx.adt_def(enum_id).is_variant_list_non_exhaustive() - && let header_span = cx.sess().source_map().span_until_char(enum_span, '{') - && let Some(snippet) = snippet_opt(cx, header_span) - { - diag.span_suggestion( - header_span, - "add the attribute", - format!("#[non_exhaustive] {snippet}"), - Applicability::Unspecified, - ); + let header_span = cx.sess().source_map().span_until_char(enum_span, '{'); + if let Some(snippet) = snippet_opt(cx, header_span) { + diag.span_suggestion( + header_span, + "add the attribute", + format!("#[non_exhaustive] {snippet}"), + Applicability::Unspecified, + ); } diag.span_help(variant_span, "remove this variant"); }, diff --git a/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs b/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs index 90557b555..d24bfe182 100644 --- a/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs @@ -22,12 +22,12 @@ declare_clippy_lint! { /// in order to support negative numbers. /// /// ### Example - /// ```rust + /// ```no_run /// let x = 6; /// let foo = matches!(x, 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let x = 6; /// let foo = matches!(x, 1..=10); /// ``` diff --git a/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs index 0e89ca132..bc8372fbd 100644 --- a/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs +++ b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs @@ -1,6 +1,6 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{constant_full_int, 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::{in_constant, path_to_local}; use rustc_errors::Applicability; @@ -18,12 +18,12 @@ declare_clippy_lint! { /// It's simpler and more readable. /// /// ### Example - /// ```rust + /// ```no_run /// let x: i32 = 24; /// let rem = ((x % 4) + 4) % 4; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let x: i32 = 24; /// let rem = x.rem_euclid(4); /// ``` @@ -76,30 +76,31 @@ impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid { // Also ensures the const is nonzero since zero can't be a divisor && const1 == const2 && const2 == const3 && let Some(hir_id) = path_to_local(expr3) - && let Some(Node::Pat(_)) = cx.tcx.hir().find(hir_id) { - // Apply only to params or locals with annotated types - match cx.tcx.hir().find_parent(hir_id) { - Some(Node::Param(..)) => (), - Some(Node::Local(local)) => { - let Some(ty) = local.ty else { return }; - if matches!(ty.kind, TyKind::Infer) { - return; - } + && let Some(Node::Pat(_)) = cx.tcx.hir().find(hir_id) + { + // Apply only to params or locals with annotated types + match cx.tcx.hir().find_parent(hir_id) { + Some(Node::Param(..)) => (), + Some(Node::Local(local)) => { + let Some(ty) = local.ty else { return }; + if matches!(ty.kind, TyKind::Infer) { + return; } - _ => return, - }; + }, + _ => return, + }; - let mut app = Applicability::MachineApplicable; - let rem_of = snippet_with_context(cx, expr3.span, ctxt, "_", &mut app).0; - span_lint_and_sugg( - cx, - MANUAL_REM_EUCLID, - expr.span, - "manual `rem_euclid` implementation", - "consider using", - format!("{rem_of}.rem_euclid({const1})"), - app, - ); + let mut app = Applicability::MachineApplicable; + let rem_of = snippet_with_context(cx, expr3.span, ctxt, "_", &mut app).0; + span_lint_and_sugg( + cx, + MANUAL_REM_EUCLID, + expr.span, + "manual `rem_euclid` implementation", + "consider using", + format!("{rem_of}.rem_euclid({const1})"), + app, + ); } } diff --git a/src/tools/clippy/clippy_lints/src/manual_retain.rs b/src/tools/clippy/clippy_lints/src/manual_retain.rs index 1a69a48c5..2f8682d04 100644 --- a/src/tools/clippy/clippy_lints/src/manual_retain.rs +++ b/src/tools/clippy/clippy_lints/src/manual_retain.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, is_type_lang_item}; use clippy_utils::{get_parent_expr, match_def_path, paths, SpanlessEq}; @@ -35,13 +35,13 @@ declare_clippy_lint! { /// ### Why is this bad? /// `.retain()` is simpler and avoids needless allocation. /// ### Example - /// ```rust + /// ```no_run /// let mut vec = vec![0, 1, 2]; /// vec = vec.iter().filter(|&x| x % 2 == 0).copied().collect(); /// vec = vec.into_iter().filter(|x| x % 2 == 0).collect(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let mut vec = vec![0, 1, 2]; /// vec.retain(|x| x % 2 == 0); /// ``` @@ -97,7 +97,8 @@ fn check_into_iter( && let Some(into_iter_def_id) = cx.typeck_results().type_dependent_def_id(into_iter_expr.hir_id) && Some(into_iter_def_id) == cx.tcx.lang_items().into_iter_fn() && match_acceptable_type(cx, left_expr, msrv) - && SpanlessEq::new(cx).eq_expr(left_expr, struct_expr) { + && SpanlessEq::new(cx).eq_expr(left_expr, struct_expr) + { suggest(cx, parent_expr, left_expr, target_expr); } } @@ -120,7 +121,8 @@ fn check_iter( && let Some(iter_expr_def_id) = cx.typeck_results().type_dependent_def_id(iter_expr.hir_id) && match_acceptable_def_path(cx, iter_expr_def_id) && match_acceptable_type(cx, left_expr, msrv) - && SpanlessEq::new(cx).eq_expr(left_expr, struct_expr) { + && SpanlessEq::new(cx).eq_expr(left_expr, struct_expr) + { suggest(cx, parent_expr, left_expr, filter_expr); } } @@ -135,7 +137,7 @@ fn check_to_owned( if msrv.meets(msrvs::STRING_RETAIN) && let hir::ExprKind::MethodCall(_, filter_expr, [], _) = &target_expr.kind && let Some(to_owned_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id) - && match_def_path(cx, to_owned_def_id, &paths::TO_OWNED_METHOD) + && cx.tcx.is_diagnostic_item(sym::to_owned_method, to_owned_def_id) && let hir::ExprKind::MethodCall(_, chars_expr, [_], _) = &filter_expr.kind && let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(filter_expr.hir_id) && match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER) @@ -144,33 +146,35 @@ fn check_to_owned( && match_def_path(cx, chars_expr_def_id, &paths::STR_CHARS) && let ty = cx.typeck_results().expr_ty(str_expr).peel_refs() && is_type_lang_item(cx, ty, hir::LangItem::String) - && SpanlessEq::new(cx).eq_expr(left_expr, str_expr) { + && SpanlessEq::new(cx).eq_expr(left_expr, str_expr) + { suggest(cx, parent_expr, left_expr, filter_expr); } } fn suggest(cx: &LateContext<'_>, parent_expr: &hir::Expr<'_>, left_expr: &hir::Expr<'_>, filter_expr: &hir::Expr<'_>) { if let hir::ExprKind::MethodCall(_, _, [closure], _) = filter_expr.kind - && let hir::ExprKind::Closure(&hir::Closure { body, ..}) = closure.kind + && let hir::ExprKind::Closure(&hir::Closure { body, .. }) = closure.kind && let filter_body = cx.tcx.hir().body(body) && let [filter_params] = filter_body.params && let Some(sugg) = match filter_params.pat.kind { - hir::PatKind::Binding(_, _, filter_param_ident, None) => { - Some(format!("{}.retain(|{filter_param_ident}| {})", snippet(cx, left_expr.span, ".."), snippet(cx, filter_body.value.span, ".."))) - }, - hir::PatKind::Tuple([key_pat, value_pat], _) => { - make_sugg(cx, key_pat, value_pat, left_expr, filter_body) - }, - hir::PatKind::Ref(pat, _) => { - match pat.kind { - hir::PatKind::Binding(_, _, filter_param_ident, None) => { - Some(format!("{}.retain(|{filter_param_ident}| {})", snippet(cx, left_expr.span, ".."), snippet(cx, filter_body.value.span, ".."))) - }, - _ => None - } + hir::PatKind::Binding(_, _, filter_param_ident, None) => Some(format!( + "{}.retain(|{filter_param_ident}| {})", + snippet(cx, left_expr.span, ".."), + snippet(cx, filter_body.value.span, "..") + )), + hir::PatKind::Tuple([key_pat, value_pat], _) => make_sugg(cx, key_pat, value_pat, left_expr, filter_body), + hir::PatKind::Ref(pat, _) => match pat.kind { + hir::PatKind::Binding(_, _, filter_param_ident, None) => Some(format!( + "{}.retain(|{filter_param_ident}| {})", + snippet(cx, left_expr.span, ".."), + snippet(cx, filter_body.value.span, "..") + )), + _ => None, }, - _ => None - } { + _ => None, + } + { span_lint_and_sugg( cx, MANUAL_RETAIN, @@ -178,7 +182,7 @@ fn suggest(cx: &LateContext<'_>, parent_expr: &hir::Expr<'_>, left_expr: &hir::E "this expression can be written more simply using `.retain()`", "consider calling `.retain()` instead", sugg, - Applicability::MachineApplicable + Applicability::MachineApplicable, ); } } diff --git a/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs b/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs index f97600b53..3b97d1659 100644 --- a/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs +++ b/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs @@ -22,12 +22,12 @@ declare_clippy_lint! { /// * Less turbofishing /// /// ### Example - /// ```rust + /// ```no_run /// # let data : &[i32] = &[1, 2, 3]; /// let newlen = data.len() * std::mem::size_of::<i32>(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # let data : &[i32] = &[1, 2, 3]; /// let newlen = std::mem::size_of_val(data); /// ``` diff --git a/src/tools/clippy/clippy_lints/src/manual_string_new.rs b/src/tools/clippy/clippy_lints/src/manual_string_new.rs index c20d7959f..f8afae0e1 100644 --- a/src/tools/clippy/clippy_lints/src/manual_string_new.rs +++ b/src/tools/clippy/clippy_lints/src/manual_string_new.rs @@ -19,12 +19,12 @@ declare_clippy_lint! { /// be confusing. /// /// ### Example - /// ```rust + /// ```no_run /// let a = "".to_string(); /// let b: String = "".into(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let a = String::new(); /// let b = String::new(); /// ``` @@ -65,9 +65,9 @@ impl LateLintPass<'_> for ManualStringNew { /// Checks if an expression's kind corresponds to an empty &str. fn is_expr_kind_empty_str(expr_kind: &ExprKind<'_>) -> bool { - if let ExprKind::Lit(lit) = expr_kind && - let LitKind::Str(value, _) = lit.node && - value == symbol::kw::Empty + if let ExprKind::Lit(lit) = expr_kind + && let LitKind::Str(value, _) = lit.node + && value == symbol::kw::Empty { return true; } @@ -110,23 +110,22 @@ fn parse_call(cx: &LateContext<'_>, span: Span, func: &Expr<'_>, args: &[Expr<'_ if let ExprKind::Path(qpath) = &func.kind { if let QPath::TypeRelative(_, _) = qpath { // String::from(...) or String::try_from(...) - if let QPath::TypeRelative(ty, path_seg) = qpath && - [sym::from, sym::try_from].contains(&path_seg.ident.name) && - let TyKind::Path(qpath) = &ty.kind && - let QPath::Resolved(_, path) = qpath && - let [path_seg] = path.segments && - path_seg.ident.name == sym::String && - is_expr_kind_empty_str(arg_kind) + if let QPath::TypeRelative(ty, path_seg) = qpath + && [sym::from, sym::try_from].contains(&path_seg.ident.name) + && let TyKind::Path(qpath) = &ty.kind + && let QPath::Resolved(_, path) = qpath + && let [path_seg] = path.segments + && path_seg.ident.name == sym::String + && is_expr_kind_empty_str(arg_kind) { warn_then_suggest(cx, span); } } else if let QPath::Resolved(_, path) = qpath { // From::from(...) or TryFrom::try_from(...) - if let [path_seg1, path_seg2] = path.segments && - is_expr_kind_empty_str(arg_kind) && ( - (path_seg1.ident.name == sym::From && path_seg2.ident.name == sym::from) || - (path_seg1.ident.name == sym::TryFrom && path_seg2.ident.name == sym::try_from) - ) + if let [path_seg1, path_seg2] = path.segments + && is_expr_kind_empty_str(arg_kind) + && ((path_seg1.ident.name == sym::From && path_seg2.ident.name == sym::from) + || (path_seg1.ident.name == sym::TryFrom && path_seg2.ident.name == sym::try_from)) { warn_then_suggest(cx, span); } diff --git a/src/tools/clippy/clippy_lints/src/manual_strip.rs b/src/tools/clippy/clippy_lints/src/manual_strip.rs index 201bb56ef..9a9e6af50 100644 --- a/src/tools/clippy/clippy_lints/src/manual_strip.rs +++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs @@ -1,6 +1,6 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{multispan_sugg, 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, match_def_path, paths}; @@ -27,14 +27,14 @@ declare_clippy_lint! { /// used by `str::{starts,ends}_with` and in the slicing. /// /// ### Example - /// ```rust + /// ```no_run /// let s = "hello, world!"; /// if s.starts_with("hello, ") { /// assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!"); /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let s = "hello, world!"; /// if let Some(end) = s.strip_prefix("hello, ") { /// assert_eq!(end.to_uppercase(), "WORLD!"); diff --git a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs index f0a0f482a..817d072b9 100644 --- a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs +++ b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs @@ -8,8 +8,7 @@ use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::Span; -use rustc_span::sym; +use rustc_span::{sym, Span}; declare_clippy_lint! { /// ### What it does @@ -21,7 +20,7 @@ declare_clippy_lint! { /// an if let statement /// /// ### Example - /// ```rust + /// ```no_run /// # fn do_stuff() -> Option<String> { Some(String::new()) } /// # fn log_err_msg(foo: String) -> Option<String> { Some(foo) } /// # fn format_msg(foo: String) -> String { String::new() } @@ -33,7 +32,7 @@ declare_clippy_lint! { /// /// The correct use would be: /// - /// ```rust + /// ```no_run /// # fn do_stuff() -> Option<String> { Some(String::new()) } /// # fn log_err_msg(foo: String) -> Option<String> { Some(foo) } /// # fn format_msg(foo: String) -> String { String::new() } @@ -63,7 +62,7 @@ declare_clippy_lint! { /// an if let statement /// /// ### Example - /// ```rust + /// ```no_run /// # fn do_stuff() -> Result<String, String> { Ok(String::new()) } /// # fn log_err_msg(foo: String) -> Result<String, String> { Ok(foo) } /// # fn format_msg(foo: String) -> String { String::new() } @@ -75,7 +74,7 @@ declare_clippy_lint! { /// /// The correct use would be: /// - /// ```rust + /// ```no_run /// # fn do_stuff() -> Result<String, String> { Ok(String::new()) } /// # fn log_err_msg(foo: String) -> Result<String, String> { Ok(foo) } /// # fn format_msg(foo: String) -> String { String::new() } diff --git a/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs b/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs index 33a052c41..29b935fb6 100644 --- a/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs @@ -57,7 +57,7 @@ fn check_arm<'tcx>( } }, }; - if outer_pat.span.ctxt() == inner_scrutinee.span.ctxt(); + if outer_pat.span.eq_ctxt(inner_scrutinee.span); // match expression must be a local binding // match <local> { .. } if let Some(binding_id) = path_to_local(peel_ref_operators(cx, inner_scrutinee)); diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs b/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs index e0181a475..cdb51c33a 100644 --- a/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs +++ b/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs @@ -99,12 +99,20 @@ pub(super) fn check_match<'tcx>( ) { let ty = cx.typeck_results().expr_ty(expr); if is_type_diagnostic_item(cx, ty, sym::Option) - && let [first_arm, second_arm] = arms - && first_arm.guard.is_none() - && second_arm.guard.is_none() - { - check(cx, expr, scrutinee, first_arm.pat, first_arm.body, Some(second_arm.pat), second_arm.body); - } + && let [first_arm, second_arm] = arms + && first_arm.guard.is_none() + && second_arm.guard.is_none() + { + check( + cx, + expr, + scrutinee, + first_arm.pat, + first_arm.body, + Some(second_arm.pat), + second_arm.body, + ); + } } pub(super) fn check_if_let<'tcx>( diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs index 6b611f567..781ee138c 100644 --- a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs +++ b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs @@ -119,7 +119,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.ctxt() == expr.span.ctxt() && scrutinee.precedence().order() < PREC_POSTFIX { + let scrutinee_str = if scrutinee.span.eq_ctxt(expr.span) && scrutinee.precedence().order() < PREC_POSTFIX { format!("({scrutinee_str})") } else { scrutinee_str.into() @@ -130,7 +130,7 @@ where if_chain! { if !some_expr.needs_unsafe_block; if let Some(func) = can_pass_as_func(cx, id, some_expr.expr); - if func.span.ctxt() == some_expr.expr.span.ctxt(); + if func.span.eq_ctxt(some_expr.expr.span); then { snippet_with_applicability(cx, func.span, "..", &mut app).into_owned() } else { diff --git a/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs b/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs index de911f7a0..a2903e52a 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs @@ -19,7 +19,7 @@ pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm<' if is_type_diagnostic_item(cx, ex_ty, sym::Result) { for arm in arms { if let PatKind::TupleStruct(ref path, inner, _) = arm.pat.kind { - let path_str = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false)); + let path_str = rustc_hir_pretty::qpath_to_string(path); if path_str == "Err" { let mut matching_wild = inner.iter().any(is_wild); let mut ident_bind_name = kw::Underscore; diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs index 930386a60..dea46d4d3 100644 --- a/src/tools/clippy/clippy_lints/src/matches/mod.rs +++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs @@ -24,7 +24,7 @@ mod single_match; mod try_err; mod wild_in_or_pats; -use clippy_utils::msrvs::{self, Msrv}; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::source::{snippet_opt, walk_span_to_context}; use clippy_utils::{higher, in_constant, is_direct_expn_of, is_span_match, tokenize_with_text}; use rustc_hir::{Arm, Expr, ExprKind, Local, MatchSource, Pat}; @@ -48,7 +48,7 @@ declare_clippy_lint! { /// Just readability – `if let` nests less than a `match`. /// /// ### Example - /// ```rust + /// ```no_run /// # fn bar(stool: &str) {} /// # let x = Some("abc"); /// match x { @@ -58,7 +58,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # fn bar(stool: &str) {} /// # let x = Some("abc"); /// if let Some(ref foo) = x { @@ -85,7 +85,7 @@ declare_clippy_lint! { /// ### Example /// Using `match`: /// - /// ```rust + /// ```no_run /// # fn bar(foo: &usize) {} /// # let other_ref: usize = 1; /// # let x: Option<&usize> = Some(&1); @@ -97,7 +97,7 @@ declare_clippy_lint! { /// /// Using `if let` with `else`: /// - /// ```rust + /// ```no_run /// # fn bar(foo: &usize) {} /// # let other_ref: usize = 1; /// # let x: Option<&usize> = Some(&1); @@ -155,7 +155,7 @@ declare_clippy_lint! { /// It makes the code less readable. /// /// ### Example - /// ```rust + /// ```no_run /// # fn foo() {} /// # fn bar() {} /// let condition: bool = true; @@ -165,7 +165,7 @@ declare_clippy_lint! { /// } /// ``` /// Use if/else instead: - /// ```rust + /// ```no_run /// # fn foo() {} /// # fn bar() {} /// let condition: bool = true; @@ -190,7 +190,7 @@ declare_clippy_lint! { /// less obvious. /// /// ### Example - /// ```rust + /// ```no_run /// let x = 5; /// match x { /// 1..=10 => println!("1 ... 10"), @@ -214,7 +214,7 @@ declare_clippy_lint! { /// catching all exceptions in java with `catch(Exception)` /// /// ### Example - /// ```rust + /// ```no_run /// let x: Result<i32, &str> = Ok(3); /// match x { /// Ok(_) => println!("ok"), @@ -236,7 +236,7 @@ declare_clippy_lint! { /// Using `as_ref()` or `as_mut()` instead is shorter. /// /// ### Example - /// ```rust + /// ```no_run /// let x: Option<()> = None; /// /// let r: Option<&()> = match x { @@ -246,7 +246,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let x: Option<()> = None; /// /// let r: Option<&()> = x.as_ref(); @@ -269,7 +269,7 @@ declare_clippy_lint! { /// variants, and also may not use correct path to enum if it's not present in the current scope. /// /// ### Example - /// ```rust + /// ```no_run /// # enum Foo { A(usize), B(usize) } /// # let x = Foo::B(1); /// match x { @@ -279,7 +279,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # enum Foo { A(usize), B(usize) } /// # let x = Foo::B(1); /// match x { @@ -305,7 +305,7 @@ declare_clippy_lint! { /// if it's not present in the current scope. /// /// ### Example - /// ```rust + /// ```no_run /// # enum Foo { A, B, C } /// # let x = Foo::B; /// match x { @@ -316,7 +316,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # enum Foo { A, B, C } /// # let x = Foo::B; /// match x { @@ -340,7 +340,7 @@ declare_clippy_lint! { /// It makes the code less readable, especially to spot wildcard pattern use in match arm. /// /// ### Example - /// ```rust + /// ```no_run /// # let s = "foo"; /// match s { /// "a" => {}, @@ -349,7 +349,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let s = "foo"; /// match s { /// "a" => {}, @@ -371,7 +371,7 @@ declare_clippy_lint! { /// Just readability – `let` doesn't nest, whereas a `match` does. /// /// ### Example - /// ```rust + /// ```no_run /// enum Wrapper { /// Data(i32), /// } @@ -384,7 +384,7 @@ declare_clippy_lint! { /// ``` /// /// The correct use would be: - /// ```rust + /// ```no_run /// enum Wrapper { /// Data(i32), /// } @@ -410,7 +410,7 @@ declare_clippy_lint! { /// is actually binding temporary value, bringing a 'dropped while borrowed' error. /// /// ### Example - /// ```rust + /// ```no_run /// # let a = 1; /// # let b = 2; /// match (a, b) { @@ -421,7 +421,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let a = 1; /// # let b = 2; /// let (c, d) = (a, b); @@ -441,7 +441,7 @@ declare_clippy_lint! { /// matching all enum variants explicitly. /// /// ### Example - /// ```rust + /// ```no_run /// # struct A { a: i32 } /// let a = A { a: 5 }; /// @@ -452,7 +452,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # struct A { a: i32 } /// # let a = A { a: 5 }; /// match a { @@ -484,7 +484,7 @@ declare_clippy_lint! { /// drop order. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::task::Poll; /// # use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; /// if let Ok(_) = Ok::<i32, i32>(42) {} @@ -503,7 +503,7 @@ declare_clippy_lint! { /// /// The more idiomatic use would be: /// - /// ```rust + /// ```no_run /// # use std::task::Poll; /// # use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; /// if Ok::<i32, i32>(42).is_ok() {} @@ -535,7 +535,7 @@ declare_clippy_lint! { /// `cfg` attributes that remove an arm evaluating to `false`. /// /// ### Example - /// ```rust + /// ```no_run /// let x = Some(5); /// /// let a = match x { @@ -551,7 +551,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let x = Some(5); /// let a = matches!(x, Some(0)); /// ``` @@ -664,7 +664,7 @@ declare_clippy_lint! { /// It is unnecessarily verbose and complex. /// /// ### Example - /// ```rust + /// ```no_run /// fn func(opt: Option<Result<u64, String>>) { /// let n = match opt { /// Some(n) => match n { @@ -676,7 +676,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn func(opt: Option<Result<u64, String>>) { /// let n = match opt { /// Some(Ok(n)) => n, @@ -698,7 +698,7 @@ declare_clippy_lint! { /// Concise code helps focusing on behavior instead of boilerplate. /// /// ### Example - /// ```rust + /// ```no_run /// let foo: Option<i32> = None; /// match foo { /// Some(v) => v, @@ -707,7 +707,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let foo: Option<i32> = None; /// foo.unwrap_or(1); /// ``` @@ -761,7 +761,7 @@ declare_clippy_lint! { /// The arm is unreachable, which is likely a mistake /// /// ### Example - /// ```rust + /// ```no_run /// # let text = "Foo"; /// match &*text.to_ascii_lowercase() { /// "foo" => {}, @@ -770,7 +770,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # let text = "Foo"; /// match &*text.to_ascii_lowercase() { /// "foo" => {}, @@ -823,7 +823,7 @@ declare_clippy_lint! { /// println!("All done!"); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # use std::sync::Mutex; /// # struct State {} /// # impl State { @@ -861,7 +861,7 @@ declare_clippy_lint! { /// always return), it is more clear to write `return Err(x)`. /// /// ### Example - /// ```rust + /// ```no_run /// fn foo(fail: bool) -> Result<i32, String> { /// if fail { /// Err("failed")?; @@ -871,7 +871,7 @@ declare_clippy_lint! { /// ``` /// Could be written: /// - /// ```rust + /// ```no_run /// fn foo(fail: bool) -> Result<i32, String> { /// if fail { /// return Err("failed".into()); @@ -893,14 +893,14 @@ declare_clippy_lint! { /// Using the `map` method is clearer and more concise. /// /// ### Example - /// ```rust + /// ```no_run /// match Some(0) { /// Some(x) => Some(x + 1), /// None => None, /// }; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// Some(0).map(|x| x + 1); /// ``` #[clippy::version = "1.52.0"] @@ -917,7 +917,7 @@ declare_clippy_lint! { /// Using the `filter` method is clearer and more concise. /// /// ### Example - /// ```rust + /// ```no_run /// match Some(0) { /// Some(x) => if x % 2 == 0 { /// Some(x) @@ -928,7 +928,7 @@ declare_clippy_lint! { /// }; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// Some(0).filter(|&x| x % 2 == 0); /// ``` #[clippy::version = "1.66.0"] @@ -961,13 +961,12 @@ declare_clippy_lint! { /// _ => todo!(), /// } /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub REDUNDANT_GUARDS, complexity, "checks for unnecessary guards in match expressions" } -#[derive(Default)] pub struct Matches { msrv: Msrv, infallible_destructuring_match_linted: bool, @@ -978,7 +977,7 @@ impl Matches { pub fn new(msrv: Msrv) -> Self { Self { msrv, - ..Matches::default() + infallible_destructuring_match_linted: false, } } } diff --git a/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs b/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs index 7c0485914..8f0083f81 100644 --- a/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs +++ b/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs @@ -1,4 +1,4 @@ -use clippy_utils::consts::{constant, constant_full_int, miri_to_const, FullInt}; +use clippy_utils::consts::{constant, constant_full_int, mir_to_const, FullInt}; use clippy_utils::diagnostics::span_lint_and_note; use core::cmp::Ordering; use rustc_hir::{Arm, Expr, PatKind, RangeEnd}; @@ -37,14 +37,14 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) Some(lhs) => constant(cx, cx.typeck_results(), lhs)?, None => { let min_val_const = ty.numeric_min_val(cx.tcx)?; - miri_to_const(cx, mir::Const::from_ty_const(min_val_const, cx.tcx))? + mir_to_const(cx, mir::Const::from_ty_const(min_val_const, cx.tcx))? }, }; let rhs_const = match rhs { Some(rhs) => constant(cx, cx.typeck_results(), rhs)?, None => { let max_val_const = ty.numeric_max_val(cx.tcx)?; - miri_to_const(cx, mir::Const::from_ty_const(max_val_const, cx.tcx))? + mir_to_const(cx, mir::Const::from_ty_const(max_val_const, cx.tcx))? }, }; let lhs_val = lhs_const.int_value(cx, ty)?; diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs index 0efeeacc9..4a44d596a 100644 --- a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs +++ b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs @@ -27,8 +27,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) { arm, Arm { pat: Pat { - kind: PatKind::Wild, - .. + kind: PatKind::Wild, .. }, .. }, @@ -42,14 +41,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) { (PatKind::Ref(..), None) | (_, Some(_)) => continue, _ => arm.pat.span, }; - emit_redundant_guards( - cx, - outer_arm, - if_expr.span, - pat_span, - &binding, - arm.guard, - ); + emit_redundant_guards(cx, outer_arm, if_expr.span, pat_span, &binding, arm.guard); } // `Some(x) if let Some(2) = x` else if let Guard::IfLet(let_expr) = guard @@ -60,14 +52,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) { (PatKind::Ref(..), None) | (_, Some(_)) => continue, _ => let_expr.pat.span, }; - emit_redundant_guards( - cx, - outer_arm, - let_expr.span, - pat_span, - &binding, - None, - ); + emit_redundant_guards(cx, outer_arm, let_expr.span, pat_span, &binding, None); } // `Some(x) if x == Some(2)` // `Some(x) if Some(2) == x` @@ -93,14 +78,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) { (ExprKind::AddrOf(..), None) | (_, Some(_)) => continue, _ => pat.span, }; - emit_redundant_guards( - cx, - outer_arm, - if_expr.span, - pat_span, - &binding, - None, - ); + emit_redundant_guards(cx, outer_arm, if_expr.span, pat_span, &binding, None); } } } @@ -116,7 +94,9 @@ fn get_pat_binding<'tcx>( guard_expr: &Expr<'_>, outer_arm: &Arm<'tcx>, ) -> Option<PatBindingInfo> { - if let Some(local) = path_to_local(guard_expr) && !is_local_used(cx, outer_arm.body, local) { + if let Some(local) = path_to_local(guard_expr) + && !is_local_used(cx, outer_arm.body, local) + { let mut span = None; let mut byref_ident = None; let mut multiple_bindings = false; @@ -223,10 +203,7 @@ fn expr_can_be_pat(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Ctor(..), ..), ) }, - ExprKind::AddrOf(..) - | ExprKind::Array(..) - | ExprKind::Tup(..) - | ExprKind::Struct(..) => true, + ExprKind::AddrOf(..) | ExprKind::Array(..) | ExprKind::Tup(..) | ExprKind::Struct(..) => true, ExprKind::Lit(lit) if !matches!(lit.node, LitKind::Float(..)) => true, _ => false, } { diff --git a/src/tools/clippy/clippy_lints/src/matches/single_match.rs b/src/tools/clippy/clippy_lints/src/matches/single_match.rs index 6b05c6bff..48efd0230 100644 --- a/src/tools/clippy/clippy_lints/src/matches/single_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/single_match.rs @@ -20,8 +20,7 @@ fn empty_arm_has_comment(cx: &LateContext<'_>, span: Span) -> bool { if let Some(ff) = get_source_text(cx, span) && let Some(text) = ff.as_str() { - text.as_bytes().windows(2) - .any(|w| w == b"//" || w == b"/*") + text.as_bytes().windows(2).any(|w| w == b"//" || w == b"/*") } else { false } @@ -51,7 +50,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: // block with 2+ statements or 1 expr and 1+ statement Some(els) } else { - // not a block or an emtpy block w/ comments, don't lint + // not a block or an empty block w/ comments, don't lint return; }; diff --git a/src/tools/clippy/clippy_lints/src/mem_replace.rs b/src/tools/clippy/clippy_lints/src/mem_replace.rs index 8a921d4af..760c8f59c 100644 --- a/src/tools/clippy/clippy_lints/src/mem_replace.rs +++ b/src/tools/clippy/clippy_lints/src/mem_replace.rs @@ -1,5 +1,5 @@ +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; @@ -11,7 +11,7 @@ use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::source_map::Span; +use rustc_span::Span; use rustc_span::symbol::sym; declare_clippy_lint! { @@ -25,14 +25,14 @@ declare_clippy_lint! { /// `None`. /// /// ### Example - /// ```rust + /// ```no_run /// use std::mem; /// /// let mut an_option = Some(0); /// let replaced = mem::replace(&mut an_option, None); /// ``` /// Is better expressed with: - /// ```rust + /// ```no_run /// let mut an_option = Some(0); /// let taken = an_option.take(); /// ``` @@ -53,7 +53,7 @@ declare_clippy_lint! { /// observed in the case of a panic. /// /// ### Example - /// ``` + /// ```no_run /// use std::mem; ///# fn may_panic(v: Vec<i32>) -> Vec<i32> { v } /// @@ -84,12 +84,12 @@ declare_clippy_lint! { /// take the current value and replace it with the default value of that type. /// /// ### Example - /// ```rust + /// ```no_run /// let mut text = String::from("foo"); /// let replaced = std::mem::replace(&mut text, String::default()); /// ``` /// Is better expressed with: - /// ```rust + /// ```no_run /// let mut text = String::from("foo"); /// let taken = std::mem::take(&mut text); /// ``` diff --git a/src/tools/clippy/clippy_lints/src/methods/bytecount.rs b/src/tools/clippy/clippy_lints/src/methods/bytecount.rs index f490a7175..35370355f 100644 --- a/src/tools/clippy/clippy_lints/src/methods/bytecount.rs +++ b/src/tools/clippy/clippy_lints/src/methods/bytecount.rs @@ -1,8 +1,8 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::match_type; +use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::is_local_used; -use clippy_utils::{path_to_local_id, paths, peel_blocks, peel_ref_operators, strip_pat_refs}; +use clippy_utils::{path_to_local_id, peel_blocks, peel_ref_operators, strip_pat_refs}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Closure, Expr, ExprKind, PatKind}; @@ -25,9 +25,9 @@ pub(super) fn check<'tcx>( if let PatKind::Binding(_, arg_id, _, _) = strip_pat_refs(param.pat).kind; if let ExprKind::Binary(ref op, l, r) = body.value.kind; if op.node == BinOpKind::Eq; - if match_type(cx, + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(filter_recv).peel_refs(), - &paths::SLICE_ITER); + sym::SliceIter); let operand_is_arg = |expr| { let expr = peel_ref_operators(cx, peel_blocks(expr)); path_to_local_id(expr, arg_id) diff --git a/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs b/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs index c5fc145b2..baafb7030 100644 --- a/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs +++ b/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs @@ -24,8 +24,9 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E let n = snippet_with_applicability(cx, n_arg.span, "..", &mut applicability); if let Some(parent) = clippy_utils::get_parent_expr(cx, expr) - && let Some((name, _, _, _, _)) = method_call(parent) - && name == "unwrap" { + && let Some((name, _, _, _, _)) = method_call(parent) + && name == "unwrap" + { span_lint_and_sugg( cx, BYTES_NTH, @@ -33,7 +34,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E &format!("called `.bytes().nth().unwrap()` on a `{caller_type}`"), "try", format!("{receiver}.as_bytes()[{n}]",), - applicability + applicability, ); } else { span_lint_and_sugg( @@ -42,8 +43,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E expr.span, &format!("called `.bytes().nth()` on a `{caller_type}`"), "try", - format!("{receiver}.as_bytes().get({n}).copied()"), - applicability + format!("{receiver}.as_bytes().get({n}).copied()"), + applicability, ); }; } diff --git a/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs b/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs index ddf3c9f27..926bd06ba 100644 --- a/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs +++ b/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs @@ -1,7 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::paths; use clippy_utils::source::snippet_with_context; -use clippy_utils::ty::{is_type_diagnostic_item, match_type}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -22,15 +20,14 @@ pub(super) fn check( } let obj_ty = cx.typeck_results().expr_ty(receiver).peel_refs(); - if let ty::Adt(_, subst) = obj_ty.kind() { - let caller_type = if is_type_diagnostic_item(cx, obj_ty, sym::Rc) { - "Rc" - } else if is_type_diagnostic_item(cx, obj_ty, sym::Arc) { - "Arc" - } else if match_type(cx, obj_ty, &paths::WEAK_RC) || match_type(cx, obj_ty, &paths::WEAK_ARC) { - "Weak" - } else { - return; + if let ty::Adt(adt, subst) = obj_ty.kind() + && let Some(name) = cx.tcx.get_diagnostic_name(adt.did()) + { + let caller_type = match name { + sym::Rc => "Rc", + sym::Arc => "Arc", + sym::RcWeak | sym::ArcWeak => "Weak", + _ => return, }; // Sometimes unnecessary ::<_> after Rc/Arc/Weak diff --git a/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs b/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs index 4e6ec61f6..fcafa1622 100644 --- a/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs +++ b/src/tools/clippy/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/src/tools/clippy/clippy_lints/src/methods/err_expect.rs b/src/tools/clippy/clippy_lints/src/methods/err_expect.rs index 3d82441c0..a8d4dd5e4 100644 --- a/src/tools/clippy/clippy_lints/src/methods/err_expect.rs +++ b/src/tools/clippy/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/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs index 40e487bf6..a49970b53 100644 --- a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs +++ b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::source_map::Span; +use rustc_span::Span; use rustc_span::symbol::sym; use std::borrow::Cow; diff --git a/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs b/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs index 3fef53739..7818be811 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs @@ -4,8 +4,7 @@ use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::source_map::Span; -use rustc_span::sym; +use rustc_span::{sym, Span}; use super::FILETYPE_IS_FILE; diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs index c9eaa185a..5bb8c7a6b 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs @@ -11,7 +11,7 @@ use rustc_hir::def::Res; use rustc_hir::{Closure, Expr, ExprKind, PatKind, PathSegment, QPath, UnOp}; use rustc_lint::LateContext; use rustc_middle::ty::adjustment::Adjust; -use rustc_span::source_map::Span; +use rustc_span::Span; use rustc_span::symbol::{sym, Ident, Symbol}; use std::borrow::Cow; @@ -159,7 +159,7 @@ impl<'tcx> OffendingFilterExpr<'tcx> { OffendingFilterExpr::IsSome { .. } => CalledMethod::OptionIsSome, OffendingFilterExpr::IsOk { .. } => CalledMethod::ResultIsOk, OffendingFilterExpr::Matches { .. } => unreachable!("only IsSome and IsOk can get here"), - } + }, }) } else { None @@ -189,7 +189,8 @@ impl<'tcx> OffendingFilterExpr<'tcx> { // scrutinee variant_span variant_ident else_ let (scrutinee, else_, variant_ident, variant_span) = match higher::IfLetOrMatch::parse(cx, map_body.value) { - // For `if let` we want to check that the variant matching arm references the local created by its pattern + // For `if let` we want to check that the variant matching arm references the local created by + // its pattern Some(higher::IfLetOrMatch::IfLet(sc, pat, then, Some(else_))) if let Some((ident, span)) = expr_uses_local(pat, then) => { @@ -211,7 +212,10 @@ impl<'tcx> OffendingFilterExpr<'tcx> { && let Some(mac) = root_macro_call(else_.peel_blocks().span) && (is_panic(cx, mac.def_id) || cx.tcx.opt_item_name(mac.def_id) == Some(sym::unreachable)) { - Some(CheckResult::PatternMatching { variant_span, variant_ident }) + Some(CheckResult::PatternMatching { + variant_span, + variant_ident, + }) } else { None } @@ -228,18 +232,20 @@ impl<'tcx> OffendingFilterExpr<'tcx> { // .filter(|x| effect(x).is_some()).map(|x| effect(x).unwrap()) // vs. // .filter_map(|x| effect(x)) - // + // // the latter only calls `effect` once let side_effect_expr_span = receiver.can_have_side_effects().then_some(receiver.span); - if cx.tcx.is_diagnostic_item(sym::Option, recv_ty.did()) - && path.ident.name == sym!(is_some) - { - Some(Self::IsSome { receiver, side_effect_expr_span }) - } else if cx.tcx.is_diagnostic_item(sym::Result, recv_ty.did()) - && path.ident.name == sym!(is_ok) - { - Some(Self::IsOk { receiver, side_effect_expr_span }) + if cx.tcx.is_diagnostic_item(sym::Option, recv_ty.did()) && path.ident.name == sym!(is_some) { + Some(Self::IsSome { + receiver, + side_effect_expr_span, + }) + } else if cx.tcx.is_diagnostic_item(sym::Result, recv_ty.did()) && path.ident.name == sym!(is_ok) { + Some(Self::IsOk { + receiver, + side_effect_expr_span, + }) } else { None } diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs index 336572549..9950c4428 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs @@ -54,7 +54,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: & "use `filter` then `map` instead", format!( "filter(|&{param_snippet}| {derefs}{filter}).map(|{param_snippet}| {map})", - derefs="*".repeat(needed_derefs) + derefs = "*".repeat(needed_derefs) ), Applicability::MachineApplicable, ); diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs index 3337b250c..8291c373f 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs @@ -1,15 +1,14 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::{is_expr_identity_function, is_trait_method}; +use clippy_utils::{is_expr_untyped_identity_function, is_trait_method}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::source_map::Span; -use rustc_span::sym; +use rustc_span::{sym, Span}; use super::FILTER_MAP_IDENTITY; pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, filter_map_arg: &hir::Expr<'_>, filter_map_span: Span) { - if is_trait_method(cx, expr, sym::Iterator) && is_expr_identity_function(cx, filter_map_arg) { + if is_trait_method(cx, expr, sym::Iterator) && is_expr_untyped_identity_function(cx, filter_map_arg) { span_lint_and_sugg( cx, FILTER_MAP_IDENTITY, diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs index 3f89e5931..f94fe2218 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs +++ b/src/tools/clippy/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/src/tools/clippy/clippy_lints/src/methods/flat_map_identity.rs b/src/tools/clippy/clippy_lints/src/methods/flat_map_identity.rs index 84a21de0a..651ea34f9 100644 --- a/src/tools/clippy/clippy_lints/src/methods/flat_map_identity.rs +++ b/src/tools/clippy/clippy_lints/src/methods/flat_map_identity.rs @@ -1,10 +1,9 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::{is_expr_identity_function, is_trait_method}; +use clippy_utils::{is_expr_untyped_identity_function, is_trait_method}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::source_map::Span; -use rustc_span::sym; +use rustc_span::{sym, Span}; use super::FLAT_MAP_IDENTITY; @@ -15,7 +14,7 @@ pub(super) fn check<'tcx>( flat_map_arg: &'tcx hir::Expr<'_>, flat_map_span: Span, ) { - if is_trait_method(cx, expr, sym::Iterator) && is_expr_identity_function(cx, flat_map_arg) { + if is_trait_method(cx, expr, sym::Iterator) && is_expr_untyped_identity_function(cx, flat_map_arg) { span_lint_and_sugg( cx, FLAT_MAP_IDENTITY, diff --git a/src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs b/src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs index 172c397fb..0a4a381b8 100644 --- a/src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs +++ b/src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs @@ -4,8 +4,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::source_map::Span; -use rustc_span::sym; +use rustc_span::{sym, Span}; use super::FLAT_MAP_OPTION; use clippy_utils::ty::is_type_diagnostic_item; diff --git a/src/tools/clippy/clippy_lints/src/methods/format_collect.rs b/src/tools/clippy/clippy_lints/src/methods/format_collect.rs index 1f8863f85..3e5162ef4 100644 --- a/src/tools/clippy/clippy_lints/src/methods/format_collect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/format_collect.rs @@ -24,10 +24,16 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, map_arg: &Expr<'_>, m && let Some(mac) = root_macro_call_first_node(cx, value) && is_format_macro(cx, mac.def_id) { - span_lint_and_then(cx, FORMAT_COLLECT, expr.span, "use of `format!` to build up a string from an iterator", |diag| { - diag.span_help(map_span, "call `fold` instead") - .span_help(value.span.source_callsite(), "... and use the `write!` macro here") - .note("this can be written more efficiently by appending to a `String` directly"); - }); + span_lint_and_then( + cx, + FORMAT_COLLECT, + expr.span, + "use of `format!` to build up a string from an iterator", + |diag| { + diag.span_help(map_span, "call `fold` instead") + .span_help(value.span.source_callsite(), "... and use the `write!` macro here") + .note("this can be written more efficiently by appending to a `String` directly"); + }, + ); } } diff --git a/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs b/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs index 66dfce368..4040d3a5f 100644 --- a/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; use clippy_utils::ty::implements_trait; -use clippy_utils::{is_expr_path_def_path, paths, sugg}; +use clippy_utils::{is_path_diagnostic_item, sugg}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; @@ -13,7 +13,7 @@ use super::FROM_ITER_INSTEAD_OF_COLLECT; pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>], func: &hir::Expr<'_>) { if_chain! { - if is_expr_path_def_path(cx, func, &paths::FROM_ITERATOR_METHOD); + if is_path_diagnostic_item(cx, func, sym::from_iter_fn); let ty = cx.typeck_results().expr_ty(expr); let arg_ty = cx.typeck_results().expr_ty(&args[0]); if let Some(iter_id) = cx.tcx.get_diagnostic_item(sym::Iterator); diff --git a/src/tools/clippy/clippy_lints/src/methods/get_first.rs b/src/tools/clippy/clippy_lints/src/methods/get_first.rs index ee063adac..2e1dd3ec6 100644 --- a/src/tools/clippy/clippy_lints/src/methods/get_first.rs +++ b/src/tools/clippy/clippy_lints/src/methods/get_first.rs @@ -1,12 +1,13 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::is_slice_of_primitives; use clippy_utils::source::snippet_with_applicability; +use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_ast::LitKind; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::source_map::Spanned; +use rustc_span::sym; use super::GET_FIRST; @@ -19,21 +20,34 @@ pub(super) fn check<'tcx>( if_chain! { if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if let Some(impl_id) = cx.tcx.impl_of_method(method_id); - if cx.tcx.type_of(impl_id).instantiate_identity().is_slice(); - if let Some(_) = is_slice_of_primitives(cx, recv); + let identity = cx.tcx.type_of(impl_id).instantiate_identity(); if let hir::ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = arg.kind; then { - let mut app = Applicability::MachineApplicable; - let slice_name = snippet_with_applicability(cx, recv.span, "..", &mut app); - span_lint_and_sugg( - cx, - GET_FIRST, - expr.span, - &format!("accessing first element with `{slice_name}.get(0)`"), - "try", - format!("{slice_name}.first()"), - app, - ); + if identity.is_slice() { + let mut app = Applicability::MachineApplicable; + let slice_name = snippet_with_applicability(cx, recv.span, "..", &mut app); + span_lint_and_sugg( + cx, + GET_FIRST, + expr.span, + &format!("accessing first element with `{slice_name}.get(0)`"), + "try", + format!("{slice_name}.first()"), + app, + ); + } else if is_type_diagnostic_item(cx, identity, sym::VecDeque){ + let mut app = Applicability::MachineApplicable; + let slice_name = snippet_with_applicability(cx, recv.span, "..", &mut app); + span_lint_and_sugg( + cx, + GET_FIRST, + expr.span, + &format!("accessing first element with `{slice_name}.get(0)`"), + "try", + format!("{slice_name}.front()"), + app, + ); + } } } } diff --git a/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs index a8f090d1d..afdcb3b65 100644 --- a/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs +++ b/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs @@ -43,9 +43,9 @@ pub(super) fn check<'tcx>( // by not requiring an explicit reference let needs_ref = if let Some(parent) = get_parent_expr(cx, expr) && let hir::ExprKind::Unary(hir::UnOp::Deref, _) - | hir::ExprKind::MethodCall(..) - | hir::ExprKind::Field(..) - | hir::ExprKind::Index(..) = parent.kind + | hir::ExprKind::MethodCall(..) + | hir::ExprKind::Field(..) + | hir::ExprKind::Index(..) = parent.kind { if let hir::ExprKind::Unary(hir::UnOp::Deref, _) = parent.kind { // if the user explicitly dereferences the result, we can adjust diff --git a/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs b/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs index 631741d92..6686d42c9 100644 --- a/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs +++ b/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{is_type_lang_item, walk_ptrs_ty_depth}; -use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; @@ -22,7 +21,7 @@ pub fn check( if_chain! { if args.is_empty() && method_name == sym::to_string; if let Some(to_string_meth_did) = cx.typeck_results().type_dependent_def_id(expr.hir_id); - if match_def_path(cx, to_string_meth_did, &paths::TO_STRING_METHOD); + if cx.tcx.is_diagnostic_item(sym::to_string_method, to_string_meth_did); if let Some(args) = cx.typeck_results().node_args_opt(expr.hir_id); let arg_ty = cx.typeck_results().expr_ty_adjusted(receiver); let self_ty = args.type_at(0); diff --git a/src/tools/clippy/clippy_lints/src/methods/inspect_for_each.rs b/src/tools/clippy/clippy_lints/src/methods/inspect_for_each.rs index 23cc192c3..ad4b6fa13 100644 --- a/src/tools/clippy/clippy_lints/src/methods/inspect_for_each.rs +++ b/src/tools/clippy/clippy_lints/src/methods/inspect_for_each.rs @@ -2,8 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::is_trait_method; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::source_map::Span; -use rustc_span::sym; +use rustc_span::{sym, Span}; use super::INSPECT_FOR_EACH; diff --git a/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs b/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs index 8adf9e370..bbd964c10 100644 --- a/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs +++ b/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; -use rustc_span::source_map::Span; +use rustc_span::Span; use rustc_span::symbol::{sym, Symbol}; use super::INTO_ITER_ON_REF; diff --git a/src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs b/src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs index 120f3d5f4..e96395096 100644 --- a/src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs +++ b/src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs @@ -1,9 +1,9 @@ //! Lint for `c.is_digit(10)` use super::IS_DIGIT_ASCII_RADIX; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{constant_full_int, 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/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs index 674d34517..625325d4c 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs @@ -3,9 +3,8 @@ use super::ITER_KV_MAP; use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::{snippet, snippet_with_applicability}; -use clippy_utils::sugg; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::visitors::is_local_used; +use clippy_utils::{pat_is_wild, sugg}; use rustc_hir::{BindingAnnotation, Body, BorrowKind, ByRef, Expr, ExprKind, Mutability, Pat, PatKind}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty; @@ -26,7 +25,7 @@ pub(super) fn check<'tcx>( if_chain! { if !expr.span.from_expansion(); if let ExprKind::Closure(c) = m_arg.kind; - if let Body {params: [p], value: body_expr, generator_kind: _ } = cx.tcx.hir().body(c.body); + if let Body {params: [p], value: body_expr, coroutine_kind: _ } = cx.tcx.hir().body(c.body); if let PatKind::Tuple([key_pat, val_pat], _) = p.pat.kind; let (replacement_kind, annotation, bound_ident) = match (&key_pat.kind, &val_pat.kind) { @@ -84,13 +83,3 @@ pub(super) fn check<'tcx>( } } } - -/// Returns `true` if the pattern is a `PatWild`, or is an ident prefixed with `_` -/// that is not locally used. -fn pat_is_wild<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx PatKind<'_>, body: &'tcx Expr<'_>) -> bool { - match *pat { - PatKind::Wild => true, - PatKind::Binding(_, id, ident, None) if ident.as_str().starts_with('_') => !is_local_used(cx, body, id), - _ => false, - } -} diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_out_of_bounds.rs b/src/tools/clippy/clippy_lints/src/methods/iter_out_of_bounds.rs index 79c6d6325..29e69b111 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_out_of_bounds.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_out_of_bounds.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_note; use clippy_utils::higher::VecArgs; -use clippy_utils::{expr_or_init, is_trait_method, match_def_path, paths}; +use clippy_utils::{expr_or_init, is_trait_method}; use rustc_ast::LitKind; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; @@ -26,14 +26,14 @@ fn get_iterator_length<'tcx>(cx: &LateContext<'tcx>, iter: &'tcx Expr<'tcx>) -> }; let did = adt.did(); - if match_def_path(cx, did, &paths::ARRAY_INTO_ITER) { + if cx.tcx.is_diagnostic_item(sym::ArrayIntoIter, did) { // For array::IntoIter<T, const N: usize>, the length is the second generic // parameter. substs .const_at(1) .try_eval_target_usize(cx.tcx, cx.param_env) .map(u128::from) - } else if match_def_path(cx, did, &paths::SLICE_ITER) + } else if cx.tcx.is_diagnostic_item(sym::SliceIter, did) && let ExprKind::MethodCall(_, recv, ..) = iter.kind { if let ty::Array(_, len) = cx.typeck_results().expr_ty(recv).peel_refs().kind() { @@ -47,11 +47,11 @@ fn get_iterator_length<'tcx>(cx: &LateContext<'tcx>, iter: &'tcx Expr<'tcx>) -> } else { None } - } else if match_def_path(cx, did, &paths::ITER_EMPTY) { + } else if cx.tcx.is_diagnostic_item(sym::IterEmpty, did) { Some(0) - } else if match_def_path(cx, did, &paths::ITER_ONCE) { + } else if cx.tcx.is_diagnostic_item(sym::IterOnce, did) { Some(1) - } else { + } else { None } } diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs index a49dd98db..eac6df054 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs @@ -60,9 +60,15 @@ pub(super) fn check<'tcx>( } if let Op::NeedlessMove(_, expr) = op { - let rustc_hir::ExprKind::Closure(closure) = expr.kind else { return } ; - let body @ Body { params: [p], .. } = cx.tcx.hir().body(closure.body) else { return }; - let mut delegate = MoveDelegate {used_move : HirIdSet::default()}; + let rustc_hir::ExprKind::Closure(closure) = expr.kind else { + return; + }; + let body @ Body { params: [p], .. } = cx.tcx.hir().body(closure.body) else { + return; + }; + let mut delegate = MoveDelegate { + used_move: HirIdSet::default(), + }; let infcx = cx.tcx.infer_ctxt().build(); ExprUseVisitor::new( @@ -77,7 +83,7 @@ pub(super) fn check<'tcx>( let mut to_be_discarded = false; p.pat.walk(|it| { - if delegate.used_move.contains(&it.hir_id){ + if delegate.used_move.contains(&it.hir_id) { to_be_discarded = true; return false; } @@ -87,8 +93,8 @@ pub(super) fn check<'tcx>( | PatKind::Ref(_, Mutability::Mut) => { to_be_discarded = true; false - } - _ => { true } + }, + _ => true, } }); @@ -99,46 +105,42 @@ pub(super) fn check<'tcx>( let (lint, msg, trailing_clone) = match op { Op::RmCloned | Op::NeedlessMove(_, _) => (REDUNDANT_CLONE, "unneeded cloning of iterator items", ""), - Op::LaterCloned | Op::FixClosure(_, _) => (ITER_OVEREAGER_CLONED, "unnecessarily eager cloning of iterator items", ".cloned()"), + Op::LaterCloned | Op::FixClosure(_, _) => ( + ITER_OVEREAGER_CLONED, + "unnecessarily eager cloning of iterator items", + ".cloned()", + ), }; - span_lint_and_then( - cx, - lint, - expr.span, - msg, - |diag| { - match op { - Op::RmCloned | Op::LaterCloned => { - let method_span = expr.span.with_lo(cloned_call.span.hi()); - if let Some(mut snip) = snippet_opt(cx, method_span) { - snip.push_str(trailing_clone); - let replace_span = expr.span.with_lo(cloned_recv.span.hi()); - diag.span_suggestion(replace_span, "try", snip, Applicability::MachineApplicable); - } - } - Op::FixClosure(name, predicate_expr) => { - if let Some(predicate) = snippet_opt(cx, predicate_expr.span) { - let new_closure = if let ExprKind::Closure(_) = predicate_expr.kind { - predicate.replacen('|', "|&", 1) - } else { - format!("|&x| {predicate}(x)") - }; - let snip = format!(".{name}({new_closure}).cloned()" ); - let replace_span = expr.span.with_lo(cloned_recv.span.hi()); - diag.span_suggestion(replace_span, "try", snip, Applicability::MachineApplicable); - } - } - Op::NeedlessMove(_, _) => { - let method_span = expr.span.with_lo(cloned_call.span.hi()); - if let Some(snip) = snippet_opt(cx, method_span) { - let replace_span = expr.span.with_lo(cloned_recv.span.hi()); - diag.span_suggestion(replace_span, "try", snip, Applicability::MaybeIncorrect); - } - } + span_lint_and_then(cx, lint, expr.span, msg, |diag| match op { + Op::RmCloned | Op::LaterCloned => { + let method_span = expr.span.with_lo(cloned_call.span.hi()); + if let Some(mut snip) = snippet_opt(cx, method_span) { + snip.push_str(trailing_clone); + let replace_span = expr.span.with_lo(cloned_recv.span.hi()); + diag.span_suggestion(replace_span, "try", snip, Applicability::MachineApplicable); } - } - ); + }, + Op::FixClosure(name, predicate_expr) => { + if let Some(predicate) = snippet_opt(cx, predicate_expr.span) { + let new_closure = if let ExprKind::Closure(_) = predicate_expr.kind { + predicate.replacen('|', "|&", 1) + } else { + format!("|&x| {predicate}(x)") + }; + let snip = format!(".{name}({new_closure}).cloned()"); + let replace_span = expr.span.with_lo(cloned_recv.span.hi()); + diag.span_suggestion(replace_span, "try", snip, Applicability::MachineApplicable); + } + }, + Op::NeedlessMove(_, _) => { + let method_span = expr.span.with_lo(cloned_call.span.hi()); + if let Some(snip) = snippet_opt(cx, method_span) { + let replace_span = expr.span.with_lo(cloned_recv.span.hi()); + diag.span_suggestion(replace_span, "try", snip, Applicability::MaybeIncorrect); + } + }, + }); } } diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs b/src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs index dabed0aff..51145afda 100644 --- a/src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs +++ b/src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs @@ -1,6 +1,6 @@ +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::{Msrv, ITERATOR_TRY_FOLD}; use clippy_utils::source::snippet_opt; use clippy_utils::ty::implements_trait; use rustc_errors::Applicability; @@ -21,7 +21,7 @@ pub(super) fn check<'tcx>( msrv: &Msrv, ) { if !in_external_macro(cx.sess(), fold_span) - && msrv.meets(ITERATOR_TRY_FOLD) + && msrv.meets(msrvs::ITERATOR_TRY_FOLD) && let init_ty = cx.typeck_results().expr_ty(init) && let Some(try_trait) = cx.tcx.lang_items().try_trait() && implements_trait(cx, init_ty, try_trait, &[]) @@ -44,7 +44,7 @@ pub(super) fn check<'tcx>( fold_span, "usage of `Iterator::fold` on a type that implements `Try`", "use `try_fold` instead", - format!("try_fold({init_snip}, {args_snip} ...)", ), + format!("try_fold({init_snip}, {args_snip} ...)",), Applicability::HasPlaceholders, ); } diff --git a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs index 880efe60c..e0f8cb1b9 100644 --- a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs +++ b/src/tools/clippy/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}; use clippy_utils::{is_diag_trait_item, peel_blocks}; diff --git a/src/tools/clippy/clippy_lints/src/methods/map_identity.rs b/src/tools/clippy/clippy_lints/src/methods/map_identity.rs index 7be1ce483..bcfd0de8e 100644 --- a/src/tools/clippy/clippy_lints/src/methods/map_identity.rs +++ b/src/tools/clippy/clippy_lints/src/methods/map_identity.rs @@ -1,11 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{is_expr_identity_function, is_trait_method}; +use clippy_utils::{is_expr_untyped_identity_function, is_trait_method}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::source_map::Span; -use rustc_span::sym; +use rustc_span::{sym, Span}; use super::MAP_IDENTITY; @@ -23,7 +22,7 @@ pub(super) fn check( if is_trait_method(cx, expr, sym::Iterator) || is_type_diagnostic_item(cx, caller_ty, sym::Result) || is_type_diagnostic_item(cx, caller_ty, sym::Option); - if is_expr_identity_function(cx, map_arg); + if is_expr_untyped_identity_function(cx, map_arg); if let Some(sugg_span) = expr.span.trim_start(caller.span); then { span_lint_and_sugg( diff --git a/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs index 5464e455d..cb81b3919 100644 --- a/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs +++ b/src/tools/clippy/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; @@ -56,7 +56,7 @@ pub(super) fn check<'tcx>( // lint, with note if neither arg is > 1 line and both map() and // unwrap_or_else() have the same span let multiline = map_snippet.lines().count() > 1 || unwrap_snippet.lines().count() > 1; - let same_span = map_arg.span.ctxt() == unwrap_arg.span.ctxt(); + let same_span = map_arg.span.eq_ctxt(unwrap_arg.span); if same_span && !multiline { let var_snippet = snippet(cx, recv.span, ".."); span_lint_and_sugg( diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index e7fcef9e9..a71a136eb 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -99,6 +99,7 @@ mod suspicious_to_owned; mod type_id_on_box; mod uninit_assumed_init; mod unit_hash; +mod unnecessary_fallible_conversions; mod unnecessary_filter_map; mod unnecessary_fold; mod unnecessary_iter_cloned; @@ -112,13 +113,14 @@ mod useless_asref; mod utils; mod vec_resize_to_zero; mod verbose_file_reads; +mod waker_clone_wake; mod wrong_self_convention; mod zst_offset; use bind_instead_of_map::BindInsteadOfMap; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; -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}; use if_chain::if_chain; @@ -142,11 +144,11 @@ declare_clippy_lint! { /// implements `Copy`. /// /// ### Example - /// ```rust + /// ```no_run /// [1, 2, 3].iter().cloned(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// [1, 2, 3].iter().copied(); /// ``` #[clippy::version = "1.53.0"] @@ -165,14 +167,14 @@ declare_clippy_lint! { /// with repetitive code. /// /// ### Example - /// ```rust + /// ```no_run /// let hello = "hesuo worpd" /// .replace('s', "l") /// .replace("u", "l") /// .replace('p', "l"); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let hello = "hesuo worpd".replace(['s', 'u', 'p'], "l"); /// ``` #[clippy::version = "1.65.0"] @@ -194,14 +196,14 @@ declare_clippy_lint! { /// A code that relies on that side-effect could fail. /// /// ### Examples - /// ```rust + /// ```no_run /// # let vec = vec!["string".to_string()]; /// vec.iter().cloned().take(10); /// vec.iter().cloned().last(); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let vec = vec!["string".to_string()]; /// vec.iter().take(10).cloned(); /// vec.iter().last().cloned(); @@ -222,11 +224,11 @@ declare_clippy_lint! { /// `Option` is used to produce 0 or 1 items. /// /// ### Example - /// ```rust + /// ```no_run /// let nums: Vec<i32> = ["1", "2", "whee!"].iter().flat_map(|x| x.parse().ok()).collect(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let nums: Vec<i32> = ["1", "2", "whee!"].iter().filter_map(|x| x.parse().ok()).collect(); /// ``` #[clippy::version = "1.53.0"] @@ -254,7 +256,7 @@ declare_clippy_lint! { /// where they may get displayed. Activate this lint to do just that. /// /// ### Examples - /// ```rust + /// ```no_run /// # let option = Some(1); /// # let result: Result<usize, ()> = Ok(1); /// option.unwrap(); @@ -262,7 +264,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let option = Some(1); /// # let result: Result<usize, ()> = Ok(1); /// option.expect("more helpful message"); @@ -293,14 +295,14 @@ declare_clippy_lint! { /// It is better to write the value directly without the indirection. /// /// ### Examples - /// ```rust + /// ```no_run /// let val1 = Some(1).unwrap(); /// let val2 = Ok::<_, ()>(1).unwrap(); /// let val3 = Err::<(), _>(1).unwrap_err(); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let val1 = 1; /// let val2 = 1; /// let val3 = 1; @@ -363,7 +365,7 @@ declare_clippy_lint! { /// them. /// /// ### Example - /// ```rust + /// ```no_run /// struct X; /// impl X { /// fn add(&self, other: &X) -> X { @@ -412,7 +414,7 @@ declare_clippy_lint! { /// mutable reference to a `as_..` function. /// /// ### Example - /// ```rust + /// ```no_run /// # struct X; /// impl X { /// fn as_str(self) -> &'static str { @@ -439,13 +441,13 @@ declare_clippy_lint! { /// The error type needs to implement `Debug` /// /// ### Example - /// ```rust + /// ```no_run /// # let x = Ok::<_, ()>(()); /// x.ok().expect("why did I do this again?"); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let x = Ok::<_, ()>(()); /// x.expect("why did I do this again?"); /// ``` @@ -496,7 +498,7 @@ declare_clippy_lint! { /// heuristic to try to identify such cases. However, the heuristic can produce false negatives. /// /// ### Examples - /// ```rust + /// ```no_run /// # let x = Some(1); /// # let mut map = std::collections::HashMap::<u64, String>::new(); /// x.unwrap_or(Default::default()); @@ -504,7 +506,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let x = Some(1); /// # let mut map = std::collections::HashMap::<u64, String>::new(); /// x.unwrap_or_default(); @@ -529,7 +531,7 @@ declare_clippy_lint! { /// The order of the arguments is not in execution order /// /// ### Examples - /// ```rust + /// ```no_run /// # let option = Some(1); /// # let result: Result<usize, ()> = Ok(1); /// # fn some_function(foo: ()) -> usize { 1 } @@ -539,7 +541,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let option = Some(1); /// # let result: Result<usize, ()> = Ok(1); /// # fn some_function(foo: ()) -> usize { 1 } @@ -565,13 +567,13 @@ declare_clippy_lint! { /// The order of the arguments is not in execution order. /// /// ### Example - /// ```rust + /// ```no_run /// # let opt = Some(1); /// opt.map_or(None, |a| Some(a + 1)); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let opt = Some(1); /// opt.and_then(|a| Some(a + 1)); /// ``` @@ -590,13 +592,13 @@ declare_clippy_lint! { /// `_.ok()`. /// /// ### Example - /// ```rust + /// ```no_run /// # let r: Result<u32, &str> = Ok(1); /// assert_eq!(Some(1), r.map_or(None, Some)); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let r: Result<u32, &str> = Ok(1); /// assert_eq!(Some(1), r.ok()); /// ``` @@ -616,7 +618,7 @@ declare_clippy_lint! { /// `_.map(|x| y)` or `_.map_err(|x| y)`. /// /// ### Example - /// ```rust + /// ```no_run /// # fn opt() -> Option<&'static str> { Some("42") } /// # fn res() -> Result<&'static str, &'static str> { Ok("42") } /// let _ = opt().and_then(|s| Some(s.len())); @@ -626,7 +628,7 @@ declare_clippy_lint! { /// /// The correct use would be: /// - /// ```rust + /// ```no_run /// # fn opt() -> Option<&'static str> { Some("42") } /// # fn res() -> Result<&'static str, &'static str> { Ok("42") } /// let _ = opt().map(|s| s.len()); @@ -648,13 +650,13 @@ declare_clippy_lint! { /// `_.find(_)`. /// /// ### Example - /// ```rust + /// ```no_run /// # let vec = vec![1]; /// vec.iter().filter(|x| **x == 0).next(); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let vec = vec![1]; /// vec.iter().find(|x| **x == 0); /// ``` @@ -673,13 +675,13 @@ declare_clippy_lint! { /// `_.find(!condition)`. /// /// ### Example - /// ```rust + /// ```no_run /// # let vec = vec![1]; /// vec.iter().skip_while(|x| **x == 0).next(); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let vec = vec![1]; /// vec.iter().find(|x| **x != 0); /// ``` @@ -698,7 +700,7 @@ declare_clippy_lint! { /// `_.flat_map(_)` for `Iterator` or `_.and_then(_)` for `Option` /// /// ### Example - /// ```rust + /// ```no_run /// let vec = vec![vec![1]]; /// let opt = Some(5); /// @@ -707,7 +709,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let vec = vec![vec![1]]; /// # let opt = Some(5); /// vec.iter().flat_map(|x| x.iter()); @@ -729,7 +731,7 @@ declare_clippy_lint! { /// less performant. /// /// ### Example - /// ```rust + /// ```no_run /// # #![allow(unused)] /// (0_i32..10) /// .filter(|n| n.checked_add(1).is_some()) @@ -737,7 +739,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # #[allow(unused)] /// (0_i32..10).filter_map(|n| n.checked_add(1)); /// ``` @@ -757,14 +759,14 @@ declare_clippy_lint! { /// less performant. /// /// ### Example - /// ```rust + /// ```no_run /// (0_i32..10) /// .find(|n| n.checked_add(1).is_some()) /// .map(|n| n.checked_add(1).unwrap()); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// (0_i32..10).find_map(|n| n.checked_add(1)); /// ``` #[clippy::version = "1.51.0"] @@ -782,12 +784,12 @@ declare_clippy_lint! { /// `_.find_map(_)`. /// /// ### Example - /// ```rust + /// ```no_run /// (0..3).filter_map(|x| if x == 2 { Some(x) } else { None }).next(); /// ``` /// Can be written as /// - /// ```rust + /// ```no_run /// (0..3).find_map(|x| if x == 2 { Some(x) } else { None }); /// ``` #[clippy::version = "1.36.0"] @@ -804,12 +806,12 @@ declare_clippy_lint! { /// Readability, this can be written more concisely by using `flatten`. /// /// ### Example - /// ```rust + /// ```no_run /// # let iter = vec![vec![0]].into_iter(); /// iter.flat_map(|x| x); /// ``` /// Can be written as - /// ```rust + /// ```no_run /// # let iter = vec![vec![0]].into_iter(); /// iter.flatten(); /// ``` @@ -830,7 +832,7 @@ declare_clippy_lint! { /// * `!_.any(_)`, or `!_.contains(_)` for `is_none()`. /// /// ### Example - /// ```rust + /// ```no_run /// # #![allow(unused)] /// let vec = vec![1]; /// vec.iter().find(|x| **x == 0).is_some(); @@ -839,7 +841,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let vec = vec![1]; /// vec.iter().any(|x| *x == 0); /// @@ -862,13 +864,13 @@ declare_clippy_lint! { /// `_.starts_with(_)`. /// /// ### Example - /// ```rust + /// ```no_run /// let name = "foo"; /// if name.chars().next() == Some('_') {}; /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let name = "foo"; /// if name.starts_with('_') {}; /// ``` @@ -897,13 +899,13 @@ declare_clippy_lint! { /// actually expensive to call or not. /// /// ### Example - /// ```rust + /// ```no_run /// # let foo = Some(String::new()); /// foo.unwrap_or(String::from("empty")); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let foo = Some(String::new()); /// foo.unwrap_or_else(|| String::from("empty")); /// ``` @@ -921,7 +923,7 @@ declare_clippy_lint! { /// You should use `.unwrap_or(…)` instead for clarity. /// /// ### Example - /// ```rust + /// ```no_run /// # let fallback = "fallback"; /// // Result /// # type Error = &'static str; @@ -933,7 +935,7 @@ declare_clippy_lint! { /// let value = option.or(Some(fallback)).unwrap(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # let fallback = "fallback"; /// // Result /// # let result: Result<&str, &str> = Err("error"); @@ -962,7 +964,7 @@ declare_clippy_lint! { /// change the semantics of the program, but you shouldn't rely on that anyway. /// /// ### Example - /// ```rust + /// ```no_run /// # let foo = Some(String::new()); /// # let err_code = "418"; /// # let err_msg = "I'm a teapot"; @@ -975,7 +977,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let foo = Some(String::new()); /// # let err_code = "418"; /// # let err_msg = "I'm a teapot"; @@ -996,7 +998,7 @@ declare_clippy_lint! { /// generics, not for using the `clone` method on a concrete type. /// /// ### Example - /// ```rust + /// ```no_run /// 42u64.clone(); /// ``` #[clippy::version = "pre 1.29.0"] @@ -1017,7 +1019,7 @@ declare_clippy_lint! { /// data. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::rc::Rc; /// let x = Rc::new(1); /// @@ -1025,7 +1027,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # use std::rc::Rc; /// # let x = Rc::new(1); /// Rc::clone(&x); @@ -1047,7 +1049,7 @@ declare_clippy_lint! { /// facilities. /// /// ### Example - /// ```rust + /// ```no_run /// // Generic implementation for `T: Display` is used (slow) /// ["foo", "bar"].iter().map(|s| s.to_string()); /// @@ -1070,7 +1072,7 @@ declare_clippy_lint! { /// /// ### Example /// In an impl block: - /// ```rust + /// ```no_run /// # struct Foo; /// # struct NotAFoo; /// impl Foo { @@ -1080,7 +1082,7 @@ declare_clippy_lint! { /// } /// ``` /// - /// ```rust + /// ```no_run /// # struct Foo; /// struct Bar(Foo); /// impl Foo { @@ -1091,7 +1093,7 @@ declare_clippy_lint! { /// } /// ``` /// - /// ```rust + /// ```no_run /// # struct Foo; /// # struct FooError; /// impl Foo { @@ -1103,14 +1105,14 @@ declare_clippy_lint! { /// ``` /// /// Or in a trait definition: - /// ```rust + /// ```no_run /// pub trait Trait { /// // Bad. The type name must contain `Self` /// fn new(); /// } /// ``` /// - /// ```rust + /// ```no_run /// pub trait Trait { /// // Good. Return type contains `Self` /// fn new() -> Self; @@ -1178,11 +1180,11 @@ declare_clippy_lint! { /// automatically does this without suspicious-looking `unwrap` calls. /// /// ### Example - /// ```rust + /// ```no_run /// let _ = std::iter::empty::<Option<i32>>().filter(Option::is_some).map(Option::unwrap); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let _ = std::iter::empty::<Option<i32>>().flatten(); /// ``` #[clippy::version = "1.53.0"] @@ -1201,7 +1203,7 @@ declare_clippy_lint! { /// but is more readable. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::collections::HashSet; /// # let mut s = HashSet::new(); /// # s.insert(1); @@ -1209,7 +1211,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # use std::collections::HashSet; /// # let mut s = HashSet::new(); /// # s.insert(1); @@ -1231,13 +1233,13 @@ declare_clippy_lint! { /// readable. /// /// ### Example - /// ```rust + /// ```no_run /// let some_vec = vec![0, 1, 2, 3]; /// let bad_vec = some_vec.iter().nth(3); /// let bad_slice = &some_vec[..].iter().nth(3); /// ``` /// The correct use would be: - /// ```rust + /// ```no_run /// let some_vec = vec![0, 1, 2, 3]; /// let bad_vec = some_vec.get(3); /// let bad_slice = &some_vec[..].get(3); @@ -1256,13 +1258,13 @@ declare_clippy_lint! { /// `.nth(x)` is cleaner /// /// ### Example - /// ```rust + /// ```no_run /// let some_vec = vec![0, 1, 2, 3]; /// let bad_vec = some_vec.iter().skip(3).next(); /// let bad_slice = &some_vec[..].iter().skip(3).next(); /// ``` /// The correct use would be: - /// ```rust + /// ```no_run /// let some_vec = vec![0, 1, 2, 3]; /// let bad_vec = some_vec.iter().nth(3); /// let bad_slice = &some_vec[..].iter().nth(3); @@ -1281,13 +1283,13 @@ declare_clippy_lint! { /// `.into_iter()` is simpler with better performance. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::collections::HashSet; /// let mut foo = vec![0, 1, 2, 3]; /// let bar: HashSet<usize> = foo.drain(..).collect(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # use std::collections::HashSet; /// let foo = vec![0, 1, 2, 3]; /// let bar: HashSet<usize> = foo.into_iter().collect(); @@ -1315,13 +1317,13 @@ declare_clippy_lint! { /// `x.get(index).unwrap()` instead of `x[index]`. /// /// ### Example - /// ```rust + /// ```no_run /// let x = vec![2, 3, 5]; /// let last_element = x.get(x.len() - 1); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let x = vec![2, 3, 5]; /// let last_element = x.last(); /// ``` @@ -1351,13 +1353,13 @@ declare_clippy_lint! { /// trait. /// /// ### Example - /// ```rust + /// ```no_run /// let mut some_vec = vec![0, 1, 2, 3]; /// let last = some_vec.get(3).unwrap(); /// *some_vec.get_mut(0).unwrap() = 1; /// ``` /// The correct use would be: - /// ```rust + /// ```no_run /// let mut some_vec = vec![0, 1, 2, 3]; /// let last = some_vec[3]; /// some_vec[0] = 1; @@ -1376,7 +1378,7 @@ declare_clippy_lint! { /// Using `append` instead of `extend` is more concise and faster /// /// ### Example - /// ```rust + /// ```no_run /// let mut a = vec![1, 2, 3]; /// let mut b = vec![4, 5, 6]; /// @@ -1384,7 +1386,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let mut a = vec![1, 2, 3]; /// let mut b = vec![4, 5, 6]; /// @@ -1405,7 +1407,7 @@ declare_clippy_lint! { /// `.push_str(s)` is clearer /// /// ### Example - /// ```rust + /// ```no_run /// let abc = "abc"; /// let def = String::from("def"); /// let mut s = String::new(); @@ -1413,7 +1415,7 @@ declare_clippy_lint! { /// s.extend(def.chars()); /// ``` /// The correct use would be: - /// ```rust + /// ```no_run /// let abc = "abc"; /// let def = String::from("def"); /// let mut s = String::new(); @@ -1435,12 +1437,12 @@ declare_clippy_lint! { /// `.to_vec()` is clearer /// /// ### Example - /// ```rust + /// ```no_run /// let s = [1, 2, 3, 4, 5]; /// let s2: Vec<isize> = s[..].iter().cloned().collect(); /// ``` /// The better use would be: - /// ```rust + /// ```no_run /// let s = [1, 2, 3, 4, 5]; /// let s2: Vec<isize> = s.to_vec(); /// ``` @@ -1460,13 +1462,13 @@ declare_clippy_lint! { /// `_.ends_with(_)`. /// /// ### Example - /// ```rust + /// ```no_run /// # let name = "_"; /// name.chars().last() == Some('_') || name.chars().next_back() == Some('-'); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let name = "_"; /// name.ends_with('_') || name.ends_with('-'); /// ``` @@ -1485,13 +1487,13 @@ declare_clippy_lint! { /// The call is unnecessary. /// /// ### Example - /// ```rust + /// ```no_run /// # fn do_stuff(x: &[i32]) {} /// let x: &[i32] = &[1, 2, 3, 4, 5]; /// do_stuff(x.as_ref()); /// ``` /// The correct use would be: - /// ```rust + /// ```no_run /// # fn do_stuff(x: &[i32]) {} /// let x: &[i32] = &[1, 2, 3, 4, 5]; /// do_stuff(x); @@ -1512,13 +1514,13 @@ declare_clippy_lint! { /// Readability. /// /// ### Example - /// ```rust + /// ```no_run /// # #[allow(unused)] /// (0..3).fold(false, |acc, x| acc || x > 2); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// (0..3).any(|x| x > 2); /// ``` #[clippy::version = "pre 1.29.0"] @@ -1538,14 +1540,14 @@ declare_clippy_lint! { /// operation is being performed. /// /// ### Example - /// ```rust + /// ```no_run /// let _ = (0..3).filter_map(|x| if x > 2 { Some(x) } else { None }); /// /// // As there is no transformation of the argument this could be written as: /// let _ = (0..3).filter(|&x| x > 2); /// ``` /// - /// ```rust + /// ```no_run /// let _ = (0..4).filter_map(|x| Some(x + 1)); /// /// // As there is no conditional check on the argument this could be written as: @@ -1568,14 +1570,14 @@ declare_clippy_lint! { /// operation is being performed. /// /// ### Example - /// ```rust + /// ```no_run /// let _ = (0..3).find_map(|x| if x > 2 { Some(x) } else { None }); /// /// // As there is no transformation of the argument this could be written as: /// let _ = (0..3).find(|&x| x > 2); /// ``` /// - /// ```rust + /// ```no_run /// let _ = (0..4).find_map(|x| Some(x + 1)); /// /// // As there is no conditional check on the argument this could be written as: @@ -1598,13 +1600,13 @@ declare_clippy_lint! { /// `iter_mut` directly. /// /// ### Example - /// ```rust + /// ```no_run /// # let vec = vec![3, 4, 5]; /// (&vec).into_iter(); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let vec = vec![3, 4, 5]; /// (&vec).iter(); /// ``` @@ -1625,7 +1627,7 @@ declare_clippy_lint! { /// completion, you can just use `for_each` instead. /// /// ### Example - /// ```rust + /// ```no_run /// let _ = (0..3).map(|x| x + 2).count(); /// ``` #[clippy::version = "1.39.0"] @@ -1647,7 +1649,7 @@ declare_clippy_lint! { /// data, but those are not yet rigorously defined. /// /// ### Example - /// ```rust + /// ```no_run /// // Beware the UB /// use std::mem::MaybeUninit; /// @@ -1656,7 +1658,7 @@ declare_clippy_lint! { /// /// Note that the following is OK: /// - /// ```rust + /// ```no_run /// use std::mem::MaybeUninit; /// /// let _: [MaybeUninit<bool>; 5] = unsafe { @@ -1677,7 +1679,7 @@ declare_clippy_lint! { /// These can be written simply with `saturating_add/sub` methods. /// /// ### Example - /// ```rust + /// ```no_run /// # let y: u32 = 0; /// # let x: u32 = 100; /// let add = x.checked_add(y).unwrap_or(u32::MAX); @@ -1686,7 +1688,7 @@ declare_clippy_lint! { /// /// can be written using dedicated methods for saturating addition/subtraction as: /// - /// ```rust + /// ```no_run /// # let y: u32 = 0; /// # let x: u32 = 100; /// let add = x.saturating_add(y); @@ -1707,7 +1709,7 @@ declare_clippy_lint! { /// This is a no-op, and likely unintended /// /// ### Example - /// ```rust + /// ```no_run /// unsafe { (&() as *const ()).offset(1) }; /// ``` #[clippy::version = "1.41.0"] @@ -1727,7 +1729,7 @@ declare_clippy_lint! { /// symlink in windows. Using `!FileType::is_dir()` is a better way to that intention. /// /// ### Example - /// ```rust + /// ```no_run /// # || { /// let metadata = std::fs::metadata("foo.txt")?; /// let filetype = metadata.file_type(); @@ -1741,7 +1743,7 @@ declare_clippy_lint! { /// /// should be written as: /// - /// ```rust + /// ```no_run /// # || { /// let metadata = std::fs::metadata("foo.txt")?; /// let filetype = metadata.file_type(); @@ -1767,13 +1769,13 @@ declare_clippy_lint! { /// `_.as_deref()`. /// /// ### Example - /// ```rust + /// ```no_run /// # let opt = Some("".to_string()); /// opt.as_ref().map(String::as_str) /// # ; /// ``` /// Can be written as - /// ```rust + /// ```no_run /// # let opt = Some("".to_string()); /// opt.as_deref() /// # ; @@ -1792,14 +1794,14 @@ declare_clippy_lint! { /// These can be shortened into `.get()` /// /// ### Example - /// ```rust + /// ```no_run /// # let a = [1, 2, 3]; /// # let b = vec![1, 2, 3]; /// a[2..].iter().next(); /// b.iter().next(); /// ``` /// should be written as: - /// ```rust + /// ```no_run /// # let a = [1, 2, 3]; /// # let b = vec![1, 2, 3]; /// a.get(2); @@ -1820,14 +1822,14 @@ declare_clippy_lint! { /// It's less clear that we are pushing a single character. /// /// ### Example - /// ```rust + /// ```no_run /// # let mut string = String::new(); /// string.insert_str(0, "R"); /// string.push_str("R"); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let mut string = String::new(); /// string.insert(0, 'R'); /// string.push('R'); @@ -1860,14 +1862,14 @@ declare_clippy_lint! { /// side effects. Eagerly evaluating them can change the semantics of the program. /// /// ### Example - /// ```rust + /// ```no_run /// // example code where clippy issues a warning /// let opt: Option<u32> = None; /// /// opt.unwrap_or_else(|| 42); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let opt: Option<u32> = None; /// /// opt.unwrap_or(42); @@ -1886,11 +1888,11 @@ declare_clippy_lint! { /// Using `try_for_each` instead is more readable and idiomatic. /// /// ### Example - /// ```rust + /// ```no_run /// (0..3).map(|t| Err(t)).collect::<Result<(), _>>(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// (0..3).try_for_each(|t| Err(t)); /// ``` #[clippy::version = "1.49.0"] @@ -1909,7 +1911,7 @@ declare_clippy_lint! { /// [FromIterator documentation](https://doc.rust-lang.org/std/iter/trait.FromIterator.html) /// /// ### Example - /// ```rust + /// ```no_run /// let five_fives = std::iter::repeat(5).take(5); /// /// let v = Vec::from_iter(five_fives); @@ -1917,7 +1919,7 @@ declare_clippy_lint! { /// assert_eq!(v, vec![5, 5, 5, 5, 5]); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let five_fives = std::iter::repeat(5).take(5); /// /// let v: Vec<i32> = five_fives.collect(); @@ -1939,7 +1941,7 @@ declare_clippy_lint! { /// inside `inspect` at the beginning of the closure in `for_each`. /// /// ### Example - /// ```rust + /// ```no_run /// [1,2,3,4,5].iter() /// .inspect(|&x| println!("inspect the number: {}", x)) /// .for_each(|&x| { @@ -1947,7 +1949,7 @@ declare_clippy_lint! { /// }); /// ``` /// Can be written as - /// ```rust + /// ```no_run /// [1,2,3,4,5].iter() /// .for_each(|&x| { /// println!("inspect the number: {}", x); @@ -1968,12 +1970,12 @@ declare_clippy_lint! { /// Readability, this can be written more concisely by using `flatten`. /// /// ### Example - /// ```rust + /// ```no_run /// # let iter = vec![Some(1)].into_iter(); /// iter.filter_map(|x| x); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # let iter = vec![Some(1)].into_iter(); /// iter.flatten(); /// ``` @@ -1991,12 +1993,12 @@ declare_clippy_lint! { /// It can be written more concisely without the call to `map`. /// /// ### Example - /// ```rust + /// ```no_run /// let x = [1, 2, 3]; /// let y: Vec<_> = x.iter().map(|x| x).map(|x| 2*x).collect(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let x = [1, 2, 3]; /// let y: Vec<_> = x.iter().map(|x| 2*x).collect(); /// ``` @@ -2015,13 +2017,13 @@ declare_clippy_lint! { /// readable. /// /// ### Example - /// ```rust + /// ```no_run /// # #[allow(unused)] /// "Hello".bytes().nth(3); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # #[allow(unused)] /// "Hello".as_bytes().get(3); /// ``` @@ -2040,13 +2042,13 @@ declare_clippy_lint! { /// to why we are calling `to_vec` on something that is already a `Vec` or calling `to_owned` on something that is already owned. /// /// ### Example - /// ```rust + /// ```no_run /// let a = vec![1, 2, 3]; /// let b = a.to_vec(); /// let c = a.to_owned(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let a = vec![1, 2, 3]; /// let b = a.clone(); /// let c = a.clone(); @@ -2066,7 +2068,7 @@ declare_clippy_lint! { /// readable. /// /// ### Example - /// ```rust + /// ```no_run /// # #![allow(unused)] /// let some_vec = vec![0, 1, 2, 3]; /// @@ -2075,7 +2077,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let some_vec = vec![0, 1, 2, 3]; /// /// some_vec.len(); @@ -2104,7 +2106,7 @@ declare_clippy_lint! { /// was the original intent, using `into_owned` instead. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::borrow::Cow; /// let s = "Hello world!"; /// let cow = Cow::Borrowed(s); @@ -2113,7 +2115,7 @@ declare_clippy_lint! { /// assert!(matches!(data, Cow::Borrowed(_))) /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # use std::borrow::Cow; /// let s = "Hello world!"; /// let cow = Cow::Borrowed(s); @@ -2122,7 +2124,7 @@ declare_clippy_lint! { /// assert!(matches!(data, Cow::Borrowed(_))) /// ``` /// or - /// ```rust + /// ```no_run /// # use std::borrow::Cow; /// let s = "Hello world!"; /// let cow = Cow::Borrowed(s); @@ -2146,7 +2148,7 @@ declare_clippy_lint! { /// likely to be intended as a different number. /// /// ### Example - /// ```rust + /// ```no_run /// # let s = ""; /// for x in s.splitn(1, ":") { /// // .. @@ -2154,7 +2156,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let s = ""; /// for x in s.splitn(2, ":") { /// // .. @@ -2174,12 +2176,12 @@ declare_clippy_lint! { /// These are both harder to read, as well as less performant. /// /// ### Example - /// ```rust + /// ```no_run /// let x: String = std::iter::repeat('x').take(10).collect(); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let x: String = "x".repeat(10); /// ``` #[clippy::version = "1.54.0"] @@ -2231,13 +2233,13 @@ declare_clippy_lint! { /// The function `split` is simpler and there is no performance difference in these cases, considering /// that both functions return a lazy iterator. /// ### Example - /// ```rust + /// ```no_run /// let str = "key=value=add"; /// let _ = str.splitn(3, '=').next().unwrap(); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let str = "key=value=add"; /// let _ = str.split('=').next().unwrap(); /// ``` @@ -2261,13 +2263,13 @@ declare_clippy_lint! { /// [#8148](https://github.com/rust-lang/rust-clippy/issues/8148). /// /// ### Example - /// ```rust + /// ```no_run /// let path = std::path::Path::new("x"); /// foo(&path.to_string_lossy().to_string()); /// fn foo(s: &str) {} /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let path = std::path::Path::new("x"); /// foo(&path.to_string_lossy()); /// fn foo(s: &str) {} @@ -2286,13 +2288,13 @@ declare_clippy_lint! { /// `.collect::<String>()` is more concise and might be more performant /// /// ### Example - /// ```rust + /// ```no_run /// let vector = vec!["hello", "world"]; /// let output = vector.iter().map(|item| item.to_uppercase()).collect::<Vec<String>>().join(""); /// println!("{}", output); /// ``` /// The correct use would be: - /// ```rust + /// ```no_run /// let vector = vec!["hello", "world"]; /// let output = vector.iter().map(|item| item.to_uppercase()).collect::<String>(); /// println!("{}", output); @@ -2319,13 +2321,13 @@ declare_clippy_lint! { /// Redundant code and improving readability. /// /// ### Example - /// ```rust + /// ```no_run /// let a = Some(&1); /// let b = a.as_deref(); // goes from Option<&i32> to Option<&i32> /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let a = Some(&1); /// let b = a; /// ``` @@ -2345,13 +2347,13 @@ declare_clippy_lint! { /// `is_digit(..)` is slower and requires specifying the radix. /// /// ### Example - /// ```rust + /// ```no_run /// let c: char = '6'; /// c.is_digit(10); /// c.is_digit(16); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let c: char = '6'; /// c.is_ascii_digit(); /// c.is_ascii_hexdigit(); @@ -2371,12 +2373,12 @@ declare_clippy_lint! { /// In this case the modification is useless as it's a temporary that cannot be read from afterwards. /// /// ### Example - /// ```rust + /// ```no_run /// let x = Some(3); /// x.as_ref().take(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let x = Some(3); /// x.as_ref(); /// ``` @@ -2394,7 +2396,7 @@ declare_clippy_lint! { /// It's either a mistake or confusing. /// /// ### Example - /// ```rust + /// ```no_run /// "1234".replace("12", "12"); /// "1234".replacen("12", "12", 1); /// ``` @@ -2417,12 +2419,12 @@ declare_clippy_lint! { /// to account for similar patterns. /// /// ### Example - /// ```rust + /// ```no_run /// let x = true; /// x.then_some("a").unwrap_or("b"); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let x = true; /// if x { "a" } else { "b" }; /// ``` @@ -2444,12 +2446,12 @@ declare_clippy_lint! { /// /// ### Example /// - /// ```rust + /// ```no_run /// let a = [123].iter(); /// let b = Some(123).into_iter(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::iter; /// let a = iter::once(&123); /// let b = iter::once(123); @@ -2475,13 +2477,13 @@ declare_clippy_lint! { /// /// ### Example /// - /// ```rust + /// ```no_run /// use std::{slice, option}; /// let a: slice::Iter<i32> = [].iter(); /// let f: option::IntoIter<i32> = None.into_iter(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::iter; /// let a: iter::Empty<i32> = iter::empty(); /// let b: iter::Empty<i32> = iter::empty(); @@ -2511,7 +2513,7 @@ declare_clippy_lint! { /// faster in those cases. /// /// ### Example - /// ```rust + /// ```no_run /// # let vec = vec![1_u8]; /// let count = vec.iter().filter(|x| **x == 0u8).count(); /// ``` @@ -2537,12 +2539,12 @@ declare_clippy_lint! { /// `str::len()`. /// /// ### Example - /// ```rust + /// ```no_run /// "hello".bytes().count(); /// String::from("hello").bytes().count(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// "hello".len(); /// String::from("hello").len(); /// ``` @@ -2561,13 +2563,13 @@ declare_clippy_lint! { /// `ends_with` is case-sensitive and may not detect files with a valid extension. /// /// ### Example - /// ```rust + /// ```no_run /// fn is_rust_file(filename: &str) -> bool { /// filename.ends_with(".rs") /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn is_rust_file(filename: &str) -> bool { /// let filename = std::path::Path::new(filename); /// filename.extension() @@ -2590,13 +2592,13 @@ declare_clippy_lint! { /// result. /// /// ### Example - /// ```rust + /// ```no_run /// let x = vec![2, 3, 5]; /// let first_element = x.get(0); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let x = vec![2, 3, 5]; /// let first_element = x.first(); /// ``` @@ -2616,13 +2618,13 @@ declare_clippy_lint! { /// Concise code helps focusing on behavior instead of boilerplate. /// /// ### Examples - /// ```rust + /// ```no_run /// let foo: Option<i32> = None; /// foo.map_or(Err("error"), |v| Ok(v)); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let foo: Option<i32> = None; /// foo.ok_or("error"); /// ``` @@ -2642,7 +2644,7 @@ declare_clippy_lint! { /// Readability, this can be written more concisely /// /// ### Example - /// ```rust + /// ```no_run /// let x = vec![42, 43]; /// let y = x.iter(); /// let z = y.map(|i| *i); @@ -2650,7 +2652,7 @@ declare_clippy_lint! { /// /// The correct use would be: /// - /// ```rust + /// ```no_run /// let x = vec![42, 43]; /// let y = x.iter(); /// let z = y.cloned(); @@ -2670,7 +2672,7 @@ declare_clippy_lint! { /// /// ### Example /// Before: - /// ```rust + /// ```no_run /// use std::fmt; /// /// #[derive(Debug)] @@ -2772,7 +2774,7 @@ declare_clippy_lint! { /// guarantee. /// /// ### Example - /// ```rust + /// ```no_run /// use std::sync::{Arc, Mutex}; /// /// let mut value_rc = Arc::new(Mutex::new(42_u8)); @@ -2782,7 +2784,7 @@ declare_clippy_lint! { /// *value += 1; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::sync::{Arc, Mutex}; /// /// let mut value_rc = Arc::new(Mutex::new(42_u8)); @@ -2807,7 +2809,7 @@ declare_clippy_lint! { /// necessary. I don't know the worst case. /// /// ### Example - /// ```rust + /// ```no_run /// use std::fs::OpenOptions; /// /// OpenOptions::new().read(true).truncate(true); @@ -2828,7 +2830,7 @@ declare_clippy_lint! { /// previous defined path. /// /// ### Example - /// ```rust + /// ```no_run /// use std::path::PathBuf; /// /// let mut x = PathBuf::from("/foo"); @@ -2837,7 +2839,7 @@ declare_clippy_lint! { /// ``` /// Could be written: /// - /// ```rust + /// ```no_run /// use std::path::PathBuf; /// /// let mut x = PathBuf::from("/foo"); @@ -2859,13 +2861,13 @@ declare_clippy_lint! { /// The code is better expressed with `.enumerate()`. /// /// ### Example - /// ```rust + /// ```no_run /// # let x = vec![1]; /// let _ = x.iter().zip(0..x.len()); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let x = vec![1]; /// let _ = x.iter().enumerate(); /// ``` @@ -2890,13 +2892,13 @@ declare_clippy_lint! { /// the string is the intention behind this, `clone()` should be used. /// /// ### Example - /// ```rust + /// ```no_run /// fn main() { /// let x = String::from("hello world").repeat(1); /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn main() { /// let x = String::from("hello world").clone(); /// } @@ -2930,12 +2932,12 @@ declare_clippy_lint! { /// issue linked above. /// /// ### Example - /// ```rust + /// ```no_run /// let mut vec = vec![2, 1, 3]; /// vec.sort(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let mut vec = vec![2, 1, 3]; /// vec.sort_unstable(); /// ``` @@ -2963,14 +2965,14 @@ declare_clippy_lint! { /// assert_eq!(any_box.type_id(), TypeId::of::<i32>()); // ⚠️ this fails! /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::any::{Any, TypeId}; /// /// let any_box: Box<dyn Any> = Box::new(42_i32); /// assert_eq!((*any_box).type_id(), TypeId::of::<i32>()); /// // ^ dereference first, to call `type_id` on `dyn Any` /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub TYPE_ID_ON_BOX, suspicious, "calling `.type_id()` on `Box<dyn Any>`" @@ -2984,7 +2986,7 @@ declare_clippy_lint! { /// Hashing a unit value doesn't do anything as the implementation of `Hash` for `()` is a no-op. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::hash::Hash; /// # use std::collections::hash_map::DefaultHasher; /// # enum Foo { Empty, WithValue(u8) } @@ -2997,7 +2999,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # use std::hash::Hash; /// # use std::collections::hash_map::DefaultHasher; /// # enum Foo { Empty, WithValue(u8) } @@ -3030,14 +3032,14 @@ declare_clippy_lint! { /// imported by a use statement, then it will need to be added manually. /// /// ### Example - /// ```rust + /// ```no_run /// # struct A; /// # impl A { fn foo(&self) {} } /// # let mut vec: Vec<A> = Vec::new(); /// vec.sort_by(|a, b| a.foo().cmp(&b.foo())); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # struct A; /// # impl A { fn foo(&self) {} } /// # let mut vec: Vec<A> = Vec::new(); @@ -3057,12 +3059,12 @@ declare_clippy_lint! { /// This is probably an argument inversion mistake. /// /// ### Example - /// ```rust + /// ```no_run /// vec![1, 2, 3, 4, 5].resize(0, 5) /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// vec![1, 2, 3, 4, 5].clear() /// ``` #[clippy::version = "1.46.0"] @@ -3111,14 +3113,14 @@ declare_clippy_lint! { /// /// ### Example /// - /// ``` + /// ```no_run /// # use std::collections::HashMap; /// let map: HashMap<u32, u32> = HashMap::new(); /// let values = map.iter().map(|(_, value)| value).collect::<Vec<_>>(); /// ``` /// /// Use instead: - /// ``` + /// ```no_run /// # use std::collections::HashMap; /// let map: HashMap<u32, u32> = HashMap::new(); /// let values = map.values().collect::<Vec<_>>(); @@ -3184,14 +3186,14 @@ declare_clippy_lint! { /// this exact scenario. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::io; /// fn foo<T: io::Seek>(t: &mut T) { /// t.seek(io::SeekFrom::Start(0)); /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # use std::io; /// fn foo<T: io::Seek>(t: &mut T) { /// t.rewind(); @@ -3213,12 +3215,12 @@ declare_clippy_lint! { /// when this allocation may not be needed. /// /// ### Example - /// ```rust + /// ```no_run /// # let iterator = vec![1].into_iter(); /// let len = iterator.collect::<Vec<_>>().len(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # let iterator = vec![1].into_iter(); /// let len = iterator.count(); /// ``` @@ -3241,11 +3243,11 @@ declare_clippy_lint! { /// which is likely not what was intended. /// /// ### Example - /// ```rust + /// ```no_run /// std::process::Command::new("echo").arg("-n hello").spawn().unwrap(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// std::process::Command::new("echo").args(["-n", "hello"]).spawn().unwrap(); /// ``` #[clippy::version = "1.69.0"] @@ -3264,12 +3266,12 @@ declare_clippy_lint! { /// Calling `.clear()` also makes the intent clearer. /// /// ### Example - /// ```rust + /// ```no_run /// let mut v = vec![1, 2, 3]; /// v.drain(..); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let mut v = vec![1, 2, 3]; /// v.clear(); /// ``` @@ -3287,12 +3289,12 @@ declare_clippy_lint! { /// `.next_back()` is cleaner. /// /// ### Example - /// ```rust + /// ```no_run /// # let foo = [0; 10]; /// foo.iter().rev().next(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # let foo = [0; 10]; /// foo.iter().next_back(); /// ``` @@ -3320,13 +3322,13 @@ declare_clippy_lint! { /// to keep the capacity on the original `Vec`. /// /// ### Example - /// ```rust + /// ```no_run /// fn remove_all(v: &mut Vec<i32>) -> Vec<i32> { /// v.drain(..).collect() /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::mem; /// fn remove_all(v: &mut Vec<i32>) -> Vec<i32> { /// mem::take(v) @@ -3354,11 +3356,11 @@ declare_clippy_lint! { /// desirable in those cases. /// /// ### Example - /// ```rust + /// ```no_run /// vec![1, 2, 3].iter().fold(Some(0i32), |sum, i| sum?.checked_add(*i)); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// vec![1, 2, 3].iter().try_fold(0i32, |sum, i| sum.checked_add(*i)); /// ``` #[clippy::version = "1.72.0"] @@ -3368,6 +3370,7 @@ declare_clippy_lint! { } declare_clippy_lint! { + /// ### What it does /// Looks for calls to [`Stdin::read_line`] to read a line from the standard input /// into a string, then later attempting to parse this string into a type without first trimming it, which will /// always fail because the string has a trailing newline in it. @@ -3390,7 +3393,7 @@ declare_clippy_lint! { /// // ^^^^^^^^^^^ remove the trailing newline /// assert_eq!(num, 42); /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub READ_LINE_WITHOUT_TRIM, correctness, "calling `Stdin::read_line`, then trying to parse it without first trimming" @@ -3409,16 +3412,16 @@ declare_clippy_lint! { /// for situations where that additional performance is absolutely necessary. /// /// ### Example - /// ```rust + /// ```no_run /// # let c = 'c'; /// "\\.+*?()|[]{}^$#&-~".chars().any(|x| x == c); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # let c = 'c'; /// matches!(c, '\\' | '.' | '+' | '*' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~'); /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub STRING_LIT_CHARS_ANY, restriction, "checks for `<string_lit>.chars().any(|i| i == c)`" @@ -3438,13 +3441,13 @@ declare_clippy_lint! { /// so it can be safely ignored or unwrapped. /// /// ### Example - /// ```rust + /// ```no_run /// fn hex_encode(bytes: &[u8]) -> String { /// bytes.iter().map(|b| format!("{b:02X}")).collect() /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::fmt::Write; /// fn hex_encode(bytes: &[u8]) -> String { /// bytes.iter().fold(String::new(), |mut output, b| { @@ -3453,7 +3456,7 @@ declare_clippy_lint! { /// }) /// } /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub FORMAT_COLLECT, perf, "`format!`ing every element in a collection, then collecting the strings into a new `String`" @@ -3468,13 +3471,13 @@ declare_clippy_lint! { /// nothing. If not, the call should be removed. /// /// ### Example - /// ```rust + /// ```no_run /// let v = vec![1, 2, 3]; /// let x = v.iter().skip(0).collect::<Vec<_>>(); /// let y = v.iter().collect::<Vec<_>>(); /// assert_eq!(x, y); /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub ITER_SKIP_ZERO, correctness, "disallows `.skip(0)`" @@ -3494,18 +3497,18 @@ declare_clippy_lint! { /// This can create differing behavior, so better safe than sorry. /// /// ### Example - /// ```rust + /// ```no_run /// # fn really_expensive_fn(i: i32) -> i32 { i } /// # let v = vec![]; /// _ = v.into_iter().filter_map(|i| (i % 2 == 0).then(|| really_expensive_fn(i))); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # fn really_expensive_fn(i: i32) -> i32 { i } /// # let v = vec![]; /// _ = v.into_iter().filter(|i| i % 2 == 0).map(|i| really_expensive_fn(i)); /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub FILTER_MAP_BOOL_THEN, style, "checks for usage of `bool::then` in `Iterator::filter_map`" @@ -3520,7 +3523,7 @@ declare_clippy_lint! { /// can access the lock while this writer is active. /// /// ### Example - /// ```rust + /// ```no_run /// use std::sync::RwLock; /// fn assert_is_zero(lock: &RwLock<i32>) { /// let num = lock.write().unwrap(); @@ -3529,7 +3532,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// use std::sync::RwLock; /// fn assert_is_zero(lock: &RwLock<i32>) { /// let num = lock.read().unwrap(); @@ -3553,11 +3556,11 @@ declare_clippy_lint! { /// This is most likely not what the user intended to do. /// /// ### Example - /// ```rust + /// ```no_run /// for _ in [1, 2, 3].iter().take(4) {} /// ``` /// Use instead: - /// ```rust + /// ```no_run /// for _ in [1, 2, 3].iter() {} /// ``` #[clippy::version = "1.74.0"] @@ -3586,14 +3589,14 @@ declare_clippy_lint! { /// therefore ignored. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::path::Path; /// fn is_markdown(path: &Path) -> bool { /// path.ends_with(".md") /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # use std::path::Path; /// fn is_markdown(path: &Path) -> bool { /// path.extension().is_some_and(|ext| ext == "md") @@ -3613,14 +3616,14 @@ declare_clippy_lint! { /// The `as_str()` conversion is pointless and can be removed for simplicity and cleanliness. /// /// ### Example - /// ```rust + /// ```no_run /// # #![allow(unused)] /// let owned_string = "This is a string".to_owned(); /// owned_string.as_str().as_bytes(); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # #![allow(unused)] /// let owned_string = "This is a string".to_owned(); /// owned_string.as_bytes(); @@ -3631,6 +3634,55 @@ declare_clippy_lint! { "`as_str` used to call a method on `str` that is also available on `String`" } +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `waker.clone().wake()` + /// + /// ### Why is this bad? + /// Cloning the waker is not necessary, `wake_by_ref()` enables the same operation + /// without extra cloning/dropping. + /// + /// ### Example + /// ```rust,ignore + /// waker.clone().wake(); + /// ``` + /// Should be written + /// ```rust,ignore + /// waker.wake_by_ref(); + /// ``` + #[clippy::version = "1.75.0"] + pub WAKER_CLONE_WAKE, + perf, + "cloning a `Waker` only to wake it" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for calls to `TryInto::try_into` and `TryFrom::try_from` when their infallible counterparts + /// could be used. + /// + /// ### Why is this bad? + /// In those cases, the `TryInto` and `TryFrom` trait implementation is a blanket impl that forwards + /// to `Into` or `From`, which always succeeds. + /// The returned `Result<_, Infallible>` requires error handling to get the contained value + /// even though the conversion can never fail. + /// + /// ### Example + /// ```rust + /// let _: Result<i64, _> = 1i32.try_into(); + /// let _: Result<i64, _> = <_>::try_from(1i32); + /// ``` + /// Use `from`/`into` instead: + /// ```rust + /// let _: i64 = 1i32.into(); + /// let _: i64 = <_>::from(1i32); + /// ``` + #[clippy::version = "1.75.0"] + pub UNNECESSARY_FALLIBLE_CONVERSIONS, + style, + "calling the `try_from` and `try_into` trait methods when `From`/`Into` is implemented" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, @@ -3776,6 +3828,8 @@ impl_lint_pass!(Methods => [ ITER_OUT_OF_BOUNDS, PATH_ENDS_WITH_EXT, REDUNDANT_AS_STR, + WAKER_CLONE_WAKE, + UNNECESSARY_FALLIBLE_CONVERSIONS, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -3802,6 +3856,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { match expr.kind { hir::ExprKind::Call(func, args) => { from_iter_instead_of_collect::check(cx, expr, args, func); + unnecessary_fallible_conversions::check_function(cx, expr, func); }, hir::ExprKind::MethodCall(method_call, receiver, args, _) => { let method_span = method_call.ident.span; @@ -3877,21 +3932,21 @@ impl<'tcx> LateLintPass<'tcx> for Methods { } if sig.decl.implicit_self.has_implicit_self() - && !(self.avoid_breaking_exported_api + && !(self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(impl_item.owner_id.def_id)) - && let Some(first_arg) = iter_input_pats(sig.decl, cx.tcx.hir().body(id)).next() - && let Some(first_arg_ty) = first_arg_ty_opt - { - wrong_self_convention::check( - cx, - name, - self_ty, - first_arg_ty, - first_arg.pat.span, - implements_trait, - false - ); - } + && let Some(first_arg) = iter_input_pats(sig.decl, cx.tcx.hir().body(id)).next() + && let Some(first_arg_ty) = first_arg_ty_opt + { + wrong_self_convention::check( + cx, + name, + self_ty, + first_arg_ty, + first_arg.pat.span, + implements_trait, + false, + ); + } } // if this impl block implements a trait, lint in trait definition instead @@ -3976,10 +4031,16 @@ impl Methods { }, ("all", [arg]) => { if let Some(("cloned", recv2, [], _, _)) = method_call(recv) { - iter_overeager_cloned::check(cx, expr, recv, recv2, - iter_overeager_cloned::Op::NeedlessMove(name, arg), false); + iter_overeager_cloned::check( + cx, + expr, + recv, + recv2, + iter_overeager_cloned::Op::NeedlessMove(name, arg), + false, + ); } - } + }, ("and_then", [arg]) => { let biom_option_linted = bind_instead_of_map::OptionAndThenSome::check(cx, expr, recv, arg); let biom_result_linted = bind_instead_of_map::ResultAndThenOk::check(cx, expr, recv, arg); @@ -3987,24 +4048,35 @@ impl Methods { unnecessary_lazy_eval::check(cx, expr, recv, arg, "and"); } }, - ("any", [arg]) => { - match method_call(recv) { - Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::NeedlessMove(name, arg), false), - Some(("chars", recv, _, _, _)) if let ExprKind::Closure(arg) = arg.kind - && let body = cx.tcx.hir().body(arg.body) - && let [param] = body.params => { - string_lit_chars_any::check(cx, expr, recv, param, peel_blocks(body.value), &self.msrv); - } - _ => {} - } - } + ("any", [arg]) => match method_call(recv) { + Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check( + cx, + expr, + recv, + recv2, + iter_overeager_cloned::Op::NeedlessMove(name, arg), + false, + ), + Some(("chars", recv, _, _, _)) + if let ExprKind::Closure(arg) = arg.kind + && let body = cx.tcx.hir().body(arg.body) + && let [param] = body.params => + { + string_lit_chars_any::check(cx, expr, recv, param, peel_blocks(body.value), &self.msrv); + }, + _ => {}, + }, ("arg", [arg]) => { suspicious_command_arg_space::check(cx, recv, arg, span); - } + }, ("as_deref" | "as_deref_mut", []) => { needless_option_as_deref::check(cx, expr, recv, name); }, - ("as_bytes" | "is_empty", []) => if let Some(("as_str", recv, [], as_str_span, _)) = method_call(recv) { redundant_as_str::check(cx, expr, recv, as_str_span, span); }, + ("as_bytes" | "is_empty", []) => { + if let Some(("as_str", recv, [], as_str_span, _)) = method_call(recv) { + redundant_as_str::check(cx, expr, recv, as_str_span, span); + } + }, ("as_mut", []) => useless_asref::check(cx, expr, "as_mut", recv), ("as_ref", []) => useless_asref::check(cx, expr, "as_ref", recv), ("assume_init", []) => uninit_assumed_init::check(cx, expr, recv), @@ -4026,12 +4098,14 @@ impl Methods { }, Some(("drain", recv, args, ..)) => { drain_collect::check(cx, args, expr, recv); - } + }, _ => {}, } }, ("count", []) if is_trait_method(cx, expr, sym::Iterator) => match method_call(recv) { - Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::RmCloned , false), + Some(("cloned", recv2, [], _, _)) => { + iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::RmCloned, false); + }, Some((name2 @ ("into_iter" | "iter" | "iter_mut"), recv2, [], _, _)) => { iter_count::check(cx, expr, recv2, name2); }, @@ -4059,7 +4133,9 @@ impl Methods { ("expect", [_]) => { match method_call(recv) { Some(("ok", recv, [], _, _)) => ok_expect::check(cx, expr, recv), - Some(("err", recv, [], err_span, _)) => err_expect::check(cx, expr, recv, span, err_span, &self.msrv), + Some(("err", recv, [], err_span, _)) => { + err_expect::check(cx, expr, recv, span, err_span, &self.msrv); + }, _ => unwrap_expect_used::check( cx, expr, @@ -4086,13 +4162,19 @@ impl Methods { string_extend_chars::check(cx, expr, recv, arg); extend_with_drain::check(cx, expr, recv, arg); }, - (name @ ( "filter" | "find" ) , [arg]) => { + (name @ ("filter" | "find"), [arg]) => { if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) { // if `arg` has side-effect, the semantic will change - iter_overeager_cloned::check(cx, expr, recv, recv2, - iter_overeager_cloned::Op::FixClosure(name, arg), false); + iter_overeager_cloned::check( + cx, + expr, + recv, + recv2, + iter_overeager_cloned::Op::FixClosure(name, arg), + false, + ); } - } + }, ("filter_map", [arg]) => { unnecessary_filter_map::check(cx, expr, arg, name); filter_map_bool_then::check(cx, expr, arg, call_span); @@ -4106,20 +4188,34 @@ impl Methods { flat_map_option::check(cx, expr, arg, span); }, ("flatten", []) => match method_call(recv) { - Some(("map", recv, [map_arg], map_span, _)) => map_flatten::check(cx, expr, recv, map_arg, map_span), - Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::LaterCloned , true), + Some(("map", recv, [map_arg], map_span, _)) => { + map_flatten::check(cx, expr, recv, map_arg, map_span); + }, + Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check( + cx, + expr, + recv, + recv2, + iter_overeager_cloned::Op::LaterCloned, + true, + ), _ => {}, }, ("fold", [init, acc]) => { manual_try_fold::check(cx, expr, init, acc, call_span, &self.msrv); unnecessary_fold::check(cx, expr, init, acc, span); }, - ("for_each", [arg]) => { - match method_call(recv) { - Some(("inspect", _, [_], span2, _)) => inspect_for_each::check(cx, expr, span2), - Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::NeedlessMove(name, arg), false), - _ => {} - } + ("for_each", [arg]) => match method_call(recv) { + Some(("inspect", _, [_], span2, _)) => inspect_for_each::check(cx, expr, span2), + Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check( + cx, + expr, + recv, + recv2, + iter_overeager_cloned::Op::NeedlessMove(name, arg), + false, + ), + _ => {}, }, ("get", [arg]) => { get_first::check(cx, expr, recv, arg); @@ -4143,8 +4239,14 @@ impl Methods { }, ("last", []) => { if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) { - iter_overeager_cloned::check(cx, expr, recv, recv2, - iter_overeager_cloned::Op::LaterCloned , false); + iter_overeager_cloned::check( + cx, + expr, + recv, + recv2, + iter_overeager_cloned::Op::LaterCloned, + false, + ); } }, ("lock", []) => { @@ -4154,14 +4256,23 @@ impl Methods { if name == "map" { map_clone::check(cx, expr, recv, m_arg, &self.msrv); match method_call(recv) { - Some((map_name @ ("iter" | "into_iter"), recv2, _, _, _)) => iter_kv_map::check(cx, map_name, expr, recv2, m_arg), - Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::NeedlessMove(name, m_arg), false), - _ => {} + Some((map_name @ ("iter" | "into_iter"), recv2, _, _, _)) => { + iter_kv_map::check(cx, map_name, expr, recv2, m_arg); + }, + Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check( + cx, + expr, + recv, + recv2, + iter_overeager_cloned::Op::NeedlessMove(name, m_arg), + false, + ), + _ => {}, } } else { map_err_ignore::check(cx, expr, m_arg); } - if let Some((name, recv2, args, span2,_)) = method_call(recv) { + if let Some((name, recv2, args, span2, _)) = method_call(recv) { match (name, args) { ("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, &self.msrv), ("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, &self.msrv), @@ -4183,20 +4294,34 @@ impl Methods { ("next", []) => { if let Some((name2, recv2, args2, _, _)) = method_call(recv) { match (name2, args2) { - ("cloned", []) => iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::LaterCloned, false), + ("cloned", []) => iter_overeager_cloned::check( + cx, + expr, + recv, + recv2, + iter_overeager_cloned::Op::LaterCloned, + false, + ), ("filter", [arg]) => filter_next::check(cx, expr, recv2, arg), ("filter_map", [arg]) => filter_map_next::check(cx, expr, recv2, arg, &self.msrv), ("iter", []) => iter_next_slice::check(cx, expr, recv2), ("skip", [arg]) => iter_skip_next::check(cx, expr, recv2, arg), ("skip_while", [_]) => skip_while_next::check(cx, expr), - ("rev", [])=> manual_next_back::check(cx, expr, recv, recv2), + ("rev", []) => manual_next_back::check(cx, expr, recv, recv2), _ => {}, } } }, ("nth", [n_arg]) => match method_call(recv) { Some(("bytes", recv2, [], _, _)) => bytes_nth::check(cx, expr, recv2, n_arg), - Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::LaterCloned , false), + Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check( + cx, + expr, + recv, + recv2, + iter_overeager_cloned::Op::LaterCloned, + false, + ), Some(("iter", recv2, [], _, _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, false), Some(("iter_mut", recv2, [], _, _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, true), _ => iter_nth_zero::check(cx, expr, recv, n_arg), @@ -4221,7 +4346,7 @@ impl Methods { }, ("read_line", [arg]) => { read_line_without_trim::check(cx, expr, recv, arg); - } + }, ("repeat", [arg]) => { repeat_once::check(cx, expr, recv, arg); }, @@ -4252,10 +4377,16 @@ impl Methods { iter_out_of_bounds::check_skip(cx, expr, recv, arg); if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) { - iter_overeager_cloned::check(cx, expr, recv, recv2, - iter_overeager_cloned::Op::LaterCloned , false); + iter_overeager_cloned::check( + cx, + expr, + recv, + recv2, + iter_overeager_cloned::Op::LaterCloned, + false, + ); } - } + }, ("sort", []) => { stable_sort_primitive::check(cx, expr, recv); }, @@ -4280,8 +4411,14 @@ impl Methods { ("take", [arg]) => { iter_out_of_bounds::check_take(cx, expr, recv, arg); if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) { - iter_overeager_cloned::check(cx, expr, recv, recv2, - iter_overeager_cloned::Op::LaterCloned, false); + iter_overeager_cloned::check( + cx, + expr, + recv, + recv2, + iter_overeager_cloned::Op::LaterCloned, + false, + ); } }, ("take", []) => needless_option_take::check(cx, expr, recv), @@ -4291,6 +4428,9 @@ impl Methods { } unnecessary_lazy_eval::check(cx, expr, recv, arg, "then_some"); }, + ("try_into", []) if is_trait_method(cx, expr, sym::TryInto) => { + unnecessary_fallible_conversions::check_method(cx, expr); + }, ("to_owned", []) => { if !suspicious_to_owned::check(cx, expr, recv) { implicit_clone::check(cx, name, expr, recv); @@ -4301,7 +4441,7 @@ impl Methods { }, ("type_id", []) => { type_id_on_box::check(cx, recv, expr.span); - } + }, ("unwrap", []) => { match method_call(recv) { Some(("get", recv, [get_arg], _, _)) => { @@ -4353,7 +4493,7 @@ impl Methods { }, ("unwrap_or_default" | "unwrap_unchecked" | "unwrap_err_unchecked", []) => { unnecessary_literal_unwrap::check(cx, expr, recv, name, args); - } + }, ("unwrap_or_else", [u_arg]) => { match method_call(recv) { Some(("map", recv, [map_arg], _, _)) @@ -4364,9 +4504,12 @@ impl Methods { } unnecessary_literal_unwrap::check(cx, expr, recv, name, args); }, + ("wake", []) => { + waker_clone_wake::check(cx, expr, recv); + }, ("write", []) => { readonly_write_lock::check(cx, expr, recv); - } + }, ("zip", [arg]) => { if let ExprKind::MethodCall(name, iter_recv, [], _) = recv.kind && name.ident.name == sym::iter diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs index dbd965d65..2ef71be32 100644 --- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs @@ -17,7 +17,7 @@ use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, AssocKind, ClauseKind, EarlyBinder, GenericArg, GenericArgKind, Ty}; use rustc_span::symbol::Ident; -use rustc_span::{sym, Span, Symbol}; +use rustc_span::{sym, Span}; const NEEDLESS_COLLECT_MSG: &str = "avoid using `collect()` when not needed"; @@ -87,21 +87,17 @@ pub(super) fn check<'tcx>( } }, Node::Local(l) => { - if let PatKind::Binding(BindingAnnotation::NONE | BindingAnnotation::MUT, id, _, None) - = l.pat.kind + if let PatKind::Binding(BindingAnnotation::NONE | BindingAnnotation::MUT, id, _, None) = l.pat.kind && let ty = cx.typeck_results().expr_ty(collect_expr) - && [sym::Vec, sym::VecDeque, sym::BinaryHeap, sym::LinkedList].into_iter() + && [sym::Vec, sym::VecDeque, sym::BinaryHeap, sym::LinkedList] + .into_iter() .any(|item| is_type_diagnostic_item(cx, ty, item)) && let iter_ty = cx.typeck_results().expr_ty(iter_expr) && let Some(block) = get_enclosing_block(cx, l.hir_id) && let Some(iter_calls) = detect_iter_and_into_iters(block, id, cx, get_captured_ids(cx, iter_ty)) && let [iter_call] = &*iter_calls { - let mut used_count_visitor = UsedCountVisitor { - cx, - id, - count: 0, - }; + let mut used_count_visitor = UsedCountVisitor { cx, id, count: 0 }; walk_block(&mut used_count_visitor, block); if used_count_visitor.count > 1 { return; @@ -117,13 +113,11 @@ pub(super) fn check<'tcx>( span, NEEDLESS_COLLECT_MSG, |diag| { - let iter_replacement = format!("{}{}", Sugg::hir(cx, iter_expr, ".."), iter_call.get_iter_method(cx)); + let iter_replacement = + format!("{}{}", Sugg::hir(cx, iter_expr, ".."), iter_call.get_iter_method(cx)); diag.multipart_suggestion( iter_call.get_suggestion_text(), - vec![ - (l.span, String::new()), - (iter_call.span, iter_replacement) - ], + vec![(l.span, String::new()), (iter_call.span, iter_replacement)], Applicability::MaybeIncorrect, ); }, @@ -175,11 +169,12 @@ fn check_collect_into_intoiterator<'tcx>( .into_iter() .filter_map(|p| { if let ClauseKind::Trait(t) = p.kind().skip_binder() - && cx.tcx.is_diagnostic_item(sym::IntoIterator,t.trait_ref.def_id) { - Some(t.self_ty()) - } else { - None - } + && cx.tcx.is_diagnostic_item(sym::IntoIterator, t.trait_ref.def_id) + { + Some(t.self_ty()) + } else { + None + } }) .any(|ty| ty == inputs[arg_idx]) { @@ -207,14 +202,13 @@ fn is_is_empty_sig(cx: &LateContext<'_>, call_id: HirId) -> bool { /// Checks if `<iter_ty as Iterator>::Item` is the same as `<collect_ty as IntoIter>::Item` fn iterates_same_ty<'tcx>(cx: &LateContext<'tcx>, iter_ty: Ty<'tcx>, collect_ty: Ty<'tcx>) -> bool { - let item = Symbol::intern("Item"); if let Some(iter_trait) = cx.tcx.get_diagnostic_item(sym::Iterator) && let Some(into_iter_trait) = cx.tcx.get_diagnostic_item(sym::IntoIterator) - && let Some(iter_item_ty) = make_normalized_projection(cx.tcx, cx.param_env, iter_trait, item, [iter_ty]) - && let Some(into_iter_item_proj) = make_projection(cx.tcx, into_iter_trait, item, [collect_ty]) + && let Some(iter_item_ty) = make_normalized_projection(cx.tcx, cx.param_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, - Ty::new_projection(cx.tcx,into_iter_item_proj.def_id, into_iter_item_proj.args) + Ty::new_projection(cx.tcx, into_iter_item_proj.def_id, into_iter_item_proj.args), ) { iter_item_ty == into_iter_item_ty @@ -233,11 +227,14 @@ fn is_contains_sig(cx: &LateContext<'_>, call_id: HirId, iter_expr: &Expr<'_>) - && let [_, search_ty] = *sig.skip_binder().inputs() && let ty::Ref(_, search_ty, Mutability::Not) = *cx.tcx.erase_late_bound_regions(sig.rebind(search_ty)).kind() && let Some(iter_trait) = cx.tcx.get_diagnostic_item(sym::Iterator) - && let Some(iter_item) = cx.tcx - .associated_items(iter_trait) - .find_by_name_and_kind(cx.tcx, Ident::with_dummy_span(Symbol::intern("Item")), AssocKind::Type, iter_trait) + && let Some(iter_item) = cx.tcx.associated_items(iter_trait).find_by_name_and_kind( + cx.tcx, + Ident::with_dummy_span(sym::Item), + AssocKind::Type, + iter_trait, + ) && let args = cx.tcx.mk_args(&[GenericArg::from(typeck.expr_ty_adjusted(iter_expr))]) - && let proj_ty = Ty::new_projection(cx.tcx,iter_item.def_id, args) + && let proj_ty = Ty::new_projection(cx.tcx, iter_item.def_id, args) && let Ok(item_ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, proj_ty) { item_ty == EarlyBinder::bind(search_ty).instantiate(cx.tcx, cx.typeck_results().node_args(call_id)) diff --git a/src/tools/clippy/clippy_lints/src/methods/open_options.rs b/src/tools/clippy/clippy_lints/src/methods/open_options.rs index 1c664e76d..65c986dca 100644 --- a/src/tools/clippy/clippy_lints/src/methods/open_options.rs +++ b/src/tools/clippy/clippy_lints/src/methods/open_options.rs @@ -1,17 +1,17 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::paths; -use clippy_utils::ty::match_type; +use clippy_utils::ty::is_type_diagnostic_item; use rustc_ast::ast::LitKind; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; -use rustc_span::source_map::{Span, Spanned}; +use rustc_span::source_map::Spanned; +use rustc_span::{sym, Span}; use super::NONSENSICAL_OPEN_OPTIONS; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) { if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id) && let Some(impl_id) = cx.tcx.impl_of_method(method_id) - && match_type(cx, cx.tcx.type_of(impl_id).instantiate_identity(), &paths::OPEN_OPTIONS) + && is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::FsOpenOptions) { let mut options = Vec::new(); get_open_options(cx, recv, &mut options); @@ -40,7 +40,7 @@ fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec let obj_ty = cx.typeck_results().expr_ty(receiver).peel_refs(); // Only proceed if this is a call on some object of type std::fs::OpenOptions - if match_type(cx, obj_ty, &paths::OPEN_OPTIONS) && !arguments.is_empty() { + if is_type_diagnostic_item(cx, obj_ty, sym::FsOpenOptions) && !arguments.is_empty() { let argument_option = match arguments[0].kind { ExprKind::Lit(span) => { if let Spanned { diff --git a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs index 3e33f9193..7b81d4571 100644 --- a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs +++ b/src/tools/clippy/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::{match_def_path, path_to_local_id, paths, peel_blocks}; @@ -32,8 +32,7 @@ pub(super) fn check( return; } - let deref_aliases: [&[&str]; 8] = [ - &paths::DEREF_MUT_TRAIT_METHOD, + let deref_aliases: [&[&str]; 7] = [ &paths::CSTRING_AS_C_STR, &paths::OS_STRING_AS_OS_STR, &paths::PATH_BUF_AS_PATH, @@ -49,6 +48,7 @@ pub(super) fn check( .opt_def_id() .map_or(false, |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.iter().any(|path| match_def_path(cx, fun_def_id, path)) }) }, @@ -70,6 +70,7 @@ pub(super) fn check( then { let method_did = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id).unwrap(); cx.tcx.is_diagnostic_item(sym::deref_method, method_did) + || cx.tcx.is_diagnostic_item(sym::deref_mut_method, method_did) || deref_aliases.iter().any(|path| match_def_path(cx, method_did, path)) } else { false diff --git a/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs index fcbe005fb..c78f8b71c 100644 --- a/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/src/tools/clippy/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; @@ -9,8 +9,7 @@ use rustc_hir::intravisit::{walk_path, Visitor}; use rustc_hir::{self, ExprKind, HirId, Node, PatKind, Path, QPath}; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; -use rustc_span::source_map::Span; -use rustc_span::sym; +use rustc_span::{sym, Span}; use super::MAP_UNWRAP_OR; diff --git a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs index 942f3bd79..b89c15146 100644 --- a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs +++ b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs @@ -7,7 +7,7 @@ use if_chain::if_chain; use rustc_errors::Applicability; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::source_map::Span; +use rustc_span::Span; use rustc_span::symbol::{self, sym, Symbol}; use {rustc_ast as ast, rustc_hir as hir}; @@ -235,10 +235,10 @@ fn closure_body_returns_empty_to_string(cx: &LateContext<'_>, e: &hir::Expr<'_>) let body = cx.tcx.hir().body(body); if body.params.is_empty() - && let hir::Expr{ kind, .. } = &body.value - && let hir::ExprKind::MethodCall(hir::PathSegment {ident, ..}, self_arg, _, _) = kind + && let hir::Expr { kind, .. } = &body.value + && let hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, self_arg, _, _) = kind && ident.name == sym::to_string - && let hir::Expr{ kind, .. } = self_arg + && let hir::Expr { kind, .. } = self_arg && let hir::ExprKind::Lit(lit) = kind && let ast::LitKind::Str(symbol::kw::Empty, _) = lit.node { diff --git a/src/tools/clippy/clippy_lints/src/methods/path_ends_with_ext.rs b/src/tools/clippy/clippy_lints/src/methods/path_ends_with_ext.rs index 3347c8c16..094ead9f4 100644 --- a/src/tools/clippy/clippy_lints/src/methods/path_ends_with_ext.rs +++ b/src/tools/clippy/clippy_lints/src/methods/path_ends_with_ext.rs @@ -1,7 +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; -use clippy_utils::msrvs::Msrv; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use rustc_ast::{LitKind, StrStyle}; @@ -47,7 +46,7 @@ pub(super) fn check( "this looks like a failed attempt at checking for the file extension", "try", sugg, - Applicability::MaybeIncorrect + Applicability::MaybeIncorrect, ); } } diff --git a/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs b/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs index 81f9e2a77..3b903ec5c 100644 --- a/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs +++ b/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs @@ -46,9 +46,12 @@ pub fn check(cx: &LateContext<'_>, call: &Expr<'_>, recv: &Expr<'_>, arg: &Expr< span, "calling `.parse()` without trimming the trailing newline character", |diag| { - diag.span_note(call.span, "call to `.read_line()` here, \ + diag.span_note( + call.span, + "call to `.read_line()` here, \ which leaves a trailing newline character in the buffer, \ - which in turn will cause `.parse()` to fail"); + which in turn will cause `.parse()` to fail", + ); diag.span_suggestion( expr.span, @@ -56,7 +59,7 @@ pub fn check(cx: &LateContext<'_>, call: &Expr<'_>, recv: &Expr<'_>, arg: &Expr< format!("{local_snippet}.trim_end()"), Applicability::MachineApplicable, ); - } + }, ); } diff --git a/src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs b/src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs index e3ec921da..1184dd452 100644 --- a/src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs +++ b/src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs @@ -26,13 +26,18 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, receiver && let parent = cx.tcx.hir().get_parent(unwrap_call_expr.hir_id) && let Node::Local(local) = parent && let Some(mir) = enclosing_mir(cx.tcx, expr.hir_id) - && let Some((local, _)) = mir.local_decls.iter_enumerated().find(|(_, decl)| { - local.span.contains(decl.source_info.span) - }) - && let Some(usages) = visit_local_usage(&[local], mir, Location { - block: START_BLOCK, - statement_index: 0, - }) + && let Some((local, _)) = mir + .local_decls + .iter_enumerated() + .find(|(_, decl)| local.span.contains(decl.source_info.span)) + && let Some(usages) = visit_local_usage( + &[local], + mir, + Location { + block: START_BLOCK, + statement_index: 0, + }, + ) && let [usage] = usages.as_slice() { let writer_never_mutated = usage.local_consume_or_mutate_locs.is_empty(); @@ -45,7 +50,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, receiver "this write lock is used only for reading", "consider using a read lock instead", format!("{}.read()", snippet(cx, receiver.span, "<receiver>")), - Applicability::MaybeIncorrect // write lock might be intentional for enforcing exclusiveness + Applicability::MaybeIncorrect, // write lock might be intentional for enforcing exclusiveness ); } } diff --git a/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs b/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs index afdb8ce94..05a9a06c8 100644 --- a/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs +++ b/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs @@ -8,7 +8,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::PatKind; use rustc_lint::LateContext; -use rustc_span::source_map::Span; +use rustc_span::Span; use rustc_span::symbol::sym; use super::SEARCH_IS_SOME; @@ -39,7 +39,7 @@ pub(super) fn check<'tcx>( if search_method == "find"; if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = search_arg.kind; let closure_body = cx.tcx.hir().body(body); - if let Some(closure_arg) = closure_body.params.get(0); + if let Some(closure_arg) = closure_body.params.first(); then { if let hir::PatKind::Ref(..) = closure_arg.pat.kind { Some(search_snippet.replacen('&', "", 1)) diff --git a/src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs b/src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs index f3d6a15ed..63d41677f 100644 --- a/src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs +++ b/src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs @@ -2,18 +2,19 @@ use rustc_ast::ast::{LitIntType, LitKind}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; +use rustc_span::sym; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::implements_trait; -use clippy_utils::{get_trait_def_id, match_def_path, paths}; +use clippy_utils::{match_def_path, paths}; use super::SEEK_FROM_CURRENT; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>, arg: &'tcx Expr<'_>) { let ty = cx.typeck_results().expr_ty(recv); - if let Some(def_id) = get_trait_def_id(cx, &paths::STD_IO_SEEK) { + if let Some(def_id) = cx.tcx.get_diagnostic_item(sym::IoSeek) { if implements_trait(cx, ty, def_id, &[]) && arg_is_seek_from_current(cx, arg) { let mut applicability = Applicability::MachineApplicable; let snip = snippet_with_applicability(cx, recv.span, "..", &mut applicability); @@ -32,15 +33,17 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &' } fn arg_is_seek_from_current<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool { - if let ExprKind::Call(f, args) = expr.kind && - let ExprKind::Path(ref path) = f.kind && - let Some(def_id) = cx.qpath_res(path, f.hir_id).opt_def_id() && - match_def_path(cx, def_id, &paths::STD_IO_SEEK_FROM_CURRENT) { + if let ExprKind::Call(f, args) = expr.kind + && let ExprKind::Path(ref path) = f.kind + && let Some(def_id) = cx.qpath_res(path, f.hir_id).opt_def_id() + && match_def_path(cx, def_id, &paths::STD_IO_SEEK_FROM_CURRENT) + { // check if argument of `SeekFrom::Current` is `0` - if args.len() == 1 && - let ExprKind::Lit(lit) = args[0].kind && - let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node { - return true + if args.len() == 1 + && let ExprKind::Lit(lit) = args[0].kind + && let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node + { + return true; } } diff --git a/src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs b/src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs index 787e9e0eb..9f3846035 100644 --- a/src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs +++ b/src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs @@ -1,11 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::implements_trait; -use clippy_utils::{get_trait_def_id, is_expr_used_or_unified, match_def_path, paths}; +use clippy_utils::{is_expr_used_or_unified, match_def_path, paths}; use rustc_ast::ast::{LitIntType, LitKind}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; -use rustc_span::Span; +use rustc_span::{sym, Span}; use super::SEEK_TO_START_INSTEAD_OF_REWIND; @@ -23,15 +23,15 @@ pub(super) fn check<'tcx>( return; } - if let Some(seek_trait_id) = get_trait_def_id(cx, &paths::STD_IO_SEEK) && - implements_trait(cx, ty, seek_trait_id, &[]) && - let ExprKind::Call(func, args1) = arg.kind && - let ExprKind::Path(ref path) = func.kind && - let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id() && - match_def_path(cx, def_id, &paths::STD_IO_SEEKFROM_START) && - args1.len() == 1 && - let ExprKind::Lit(lit) = args1[0].kind && - let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node + if let Some(seek_trait_id) = cx.tcx.get_diagnostic_item(sym::IoSeek) + && implements_trait(cx, ty, seek_trait_id, &[]) + && let ExprKind::Call(func, args1) = arg.kind + && let ExprKind::Path(ref path) = func.kind + && let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id() + && match_def_path(cx, def_id, &paths::STD_IO_SEEKFROM_START) + && args1.len() == 1 + && let ExprKind::Lit(lit) = args1[0].kind + && let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node { let method_call_span = expr.span.with_lo(name_span.lo()); span_lint_and_then( diff --git a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs index 7016ad0a8..9da61bca5 100644 --- a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs +++ b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs @@ -1,6 +1,6 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{constant, 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::{for_each_expr_with_closures, Descend}; @@ -115,7 +115,7 @@ fn check_manual_split_once( /// checks for /// -/// ``` +/// ```no_run /// let mut iter = "a.b.c".splitn(2, '.'); /// let a = iter.next(); /// let b = iter.next(); @@ -133,13 +133,11 @@ fn check_manual_split_once_indirect( && let PatKind::Binding(BindingAnnotation::MUT, iter_binding_id, iter_ident, None) = local.pat.kind && let (iter_stmt_id, Node::Stmt(_)) = parents.next()? && let (_, Node::Block(enclosing_block)) = parents.next()? - && let mut stmts = enclosing_block .stmts .iter() .skip_while(|stmt| stmt.hir_id != iter_stmt_id) .skip(1) - && let first = indirect_usage(cx, stmts.next()?, iter_binding_id, ctxt)? && let second = indirect_usage(cx, stmts.next()?, iter_binding_id, ctxt)? && first.unwrap_kind == second.unwrap_kind @@ -173,18 +171,8 @@ fn check_manual_split_once_indirect( ); let remove_msg = format!("remove the `{iter_ident}` usages"); - diag.span_suggestion( - first.span, - remove_msg.clone(), - "", - app, - ); - diag.span_suggestion( - second.span, - remove_msg, - "", - app, - ); + diag.span_suggestion(first.span, remove_msg.clone(), "", app); + diag.span_suggestion(second.span, remove_msg, "", app); }); } diff --git a/src/tools/clippy/clippy_lints/src/methods/string_lit_chars_any.rs b/src/tools/clippy/clippy_lints/src/methods/string_lit_chars_any.rs index 70da6ad58..5f6f027a3 100644 --- a/src/tools/clippy/clippy_lints/src/methods/string_lit_chars_any.rs +++ b/src/tools/clippy/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::{Msrv, MATCHES_MACRO}; use clippy_utils::source::snippet_opt; use clippy_utils::{is_from_proc_macro, is_trait_method, path_to_local}; use itertools::Itertools; @@ -19,7 +19,7 @@ pub(super) fn check<'tcx>( body: &Expr<'_>, msrv: &Msrv, ) { - if msrv.meets(MATCHES_MACRO) + if msrv.meets(msrvs::MATCHES_MACRO) && is_trait_method(cx, expr, sym::Iterator) && let PatKind::Binding(_, arg, _, _) = param.pat.kind && let ExprKind::Lit(lit_kind) = recv.kind @@ -52,7 +52,7 @@ pub(super) fn check<'tcx>( format!("matches!({scrutinee_snip}, {pat_snip})"), Applicability::MachineApplicable, ); - } + }, ); } } diff --git a/src/tools/clippy/clippy_lints/src/methods/suspicious_command_arg_space.rs b/src/tools/clippy/clippy_lints/src/methods/suspicious_command_arg_space.rs index bc8f01767..b2c5987e4 100644 --- a/src/tools/clippy/clippy_lints/src/methods/suspicious_command_arg_space.rs +++ b/src/tools/clippy/clippy_lints/src/methods/suspicious_command_arg_space.rs @@ -1,9 +1,8 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::paths; -use clippy_utils::ty::match_type; +use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::{Applicability, Diagnostic}; use rustc_lint::LateContext; -use rustc_span::Span; +use rustc_span::{sym, Span}; use {rustc_ast as ast, rustc_hir as hir}; use super::SUSPICIOUS_COMMAND_ARG_SPACE; @@ -11,7 +10,7 @@ use super::SUSPICIOUS_COMMAND_ARG_SPACE; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, recv: &'tcx hir::Expr<'_>, arg: &'tcx hir::Expr<'_>, span: Span) { let ty = cx.typeck_results().expr_ty(recv).peel_refs(); - if match_type(cx, ty, &paths::STD_PROCESS_COMMAND) + if is_type_diagnostic_item(cx, ty, sym::Command) && let hir::ExprKind::Lit(lit) = &arg.kind && let ast::LitKind::Str(s, _) = &lit.node && let Some((arg1, arg2)) = s.as_str().split_once(' ') @@ -26,13 +25,10 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, recv: &'tcx hir::Expr<'_>, arg |diag: &mut Diagnostic| { diag.multipart_suggestion_verbose( "consider splitting the argument", - vec![ - (span, "args".to_string()), - (arg.span, format!("[{arg1:?}, {arg2:?}]")), - ], + vec![(span, "args".to_string()), (arg.span, format!("[{arg1:?}, {arg2:?}]"))], Applicability::MaybeIncorrect, ); - } + }, ); } } diff --git a/src/tools/clippy/clippy_lints/src/methods/type_id_on_box.rs b/src/tools/clippy/clippy_lints/src/methods/type_id_on_box.rs index 3404bdfe7..4917936a9 100644 --- a/src/tools/clippy/clippy_lints/src/methods/type_id_on_box.rs +++ b/src/tools/clippy/clippy_lints/src/methods/type_id_on_box.rs @@ -44,11 +44,11 @@ pub(super) fn check(cx: &LateContext<'_>, receiver: &Expr<'_>, call_span: Span) diag.note( "this returns the type id of the literal type `Box<dyn Any>` instead of the \ - type id of the boxed value, which is most likely not what you want" + type id of the boxed value, which is most likely not what you want", ) .note( "if this is intentional, use `TypeId::of::<Box<dyn Any>>()` instead, \ - which makes it more clear" + which makes it more clear", ) .span_suggestion( receiver.span, diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fallible_conversions.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fallible_conversions.rs new file mode 100644 index 000000000..bb32b1bb7 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fallible_conversions.rs @@ -0,0 +1,122 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::get_parent_expr; +use clippy_utils::ty::implements_trait; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_middle::ty; +use rustc_span::{sym, Span}; + +use super::UNNECESSARY_FALLIBLE_CONVERSIONS; + +/// What function is being called and whether that call is written as a method call or a function +/// call +#[derive(Copy, Clone)] +#[expect(clippy::enum_variant_names)] +enum FunctionKind { + /// `T::try_from(U)` + TryFromFunction, + /// `t.try_into()` + TryIntoMethod, + /// `U::try_into(t)` + TryIntoFunction, +} + +fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &Expr<'_>, + node_args: ty::GenericArgsRef<'tcx>, + kind: FunctionKind, + primary_span: Span, +) { + if let &[self_ty, other_ty] = node_args.as_slice() + // useless_conversion already warns `T::try_from(T)`, so ignore it here + && self_ty != other_ty + && let Some(self_ty) = self_ty.as_type() + && let Some(from_into_trait) = cx.tcx.get_diagnostic_item(match kind { + FunctionKind::TryFromFunction => sym::From, + FunctionKind::TryIntoMethod | FunctionKind::TryIntoFunction => sym::Into, + }) + // If `T: TryFrom<U>` and `T: From<U>` both exist, then that means that the `TryFrom` + // _must_ be from the blanket impl and cannot have been manually implemented + // (else there would be conflicting impls, even with #![feature(spec)]), so we don't even need to check + // what `<T as TryFrom<U>>::Error` is: it's always `Infallible` + && implements_trait(cx, self_ty, from_into_trait, &[other_ty]) + { + let parent_unwrap_call = get_parent_expr(cx, expr).and_then(|parent| { + if let ExprKind::MethodCall(path, .., span) = parent.kind + && let sym::unwrap | sym::expect = path.ident.name + { + Some(span) + } else { + None + } + }); + + let (sugg, span, applicability) = match kind { + FunctionKind::TryIntoMethod if let Some(unwrap_span) = parent_unwrap_call => { + // Extend the span to include the unwrap/expect call: + // `foo.try_into().expect("..")` + // ^^^^^^^^^^^^^^^^^^^^^^^ + // + // `try_into().unwrap()` specifically can be trivially replaced with just `into()`, + // so that can be machine-applicable + + ( + "into()", + primary_span.with_hi(unwrap_span.hi()), + Applicability::MachineApplicable, + ) + }, + FunctionKind::TryFromFunction => ("From::from", primary_span, Applicability::Unspecified), + FunctionKind::TryIntoFunction => ("Into::into", primary_span, Applicability::Unspecified), + FunctionKind::TryIntoMethod => ("into", primary_span, Applicability::Unspecified), + }; + + span_lint_and_sugg( + cx, + UNNECESSARY_FALLIBLE_CONVERSIONS, + span, + "use of a fallible conversion when an infallible one could be used", + "use", + sugg.into(), + applicability, + ); + } +} + +/// Checks method call exprs: +/// - `0i32.try_into()` +pub(super) fn check_method(cx: &LateContext<'_>, expr: &Expr<'_>) { + if let ExprKind::MethodCall(path, ..) = expr.kind { + check( + cx, + expr, + cx.typeck_results().node_args(expr.hir_id), + FunctionKind::TryIntoMethod, + path.ident.span, + ); + } +} + +/// Checks function call exprs: +/// - `<i64 as TryFrom<_>>::try_from(0i32)` +/// - `<_ as TryInto<i64>>::try_into(0i32)` +pub(super) fn check_function(cx: &LateContext<'_>, expr: &Expr<'_>, callee: &Expr<'_>) { + if let ExprKind::Path(ref qpath) = callee.kind + && let Some(item_def_id) = cx.qpath_res(qpath, callee.hir_id).opt_def_id() + && let Some(trait_def_id) = cx.tcx.trait_of_item(item_def_id) + { + check( + cx, + expr, + cx.typeck_results().node_args(callee.hir_id), + match cx.tcx.get_diagnostic_name(trait_def_id) { + Some(sym::TryFrom) => FunctionKind::TryFromFunction, + Some(sym::TryInto) => FunctionKind::TryIntoFunction, + _ => return, + }, + callee.span, + ); + } +} diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs index 6e23754bf..6d51c4ab0 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs @@ -8,8 +8,7 @@ use rustc_hir as hir; use rustc_hir::PatKind; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::source_map::Span; -use rustc_span::sym; +use rustc_span::{sym, Span}; use super::UNNECESSARY_FOLD; diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs index 47e2e7441..4429f0326 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs @@ -2,6 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{eager_or_lazy, is_from_proc_macro, usage}; +use hir::FnRetTy; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -18,20 +19,16 @@ pub(super) fn check<'tcx>( arg: &'tcx hir::Expr<'_>, simplify_using: &str, ) { - if is_from_proc_macro(cx, expr) { - return; - } - let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Option); let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result); let is_bool = cx.typeck_results().expr_ty(recv).is_bool(); if is_option || is_result || is_bool { - if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = arg.kind { + if let hir::ExprKind::Closure(&hir::Closure { body, fn_decl, .. }) = arg.kind { let body = cx.tcx.hir().body(body); let body_expr = &body.value; - if usage::BindingUsageFinder::are_params_used(cx, body) { + if usage::BindingUsageFinder::are_params_used(cx, body) || is_from_proc_macro(cx, expr) { return; } @@ -48,7 +45,14 @@ pub(super) fn check<'tcx>( .iter() // bindings are checked to be unused above .all(|param| matches!(param.pat.kind, hir::PatKind::Binding(..) | hir::PatKind::Wild)) - { + && matches!( + fn_decl.output, + FnRetTy::DefaultReturn(_) + | FnRetTy::Return(hir::Ty { + kind: hir::TyKind::Infer, + .. + }) + ) { Applicability::MachineApplicable } else { // replacing the lambda may break type inference diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs index 937aac8d2..a1125d70d 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs @@ -24,7 +24,6 @@ fn get_ty_from_args<'a>(args: Option<&'a [hir::GenericArg<'a>]>, index: usize) - } } -#[expect(clippy::too_many_lines)] pub(super) fn check( cx: &LateContext<'_>, expr: &hir::Expr<'_>, @@ -82,7 +81,7 @@ pub(super) fn check( { suggs.extend([ (block.span.shrink_to_lo().to(expr.span.shrink_to_lo()), String::new()), - (expr.span.shrink_to_hi().to(block.span.shrink_to_hi()), String::new()) + (expr.span.shrink_to_hi().to(block.span.shrink_to_hi()), String::new()), ]); } Some(suggs) @@ -101,15 +100,11 @@ pub(super) fn check( (expr.span.with_lo(args[0].span.hi()), String::new()), ]), ("None", "unwrap_or_else", _) => match args[0].kind { - hir::ExprKind::Closure(hir::Closure { - fn_decl: - hir::FnDecl { - output: hir::FnRetTy::DefaultReturn(span) | hir::FnRetTy::Return(hir::Ty { span, .. }), - .. - }, - .. - }) => Some(vec![ - (expr.span.with_hi(span.hi()), String::new()), + hir::ExprKind::Closure(hir::Closure { body, .. }) => Some(vec![ + ( + expr.span.with_hi(cx.tcx.hir().body(*body).value.span.lo()), + String::new(), + ), (expr.span.with_lo(args[0].span.hi()), String::new()), ]), _ => None, diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs index 50d6f3b7e..7a50feff6 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/src/tools/clippy/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; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_opt; use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy, peel_mid_ty_refs}; use clippy_utils::visitors::find_all_ret_expressions; @@ -15,8 +15,7 @@ use rustc_lint::LateContext; use rustc_middle::mir::Mutability; use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref}; use rustc_middle::ty::{ - self, ClauseKind, EarlyBinder, GenericArg, GenericArgKind, GenericArgsRef, ParamTy, ProjectionPredicate, - TraitPredicate, Ty, + self, ClauseKind, GenericArg, GenericArgKind, GenericArgsRef, ParamTy, ProjectionPredicate, TraitPredicate, Ty, }; use rustc_span::{sym, Symbol}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; @@ -375,6 +374,7 @@ fn get_input_traits_and_projections<'tcx>( (trait_predicates, projection_predicates) } +#[expect(clippy::too_many_lines)] fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<'a>) -> bool { for (_, node) in cx.tcx.hir().parent_iter(expr.hir_id) { match node { @@ -382,10 +382,10 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< Node::Block(..) => continue, Node::Item(item) => { if let ItemKind::Fn(_, _, body_id) = &item.kind - && let output_ty = return_ty(cx, item.owner_id) - && let inherited = Inherited::new(cx.tcx, item.owner_id.def_id) - && let fn_ctxt = FnCtxt::new(&inherited, cx.param_env, item.owner_id.def_id) - && fn_ctxt.can_coerce(ty, output_ty) + && let output_ty = return_ty(cx, item.owner_id) + && let inherited = Inherited::new(cx.tcx, item.owner_id.def_id) + && let fn_ctxt = FnCtxt::new(&inherited, cx.param_env, item.owner_id.def_id) + && fn_ctxt.can_coerce(ty, output_ty) { if has_lifetime(output_ty) && has_lifetime(ty) { return false; @@ -393,67 +393,78 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< let body = cx.tcx.hir().body(*body_id); let body_expr = &body.value; let mut count = 0; - return find_all_ret_expressions(cx, body_expr, |_| { count += 1; count <= 1 }); + return find_all_ret_expressions(cx, body_expr, |_| { + count += 1; + count <= 1 + }); } - } + }, Node::Expr(parent_expr) => { - if let Some((callee_def_id, call_generic_args, recv, call_args)) - = get_callee_generic_args_and_args(cx, parent_expr) + if let Some((callee_def_id, call_generic_args, recv, call_args)) = + get_callee_generic_args_and_args(cx, parent_expr) { - // FIXME: the `instantiate_identity()` below seems incorrect, since we eventually - // call `tcx.try_instantiate_and_normalize_erasing_regions` further down - // (i.e., we are explicitly not in the identity context). - let fn_sig = cx.tcx.fn_sig(callee_def_id).instantiate_identity().skip_binder(); + let bound_fn_sig = cx.tcx.fn_sig(callee_def_id); + let fn_sig = bound_fn_sig.skip_binder(); if let Some(arg_index) = recv.into_iter().chain(call_args).position(|arg| arg.hir_id == expr.hir_id) - && let Some(param_ty) = fn_sig.inputs().get(arg_index) - && let ty::Param(ParamTy { index: param_index , ..}) = param_ty.kind() + && let param_ty = fn_sig.input(arg_index).skip_binder() + && let ty::Param(ParamTy { index: param_index , ..}) = *param_ty.kind() // https://github.com/rust-lang/rust-clippy/issues/9504 and https://github.com/rust-lang/rust-clippy/issues/10021 - && (*param_index as usize) < call_generic_args.len() + && (param_index as usize) < call_generic_args.len() { if fn_sig + .skip_binder() .inputs() .iter() .enumerate() .filter(|(i, _)| *i != arg_index) - .any(|(_, ty)| ty.contains(*param_ty)) + .any(|(_, ty)| ty.contains(param_ty)) { return false; } - let mut trait_predicates = cx.tcx.param_env(callee_def_id) - .caller_bounds().iter().filter(|predicate| { - if let ClauseKind::Trait(trait_predicate) - = predicate.kind().skip_binder() - && trait_predicate.trait_ref.self_ty() == *param_ty - { - true - } else { - false - } - }); + let mut trait_predicates = + cx.tcx + .param_env(callee_def_id) + .caller_bounds() + .iter() + .filter(|predicate| { + if let ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() + && trait_predicate.trait_ref.self_ty() == param_ty + { + true + } else { + false + } + }); - let new_subst = cx.tcx.mk_args_from_iter( - call_generic_args.iter() - .enumerate() - .map(|(i, t)| - if i == (*param_index as usize) { - GenericArg::from(ty) - } else { - t - })); + let new_subst = cx + .tcx + .mk_args_from_iter(call_generic_args.iter().enumerate().map(|(i, t)| { + if i == param_index as usize { + GenericArg::from(ty) + } else { + t + } + })); if trait_predicates.any(|predicate| { - let predicate = EarlyBinder::bind(predicate).instantiate(cx.tcx, new_subst); + let predicate = bound_fn_sig.rebind(predicate).instantiate(cx.tcx, new_subst); let obligation = Obligation::new(cx.tcx, ObligationCause::dummy(), cx.param_env, predicate); - !cx.tcx.infer_ctxt().build().predicate_must_hold_modulo_regions(&obligation) + !cx.tcx + .infer_ctxt() + .build() + .predicate_must_hold_modulo_regions(&obligation) }) { return false; } - let output_ty = fn_sig.output(); - if output_ty.contains(*param_ty) { - if let Ok(new_ty) = cx.tcx.try_instantiate_and_normalize_erasing_regions( - new_subst, cx.param_env, EarlyBinder::bind(output_ty)) { + let output_ty = cx.tcx.erase_late_bound_regions(fn_sig.output()); + if output_ty.contains(param_ty) { + if let Ok(new_ty) = cx.tcx.try_instantiate_and_normalize_erasing_regions( + new_subst, + cx.param_env, + bound_fn_sig.rebind(output_ty), + ) { expr = parent_expr; ty = new_ty; continue; @@ -515,10 +526,11 @@ fn is_to_string_on_string_like<'a>( && let GenericArgKind::Type(ty) = generic_arg.unpack() && let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref) && let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef) - && (cx.get_associated_type(ty, deref_trait_id, "Target") == Some(cx.tcx.types.str_) || - implements_trait(cx, ty, as_ref_trait_id, &[cx.tcx.types.str_.into()])) { - true - } else { - false - } + && (cx.get_associated_type(ty, deref_trait_id, "Target") == Some(cx.tcx.types.str_) + || implements_trait(cx, ty, as_ref_trait_id, &[cx.tcx.types.str_.into()])) + { + true + } else { + false + } } diff --git a/src/tools/clippy/clippy_lints/src/methods/waker_clone_wake.rs b/src/tools/clippy/clippy_lints/src/methods/waker_clone_wake.rs new file mode 100644 index 000000000..da66632d5 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/methods/waker_clone_wake.rs @@ -0,0 +1,32 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::{is_trait_method, match_def_path, paths}; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_span::sym; + +use super::WAKER_CLONE_WAKE; + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) { + let ty = cx.typeck_results().expr_ty(recv); + + if let Some(did) = ty.ty_adt_def() + && match_def_path(cx, did.did(), &paths::WAKER) + && let ExprKind::MethodCall(_, waker_ref, &[], _) = recv.kind + && is_trait_method(cx, recv, sym::Clone) + { + let mut applicability = Applicability::MachineApplicable; + let snippet = snippet_with_applicability(cx, waker_ref.span.source_callsite(), "..", &mut applicability); + + span_lint_and_sugg( + cx, + WAKER_CLONE_WAKE, + expr.span, + "cloning a `Waker` only to wake it", + "replace with", + format!("{snippet}.wake_by_ref()"), + applicability, + ); + } +} diff --git a/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs b/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs index 1fbf783b8..0a810a13f 100644 --- a/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs +++ b/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::is_copy; use rustc_lint::LateContext; use rustc_middle::ty::Ty; -use rustc_span::source_map::Span; +use rustc_span::Span; use std::fmt; use super::WRONG_SELF_CONVENTION; diff --git a/src/tools/clippy/clippy_lints/src/min_ident_chars.rs b/src/tools/clippy/clippy_lints/src/min_ident_chars.rs index c79a1a7b9..4ad12e899 100644 --- a/src/tools/clippy/clippy_lints/src/min_ident_chars.rs +++ b/src/tools/clippy/clippy_lints/src/min_ident_chars.rs @@ -107,13 +107,17 @@ impl Visitor<'_> for IdentVisitor<'_, '_> { let str = ident.as_str(); if conf.is_ident_too_short(cx, str, ident.span) { - if let Node::Item(item) = node && let ItemKind::Use(..) = item.kind { + if let Node::Item(item) = node + && let ItemKind::Use(..) = item.kind + { return; } // `struct Awa<T>(T)` // ^ if let Node::PathSegment(path) = node { - if let Res::Def(def_kind, ..) = path.res && let DefKind::TyParam = def_kind { + if let Res::Def(def_kind, ..) = path.res + && let DefKind::TyParam = def_kind + { return; } if matches!(path.res, Res::PrimTy(..)) || path.res.opt_def_id().is_some_and(|def_id| !def_id.is_local()) diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs index 9c8b47fb3..f4af5f37b 100644 --- a/src/tools/clippy/clippy_lints/src/misc.rs +++ b/src/tools/clippy/clippy_lints/src/misc.rs @@ -16,7 +16,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::def_id::LocalDefId; -use rustc_span::source_map::Span; +use rustc_span::Span; use crate::ref_patterns::REF_PATTERNS; @@ -41,12 +41,12 @@ declare_clippy_lint! { /// dereferences, e.g., changing `*x` to `x` within the function. /// /// ### Example - /// ```rust + /// ```no_run /// fn foo(ref _x: u8) {} /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// fn foo(_x: &u8) {} /// ``` #[clippy::version = "pre 1.29.0"] @@ -70,7 +70,7 @@ declare_clippy_lint! { /// macro, it has been allowed in the mean time. /// /// ### Example - /// ```rust + /// ```no_run /// let _x = 0; /// let y = _x + 1; // Here we are using `_x`, even though it has a leading /// // underscore. We should rename `_x` to `x` @@ -263,7 +263,7 @@ impl<'tcx> LateLintPass<'tcx> for LintPass { ), |diag| { diag.span_note(definition_span, format!("`{name}` is defined here")); - } + }, ); } } diff --git a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs index b226b8781..df0dd9e4e 100644 --- a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs +++ b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs @@ -17,7 +17,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::Span; +use rustc_span::Span; declare_clippy_lint! { /// ### What it does @@ -28,7 +28,7 @@ declare_clippy_lint! { /// the fields that are actually bound. /// /// ### Example - /// ```rust + /// ```no_run /// # struct Foo { /// # a: i32, /// # b: i32, @@ -43,7 +43,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # struct Foo { /// # a: i32, /// # b: i32, @@ -71,12 +71,12 @@ declare_clippy_lint! { /// It affects code readability. /// /// ### Example - /// ```rust + /// ```no_run /// fn foo(a: i32, _a: i32) {} /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// fn bar(a: i32, _b: i32) {} /// ``` #[clippy::version = "pre 1.29.0"] @@ -94,7 +94,7 @@ declare_clippy_lint! { /// decremented. /// /// ### Example - /// ```rust + /// ```no_run /// let mut x = 3; /// --x; /// ``` @@ -113,14 +113,14 @@ declare_clippy_lint! { /// It looks confusing. /// /// ### Example - /// ```rust + /// ```no_run /// # let _ = /// 0x1a9BAcD /// # ; /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let _ = /// 0x1A9BACD /// # ; @@ -142,14 +142,14 @@ declare_clippy_lint! { /// Suffix style should be consistent. /// /// ### Example - /// ```rust + /// ```no_run /// # let _ = /// 123832i32 /// # ; /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let _ = /// 123832_i32 /// # ; @@ -170,14 +170,14 @@ declare_clippy_lint! { /// Suffix style should be consistent. /// /// ### Example - /// ```rust + /// ```no_run /// # let _ = /// 123832_i32 /// # ; /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let _ = /// 123832i32 /// # ; @@ -202,7 +202,7 @@ declare_clippy_lint! { /// ### Example /// /// In Rust: - /// ```rust + /// ```no_run /// fn main() { /// let a = 0123; /// println!("{}", a); @@ -258,7 +258,7 @@ declare_clippy_lint! { /// bindings. /// /// ### Example - /// ```rust + /// ```no_run /// # let v = Some("abc"); /// match v { /// Some(x) => (), @@ -267,7 +267,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let v = Some("abc"); /// match v { /// Some(x) => (), @@ -295,7 +295,7 @@ declare_clippy_lint! { /// can match that element as well. /// /// ### Example - /// ```rust + /// ```no_run /// # struct TupleStruct(u32, u32, u32); /// # let t = TupleStruct(1, 2, 3); /// match t { @@ -305,7 +305,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # struct TupleStruct(u32, u32, u32); /// # let t = TupleStruct(1, 2, 3); /// match t { diff --git a/src/tools/clippy/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs b/src/tools/clippy/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs index 7c4ae746e..00f46629f 100644 --- a/src/tools/clippy/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs +++ b/src/tools/clippy/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use rustc_ast::ast::{Pat, PatKind}; use rustc_errors::Applicability; use rustc_lint::EarlyContext; -use rustc_span::source_map::Span; +use rustc_span::Span; use super::UNNEEDED_WILDCARD_PATTERN; diff --git a/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs b/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs index 28e041dee..0d79ece08 100644 --- a/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs +++ b/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs @@ -24,7 +24,7 @@ declare_clippy_lint! { /// ignored. /// /// ### Example - /// ```rust + /// ```no_run /// struct Foo<A, B> { /// x: A, /// y: B, @@ -33,7 +33,7 @@ declare_clippy_lint! { /// impl<B, A> Foo<B, A> {} /// ``` /// Use instead: - /// ```rust + /// ```no_run /// struct Foo<A, B> { /// x: A, /// y: B, diff --git a/src/tools/clippy/clippy_lints/src/missing_assert_message.rs b/src/tools/clippy/clippy_lints/src/missing_assert_message.rs index c17f00c42..4e00215c5 100644 --- a/src/tools/clippy/clippy_lints/src/missing_assert_message.rs +++ b/src/tools/clippy/clippy_lints/src/missing_assert_message.rs @@ -15,6 +15,10 @@ declare_clippy_lint! { /// A good custom message should be more about why the failure of the assertion is problematic /// and not what is failed because the assertion already conveys that. /// + /// Although the same reasoning applies to testing functions, this lint ignores them as they would be too noisy. + /// Also, in most cases understanding the test failure would be easier + /// compared to understanding a complex invariant distributed around the codebase. + /// /// ### Known problems /// This lint cannot check the quality of the custom panic messages. /// Hence, you can suppress this lint simply by adding placeholder messages @@ -23,14 +27,14 @@ declare_clippy_lint! { /// don't provide any extra information. /// /// ### Example - /// ```rust + /// ```no_run /// # struct Service { ready: bool } /// fn call(service: Service) { /// assert!(service.ready); /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # struct Service { ready: bool } /// fn call(service: Service) { /// assert!(service.ready, "`service.poll_ready()` must be called first to ensure that service is ready to receive requests"); diff --git a/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs b/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs index 08fec2b8e..dccf72d3c 100644 --- a/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs +++ b/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs @@ -43,14 +43,14 @@ declare_clippy_lint! { /// about the length of a slice, but this lint will not detect that. /// /// ### Example - /// ```rust + /// ```no_run /// fn sum(v: &[u8]) -> u8 { /// // 4 bounds checks /// v[0] + v[1] + v[2] + v[3] /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn sum(v: &[u8]) -> u8 { /// assert!(v.len() > 4); /// // no bounds checks @@ -200,9 +200,13 @@ impl<'hir> IndexEntry<'hir> { /// E.g. for `5` this returns `Some(5)`, for `..5` this returns `Some(4)`, /// for `..=5` this returns `Some(5)` fn upper_index_expr(expr: &Expr<'_>) -> Option<usize> { - if let ExprKind::Lit(lit) = &expr.kind && let LitKind::Int(index, _) = lit.node { + if let ExprKind::Lit(lit) = &expr.kind + && let LitKind::Int(index, _) = lit.node + { Some(index as usize) - } else if let Some(higher::Range { end: Some(end), limits, .. }) = higher::Range::hir(expr) + } else if let Some(higher::Range { + end: Some(end), limits, .. + }) = higher::Range::hir(expr) && let ExprKind::Lit(lit) = &end.kind && let LitKind::Int(index @ 1.., _) = lit.node { @@ -228,7 +232,12 @@ fn check_index<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>, map: &mut Unh if let Some(entry) = entry { match entry { - IndexEntry::StrayAssert { asserted_len, comparison, assert_span, slice } => { + IndexEntry::StrayAssert { + asserted_len, + comparison, + assert_span, + slice, + } => { *entry = IndexEntry::AssertWithIndex { highest_index: index, asserted_len: *asserted_len, @@ -238,8 +247,12 @@ fn check_index<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>, map: &mut Unh comparison: *comparison, }; }, - IndexEntry::IndexWithoutAssert { highest_index, indexes, .. } - | IndexEntry::AssertWithIndex { highest_index, indexes, .. } => { + IndexEntry::IndexWithoutAssert { + highest_index, indexes, .. + } + | IndexEntry::AssertWithIndex { + highest_index, indexes, .. + } => { indexes.push(expr.span); *highest_index = (*highest_index).max(index); }, diff --git a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs index f598a65d2..97522cbe6 100644 --- a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs +++ b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs @@ -1,5 +1,5 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::qualify_min_const_fn::is_min_const_fn; use clippy_utils::ty::has_drop; use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, is_from_proc_macro, trait_ref_of_method}; @@ -27,7 +27,7 @@ declare_clippy_lint! { /// /// Also, the lint only runs one pass over the code. Consider these two non-const functions: /// - /// ```rust + /// ```no_run /// fn a() -> i32 { /// 0 /// } @@ -42,7 +42,7 @@ declare_clippy_lint! { /// /// If you are marking a public function with `const`, removing it again will break API compatibility. /// ### Example - /// ```rust + /// ```no_run /// # struct Foo { /// # random_number: usize, /// # } @@ -55,7 +55,7 @@ declare_clippy_lint! { /// /// Could be a const fn: /// - /// ```rust + /// ```no_run /// # struct Foo { /// # random_number: usize, /// # } diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs index f2773cad4..973caa72b 100644 --- a/src/tools/clippy/clippy_lints/src/missing_doc.rs +++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs @@ -16,8 +16,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::Visibility; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::def_id::CRATE_DEF_ID; -use rustc_span::source_map::Span; -use rustc_span::sym; +use rustc_span::{sym, Span}; declare_clippy_lint! { /// ### What it does @@ -67,7 +66,7 @@ impl MissingDoc { if_chain! { if let Some(meta) = meta; if let MetaItemKind::List(list) = meta.kind; - if let Some(meta) = list.get(0); + if let Some(meta) = list.first(); if let Some(name) = meta.ident(); then { name.name == sym::include diff --git a/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs b/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs index 96d83e114..16ff98a59 100644 --- a/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs +++ b/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs @@ -1,6 +1,6 @@ +use clippy_config::types::Rename; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; - use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; use rustc_hir::def::Res; @@ -10,13 +10,14 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::Symbol; -use crate::utils::conf::Rename; - declare_clippy_lint! { /// ### What it does /// Checks for imports that do not rename the item as specified /// in the `enforce-import-renames` config option. /// + /// Note: Even though this lint is warn-by-default, it will only trigger if + /// import renames are defined in the clippy.toml file. + /// /// ### Why is this bad? /// Consistency is important, if a project has defined import /// renames they should be followed. More practically, some item names are too @@ -38,7 +39,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.55.0"] pub MISSING_ENFORCED_IMPORT_RENAMES, - restriction, + style, "enforce import renames" } diff --git a/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs b/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs index 2f63b9b9f..95f9df4e4 100644 --- a/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs +++ b/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs @@ -1,9 +1,9 @@ use std::ops::ControlFlow; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::ty::match_type; +use clippy_utils::is_path_lang_item; +use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::{for_each_expr, Visitable}; -use clippy_utils::{is_path_lang_item, paths}; use rustc_ast::LitKind; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def::{DefKind, Res}; @@ -40,7 +40,7 @@ declare_clippy_lint! { /// making it much less likely to accidentally forget to update the `Debug` impl when adding a new variant. /// /// ### Example - /// ```rust + /// ```no_run /// use std::fmt; /// struct Foo { /// data: String, @@ -57,7 +57,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::fmt; /// struct Foo { /// data: String, @@ -114,9 +114,11 @@ fn should_lint<'tcx>( if let ExprKind::MethodCall(path, recv, ..) = &expr.kind { let recv_ty = typeck_results.expr_ty(recv).peel_refs(); - if path.ident.name == sym::debug_struct && match_type(cx, recv_ty, &paths::FORMATTER) { + if path.ident.name == sym::debug_struct && is_type_diagnostic_item(cx, recv_ty, sym::Formatter) { has_debug_struct = true; - } else if path.ident.name == sym!(finish_non_exhaustive) && match_type(cx, recv_ty, &paths::DEBUG_STRUCT) { + } else if path.ident.name == sym!(finish_non_exhaustive) + && is_type_diagnostic_item(cx, recv_ty, sym::DebugStruct) + { has_finish_non_exhaustive = true; } } @@ -137,7 +139,7 @@ fn as_field_call<'tcx>( ) -> Option<Symbol> { if let ExprKind::MethodCall(path, recv, [debug_field, _], _) = &expr.kind && let recv_ty = typeck_results.expr_ty(recv).peel_refs() - && match_type(cx, recv_ty, &paths::DEBUG_STRUCT) + && is_type_diagnostic_item(cx, recv_ty, sym::DebugStruct) && path.ident.name == sym::field && let ExprKind::Lit(lit) = &debug_field.kind && let LitKind::Str(sym, ..) = lit.node diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs index 93f6025c7..b815da79b 100644 --- a/src/tools/clippy/clippy_lints/src/missing_inline.rs +++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs @@ -3,8 +3,7 @@ use rustc_ast::ast; use rustc_hir as hir; use rustc_lint::{self, LateContext, LateLintPass, LintContext}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::Span; -use rustc_span::sym; +use rustc_span::{sym, Span}; declare_clippy_lint! { /// ### What it does @@ -21,7 +20,7 @@ declare_clippy_lint! { /// then opt out for specific methods where this might not make sense. /// /// ### Example - /// ```rust + /// ```no_run /// pub fn foo() {} // missing #[inline] /// fn ok() {} // ok /// #[inline] pub fn bar() {} // ok diff --git a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs index 1adecd2ca..ad5f45a32 100644 --- a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs +++ b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs @@ -21,7 +21,7 @@ declare_clippy_lint! { /// Indicates that a method is missing. /// /// ### Example - /// ```rust + /// ```no_run /// trait Trait { /// fn required(); /// @@ -35,7 +35,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// trait Trait { /// fn required(); /// diff --git a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs index 367cd6bd4..215161b04 100644 --- a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs +++ b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs @@ -22,7 +22,7 @@ declare_clippy_lint! { /// order, or which is correct for any evaluation order. /// /// ### Example - /// ```rust + /// ```no_run /// let mut x = 0; /// /// let a = { @@ -33,7 +33,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let mut x = 0; /// let tmp = { /// x = 1; @@ -134,15 +134,27 @@ impl<'a, 'tcx> DivergenceVisitor<'a, 'tcx> { } } +fn stmt_might_diverge(stmt: &Stmt<'_>) -> bool { + !matches!(stmt.kind, StmtKind::Item(..)) +} + impl<'a, 'tcx> Visitor<'tcx> for DivergenceVisitor<'a, 'tcx> { fn visit_expr(&mut self, e: &'tcx Expr<'_>) { match e.kind { // fix #10776 ExprKind::Block(block, ..) => match (block.stmts, block.expr) { - ([], Some(e)) => self.visit_expr(e), - ([stmt], None) => match stmt.kind { - StmtKind::Expr(e) | StmtKind::Semi(e) => self.visit_expr(e), - _ => {}, + (stmts, Some(e)) => { + if stmts.iter().all(|stmt| !stmt_might_diverge(stmt)) { + self.visit_expr(e); + } + }, + ([first @ .., stmt], None) => { + if first.iter().all(|stmt| !stmt_might_diverge(stmt)) { + match stmt.kind { + StmtKind::Expr(e) | StmtKind::Semi(e) => self.visit_expr(e), + _ => {}, + } + } }, _ => {}, }, diff --git a/src/tools/clippy/clippy_lints/src/multi_assignments.rs b/src/tools/clippy/clippy_lints/src/multi_assignments.rs index 81eb1a085..b42dce7a1 100644 --- a/src/tools/clippy/clippy_lints/src/multi_assignments.rs +++ b/src/tools/clippy/clippy_lints/src/multi_assignments.rs @@ -13,12 +13,12 @@ declare_clippy_lint! { /// where such assignments return a copy of the assigned value. /// /// ### Example - /// ```rust + /// ```no_run ///# let (a, b); /// a = b = 42; /// ``` /// Use instead: - /// ```rust + /// ```no_run ///# let (a, b); /// b = 42; /// a = b; diff --git a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs index fe35126aa..d4f8008ae 100644 --- a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs +++ b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs @@ -9,7 +9,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::Span; +use rustc_span::{DesugaringKind, Span}; declare_clippy_lint! { /// ### What it does @@ -22,7 +22,7 @@ declare_clippy_lint! { /// elimination of unnecessary unsafe blocks through refactoring. /// /// ### Example - /// ```rust + /// ```no_run /// /// Reads a `char` from the given pointer. /// /// /// /// # Safety @@ -36,7 +36,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// /// Reads a `char` from the given pointer. /// /// /// /// # Safety @@ -64,7 +64,10 @@ declare_lint_pass!(MultipleUnsafeOpsPerBlock => [MULTIPLE_UNSAFE_OPS_PER_BLOCK]) impl<'tcx> LateLintPass<'tcx> for MultipleUnsafeOpsPerBlock { fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) { - if !matches!(block.rules, BlockCheckMode::UnsafeBlock(_)) || in_external_macro(cx.tcx.sess, block.span) { + if !matches!(block.rules, BlockCheckMode::UnsafeBlock(_)) + || in_external_macro(cx.tcx.sess, block.span) + || block.span.is_desugaring(DesugaringKind::Await) + { return; } let mut unsafe_ops = vec![]; diff --git a/src/tools/clippy/clippy_lints/src/mut_key.rs b/src/tools/clippy/clippy_lints/src/mut_key.rs index 5878f8995..ebfd53f1e 100644 --- a/src/tools/clippy/clippy_lints/src/mut_key.rs +++ b/src/tools/clippy/clippy_lints/src/mut_key.rs @@ -8,7 +8,7 @@ use rustc_middle::query::Key; use rustc_middle::ty::{Adt, Ty}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::def_id::LocalDefId; -use rustc_span::source_map::Span; +use rustc_span::Span; use rustc_span::symbol::sym; use std::iter; @@ -47,7 +47,7 @@ declare_clippy_lint! { /// [#6745](https://github.com/rust-lang/rust-clippy/issues/6745). /// /// ### Example - /// ```rust + /// ```no_run /// use std::cmp::{PartialEq, Eq}; /// use std::collections::HashSet; /// use std::hash::{Hash, Hasher}; diff --git a/src/tools/clippy/clippy_lints/src/mut_mut.rs b/src/tools/clippy/clippy_lints/src/mut_mut.rs index 64d8333a0..6989504a4 100644 --- a/src/tools/clippy/clippy_lints/src/mut_mut.rs +++ b/src/tools/clippy/clippy_lints/src/mut_mut.rs @@ -17,7 +17,7 @@ declare_clippy_lint! { /// misunderstanding of references. /// /// ### Example - /// ```rust + /// ```no_run /// # let mut y = 1; /// let x = &mut &mut y; /// ``` diff --git a/src/tools/clippy/clippy_lints/src/mut_reference.rs b/src/tools/clippy/clippy_lints/src/mut_reference.rs index e53e146ec..4f8e24422 100644 --- a/src/tools/clippy/clippy_lints/src/mut_reference.rs +++ b/src/tools/clippy/clippy_lints/src/mut_reference.rs @@ -15,14 +15,14 @@ declare_clippy_lint! { /// the value. Also the code misleads about the intent of the call site. /// /// ### Example - /// ```rust + /// ```no_run /// # let mut vec = Vec::new(); /// # let mut value = 5; /// vec.push(&mut value); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let mut vec = Vec::new(); /// # let value = 5; /// vec.push(&value); @@ -49,7 +49,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed { cx, arguments.iter().collect(), cx.typeck_results().expr_ty(fn_expr), - &rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false)), + &rustc_hir_pretty::qpath_to_string(path), "function", ); } diff --git a/src/tools/clippy/clippy_lints/src/mutex_atomic.rs b/src/tools/clippy/clippy_lints/src/mutex_atomic.rs index 99394b9e5..9d8c06cd0 100644 --- a/src/tools/clippy/clippy_lints/src/mutex_atomic.rs +++ b/src/tools/clippy/clippy_lints/src/mutex_atomic.rs @@ -29,14 +29,14 @@ declare_clippy_lint! { /// for waiting before a critical section. /// /// ### Example - /// ```rust + /// ```no_run /// # let y = true; /// # use std::sync::Mutex; /// let x = Mutex::new(&y); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let y = true; /// # use std::sync::atomic::AtomicBool; /// let x = AtomicBool::new(y); @@ -62,13 +62,13 @@ declare_clippy_lint! { /// for waiting before a critical section. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::sync::Mutex; /// let x = Mutex::new(0usize); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # use std::sync::atomic::AtomicUsize; /// let x = AtomicUsize::new(0usize); /// ``` diff --git a/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs b/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs index 5457eeec4..97e8f1c03 100644 --- a/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs +++ b/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs @@ -15,7 +15,7 @@ declare_clippy_lint! { /// Increases the amount and decreases the readability of code /// /// ### Example - /// ```rust + /// ```no_run /// enum ValType { /// I32, /// I64, @@ -35,7 +35,7 @@ declare_clippy_lint! { /// /// Could be rewritten as /// - /// ```rust + /// ```no_run /// enum ValType { /// I32, /// I64, diff --git a/src/tools/clippy/clippy_lints/src/needless_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bool.rs index f6b87b071..02c177c92 100644 --- a/src/tools/clippy/clippy_lints/src/needless_bool.rs +++ b/src/tools/clippy/clippy_lints/src/needless_bool.rs @@ -32,7 +32,7 @@ declare_clippy_lint! { /// shorter code. /// /// ### Example - /// ```rust + /// ```no_run /// # let x = true; /// if x { /// false @@ -43,7 +43,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let x = true; /// !x /// # ; @@ -207,9 +207,9 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBool { _ => (), } } - if let Some((lhs_a, a)) = fetch_assign(then) && - let Some((lhs_b, b)) = fetch_assign(r#else) && - SpanlessEq::new(cx).eq_expr(lhs_a, lhs_b) + if let Some((lhs_a, a)) = fetch_assign(then) + && let Some((lhs_b, b)) = fetch_assign(r#else) + && SpanlessEq::new(cx).eq_expr(lhs_a, lhs_b) { let mut applicability = Applicability::MachineApplicable; let cond = Sugg::hir_with_applicability(cx, cond, "..", &mut applicability); @@ -226,7 +226,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBool { "this if-then-else expression assigns a bool literal", "you can reduce it to", sugg, - applicability + applicability, ); } } diff --git a/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs b/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs index 11bf9e9ca..fdb91f0dc 100644 --- a/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs +++ b/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs @@ -13,7 +13,7 @@ declare_clippy_lint! { /// This pattern has no effect in almost all cases. /// /// ### Example - /// ```rust + /// ```no_run /// let mut v = Vec::<String>::new(); /// v.iter_mut().filter(|&ref a| a.is_empty()); /// @@ -21,7 +21,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let mut v = Vec::<String>::new(); /// v.iter_mut().filter(|a| a.is_empty()); /// diff --git a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs index d55c77a92..dcfb109a4 100644 --- a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs +++ b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs @@ -1,6 +1,6 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::mir::{enclosing_mir, expr_local, local_assignments, used_exactly_once, PossibleBorrowerMap}; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::is_copy; use clippy_utils::{expr_use_ctxt, peel_n_hir_expr_refs, DefinedTy, ExprUseNode}; @@ -36,7 +36,7 @@ declare_clippy_lint! { /// in such a case can change the semantics of the code. /// /// ### Example - /// ```rust + /// ```no_run /// fn f(_: impl AsRef<str>) {} /// /// let x = "foo"; @@ -44,7 +44,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// fn f(_: impl AsRef<str>) {} /// /// let x = "foo"; @@ -87,18 +87,24 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowsForGenericArgs<'tcx> { && let ty::Param(ty) = *ty.value.skip_binder().kind() && let Some((hir_id, fn_id, i)) = match use_cx.node { ExprUseNode::MethodArg(_, _, 0) => None, - ExprUseNode::MethodArg(hir_id, None, i) => { - cx.typeck_results().type_dependent_def_id(hir_id).map(|id| (hir_id, id, i)) - }, - ExprUseNode::FnArg(&Expr { kind: ExprKind::Path(ref p), hir_id, .. }, i) - if !path_has_args(p) => match cx.typeck_results().qpath_res(p, hir_id) { - Res::Def(DefKind::Fn | DefKind::Ctor(..) | DefKind::AssocFn, id) => { - Some((hir_id, id, i)) + ExprUseNode::MethodArg(hir_id, None, i) => cx + .typeck_results() + .type_dependent_def_id(hir_id) + .map(|id| (hir_id, id, i)), + ExprUseNode::FnArg( + &Expr { + kind: ExprKind::Path(ref p), + hir_id, + .. }, + i, + ) if !path_has_args(p) => match cx.typeck_results().qpath_res(p, hir_id) { + Res::Def(DefKind::Fn | DefKind::Ctor(..) | DefKind::AssocFn, id) => Some((hir_id, id, i)), _ => None, }, _ => None, - } && let count = needless_borrow_count( + } + && let count = needless_borrow_count( cx, &mut self.possible_borrowers, fn_id, @@ -107,7 +113,8 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowsForGenericArgs<'tcx> { ty, expr, &self.msrv, - ) && count != 0 + ) + && count != 0 { span_lint_and_then( cx, @@ -119,7 +126,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowsForGenericArgs<'tcx> { let snip_span = peel_n_hir_expr_refs(expr, count).0.span; let snip = snippet_with_context(cx, snip_span, expr.span.ctxt(), "..", &mut app).0; diag.span_suggestion(expr.span, "change this to", snip.into_owned(), app); - } + }, ); } } @@ -245,7 +252,9 @@ fn needless_borrow_count<'tcx>( predicates.iter().all(|predicate| { if let ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() - && cx.tcx.is_diagnostic_item(sym::IntoIterator, trait_predicate.trait_ref.def_id) + && cx + .tcx + .is_diagnostic_item(sym::IntoIterator, trait_predicate.trait_ref.def_id) && let ty::Param(param_ty) = trait_predicate.self_ty().kind() && let GenericArgKind::Type(ty) = args_with_referent_ty[param_ty.index as usize].unpack() && ty.is_array() @@ -308,13 +317,13 @@ fn is_mixed_projection_predicate<'tcx>( match projection_ty.self_ty().kind() { ty::Alias(ty::Projection, inner_projection_ty) => { projection_ty = *inner_projection_ty; - } + }, ty::Param(param_ty) => { return (param_ty.index as usize) >= generics.parent_count; - } + }, _ => { return false; - } + }, } } } else { diff --git a/src/tools/clippy/clippy_lints/src/needless_continue.rs b/src/tools/clippy/clippy_lints/src/needless_continue.rs index 38a75034c..cb2738947 100644 --- a/src/tools/clippy/clippy_lints/src/needless_continue.rs +++ b/src/tools/clippy/clippy_lints/src/needless_continue.rs @@ -55,7 +55,7 @@ declare_clippy_lint! { /// statement within the THEN block and omitting the else block completely. /// /// ### Example - /// ```rust + /// ```no_run /// # fn condition() -> bool { false } /// # fn update_condition() {} /// # let x = false; @@ -72,7 +72,7 @@ declare_clippy_lint! { /// /// Could be rewritten as /// - /// ```rust + /// ```no_run /// # fn condition() -> bool { false } /// # fn update_condition() {} /// # let x = false; @@ -87,7 +87,7 @@ declare_clippy_lint! { /// /// As another example, the following code /// - /// ```rust + /// ```no_run /// # fn waiting() -> bool { false } /// loop { /// if waiting() { @@ -100,7 +100,7 @@ declare_clippy_lint! { /// ``` /// Could be rewritten as /// - /// ```rust + /// ```no_run /// # fn waiting() -> bool { false } /// loop { /// if waiting() { @@ -189,7 +189,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.get(0).map_or(false, |stmt| match stmt.kind { + block.stmts.first().map_or(false, |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()) @@ -408,7 +408,7 @@ fn check_and_warn(cx: &EarlyContext<'_>, expr: &ast::Expr) { /// till a non-whitespace character is found. e.g., the string. If no closing `}` is present, the /// string will be preserved. /// -/// ```rust +/// ```no_run /// { /// let x = 5; /// } @@ -434,7 +434,7 @@ fn erode_from_back(s: &str) -> String { } fn span_of_first_expr_in_block(block: &ast::Block) -> Option<Span> { - block.stmts.get(0).map(|stmt| stmt.span) + block.stmts.first().map(|stmt| stmt.span) } #[cfg(test)] diff --git a/src/tools/clippy/clippy_lints/src/needless_else.rs b/src/tools/clippy/clippy_lints/src/needless_else.rs index 0c1fe881f..d881c13f8 100644 --- a/src/tools/clippy/clippy_lints/src/needless_else.rs +++ b/src/tools/clippy/clippy_lints/src/needless_else.rs @@ -13,7 +13,7 @@ declare_clippy_lint! { /// An empty else branch does nothing and can be removed. /// /// ### Example - /// ```rust + /// ```no_run ///# fn check() -> bool { true } /// if check() { /// println!("Check successful!"); @@ -21,7 +21,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run ///# fn check() -> bool { true } /// if check() { /// println!("Check successful!"); diff --git a/src/tools/clippy/clippy_lints/src/needless_for_each.rs b/src/tools/clippy/clippy_lints/src/needless_for_each.rs index 98bf122fa..c71996131 100644 --- a/src/tools/clippy/clippy_lints/src/needless_for_each.rs +++ b/src/tools/clippy/clippy_lints/src/needless_for_each.rs @@ -3,8 +3,7 @@ use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{Closure, Expr, ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::Span; -use rustc_span::{sym, Symbol}; +use rustc_span::{sym, Span, Symbol}; use if_chain::if_chain; @@ -25,14 +24,14 @@ declare_clippy_lint! { /// But when none of these apply, a simple `for` loop is more idiomatic. /// /// ### Example - /// ```rust + /// ```no_run /// let v = vec![0, 1, 2]; /// v.iter().for_each(|elem| { /// println!("{}", elem); /// }) /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let v = vec![0, 1, 2]; /// for elem in v.iter() { /// println!("{}", elem); diff --git a/src/tools/clippy/clippy_lints/src/needless_if.rs b/src/tools/clippy/clippy_lints/src/needless_if.rs index 1ed7ea6b3..23aabc548 100644 --- a/src/tools/clippy/clippy_lints/src/needless_if.rs +++ b/src/tools/clippy/clippy_lints/src/needless_if.rs @@ -44,7 +44,6 @@ impl LateLintPass<'_> for NeedlessIf { && block.stmts.is_empty() && block.expr.is_none() && !in_external_macro(cx.sess(), expr.span) - && !is_from_proc_macro(cx, expr) && let Some(then_snippet) = snippet_opt(cx, then.span) // Ignore // - empty macro expansions @@ -53,6 +52,7 @@ impl LateLintPass<'_> for NeedlessIf { // - #[cfg]'d out code && then_snippet.chars().all(|ch| matches!(ch, '{' | '}') || ch.is_ascii_whitespace()) && let Some(cond_snippet) = snippet_opt(cx, cond.span) + && !is_from_proc_macro(cx, expr) { span_lint_and_sugg( cx, diff --git a/src/tools/clippy/clippy_lints/src/needless_late_init.rs b/src/tools/clippy/clippy_lints/src/needless_late_init.rs index 948454d13..c8888c744 100644 --- a/src/tools/clippy/clippy_lints/src/needless_late_init.rs +++ b/src/tools/clippy/clippy_lints/src/needless_late_init.rs @@ -22,7 +22,7 @@ declare_clippy_lint! { /// Assigning in the `let` statement is less repetitive. /// /// ### Example - /// ```rust + /// ```no_run /// let a; /// a = 1; /// @@ -41,7 +41,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let a = 1; /// /// let b = match 3 { diff --git a/src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs b/src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs index d17a383e8..7bbf1fb4c 100644 --- a/src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs +++ b/src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs @@ -20,7 +20,7 @@ declare_clippy_lint! { /// /// ### Example /// - /// ```rust + /// ```no_run /// for i in (0)..10 { /// println!("{i}"); /// } @@ -28,7 +28,7 @@ declare_clippy_lint! { /// /// Use instead: /// - /// ```rust + /// ```no_run /// for i in 0..10 { /// println!("{i}"); /// } @@ -46,9 +46,9 @@ fn snippet_enclosed_in_parenthesis(snippet: &str) -> bool { } fn check_for_parens(cx: &LateContext<'_>, e: &Expr<'_>, is_start: bool) { - if is_start && - let ExprKind::Lit(literal) = e.kind && - let ast::LitKind::Float(_sym, ast::LitFloatType::Unsuffixed) = literal.node + if is_start + && let ExprKind::Lit(literal) = e.kind + && let ast::LitKind::Float(_sym, ast::LitFloatType::Unsuffixed) = literal.node { // don't check floating point literals on the start expression of a range return; diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs index 3ad9ae030..d610ba520 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs @@ -7,7 +7,8 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_qpath, FnKind, Visitor}; use rustc_hir::{ - Body, Closure, Expr, ExprKind, FnDecl, HirId, HirIdMap, HirIdSet, Impl, ItemKind, Mutability, Node, PatKind, QPath, + BlockCheckMode, Body, Closure, Expr, ExprKind, FnDecl, HirId, HirIdMap, HirIdSet, Impl, ItemKind, Mutability, Node, + PatKind, QPath, }; use rustc_hir_typeck::expr_use_visitor as euv; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; @@ -36,18 +37,18 @@ declare_clippy_lint! { /// opportunities for parallelization. /// /// ### Example - /// ```rust + /// ```no_run /// fn foo(y: &mut i32) -> i32 { /// 12 + *y /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn foo(y: &i32) -> i32 { /// 12 + *y /// } /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub NEEDLESS_PASS_BY_REF_MUT, nursery, "using a `&mut` argument when it's not mutated" @@ -139,13 +140,23 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> { let hir_id = cx.tcx.hir().local_def_id_to_hir_id(fn_def_id); let is_async = match kind { FnKind::ItemFn(.., header) => { + if header.is_unsafe() { + // We don't check unsafe functions. + return; + } let attrs = cx.tcx.hir().attrs(hir_id); if header.abi != Abi::Rust || requires_exact_signature(attrs) { return; } header.is_async() }, - FnKind::Method(.., sig) => sig.header.is_async(), + FnKind::Method(.., sig) => { + if sig.header.is_unsafe() { + // We don't check unsafe functions. + return; + } + sig.header.is_async() + }, FnKind::Closure => return, }; @@ -186,20 +197,21 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> { }; let infcx = cx.tcx.infer_ctxt().build(); euv::ExprUseVisitor::new(&mut ctx, &infcx, fn_def_id, cx.param_env, cx.typeck_results()).consume_body(body); - if is_async { - let mut checked_closures = FxHashSet::default(); - - // We retrieve all the closures declared in the async function because they will - // not be found by `euv::Delegate`. - let mut closures: FxHashSet<LocalDefId> = FxHashSet::default(); - for_each_expr_with_closures(cx, body, |expr| { - if let ExprKind::Closure(closure) = expr.kind { - closures.insert(closure.def_id); - } - ControlFlow::<()>::Continue(()) - }); - check_closures(&mut ctx, cx, &infcx, &mut checked_closures, closures); + let mut checked_closures = FxHashSet::default(); + + // We retrieve all the closures declared in the function because they will not be found + // by `euv::Delegate`. + let mut closures: FxHashSet<LocalDefId> = FxHashSet::default(); + for_each_expr_with_closures(cx, body, |expr| { + if let ExprKind::Closure(closure) = expr.kind { + closures.insert(closure.def_id); + } + ControlFlow::<()>::Continue(()) + }); + check_closures(&mut ctx, cx, &infcx, &mut checked_closures, closures); + + if is_async { while !ctx.async_closures.is_empty() { let async_closures = ctx.async_closures.clone(); ctx.async_closures.clear(); @@ -213,7 +225,10 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> { if let PatKind::Binding(_, canonical_id, ..) = arg.pat.kind && !mutably_used_vars.contains(&canonical_id) { - self.fn_def_ids_to_maybe_unused_mut.entry(fn_def_id).or_default().push(input); + self.fn_def_ids_to_maybe_unused_mut + .entry(fn_def_id) + .or_default() + .push(input); } } } @@ -304,10 +319,27 @@ impl<'tcx> MutablyUsedVariablesCtxt<'tcx> { } self.aliases.insert(alias, target); } + + // The goal here is to find if the current scope is unsafe or not. It stops when it finds + // a function or an unsafe block. + fn is_in_unsafe_block(&self, item: HirId) -> bool { + let hir = self.tcx.hir(); + for (parent, node) in hir.parent_iter(item) { + if let Some(fn_sig) = hir.fn_sig_by_hir_id(parent) { + return fn_sig.header.is_unsafe(); + } else if let Node::Block(block) = node { + if matches!(block.rules, BlockCheckMode::UnsafeBlock(_)) { + return true; + } + } + } + false + } } impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> { - fn consume(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, _id: HirId) { + #[allow(clippy::if_same_then_else)] + fn consume(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, id: HirId) { if let euv::Place { base: euv::PlaceBase::Local(vid) @@ -327,13 +359,18 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> { && matches!(base_ty.ref_mutability(), Some(Mutability::Mut)) { self.add_mutably_used_var(*vid); + } else if self.is_in_unsafe_block(id) { + // If we are in an unsafe block, any operation on this variable must not be warned + // upon! + self.add_mutably_used_var(*vid); } self.prev_bind = None; self.prev_move_to_closure.remove(vid); } } - fn borrow(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, _id: HirId, borrow: ty::BorrowKind) { + #[allow(clippy::if_same_then_else)] + fn borrow(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, id: HirId, borrow: ty::BorrowKind) { self.prev_bind = None; if let euv::Place { base: @@ -355,6 +392,10 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> { || (borrow == ty::BorrowKind::UniqueImmBorrow && base_ty.ref_mutability() == Some(Mutability::Mut)) { self.add_mutably_used_var(*vid); + } else if self.is_in_unsafe_block(id) { + // If we are in an unsafe block, any operation on this variable must not be warned + // upon! + self.add_mutably_used_var(*vid); } } else if borrow == ty::ImmBorrow { // If there is an `async block`, it'll contain a call to a closure which we need to @@ -397,7 +438,21 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> { } } - fn copy(&mut self, _cmt: &euv::PlaceWithHirId<'tcx>, _id: HirId) { + fn copy(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, id: HirId) { + if let euv::Place { + base: + euv::PlaceBase::Local(vid) + | euv::PlaceBase::Upvar(UpvarId { + var_path: UpvarPath { hir_id: vid }, + .. + }), + .. + } = &cmt.place + { + if self.is_in_unsafe_block(id) { + self.add_mutably_used_var(*vid); + } + } self.prev_bind = None; } @@ -427,8 +482,22 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> { } } - fn bind(&mut self, _cmt: &euv::PlaceWithHirId<'tcx>, id: HirId) { + fn bind(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, id: HirId) { self.prev_bind = Some(id); + if let euv::Place { + base: + euv::PlaceBase::Local(vid) + | euv::PlaceBase::Upvar(UpvarId { + var_path: UpvarPath { hir_id: vid }, + .. + }), + .. + } = &cmt.place + { + if self.is_in_unsafe_block(id) { + self.add_mutably_used_var(*vid); + } + } } } @@ -454,7 +523,11 @@ impl<'tcx> Visitor<'tcx> for FnNeedsMutVisitor<'_, 'tcx> { // #11182; do not lint if mutability is required elsewhere if let Node::Expr(expr) = cx.tcx.hir().get(hir_id) && let Some(parent) = get_parent_node(cx.tcx, expr.hir_id) - && let ty::FnDef(def_id, _) = cx.tcx.typeck(cx.tcx.hir().enclosing_body_owner(hir_id)).expr_ty(expr).kind() + && let ty::FnDef(def_id, _) = cx + .tcx + .typeck(cx.tcx.hir().enclosing_body_owner(hir_id)) + .expr_ty(expr) + .kind() && let Some(def_id) = def_id.as_local() { if let Node::Expr(e) = parent diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index 5ee26966f..8fa461ac1 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -1,10 +1,10 @@ use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; +use clippy_utils::is_self; use clippy_utils::ptr::get_spans; use clippy_utils::source::{snippet, snippet_opt}; use clippy_utils::ty::{ implements_trait, implements_trait_with_env_from_iter, is_copy, is_type_diagnostic_item, is_type_lang_item, }; -use clippy_utils::{get_trait_def_id, is_self, paths}; use if_chain::if_chain; use rustc_ast::ast::Attribute; use rustc_errors::{Applicability, Diagnostic}; @@ -43,13 +43,13 @@ declare_clippy_lint! { /// (by using `Borrow` trait, for example), depending on how the function is used. /// /// ### Example - /// ```rust + /// ```no_run /// fn foo(v: Vec<i32>) { /// assert_eq!(v.len(), 42); /// } /// ``` /// should be - /// ```rust + /// ```no_run /// fn foo(v: &[i32]) { /// assert_eq!(v.len(), 42); /// } @@ -115,7 +115,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { need!(cx.tcx.lang_items().fn_trait()), need!(cx.tcx.lang_items().fn_once_trait()), need!(cx.tcx.lang_items().fn_mut_trait()), - need!(get_trait_def_id(cx, &paths::RANGE_ARGUMENT_TRAIT)), + need!(cx.tcx.get_diagnostic_item(sym::RangeBounds)), ]; let sized_trait = need!(cx.tcx.lang_items().sized_trait()); diff --git a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs index 7b0f7eaf1..074c9fef1 100644 --- a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs @@ -4,7 +4,7 @@ use clippy_utils::source::snippet; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{AsyncGeneratorKind, Block, Body, Expr, ExprKind, GeneratorKind, LangItem, MatchSource, QPath}; +use rustc_hir::{Block, Body, CoroutineKind, CoroutineSource, Expr, ExprKind, LangItem, MatchSource, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -16,7 +16,7 @@ declare_clippy_lint! { /// There's no reason to use `?` to short-circuit when execution of the body will end there anyway. /// /// ### Example - /// ```rust + /// ```no_run /// struct TO { /// magic: Option<usize>, /// } @@ -35,7 +35,7 @@ declare_clippy_lint! { /// /// ``` /// Use instead: - /// ```rust + /// ```no_run /// struct TO { /// magic: Option<usize>, /// } @@ -87,7 +87,7 @@ impl LateLintPass<'_> for NeedlessQuestionMark { } fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) { - if let Some(GeneratorKind::Async(AsyncGeneratorKind::Fn)) = body.generator_kind { + if let Some(CoroutineKind::Async(CoroutineSource::Fn)) = body.coroutine_kind { if let ExprKind::Block( Block { expr: @@ -125,7 +125,7 @@ fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { if let ExprKind::Match(inner_expr_with_q, _, MatchSource::TryDesugar(_)) = &arg.kind; if let ExprKind::Call(called, [inner_expr]) = &inner_expr_with_q.kind; if let ExprKind::Path(QPath::LangItem(LangItem::TryTraitBranch, ..)) = &called.kind; - if expr.span.ctxt() == inner_expr.span.ctxt(); + if expr.span.eq_ctxt(inner_expr.span); let expr_ty = cx.typeck_results().expr_ty(expr); let inner_ty = cx.typeck_results().expr_ty(inner_expr); if expr_ty == inner_ty; diff --git a/src/tools/clippy/clippy_lints/src/needless_update.rs b/src/tools/clippy/clippy_lints/src/needless_update.rs index 0bd29d177..f8888d368 100644 --- a/src/tools/clippy/clippy_lints/src/needless_update.rs +++ b/src/tools/clippy/clippy_lints/src/needless_update.rs @@ -17,7 +17,7 @@ declare_clippy_lint! { /// somewhere), and make the code less readable. /// /// ### Example - /// ```rust + /// ```no_run /// # struct Point { /// # x: i32, /// # y: i32, diff --git a/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs b/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs index a022fc156..56c67406d 100644 --- a/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs +++ b/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs @@ -18,7 +18,7 @@ declare_clippy_lint! { /// especially easy to miss if the operator based comparison result is negated. /// /// ### Example - /// ```rust + /// ```no_run /// let a = 1.0; /// let b = f64::NAN; /// @@ -26,7 +26,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// use std::cmp::Ordering; /// # let a = 1.0; /// # let b = f64::NAN; diff --git a/src/tools/clippy/clippy_lints/src/neg_multiply.rs b/src/tools/clippy/clippy_lints/src/neg_multiply.rs index db0e22842..8b69f94cb 100644 --- a/src/tools/clippy/clippy_lints/src/neg_multiply.rs +++ b/src/tools/clippy/clippy_lints/src/neg_multiply.rs @@ -8,7 +8,7 @@ use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::Span; +use rustc_span::Span; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs index aee184252..3a28e511f 100644 --- a/src/tools/clippy/clippy_lints/src/no_effect.rs +++ b/src/tools/clippy/clippy_lints/src/no_effect.rs @@ -23,7 +23,7 @@ declare_clippy_lint! { /// readable. /// /// ### Example - /// ```rust + /// ```no_run /// 0; /// ``` #[clippy::version = "pre 1.29.0"] @@ -103,11 +103,16 @@ fn check_no_effect(cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool { && final_stmt.hir_id == stmt.hir_id { let expr_ty = cx.typeck_results().expr_ty(expr); - let mut ret_ty = cx.tcx.fn_sig(item.owner_id).instantiate_identity().output().skip_binder(); + let mut ret_ty = cx + .tcx + .fn_sig(item.owner_id) + .instantiate_identity() + .output() + .skip_binder(); // Remove `impl Future<Output = T>` to get `T` - if cx.tcx.ty_is_opaque_future(ret_ty) && - let Some(true_ret_ty) = cx.tcx.infer_ctxt().build().get_impl_future_output_ty(ret_ty) + if cx.tcx.ty_is_opaque_future(ret_ty) + && let Some(true_ret_ty) = cx.tcx.infer_ctxt().build().get_impl_future_output_ty(ret_ty) { ret_ty = true_ret_ty; } diff --git a/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs b/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs index 8fd9ae351..04d750148 100644 --- a/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs +++ b/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs @@ -18,13 +18,13 @@ declare_clippy_lint! { /// Rust ABI can break this at any point. /// /// ### Example - /// ```rust + /// ```no_run /// #[no_mangle] /// fn example(arg_one: u32, arg_two: usize) {} /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// #[no_mangle] /// extern "C" fn example(arg_one: u32, arg_two: usize) {} /// ``` @@ -48,7 +48,8 @@ impl<'tcx> LateLintPass<'tcx> for NoMangleWithRustAbi { && let Some((fn_attrs, _)) = snippet.split_once("fn") && !fn_attrs.contains("extern") { - let sugg_span = fn_sig.span + let sugg_span = fn_sig + .span .with_lo(fn_sig.span.lo() + BytePos::from_usize(fn_attrs.len())) .shrink_to_lo(); diff --git a/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs b/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs index 20b4b4f03..9689f63a0 100644 --- a/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs +++ b/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::paths::ORD_CMP; use clippy_utils::ty::implements_trait; -use clippy_utils::{get_parent_node, is_res_lang_ctor, last_path_segment, match_def_path, path_res, std_or_core}; +use clippy_utils::{get_parent_node, is_res_lang_ctor, last_path_segment, path_res, std_or_core}; use rustc_errors::Applicability; use rustc_hir::def_id::LocalDefId; use rustc_hir::{Expr, ExprKind, ImplItem, ImplItemKind, LangItem, Node, UnOp}; @@ -65,7 +64,7 @@ declare_clippy_lint! { /// in `Some`. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::cmp::Ordering; /// #[derive(Eq, PartialEq)] /// struct A(u32); @@ -85,7 +84,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # use std::cmp::Ordering; /// #[derive(Eq, PartialEq)] /// struct A(u32); @@ -103,7 +102,7 @@ declare_clippy_lint! { /// } /// } /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub NON_CANONICAL_PARTIAL_ORD_IMPL, suspicious, "non-canonical implementation of `PartialOrd` on an `Ord` type" @@ -132,12 +131,7 @@ impl LateLintPass<'_> for NonCanonicalImpls { if cx.tcx.is_diagnostic_item(sym::Clone, trait_impl.def_id) && let Some(copy_def_id) = cx.tcx.get_diagnostic_item(sym::Copy) - && implements_trait( - cx, - trait_impl.self_ty(), - copy_def_id, - &[], - ) + && implements_trait(cx, trait_impl.self_ty(), copy_def_id, &[]) { if impl_item.ident.name == sym::clone { if block.stmts.is_empty() @@ -145,7 +139,8 @@ impl LateLintPass<'_> for NonCanonicalImpls { && let ExprKind::Unary(UnOp::Deref, deref) = expr.kind && let ExprKind::Path(qpath) = deref.kind && last_path_segment(&qpath).ident.name == kw::SelfLower - {} else { + { + } else { span_lint_and_sugg( cx, NON_CANONICAL_CLONE_IMPL, @@ -198,10 +193,13 @@ impl LateLintPass<'_> for NonCanonicalImpls { && is_res_lang_ctor(cx, cx.qpath_res(some_path, *some_hir_id), LangItem::OptionSome) // Fix #11178, allow `Self::cmp(self, ..)` too && self_cmp_call(cx, cmp_expr, impl_item.owner_id.def_id, &mut needs_fully_qualified) - {} else { + { + } else { // If `Self` and `Rhs` are not the same type, bail. This makes creating a valid // suggestion tons more complex. - if let [lhs, rhs, ..] = trait_impl.args.as_slice() && lhs != rhs { + if let [lhs, rhs, ..] = trait_impl.args.as_slice() + && lhs != rhs + { return; } @@ -239,12 +237,8 @@ impl LateLintPass<'_> for NonCanonicalImpls { ], }; - diag.multipart_suggestion( - "change this to", - suggs, - Applicability::Unspecified, - ); - } + diag.multipart_suggestion("change this to", suggs, Applicability::Unspecified); + }, ); } } @@ -261,7 +255,7 @@ fn self_cmp_call<'tcx>( match cmp_expr.kind { ExprKind::Call(path, [_self, _other]) => path_res(cx, path) .opt_def_id() - .is_some_and(|def_id| match_def_path(cx, def_id, &ORD_CMP)), + .is_some_and(|def_id| cx.tcx.is_diagnostic_item(sym::ord_cmp_method, def_id)), ExprKind::MethodCall(_, _, [_other], ..) => { // We can set this to true here no matter what as if it's a `MethodCall` and goes to the // `else` branch, it must be a method named `cmp` that isn't `Ord::cmp` @@ -273,7 +267,7 @@ fn self_cmp_call<'tcx>( cx.tcx .typeck(def_id) .type_dependent_def_id(cmp_expr.hir_id) - .is_some_and(|def_id| match_def_path(cx, def_id, &ORD_CMP)) + .is_some_and(|def_id| cx.tcx.is_diagnostic_item(sym::ord_cmp_method, def_id)) }, _ => false, } diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs index 2b4e3260c..54cec066b 100644 --- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs +++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs @@ -5,9 +5,10 @@ use std::ptr; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::in_constant; use clippy_utils::macros::macro_backtrace; +use clippy_utils::{def_path_def_ids, in_constant}; use if_chain::if_chain; +use rustc_data_structures::fx::FxHashSet; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::{ @@ -15,9 +16,10 @@ use rustc_hir::{ }; use rustc_lint::{LateContext, LateLintPass, Lint}; use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult, GlobalId}; +use rustc_middle::query::Key; use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{sym, InnerSpan, Span}; use rustc_target::abi::VariantIdx; @@ -56,7 +58,7 @@ declare_clippy_lint! { /// [#5812](https://github.com/rust-lang/rust-clippy/issues/5812) and /// /// ### Example - /// ```rust + /// ```no_run /// use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; /// /// const CONST_ATOM: AtomicUsize = AtomicUsize::new(12); @@ -65,7 +67,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; /// static STATIC_ATOM: AtomicUsize = AtomicUsize::new(15); /// STATIC_ATOM.store(9, SeqCst); @@ -103,7 +105,7 @@ declare_clippy_lint! { /// [#3825](https://github.com/rust-lang/rust-clippy/issues/3825) /// /// ### Example - /// ```rust + /// ```no_run /// use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; /// const CONST_ATOM: AtomicUsize = AtomicUsize::new(12); /// @@ -112,7 +114,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; /// const CONST_ATOM: AtomicUsize = AtomicUsize::new(12); /// @@ -126,128 +128,6 @@ declare_clippy_lint! { "referencing `const` with interior mutability" } -fn is_unfrozen<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { - // Ignore types whose layout is unknown since `is_freeze` reports every generic types as `!Freeze`, - // making it indistinguishable from `UnsafeCell`. i.e. it isn't a tool to prove a type is - // 'unfrozen'. However, this code causes a false negative in which - // a type contains a layout-unknown type, but also an unsafe cell like `const CELL: Cell<T>`. - // Yet, it's better than `ty.has_type_flags(TypeFlags::HAS_TY_PARAM | TypeFlags::HAS_PROJECTION)` - // since it works when a pointer indirection involves (`Cell<*const T>`). - // Making up a `ParamEnv` where every generic params and assoc types are `Freeze`is another option; - // but I'm not sure whether it's a decent way, if possible. - cx.tcx.layout_of(cx.param_env.and(ty)).is_ok() && !ty.is_freeze(cx.tcx, cx.param_env) -} - -fn is_value_unfrozen_raw<'tcx>( - cx: &LateContext<'tcx>, - result: Result<Option<ty::ValTree<'tcx>>, ErrorHandled>, - ty: Ty<'tcx>, -) -> bool { - fn inner<'tcx>(cx: &LateContext<'tcx>, val: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> bool { - match *ty.kind() { - // the fact that we have to dig into every structs to search enums - // leads us to the point checking `UnsafeCell` directly is the only option. - ty::Adt(ty_def, ..) if ty_def.is_unsafe_cell() => true, - // As of 2022-09-08 miri doesn't track which union field is active so there's no safe way to check the - // contained value. - ty::Adt(def, ..) if def.is_union() => false, - ty::Array(ty, _) => val.unwrap_branch().iter().any(|field| inner(cx, *field, ty)), - ty::Adt(def, _) if def.is_union() => false, - ty::Adt(def, args) if def.is_enum() => { - let (&variant_index, fields) = val.unwrap_branch().split_first().unwrap(); - let variant_index = VariantIdx::from_u32(variant_index.unwrap_leaf().try_to_u32().ok().unwrap()); - fields - .iter() - .copied() - .zip( - def.variants()[variant_index] - .fields - .iter() - .map(|field| field.ty(cx.tcx, args)), - ) - .any(|(field, ty)| inner(cx, field, ty)) - }, - ty::Adt(def, args) => val - .unwrap_branch() - .iter() - .zip(def.non_enum_variant().fields.iter().map(|field| field.ty(cx.tcx, args))) - .any(|(field, ty)| inner(cx, *field, ty)), - ty::Tuple(tys) => val - .unwrap_branch() - .iter() - .zip(tys) - .any(|(field, ty)| inner(cx, *field, ty)), - _ => false, - } - } - result.map_or_else( - |err| { - // Consider `TooGeneric` cases as being unfrozen. - // This causes a false positive where an assoc const whose type is unfrozen - // have a value that is a frozen variant with a generic param (an example is - // `declare_interior_mutable_const::enums::BothOfCellAndGeneric::GENERIC_VARIANT`). - // However, it prevents a number of false negatives that is, I think, important: - // 1. assoc consts in trait defs referring to consts of themselves (an example is - // `declare_interior_mutable_const::traits::ConcreteTypes::ANOTHER_ATOMIC`). - // 2. a path expr referring to assoc consts whose type is doesn't have any frozen variants in trait - // defs (i.e. without substitute for `Self`). (e.g. borrowing - // `borrow_interior_mutable_const::trait::ConcreteTypes::ATOMIC`) - // 3. similar to the false positive above; but the value is an unfrozen variant, or the type has no - // enums. (An example is - // `declare_interior_mutable_const::enums::BothOfCellAndGeneric::UNFROZEN_VARIANT` and - // `declare_interior_mutable_const::enums::BothOfCellAndGeneric::NO_ENUM`). - // One might be able to prevent these FNs correctly, and replace this with `false`; - // e.g. implementing `has_frozen_variant` described above, and not running this function - // when the type doesn't have any frozen variants would be the 'correct' way for the 2nd - // case (that actually removes another suboptimal behavior (I won't say 'false positive') where, - // similar to 2., but with the a frozen variant) (e.g. borrowing - // `borrow_interior_mutable_const::enums::AssocConsts::TO_BE_FROZEN_VARIANT`). - // I chose this way because unfrozen enums as assoc consts are rare (or, hopefully, none). - matches!(err, ErrorHandled::TooGeneric(..)) - }, - |val| val.map_or(true, |val| inner(cx, val, ty)), - ) -} - -fn is_value_unfrozen_poly<'tcx>(cx: &LateContext<'tcx>, body_id: BodyId, ty: Ty<'tcx>) -> bool { - let def_id = body_id.hir_id.owner.to_def_id(); - let args = ty::GenericArgs::identity_for_item(cx.tcx, def_id); - let instance = ty::Instance::new(def_id, args); - let cid = rustc_middle::mir::interpret::GlobalId { - 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, None); - is_value_unfrozen_raw(cx, result, ty) -} - -fn is_value_unfrozen_expr<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId, def_id: DefId, ty: Ty<'tcx>) -> bool { - let args = cx.typeck_results().node_args(hir_id); - - let result = const_eval_resolve(cx.tcx, cx.param_env, ty::UnevaluatedConst::new(def_id, args), None); - is_value_unfrozen_raw(cx, result, ty) -} - -pub fn const_eval_resolve<'tcx>( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ct: ty::UnevaluatedConst<'tcx>, - span: Option<Span>, -) -> EvalToValTreeResult<'tcx> { - match ty::Instance::resolve(tcx, param_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) - }, - Ok(None) => Err(ErrorHandled::TooGeneric(span.unwrap_or(rustc_span::DUMMY_SP))), - Err(err) => Err(ErrorHandled::Reported(err.into(), span.unwrap_or(rustc_span::DUMMY_SP))), - } -} - #[derive(Copy, Clone)] enum Source { Item { item: Span }, @@ -292,13 +172,178 @@ fn lint(cx: &LateContext<'_>, source: Source) { }); } -declare_lint_pass!(NonCopyConst => [DECLARE_INTERIOR_MUTABLE_CONST, BORROW_INTERIOR_MUTABLE_CONST]); +#[derive(Clone)] +pub struct NonCopyConst { + ignore_interior_mutability: Vec<String>, + ignore_mut_def_ids: FxHashSet<DefId>, +} + +impl_lint_pass!(NonCopyConst => [DECLARE_INTERIOR_MUTABLE_CONST, BORROW_INTERIOR_MUTABLE_CONST]); + +impl NonCopyConst { + pub fn new(ignore_interior_mutability: Vec<String>) -> Self { + Self { + ignore_interior_mutability, + ignore_mut_def_ids: FxHashSet::default(), + } + } + + fn is_ty_ignored(&self, ty: Ty<'_>) -> bool { + matches!(ty.ty_adt_id(), Some(adt_id) if self.ignore_mut_def_ids.contains(&adt_id)) + } + + fn is_unfrozen<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { + // Ignore types whose layout is unknown since `is_freeze` reports every generic types as `!Freeze`, + // making it indistinguishable from `UnsafeCell`. i.e. it isn't a tool to prove a type is + // 'unfrozen'. However, this code causes a false negative in which + // a type contains a layout-unknown type, but also an unsafe cell like `const CELL: Cell<T>`. + // Yet, it's better than `ty.has_type_flags(TypeFlags::HAS_TY_PARAM | TypeFlags::HAS_PROJECTION)` + // since it works when a pointer indirection involves (`Cell<*const T>`). + // Making up a `ParamEnv` where every generic params and assoc types are `Freeze`is another option; + // but I'm not sure whether it's a decent way, if possible. + cx.tcx.layout_of(cx.param_env.and(ty)).is_ok() && !ty.is_freeze(cx.tcx, cx.param_env) + } + + fn is_value_unfrozen_raw_inner<'tcx>(&self, cx: &LateContext<'tcx>, val: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> bool { + if self.is_ty_ignored(ty) { + return false; + } + match *ty.kind() { + // the fact that we have to dig into every structs to search enums + // leads us to the point checking `UnsafeCell` directly is the only option. + ty::Adt(ty_def, ..) if ty_def.is_unsafe_cell() => true, + // As of 2022-09-08 miri doesn't track which union field is active so there's no safe way to check the + // contained value. + ty::Adt(def, ..) if def.is_union() => false, + ty::Array(ty, _) => val + .unwrap_branch() + .iter() + .any(|field| self.is_value_unfrozen_raw_inner(cx, *field, ty)), + ty::Adt(def, _) if def.is_union() => false, + ty::Adt(def, args) if def.is_enum() => { + let (&variant_index, fields) = val.unwrap_branch().split_first().unwrap(); + let variant_index = VariantIdx::from_u32(variant_index.unwrap_leaf().try_to_u32().ok().unwrap()); + fields + .iter() + .copied() + .zip( + def.variants()[variant_index] + .fields + .iter() + .map(|field| field.ty(cx.tcx, args)), + ) + .any(|(field, ty)| self.is_value_unfrozen_raw_inner(cx, field, ty)) + }, + ty::Adt(def, args) => val + .unwrap_branch() + .iter() + .zip(def.non_enum_variant().fields.iter().map(|field| field.ty(cx.tcx, args))) + .any(|(field, ty)| self.is_value_unfrozen_raw_inner(cx, *field, ty)), + ty::Tuple(tys) => val + .unwrap_branch() + .iter() + .zip(tys) + .any(|(field, ty)| self.is_value_unfrozen_raw_inner(cx, *field, ty)), + _ => false, + } + } + + fn is_value_unfrozen_raw<'tcx>( + &self, + cx: &LateContext<'tcx>, + result: Result<Option<ty::ValTree<'tcx>>, ErrorHandled>, + ty: Ty<'tcx>, + ) -> bool { + result.map_or_else( + |err| { + // Consider `TooGeneric` cases as being unfrozen. + // This causes a false positive where an assoc const whose type is unfrozen + // have a value that is a frozen variant with a generic param (an example is + // `declare_interior_mutable_const::enums::BothOfCellAndGeneric::GENERIC_VARIANT`). + // However, it prevents a number of false negatives that is, I think, important: + // 1. assoc consts in trait defs referring to consts of themselves (an example is + // `declare_interior_mutable_const::traits::ConcreteTypes::ANOTHER_ATOMIC`). + // 2. a path expr referring to assoc consts whose type is doesn't have any frozen variants in trait + // defs (i.e. without substitute for `Self`). (e.g. borrowing + // `borrow_interior_mutable_const::trait::ConcreteTypes::ATOMIC`) + // 3. similar to the false positive above; but the value is an unfrozen variant, or the type has no + // enums. (An example is + // `declare_interior_mutable_const::enums::BothOfCellAndGeneric::UNFROZEN_VARIANT` and + // `declare_interior_mutable_const::enums::BothOfCellAndGeneric::NO_ENUM`). + // One might be able to prevent these FNs correctly, and replace this with `false`; + // e.g. implementing `has_frozen_variant` described above, and not running this function + // when the type doesn't have any frozen variants would be the 'correct' way for the 2nd + // case (that actually removes another suboptimal behavior (I won't say 'false positive') where, + // similar to 2., but with the a frozen variant) (e.g. borrowing + // `borrow_interior_mutable_const::enums::AssocConsts::TO_BE_FROZEN_VARIANT`). + // I chose this way because unfrozen enums as assoc consts are rare (or, hopefully, none). + matches!(err, ErrorHandled::TooGeneric(..)) + }, + |val| val.map_or(true, |val| self.is_value_unfrozen_raw_inner(cx, val, ty)), + ) + } + + fn is_value_unfrozen_poly<'tcx>(&self, cx: &LateContext<'tcx>, body_id: BodyId, ty: Ty<'tcx>) -> bool { + let def_id = body_id.hir_id.owner.to_def_id(); + let args = ty::GenericArgs::identity_for_item(cx.tcx, def_id); + let instance = ty::Instance::new(def_id, args); + let cid = rustc_middle::mir::interpret::GlobalId { + 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, None); + self.is_value_unfrozen_raw(cx, result, ty) + } + + fn is_value_unfrozen_expr<'tcx>(&self, 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), None); + self.is_value_unfrozen_raw(cx, result, ty) + } + + pub fn const_eval_resolve<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ct: ty::UnevaluatedConst<'tcx>, + span: Option<Span>, + ) -> EvalToValTreeResult<'tcx> { + match ty::Instance::resolve(tcx, param_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) + }, + Ok(None) => Err(ErrorHandled::TooGeneric(span.unwrap_or(rustc_span::DUMMY_SP))), + Err(err) => Err(ErrorHandled::Reported(err.into(), span.unwrap_or(rustc_span::DUMMY_SP))), + } + } +} impl<'tcx> LateLintPass<'tcx> for NonCopyConst { + fn check_crate(&mut self, cx: &LateContext<'tcx>) { + self.ignore_mut_def_ids.clear(); + let mut path = Vec::new(); + for ty in &self.ignore_interior_mutability { + path.extend(ty.split("::")); + for id in def_path_def_ids(cx, &path[..]) { + self.ignore_mut_def_ids.insert(id); + } + path.clear(); + } + } + fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx Item<'_>) { if let ItemKind::Const(.., body_id) = it.kind { let ty = cx.tcx.type_of(it.owner_id).instantiate_identity(); - if !ignored_macro(cx, it) && is_unfrozen(cx, ty) && is_value_unfrozen_poly(cx, body_id, ty) { + if !ignored_macro(cx, it) + && !self.is_ty_ignored(ty) + && Self::is_unfrozen(cx, ty) + && self.is_value_unfrozen_poly(cx, body_id, ty) + { lint(cx, Source::Item { item: it.span }); } } @@ -311,7 +356,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { // 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); - if is_unfrozen(cx, normalized) + if !self.is_ty_ignored(ty) && Self::is_unfrozen(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. // This feels inconsistent with how the lint treats generic types, @@ -324,7 +369,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { // 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| is_value_unfrozen_poly(cx, body_id, normalized)) + && body_id_opt.map_or(true, |body_id| self.is_value_unfrozen_poly(cx, body_id, normalized)) { lint(cx, Source::Assoc { item: trait_item.span }); } @@ -367,8 +412,8 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { // 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); - if is_unfrozen(cx, normalized); - if is_value_unfrozen_poly(cx, *body_id, normalized); + if !self.is_ty_ignored(ty) && Self::is_unfrozen(cx, normalized); + if self.is_value_unfrozen_poly(cx, *body_id, normalized); then { lint( cx, @@ -384,7 +429,10 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { // Normalize assoc types originated from generic params. let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty); - if is_unfrozen(cx, ty) && is_value_unfrozen_poly(cx, *body_id, normalized) { + if !self.is_ty_ignored(ty) + && Self::is_unfrozen(cx, ty) + && self.is_value_unfrozen_poly(cx, *body_id, normalized) + { lint(cx, Source::Assoc { item: impl_item.span }); } }, @@ -478,7 +526,10 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { cx.typeck_results().expr_ty(dereferenced_expr) }; - if is_unfrozen(cx, ty) && is_value_unfrozen_expr(cx, expr.hir_id, item_def_id, ty) { + if !self.is_ty_ignored(ty) + && Self::is_unfrozen(cx, ty) + && self.is_value_unfrozen_expr(cx, expr.hir_id, item_def_id, ty) + { lint(cx, Source::Expr { expr: expr.span }); } } diff --git a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs index d562047cb..61622034d 100644 --- a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs +++ b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs @@ -6,8 +6,7 @@ use rustc_ast::visit::{walk_block, walk_expr, walk_pat, Visitor}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::source_map::Span; -use rustc_span::sym; +use rustc_span::{sym, Span}; use rustc_span::symbol::{Ident, Symbol}; use std::cmp::Ordering; @@ -63,7 +62,7 @@ declare_clippy_lint! { /// descriptive name. /// /// ### Example - /// ```rust + /// ```no_run /// let _1 = 1; /// let ___1 = 1; /// let __1___2 = 11; diff --git a/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs b/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs index e1de494eb..e94e45899 100644 --- a/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs +++ b/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs @@ -1,6 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{snippet_opt, snippet_with_applicability}; -use clippy_utils::ty::{is_type_diagnostic_item, match_type}; use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_errors::Applicability; @@ -45,15 +44,14 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { match &expr.kind { ExprKind::MethodCall(path, func, [param], _) => { - let obj_ty = cx.typeck_results().expr_ty(func).peel_refs(); - if_chain! { + if let Some(adt) = cx.typeck_results().expr_ty(func).peel_refs().ty_adt_def(); if (path.ident.name == sym!(mode) - && (match_type(cx, obj_ty, &paths::OPEN_OPTIONS) - || is_type_diagnostic_item(cx, obj_ty, sym::DirBuilder))) - || (path.ident.name == sym!(set_mode) && match_type(cx, obj_ty, &paths::PERMISSIONS)); + && matches!(cx.tcx.get_diagnostic_name(adt.did()), Some(sym::FsOpenOptions | sym::DirBuilder))) + || (path.ident.name == sym!(set_mode) + && cx.tcx.is_diagnostic_item(sym::FsPermissions, adt.did())); if let ExprKind::Lit(_) = param.kind; - if param.span.ctxt() == expr.span.ctxt(); + if param.span.eq_ctxt(expr.span); then { let Some(snip) = snippet_opt(cx, param.span) else { @@ -72,7 +70,7 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions { if let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id(); if match_def_path(cx, def_id, &paths::PERMISSIONS_FROM_MODE); if let ExprKind::Lit(_) = param.kind; - if param.span.ctxt() == expr.span.ctxt(); + if param.span.eq_ctxt(expr.span); if let Some(snip) = snippet_opt(cx, param.span); if !snip.starts_with("0o"); then { diff --git a/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs b/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs index c5e777c20..62ef48c8a 100644 --- a/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs +++ b/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::is_lint_allowed; use clippy_utils::source::snippet; use clippy_utils::ty::{implements_trait, is_copy}; -use clippy_utils::{is_lint_allowed, match_def_path, paths}; use rustc_ast::ImplPolarity; use rustc_hir::def_id::DefId; use rustc_hir::{FieldDef, Item, ItemKind, Node}; @@ -233,7 +233,7 @@ fn contains_pointer_like<'tcx>(cx: &LateContext<'tcx>, target_ty: Ty<'tcx>) -> b return true; }, ty::Adt(adt_def, _) => { - if match_def_path(cx, adt_def.did(), &paths::PTR_NON_NULL) { + if cx.tcx.is_diagnostic_item(sym::NonNull, adt_def.did()) { return true; } }, diff --git a/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs b/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs index bd194b935..11c3a5417 100644 --- a/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs +++ b/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs @@ -1,6 +1,4 @@ -use std::fmt; -use std::hash::{Hash, Hasher}; - +use clippy_config::types::MacroMatcher; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; use if_chain::if_chain; @@ -12,7 +10,6 @@ use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::Span; -use serde::{de, Deserialize}; declare_clippy_lint! { /// ### What it does @@ -23,11 +20,11 @@ declare_clippy_lint! { /// doesn't give you a semicolon in item position, which can be unexpected. /// /// ### Example - /// ```rust + /// ```no_run /// vec!{1, 2, 3}; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// vec![1, 2, 3]; /// ``` #[clippy::version = "1.55.0"] @@ -36,8 +33,6 @@ declare_clippy_lint! { "check consistent use of braces in macro" } -const BRACES: &[(&str, &str)] = &[("(", ")"), ("{", "}"), ("[", "]")]; - /// The (callsite span, (open brace, close brace), source snippet) type MacroInfo<'a> = (Span, &'a (String, String), String); @@ -195,81 +190,3 @@ macro_rules! macro_matcher { }; } pub(crate) use macro_matcher; - -#[derive(Clone, Debug)] -pub struct MacroMatcher { - name: String, - braces: (String, String), -} - -impl Hash for MacroMatcher { - fn hash<H: Hasher>(&self, state: &mut H) { - self.name.hash(state); - } -} - -impl PartialEq for MacroMatcher { - fn eq(&self, other: &Self) -> bool { - self.name == other.name - } -} -impl Eq for MacroMatcher {} - -impl<'de> Deserialize<'de> for MacroMatcher { - fn deserialize<D>(deser: D) -> Result<Self, D::Error> - where - D: de::Deserializer<'de>, - { - #[derive(Deserialize)] - #[serde(field_identifier, rename_all = "lowercase")] - enum Field { - Name, - Brace, - } - struct MacVisitor; - impl<'de> de::Visitor<'de> for MacVisitor { - type Value = MacroMatcher; - - fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - formatter.write_str("struct MacroMatcher") - } - - fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error> - where - V: de::MapAccess<'de>, - { - let mut name = None; - let mut brace: Option<String> = None; - while let Some(key) = map.next_key()? { - match key { - Field::Name => { - if name.is_some() { - return Err(de::Error::duplicate_field("name")); - } - name = Some(map.next_value()?); - }, - Field::Brace => { - if brace.is_some() { - return Err(de::Error::duplicate_field("brace")); - } - brace = Some(map.next_value()?); - }, - } - } - let name = name.ok_or_else(|| de::Error::missing_field("name"))?; - let brace = brace.ok_or_else(|| de::Error::missing_field("brace"))?; - Ok(MacroMatcher { - name, - braces: BRACES - .iter() - .find(|b| b.0 == brace) - .map(|(o, c)| ((*o).to_owned(), (*c).to_owned())) - .ok_or_else(|| de::Error::custom(format!("expected one of `(`, `{{`, `[` found `{brace}`")))?, - }) - } - } - - const FIELDS: &[&str] = &["name", "brace"]; - deser.deserialize_struct("MacroMatcher", FIELDS, MacVisitor) - } -} diff --git a/src/tools/clippy/clippy_lints/src/octal_escapes.rs b/src/tools/clippy/clippy_lints/src/octal_escapes.rs index 6d3865080..0faf4ce3d 100644 --- a/src/tools/clippy/clippy_lints/src/octal_escapes.rs +++ b/src/tools/clippy/clippy_lints/src/octal_escapes.rs @@ -32,13 +32,13 @@ declare_clippy_lint! { /// can see it. /// /// ### Example - /// ```rust + /// ```no_run /// let one = "\033[1m Bold? \033[0m"; // \033 intended as escape /// let two = "\033\0"; // \033 intended as null-3-3 /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let one = "\x1b[1mWill this be bold?\x1b[0m"; /// let two = "\x0033\x00"; /// ``` diff --git a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs index 3dc652f9d..ef7b36764 100644 --- a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs +++ b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs @@ -30,7 +30,7 @@ declare_clippy_lint! { /// /// In some cases, this would not catch all useless arguments. /// - /// ```rust + /// ```no_run /// fn foo(a: usize, b: usize) -> usize { /// let f = |x| x + 1; /// @@ -53,7 +53,7 @@ declare_clippy_lint! { /// Also, when you recurse the function name with path segments, it is not possible to detect. /// /// ### Example - /// ```rust + /// ```no_run /// fn f(a: usize, b: usize) -> usize { /// if a == 0 { /// 1 @@ -66,7 +66,7 @@ declare_clippy_lint! { /// # } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn f(a: usize) -> usize { /// if a == 0 { /// 1 @@ -134,6 +134,7 @@ impl Usage { /// The parameters being checked by the lint, indexed by both the parameter's `HirId` and the /// `DefId` of the function paired with the parameter's index. #[derive(Default)] +#[allow(clippy::struct_field_names)] struct Params { params: Vec<Param>, by_id: HirIdMap<usize>, @@ -243,7 +244,10 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion { })) => { #[allow(trivial_casts)] if let Some(Node::Item(item)) = get_parent_node(cx.tcx, owner_id.into()) - && let Some(trait_ref) = cx.tcx.impl_trait_ref(item.owner_id).map(EarlyBinder::instantiate_identity) + && let Some(trait_ref) = cx + .tcx + .impl_trait_ref(item.owner_id) + .map(EarlyBinder::instantiate_identity) && let Some(trait_item_id) = cx.tcx.associated_item(owner_id).trait_item_def_id { ( @@ -287,8 +291,7 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion { // Recursive call. Track which index the parameter is used in. ExprKind::Call(callee, args) if path_def_id(cx, callee).map_or(false, |id| { - id == param.fn_id - && has_matching_args(param.fn_kind, typeck.node_args(callee.hir_id)) + id == param.fn_id && has_matching_args(param.fn_kind, typeck.node_args(callee.hir_id)) }) => { if let Some(idx) = args.iter().position(|arg| arg.hir_id == child_id) { @@ -298,8 +301,7 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion { }, ExprKind::MethodCall(_, receiver, args, _) if typeck.type_dependent_def_id(parent.hir_id).map_or(false, |id| { - id == param.fn_id - && has_matching_args(param.fn_kind, typeck.node_args(parent.hir_id)) + id == param.fn_id && has_matching_args(param.fn_kind, typeck.node_args(parent.hir_id)) }) => { if let Some(idx) = iter::once(receiver).chain(args).position(|arg| arg.hir_id == child_id) { @@ -335,8 +337,8 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion { // Only allow field accesses without auto-deref ExprKind::Field(..) if typeck.adjustments().get(child_id).is_none() => { e = parent; - continue - } + continue; + }, _ => (), }, _ => (), diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs index a10aa65e5..4c6462b77 100644 --- a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs +++ b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs @@ -7,9 +7,9 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty; use rustc_session::impl_lint_pass; -use rustc_span::source_map::{Span, Spanned}; +use rustc_span::{Span, Symbol}; +use rustc_span::source_map::Spanned; use rustc_span::symbol::sym; -use rustc_span::Symbol; use {rustc_ast as ast, rustc_hir as hir}; const HARD_CODED_ALLOWED_BINARY: &[[&str; 2]] = &[["f32", "f32"], ["f64", "f64"], ["std::string::String", "str"]]; @@ -71,7 +71,7 @@ impl ArithmeticSideEffects { rhs_has_allowed_ty || rhs_from_specific.contains("*") } { - true + true } else if let Some(rhs_from_glob) = self.allowed_binary.get("*") { rhs_from_glob.contains(rhs_ty_string_elem) } else { @@ -132,7 +132,11 @@ impl ArithmeticSideEffects { } // Common entry-point to avoid code duplication. - fn issue_lint(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) { + fn issue_lint<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { + if is_from_proc_macro(cx, expr) { + return; + } + let msg = "arithmetic operation that can potentially result in unexpected side-effects"; span_lint(cx, ARITHMETIC_SIDE_EFFECTS, expr.span, msg); self.expr_span = Some(expr.span); @@ -144,8 +148,10 @@ impl ArithmeticSideEffects { /// like `i32::MAX` or constant references like `N` from `const N: i32 = 1;`, fn literal_integer(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<u128> { let actual = peel_hir_expr_unary(expr).0; - if let hir::ExprKind::Lit(lit) = actual.kind && let ast::LitKind::Int(n, _) = lit.node { - return Some(n) + if let hir::ExprKind::Lit(lit) = actual.kind + && let ast::LitKind::Int(n, _) = lit.node + { + return Some(n); } if let Some(Constant::Int(n)) = constant(cx, cx.typeck_results(), expr) { return Some(n); @@ -158,10 +164,10 @@ impl ArithmeticSideEffects { fn manage_bin_ops<'tcx>( &mut self, cx: &LateContext<'tcx>, - expr: &hir::Expr<'tcx>, + expr: &'tcx hir::Expr<'_>, op: &Spanned<hir::BinOpKind>, - lhs: &hir::Expr<'tcx>, - rhs: &hir::Expr<'tcx>, + lhs: &'tcx hir::Expr<'_>, + rhs: &'tcx hir::Expr<'_>, ) { if constant_simple(cx, cx.typeck_results(), expr).is_some() { return; @@ -234,10 +240,10 @@ impl ArithmeticSideEffects { /// provided input. fn manage_method_call<'tcx>( &mut self, - args: &[hir::Expr<'tcx>], + args: &'tcx [hir::Expr<'_>], cx: &LateContext<'tcx>, - ps: &hir::PathSegment<'tcx>, - receiver: &hir::Expr<'tcx>, + ps: &'tcx hir::PathSegment<'_>, + receiver: &'tcx hir::Expr<'_>, ) { let Some(arg) = args.first() else { return; @@ -262,8 +268,8 @@ impl ArithmeticSideEffects { fn manage_unary_ops<'tcx>( &mut self, cx: &LateContext<'tcx>, - expr: &hir::Expr<'tcx>, - un_expr: &hir::Expr<'tcx>, + expr: &'tcx hir::Expr<'_>, + un_expr: &'tcx hir::Expr<'_>, un_op: hir::UnOp, ) { let hir::UnOp::Neg = un_op else { @@ -285,14 +291,13 @@ 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) - || is_from_proc_macro(cx, expr) || self.expr_span.is_some() || self.const_span.map_or(false, |sp| sp.contains(expr.span)) } } impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'tcx>) { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { if self.should_skip_expr(cx, expr) { return; } @@ -317,7 +322,9 @@ impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects { let body_owner_kind = cx.tcx.hir().body_owner_kind(body_owner_def_id); if let hir::BodyOwnerKind::Const { .. } | hir::BodyOwnerKind::Static(_) = body_owner_kind { let body_span = cx.tcx.hir().span_with_body(body_owner); - if let Some(span) = self.const_span && span.contains(body_span) { + if let Some(span) = self.const_span + && span.contains(body_span) + { return; } self.const_span = Some(body_span); @@ -327,7 +334,9 @@ impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects { fn check_body_post(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) { let body_owner = cx.tcx.hir().body_owner(body.id()); let body_span = cx.tcx.hir().span(body_owner); - if let Some(span) = self.const_span && span.contains(body_span) { + if let Some(span) = self.const_span + && span.contains(body_span) + { return; } self.const_span = None; diff --git a/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs b/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs index c146f3ae9..2e026c369 100644 --- a/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs +++ b/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs @@ -2,7 +2,7 @@ use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; -use rustc_span::source_map::Span; +use rustc_span::Span; use super::{BAD_BIT_MASK, INEFFECTIVE_BIT_MASK}; diff --git a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs index d3de9699f..ea8ed28ba 100644 --- a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs +++ b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::path_def_id; use clippy_utils::source::snippet; use clippy_utils::ty::{implements_trait, is_copy}; -use clippy_utils::{match_def_path, path_def_id, paths}; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::LateContext; @@ -50,7 +50,7 @@ fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) }, ExprKind::Call(path, [arg]) if path_def_id(cx, path).map_or(false, |did| { - if match_def_path(cx, did, &paths::FROM_STR_METHOD) { + if cx.tcx.is_diagnostic_item(sym::from_str_method, did) { true } else if cx.tcx.is_diagnostic_item(sym::from_fn, did) { !is_copy(cx, typeck.expr_ty(expr)) diff --git a/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs b/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs index abe8df195..ec2bb8699 100644 --- a/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs +++ b/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs @@ -8,7 +8,8 @@ use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::layout::HasTyCtxt; use rustc_middle::ty::{Ty, TypeckResults}; -use rustc_span::source_map::{Span, Spanned}; +use rustc_span::Span; +use rustc_span::source_map::Spanned; use clippy_utils::diagnostics::span_lint_and_note; use clippy_utils::source::snippet; diff --git a/src/tools/clippy/clippy_lints/src/operators/double_comparison.rs b/src/tools/clippy/clippy_lints/src/operators/double_comparison.rs index 56a86d0ff..d48e8286f 100644 --- a/src/tools/clippy/clippy_lints/src/operators/double_comparison.rs +++ b/src/tools/clippy/clippy_lints/src/operators/double_comparison.rs @@ -4,7 +4,7 @@ use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; -use rustc_span::source_map::Span; +use rustc_span::Span; use super::DOUBLE_COMPARISONS; diff --git a/src/tools/clippy/clippy_lints/src/operators/eq_op.rs b/src/tools/clippy/clippy_lints/src/operators/eq_op.rs index 88d566318..fd3502ad8 100644 --- a/src/tools/clippy/clippy_lints/src/operators/eq_op.rs +++ b/src/tools/clippy/clippy_lints/src/operators/eq_op.rs @@ -8,13 +8,14 @@ use rustc_lint::LateContext; use super::EQ_OP; pub(crate) fn check_assert<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { - if let Some((macro_call, macro_name)) - = first_node_macro_backtrace(cx, e).find_map(|macro_call| { - let name = cx.tcx.item_name(macro_call.def_id); - matches!(name.as_str(), "assert_eq" | "assert_ne" | "debug_assert_eq" | "debug_assert_ne") - .then(|| (macro_call, name)) - }) - && let Some((lhs, rhs, _)) = find_assert_eq_args(cx, e, macro_call.expn) + if let Some((macro_call, macro_name)) = first_node_macro_backtrace(cx, e).find_map(|macro_call| { + let name = cx.tcx.item_name(macro_call.def_id); + matches!( + name.as_str(), + "assert_eq" | "assert_ne" | "debug_assert_eq" | "debug_assert_ne" + ) + .then(|| (macro_call, name)) + }) && let Some((lhs, rhs, _)) = find_assert_eq_args(cx, e, macro_call.expn) && eq_expr_value(cx, lhs, rhs) && macro_call.is_local() && !is_in_test_function(cx.tcx, e.hir_id) @@ -42,7 +43,9 @@ pub(crate) fn check<'tcx>( e.span, &format!("equal expressions as operands to `{}`", op.as_str()), |diag| { - if let BinOpKind::Ne = op && cx.typeck_results().expr_ty(left).is_floating_point() { + if let BinOpKind::Ne = op + && cx.typeck_results().expr_ty(left).is_floating_point() + { diag.note("if you intended to check if the operand is NaN, use `.is_nan()` instead"); } }, diff --git a/src/tools/clippy/clippy_lints/src/operators/identity_op.rs b/src/tools/clippy/clippy_lints/src/operators/identity_op.rs index 14a12da86..8ecb03862 100644 --- a/src/tools/clippy/clippy_lints/src/operators/identity_op.rs +++ b/src/tools/clippy/clippy_lints/src/operators/identity_op.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, Node}; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::source_map::Span; +use rustc_span::Span; use super::IDENTITY_OP; diff --git a/src/tools/clippy/clippy_lints/src/operators/mod.rs b/src/tools/clippy/clippy_lints/src/operators/mod.rs index 4635e1164..ee79ea276 100644 --- a/src/tools/clippy/clippy_lints/src/operators/mod.rs +++ b/src/tools/clippy/clippy_lints/src/operators/mod.rs @@ -48,7 +48,7 @@ declare_clippy_lint! { /// like `#[cfg(target_pointer_width = "64")] ..` instead. /// /// ### Example - /// ```rust + /// ```no_run /// let vec: Vec<isize> = Vec::new(); /// if vec.len() <= 0 {} /// if 100 > i32::MAX {} @@ -76,7 +76,7 @@ declare_clippy_lint! { /// desirable to explicitly call checked, wrapping or saturating arithmetic methods. /// /// #### Example - /// ```rust + /// ```no_run /// // `n` can be any number, including `i32::MAX`. /// fn foo(n: i32) -> i32 { /// n + 1 @@ -105,7 +105,7 @@ declare_clippy_lint! { /// can be useful to rule out floating-point numbers. /// /// ### Example - /// ```rust + /// ```no_run /// # let a = 0.0; /// a + 1.0; /// ``` @@ -128,7 +128,7 @@ declare_clippy_lint! { /// implementations that differ from the regular `Op` impl. /// /// ### Example - /// ```rust + /// ```no_run /// let mut a = 5; /// let b = 0; /// // ... @@ -137,7 +137,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let mut a = 5; /// let b = 0; /// // ... @@ -165,7 +165,7 @@ declare_clippy_lint! { /// written as `a = a op a op b` as it's less confusing. /// /// ### Example - /// ```rust + /// ```no_run /// let mut a = 5; /// let b = 2; /// // ... @@ -205,7 +205,7 @@ declare_clippy_lint! { /// test-case for this lint. /// /// ### Example - /// ```rust + /// ```no_run /// # let x = 1; /// if (x & 1 == 2) { } /// ``` @@ -238,7 +238,7 @@ declare_clippy_lint! { /// uncommon). /// /// ### Example - /// ```rust + /// ```no_run /// # let x = 1; /// if (x | 1 > 3) { } /// ``` @@ -261,7 +261,7 @@ declare_clippy_lint! { /// llvm generates better code for `x & 15 == 0` on x86 /// /// ### Example - /// ```rust + /// ```no_run /// # let x = 1; /// if x & 0b1111 == 0 { } /// ``` @@ -280,7 +280,7 @@ declare_clippy_lint! { /// Readability. /// /// ### Example - /// ```rust + /// ```no_run /// # let x = 1; /// # let y = 2; /// if x == y || x < y {} @@ -288,7 +288,7 @@ declare_clippy_lint! { /// /// Use instead: /// - /// ```rust + /// ```no_run /// # let x = 1; /// # let y = 2; /// if x <= y {} @@ -308,11 +308,11 @@ declare_clippy_lint! { /// which is probably not the programmer's intention /// /// ### Example - /// ```rust + /// ```no_run /// # let status_code = 200; /// if status_code <= 400 && status_code > 500 {} /// ``` - #[clippy::version = "1.71.0"] + #[clippy::version = "1.73.0"] pub IMPOSSIBLE_COMPARISONS, correctness, "double comparisons that will never evaluate to `true`" @@ -328,11 +328,11 @@ declare_clippy_lint! { /// different value entirely. /// /// ### Example - /// ```rust + /// ```no_run /// # let status_code = 200; /// if status_code <= 400 && status_code < 500 {} /// ``` - #[clippy::version = "1.71.0"] + #[clippy::version = "1.73.0"] pub REDUNDANT_COMPARISONS, correctness, "double comparisons where one of them can be removed" @@ -348,7 +348,7 @@ declare_clippy_lint! { /// `Duration::subsec_millis()` than to calculate them. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::time::Duration; /// # let duration = Duration::new(5, 0); /// let micros = duration.subsec_nanos() / 1_000; @@ -356,7 +356,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # use std::time::Duration; /// # let duration = Duration::new(5, 0); /// let micros = duration.subsec_micros(); @@ -384,7 +384,7 @@ declare_clippy_lint! { /// calls. We may introduce a list of known pure functions in the future. /// /// ### Example - /// ```rust + /// ```no_run /// # let x = 1; /// if x + 1 == x + 1 {} /// @@ -434,7 +434,7 @@ declare_clippy_lint! { /// corrected /// /// ### Example - /// ```rust + /// ```no_run /// let x = 1; /// 0 / x; /// 0 * x; @@ -462,13 +462,13 @@ declare_clippy_lint! { /// with an allow. /// /// ### Example - /// ```rust + /// ```no_run /// pub fn is_roughly_equal(a: f32, b: f32) -> bool { /// (a - b) < f32::EPSILON /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// pub fn is_roughly_equal(a: f32, b: f32) -> bool { /// (a - b).abs() < f32::EPSILON /// } @@ -488,7 +488,7 @@ declare_clippy_lint! { /// meaning. So it just obscures what's going on. Delete it mercilessly. /// /// ### Example - /// ```rust + /// ```no_run /// # let x = 1; /// x / 1 + 0 * 1 - 0 | 0; /// ``` @@ -508,13 +508,13 @@ declare_clippy_lint! { /// remainder. /// /// ### Example - /// ```rust + /// ```no_run /// let x = 3 / 2; /// println!("{}", x); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let x = 3f32 / 2f32; /// println!("{}", x); /// ``` @@ -535,14 +535,14 @@ declare_clippy_lint! { /// needlessly consuming code and heap space. /// /// ### Example - /// ```rust + /// ```no_run /// # let x = "foo"; /// # let y = String::from("foo"); /// if x.to_owned() == y {} /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let x = "foo"; /// # let y = String::from("foo"); /// if x == y {} @@ -566,7 +566,7 @@ declare_clippy_lint! { /// guide](http://www.floating-point-gui.de/errors/comparison). /// /// ### Example - /// ```rust + /// ```no_run /// let x = 1.2331f64; /// let y = 1.2332f64; /// @@ -575,7 +575,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let x = 1.2331f64; /// # let y = 1.2332f64; /// let error_margin = f64::EPSILON; // Use an epsilon for comparison @@ -603,7 +603,7 @@ declare_clippy_lint! { /// guide](http://www.floating-point-gui.de/errors/comparison). /// /// ### Example - /// ```rust + /// ```no_run /// let x: f64 = 1.0; /// const ONE: f64 = 1.00; /// @@ -611,7 +611,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let x: f64 = 1.0; /// # const ONE: f64 = 1.00; /// let error_margin = f64::EPSILON; // Use an epsilon for comparison @@ -638,7 +638,7 @@ declare_clippy_lint! { /// contest, it's probably a bad idea. Use something more underhanded. /// /// ### Example - /// ```rust + /// ```no_run /// # let x = 1; /// let a = x % 1; /// let a = x % -1; @@ -662,7 +662,7 @@ declare_clippy_lint! { /// For example, in Rust `17 % -3 = 2`, but in Python `17 % -3 = -1`. /// /// ### Example - /// ```rust + /// ```no_run /// let x = -17 % 3; /// ``` #[clippy::version = "1.42.0"] @@ -685,12 +685,12 @@ declare_clippy_lint! { /// determination is quite conservative. /// /// ### Example - /// ```rust + /// ```no_run /// let (x,y) = (true, false); /// if x & !y {} // where both x and y are booleans /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let (x,y) = (true, false); /// if x && !y {} /// ``` @@ -710,14 +710,14 @@ declare_clippy_lint! { /// comparing the values they point to. /// /// ### Example - /// ```rust + /// ```no_run /// let a = &[1, 2, 3]; /// let b = &[1, 2, 3]; /// /// assert!(a as *const _ as usize == b as *const _ as usize); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let a = &[1, 2, 3]; /// let b = &[1, 2, 3]; /// @@ -742,7 +742,7 @@ declare_clippy_lint! { /// indexing operations they are assumed not to have any side effects. /// /// ### Example - /// ```rust + /// ```no_run /// struct Event { /// x: i32, /// } @@ -753,7 +753,7 @@ declare_clippy_lint! { /// ``` /// /// Should be: - /// ```rust + /// ```no_run /// struct Event { /// x: i32, /// } diff --git a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs index 80389cbf8..ea933168c 100644 --- a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs @@ -3,7 +3,7 @@ use clippy_utils::consts::constant_simple; use clippy_utils::diagnostics::span_lint; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::source_map::Span; +use rustc_span::Span; #[derive(Default)] pub struct Context { diff --git a/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs b/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs index 9c7f7e1cd..7792efe6a 100644 --- a/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs +++ b/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs @@ -46,16 +46,19 @@ impl EarlyLintPass for OptionEnvUnwrap { ); } - if let ExprKind::MethodCall(box MethodCall { seg, receiver, .. }) = &expr.kind && - matches!(seg.ident.name, sym::expect | sym::unwrap) { - if let ExprKind::Call(caller, _) = &receiver.kind && + if let ExprKind::MethodCall(box MethodCall { seg, receiver, .. }) = &expr.kind + && matches!(seg.ident.name, sym::expect | sym::unwrap) + { + if let ExprKind::Call(caller, _) = &receiver.kind && // If it exists, it will be ::core::option::Option::Some("<env var>").unwrap() (A method call in the HIR) - is_direct_expn_of(caller.span, "option_env").is_some() { - lint(cx, expr.span); - } else if let ExprKind::Path(_, caller) = &receiver.kind && // If it doesn't exist, it will be ::core::option::Option::None::<&'static str>.unwrap() (A path in the HIR) - is_direct_expn_of(caller.span, "option_env").is_some() { - lint(cx, expr.span); - } - } + is_direct_expn_of(caller.span, "option_env").is_some() + { + lint(cx, expr.span); + } else if let ExprKind::Path(_, caller) = &receiver.kind && // If it doesn't exist, it will be ::core::option::Option::None::<&'static str>.unwrap() (A path in the HIR) + is_direct_expn_of(caller.span, "option_env").is_some() + { + lint(cx, expr.span); + } + } } } diff --git a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs index a7a7f4fd8..d7cbbe13a 100644 --- a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs +++ b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs @@ -32,7 +32,7 @@ declare_clippy_lint! { /// this lint will not be raised. /// /// ### Example - /// ```rust + /// ```no_run /// # let optional: Option<u32> = Some(0); /// # fn do_complicated_function() -> u32 { 5 }; /// let _ = if let Some(foo) = optional { @@ -54,7 +54,7 @@ declare_clippy_lint! { /// /// should be /// - /// ```rust + /// ```no_run /// # let optional: Option<u32> = Some(0); /// # fn do_complicated_function() -> u32 { 5 }; /// let _ = optional.map_or(5, |foo| foo); @@ -165,6 +165,12 @@ fn try_get_option_occurrence<'tcx>( } let mut app = Applicability::Unspecified; + + let (none_body, is_argless_call) = match none_body.kind { + ExprKind::Call(call_expr, []) if !none_body.span.from_expansion() => (call_expr, true), + _ => (none_body, false), + }; + return Some(OptionOccurrence { option: format_option_in_sugg( Sugg::hir_with_context(cx, cond_expr, ctxt, "..", &mut app), @@ -178,7 +184,7 @@ fn try_get_option_occurrence<'tcx>( ), none_expr: format!( "{}{}", - if method_sugg == "map_or" { "" } else if is_result { "|_| " } else { "|| "}, + if method_sugg == "map_or" || is_argless_call { "" } else if is_result { "|_| " } else { "|| "}, Sugg::hir_with_context(cx, none_body, ctxt, "..", &mut app), ), }); @@ -234,7 +240,7 @@ fn try_convert_match<'tcx>( if let [first_arm, second_arm] = arms && first_arm.guard.is_none() && second_arm.guard.is_none() - { + { return if is_none_or_err_arm(cx, second_arm) { Some((first_arm.pat, first_arm.body, second_arm.body)) } else if is_none_or_err_arm(cx, first_arm) { diff --git a/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs b/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs index 6dabbd480..38cd5043a 100644 --- a/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs +++ b/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs @@ -14,7 +14,7 @@ declare_clippy_lint! { /// Rust. Users can use functions like `overflowing_*` and `wrapping_*` instead. /// /// ### Example - /// ```rust + /// ```no_run /// # let a = 1; /// # let b = 2; /// a + b < a; diff --git a/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs b/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs index a049427d8..6a760f9fe 100644 --- a/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs +++ b/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs @@ -22,14 +22,14 @@ declare_clippy_lint! { /// Functions called from a function returning a `Result` may invoke a panicking macro. This is not checked. /// /// ### Example - /// ```rust + /// ```no_run /// fn result_with_panic() -> Result<bool, String> /// { /// panic!("error"); /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn result_without_panic() -> Result<bool, String> { /// Err(String::from("error")) /// } diff --git a/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs b/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs index a72aefe91..f4f1f6ddb 100644 --- a/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs +++ b/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs @@ -9,7 +9,7 @@ declare_clippy_lint! { /// Checks for usage of `panic!`. /// /// ### Why is this bad? - /// `panic!` will stop the execution of the executable + /// `panic!` will stop the execution of the executable. /// /// ### Example /// ```no_run @@ -26,7 +26,7 @@ declare_clippy_lint! { /// Checks for usage of `unimplemented!`. /// /// ### Why is this bad? - /// This macro should not be present in production code + /// This macro should not be present in production code. /// /// ### Example /// ```no_run @@ -43,12 +43,17 @@ declare_clippy_lint! { /// Checks for usage of `todo!`. /// /// ### Why is this bad? - /// This macro should not be present in production code + /// The `todo!` macro is often used for unfinished code, and it causes + /// code to panic. It should not be present in production code. /// /// ### Example /// ```no_run /// todo!(); /// ``` + /// Finish the implementation, or consider marking it as explicitly unimplemented. + /// ```no_run + /// unimplemented!(); + /// ``` #[clippy::version = "1.40.0"] pub TODO, restriction, @@ -60,7 +65,7 @@ declare_clippy_lint! { /// Checks for usage of `unreachable!`. /// /// ### Why is this bad? - /// This macro can cause code to panic + /// This macro can cause code to panic. /// /// ### Example /// ```no_run diff --git a/src/tools/clippy/clippy_lints/src/partial_pub_fields.rs b/src/tools/clippy/clippy_lints/src/partial_pub_fields.rs index f60d9d65b..99ba55b6b 100644 --- a/src/tools/clippy/clippy_lints/src/partial_pub_fields.rs +++ b/src/tools/clippy/clippy_lints/src/partial_pub_fields.rs @@ -16,7 +16,7 @@ declare_clippy_lint! { /// * Data: relatively simple objects which group a bunch of related attributes together. /// /// ### Example - /// ```rust + /// ```no_run /// pub struct Color { /// pub r: u8, /// pub g: u8, @@ -24,7 +24,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// pub struct Color { /// pub r: u8, /// pub g: u8, diff --git a/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs b/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs index a8c4823fe..68d3d00ac 100644 --- a/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs +++ b/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs @@ -16,7 +16,7 @@ declare_clippy_lint! { /// re-implement it. /// /// ### Example - /// ```rust + /// ```no_run /// struct Foo; /// /// impl PartialEq for Foo { diff --git a/src/tools/clippy/clippy_lints/src/partialeq_to_none.rs b/src/tools/clippy/clippy_lints/src/partialeq_to_none.rs index d9f5d1642..11e9a2bc3 100644 --- a/src/tools/clippy/clippy_lints/src/partialeq_to_none.rs +++ b/src/tools/clippy/clippy_lints/src/partialeq_to_none.rs @@ -21,13 +21,13 @@ declare_clippy_lint! { /// way relies on `T: PartialEq` to do the comparison, which is unneeded. /// /// ### Example - /// ```rust + /// ```no_run /// fn foo(f: Option<u32>) -> &'static str { /// if f != None { "yay" } else { "nay" } /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn foo(f: Option<u32>) -> &'static str { /// if f.is_some() { "yay" } else { "nay" } /// } diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs index 41513647f..4d7a055da 100644 --- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs +++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs @@ -58,12 +58,12 @@ declare_clippy_lint! { /// /// ### Example /// - /// ```rust + /// ```no_run /// fn foo(v: &u32) {} /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// fn foo(v: u32) {} /// ``` #[clippy::version = "pre 1.29.0"] @@ -86,7 +86,7 @@ declare_clippy_lint! { /// `memcpy`, which can be expensive. /// /// ### Example - /// ```rust + /// ```no_run /// #[derive(Clone, Copy)] /// struct TooLarge([u8; 2048]); /// @@ -94,7 +94,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # #[derive(Clone, Copy)] /// # struct TooLarge([u8; 2048]); /// fn foo(v: &TooLarge) {} @@ -208,7 +208,10 @@ impl<'tcx> PassByRefOrValue { cx, TRIVIALLY_COPY_PASS_BY_REF, input.span, - &format!("this argument ({size} byte) is passed by reference, but would be more efficient if passed by value (limit: {} byte)", self.ref_min_size), + &format!( + "this argument ({size} byte) is passed by reference, but would be more efficient if passed by value (limit: {} byte)", + self.ref_min_size + ), "consider passing by value instead", value_type, Applicability::Unspecified, diff --git a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs index 9f98195d3..dcd1e7af0 100644 --- a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs +++ b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs @@ -5,7 +5,7 @@ use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::def_id::LocalDefId; -use rustc_span::source_map::Span; +use rustc_span::Span; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs b/src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs index 664d44d65..b98005d59 100644 --- a/src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs +++ b/src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs @@ -1,10 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::paths; -use clippy_utils::ty::match_type; +use clippy_utils::ty::is_type_diagnostic_item; use rustc_ast::ast::LitKind; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -14,7 +14,7 @@ declare_clippy_lint! { /// On Unix platforms this results in the file being world writable, /// equivalent to `chmod a+w <file>`. /// ### Example - /// ```rust + /// ```no_run /// use std::fs::File; /// let f = File::create("foo.txt").unwrap(); /// let metadata = f.metadata().unwrap(); @@ -31,7 +31,7 @@ declare_lint_pass!(PermissionsSetReadonlyFalse => [PERMISSIONS_SET_READONLY_FALS impl<'tcx> LateLintPass<'tcx> for PermissionsSetReadonlyFalse { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if let ExprKind::MethodCall(path, receiver, [arg], _) = &expr.kind - && match_type(cx, cx.typeck_results().expr_ty(receiver), &paths::PERMISSIONS) + && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(receiver), sym::FsPermissions) && path.ident.name == sym!(set_readonly) && let ExprKind::Lit(lit) = &arg.kind && LitKind::Bool(false) == lit.node @@ -43,9 +43,11 @@ impl<'tcx> LateLintPass<'tcx> for PermissionsSetReadonlyFalse { "call to `set_readonly` with argument `false`", |diag| { diag.note("on Unix platforms this results in the file being world writable"); - diag.help("you can set the desired permissions using `PermissionsExt`. For more information, see\n\ - https://doc.rust-lang.org/std/os/unix/fs/trait.PermissionsExt.html"); - } + diag.help( + "you can set the desired permissions using `PermissionsExt`. For more information, see\n\ + https://doc.rust-lang.org/std/os/unix/fs/trait.PermissionsExt.html", + ); + }, ); } } diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs index 7dabdcd58..83863b92c 100644 --- a/src/tools/clippy/clippy_lints/src/ptr.rs +++ b/src/tools/clippy/clippy_lints/src/ptr.rs @@ -4,9 +4,8 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_the use clippy_utils::source::snippet_opt; use clippy_utils::ty::expr_sig; use clippy_utils::visitors::contains_unsafe_block; -use clippy_utils::{get_expr_use_or_unification_node, is_lint_allowed, path_def_id, path_to_local, paths}; +use clippy_utils::{get_expr_use_or_unification_node, is_lint_allowed, path_def_id, path_to_local}; use hir::LifetimeName; -use if_chain::if_chain; use rustc_errors::{Applicability, MultiSpan}; use rustc_hir::def_id::DefId; use rustc_hir::hir_id::HirIdMap; @@ -22,8 +21,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, Binder, ClauseKind, ExistentialPredicate, List, PredicateKind, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::Span; -use rustc_span::sym; +use rustc_span::{sym, Span}; use rustc_span::symbol::Symbol; use rustc_target::spec::abi::Abi; use rustc_trait_selection::infer::InferCtxtExt as _; @@ -271,60 +269,40 @@ impl<'tcx> LateLintPass<'tcx> for Ptr { } fn check_invalid_ptr_usage<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - // (fn_path, arg_indices) - `arg_indices` are the `arg` positions where null would cause U.B. - const INVALID_NULL_PTR_USAGE_TABLE: [(&[&str], &[usize]); 13] = [ - (&paths::SLICE_FROM_RAW_PARTS, &[0]), - (&paths::SLICE_FROM_RAW_PARTS_MUT, &[0]), - (&paths::PTR_COPY, &[0, 1]), - (&paths::PTR_COPY_NONOVERLAPPING, &[0, 1]), - (&paths::PTR_READ, &[0]), - (&paths::PTR_READ_UNALIGNED, &[0]), - (&paths::PTR_READ_VOLATILE, &[0]), - (&paths::PTR_REPLACE, &[0]), - (&paths::PTR_SLICE_FROM_RAW_PARTS, &[0]), - (&paths::PTR_SLICE_FROM_RAW_PARTS_MUT, &[0]), - (&paths::PTR_SWAP, &[0, 1]), - (&paths::PTR_SWAP_NONOVERLAPPING, &[0, 1]), - (&paths::PTR_WRITE_BYTES, &[0]), - ]; - let invalid_null_ptr_usage_table_diag_items: [(Option<DefId>, &[usize]); 3] = [ - (cx.tcx.get_diagnostic_item(sym::ptr_write), &[0]), - (cx.tcx.get_diagnostic_item(sym::ptr_write_unaligned), &[0]), - (cx.tcx.get_diagnostic_item(sym::ptr_write_volatile), &[0]), - ]; - - if_chain! { - if let ExprKind::Call(fun, args) = expr.kind; - if let ExprKind::Path(ref qpath) = fun.kind; - if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id(); - let fun_def_path = cx.get_def_path(fun_def_id).into_iter().map(Symbol::to_ident_string).collect::<Vec<_>>(); - if let Some(arg_indices) = INVALID_NULL_PTR_USAGE_TABLE - .iter() - .find_map(|&(fn_path, indices)| if fn_path == fun_def_path { Some(indices) } else { None }) - .or_else(|| { - invalid_null_ptr_usage_table_diag_items - .iter() - .find_map(|&(def_id, indices)| { - if def_id == Some(fun_def_id) { - Some(indices) - } else { - None - } - }) - }); - then { - for &arg_idx in arg_indices { - if let Some(arg) = args.get(arg_idx).filter(|arg| is_null_path(cx, arg)) { - span_lint_and_sugg( - cx, - INVALID_NULL_PTR_USAGE, - arg.span, - "pointer must be non-null", - "change this to", - "core::ptr::NonNull::dangling().as_ptr()".to_string(), - Applicability::MachineApplicable, - ); - } + if let ExprKind::Call(fun, args) = expr.kind + && let ExprKind::Path(ref qpath) = fun.kind + && let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id() + && let Some(name) = cx.tcx.get_diagnostic_name(fun_def_id) + { + // `arg` positions where null would cause U.B. + let arg_indices: &[_] = match name { + sym::ptr_read + | sym::ptr_read_unaligned + | sym::ptr_read_volatile + | sym::ptr_replace + | sym::ptr_slice_from_raw_parts + | sym::ptr_slice_from_raw_parts_mut + | sym::ptr_write + | sym::ptr_write_bytes + | sym::ptr_write_unaligned + | sym::ptr_write_volatile + | sym::slice_from_raw_parts + | sym::slice_from_raw_parts_mut => &[0], + sym::ptr_copy | sym::ptr_copy_nonoverlapping | sym::ptr_swap | sym::ptr_swap_nonoverlapping => &[0, 1], + _ => return, + }; + + for &arg_idx in arg_indices { + if let Some(arg) = args.get(arg_idx).filter(|arg| is_null_path(cx, arg)) { + span_lint_and_sugg( + cx, + INVALID_NULL_PTR_USAGE, + arg.span, + "pointer must be non-null", + "change this to", + "core::ptr::NonNull::dangling().as_ptr()".to_string(), + Applicability::MachineApplicable, + ); } } } @@ -434,7 +412,6 @@ impl<'tcx> DerefTy<'tcx> { } } -#[expect(clippy::too_many_lines)] fn check_fn_args<'cx, 'tcx: 'cx>( cx: &'cx LateContext<'tcx>, fn_sig: ty::FnSig<'tcx>, @@ -456,104 +433,93 @@ fn check_fn_args<'cx, 'tcx: 'cx>( && let [.., name] = path.segments && cx.tcx.item_name(adt.did()) == name.ident.name { - let emission_id = params.get(i).map_or(hir_ty.hir_id, |param| param.hir_id); - let (method_renames, deref_ty) = match cx.tcx.get_diagnostic_name(adt.did()) { - Some(sym::Vec) => ( - [("clone", ".to_owned()")].as_slice(), - DerefTy::Slice( - name.args - .and_then(|args| args.args.first()) - .and_then(|arg| if let GenericArg::Type(ty) = arg { - Some(ty.span) - } else { - None - }), - args.type_at(0), - ), - ), - _ if Some(adt.did()) == cx.tcx.lang_items().string() => ( - [("clone", ".to_owned()"), ("as_str", "")].as_slice(), - DerefTy::Str, - ), - Some(sym::PathBuf) => ( - [("clone", ".to_path_buf()"), ("as_path", "")].as_slice(), - DerefTy::Path, - ), - Some(sym::Cow) if mutability == Mutability::Not => { - if let Some((lifetime, ty)) = name.args - .and_then(|args| { - if let [GenericArg::Lifetime(lifetime), ty] = args.args { - return Some((lifetime, ty)); - } + let emission_id = params.get(i).map_or(hir_ty.hir_id, |param| param.hir_id); + let (method_renames, deref_ty) = match cx.tcx.get_diagnostic_name(adt.did()) { + Some(sym::Vec) => ( + [("clone", ".to_owned()")].as_slice(), + DerefTy::Slice( + name.args.and_then(|args| args.args.first()).and_then(|arg| { + if let GenericArg::Type(ty) = arg { + Some(ty.span) + } else { None - }) - { - if !lifetime.is_anonymous() - && fn_sig.output() - .walk() - .filter_map(|arg| { - arg.as_region().and_then(|lifetime| { - match lifetime.kind() { - ty::ReEarlyBound(r) => Some(r.def_id), - ty::ReLateBound(_, r) => r.kind.get_id(), - ty::ReFree(r) => r.bound_region.get_id(), - ty::ReStatic - | ty::ReVar(_) - | ty::RePlaceholder(_) - | ty::ReErased - | ty::ReError(_) => None, - } - }) - }) - .any(|def_id| { - matches!( - lifetime.res, - LifetimeName::Param(param_def_id) if def_id - .as_local() - .is_some_and(|def_id| def_id == param_def_id), - ) - }) - { - // `&Cow<'a, T>` when the return type uses 'a is okay - return None; } - - let ty_name = - snippet_opt(cx, ty.span()).unwrap_or_else(|| args.type_at(1).to_string()); - - span_lint_hir_and_then( - cx, - PTR_ARG, - emission_id, - hir_ty.span, - "using a reference to `Cow` is not recommended", - |diag| { - diag.span_suggestion( - hir_ty.span, - "change this to", - format!("&{}{ty_name}", mutability.prefix_str()), - Applicability::Unspecified, - ); - } - ); + }), + args.type_at(0), + ), + ), + _ if Some(adt.did()) == cx.tcx.lang_items().string() => { + ([("clone", ".to_owned()"), ("as_str", "")].as_slice(), DerefTy::Str) + }, + Some(sym::PathBuf) => ([("clone", ".to_path_buf()"), ("as_path", "")].as_slice(), DerefTy::Path), + Some(sym::Cow) if mutability == Mutability::Not => { + if let Some((lifetime, ty)) = name.args.and_then(|args| { + if let [GenericArg::Lifetime(lifetime), ty] = args.args { + return Some((lifetime, ty)); } - return None; - }, - _ => return None, - }; - return Some(PtrArg { - idx: i, - emission_id, - span: hir_ty.span, - ty_did: adt.did(), - ty_name: name.ident.name, - method_renames, - ref_prefix: RefPrefix { - lt: *lt, - mutability, - }, - deref_ty, - }); + None + }) { + if !lifetime.is_anonymous() + && fn_sig + .output() + .walk() + .filter_map(|arg| { + arg.as_region().and_then(|lifetime| match lifetime.kind() { + ty::ReEarlyBound(r) => Some(r.def_id), + ty::ReLateBound(_, r) => r.kind.get_id(), + ty::ReFree(r) => r.bound_region.get_id(), + ty::ReStatic + | ty::ReVar(_) + | ty::RePlaceholder(_) + | ty::ReErased + | ty::ReError(_) => None, + }) + }) + .any(|def_id| { + matches!( + lifetime.res, + LifetimeName::Param(param_def_id) if def_id + .as_local() + .is_some_and(|def_id| def_id == param_def_id), + ) + }) + { + // `&Cow<'a, T>` when the return type uses 'a is okay + return None; + } + + let ty_name = snippet_opt(cx, ty.span()).unwrap_or_else(|| args.type_at(1).to_string()); + + span_lint_hir_and_then( + cx, + PTR_ARG, + emission_id, + hir_ty.span, + "using a reference to `Cow` is not recommended", + |diag| { + diag.span_suggestion( + hir_ty.span, + "change this to", + format!("&{}{ty_name}", mutability.prefix_str()), + Applicability::Unspecified, + ); + }, + ); + } + return None; + }, + _ => return None, + }; + return Some(PtrArg { + idx: i, + emission_id, + span: hir_ty.span, + ty_did: adt.did(), + ty_name: name.ident.name, + method_renames, + ref_prefix: RefPrefix { lt: *lt, mutability }, + deref_ty, + }); } None }) diff --git a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs b/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs index 20e032d4b..66d869bc4 100644 --- a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs +++ b/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs @@ -17,7 +17,7 @@ declare_clippy_lint! { /// cast by using the `add` method instead. /// /// ### Example - /// ```rust + /// ```no_run /// let vec = vec![b'a', b'b', b'c']; /// let ptr = vec.as_ptr(); /// let offset = 1_usize; @@ -29,7 +29,7 @@ declare_clippy_lint! { /// /// Could be written: /// - /// ```rust + /// ```no_run /// let vec = vec![b'a', b'b', b'c']; /// let ptr = vec.as_ptr(); /// let offset = 1_usize; diff --git a/src/tools/clippy/clippy_lints/src/pub_use.rs b/src/tools/clippy/clippy_lints/src/pub_use.rs index 9d2b0cedb..316a72988 100644 --- a/src/tools/clippy/clippy_lints/src/pub_use.rs +++ b/src/tools/clippy/clippy_lints/src/pub_use.rs @@ -14,7 +14,7 @@ declare_clippy_lint! { /// unintentional exports or to encourage placing exported items directly in public modules /// /// ### Example - /// ```rust + /// ```no_run /// pub mod outer { /// mod inner { /// pub struct Test {} @@ -25,7 +25,7 @@ declare_clippy_lint! { /// use outer::Test; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// pub mod outer { /// pub struct Test {} /// } @@ -41,16 +41,17 @@ declare_lint_pass!(PubUse => [PUB_USE]); impl EarlyLintPass for PubUse { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { - if let ItemKind::Use(_) = item.kind && - let VisibilityKind::Public = item.vis.kind { - span_lint_and_help( - cx, - PUB_USE, - item.span, - "using `pub use`", - None, - "move the exported item to a public module instead", - ); - } + if let ItemKind::Use(_) = item.kind + && let VisibilityKind::Public = item.vis.kind + { + span_lint_and_help( + cx, + PUB_USE, + item.span, + "using `pub use`", + None, + "move the exported item to a public module instead", + ); + } } } diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs index 734ca2914..b133635e8 100644 --- a/src/tools/clippy/clippy_lints/src/question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/question_mark.rs @@ -1,7 +1,8 @@ -use crate::manual_let_else::{MatchLintBehaviour, MANUAL_LET_ELSE}; +use crate::manual_let_else::MANUAL_LET_ELSE; use crate::question_mark_used::QUESTION_MARK_USED; +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::is_type_diagnostic_item; use clippy_utils::{ @@ -97,16 +98,23 @@ enum IfBlockType<'hir> { } fn check_let_some_else_return_none(cx: &LateContext<'_>, stmt: &Stmt<'_>) { - if let StmtKind::Local(Local { pat, init: Some(init_expr), els: Some(els), .. }) = stmt.kind && - let Block { stmts: &[], expr: Some(els), .. } = els && - let Some(inner_pat) = pat_and_expr_can_be_question_mark(cx, pat, els) + if let StmtKind::Local(Local { + pat, + init: Some(init_expr), + els: Some(els), + .. + }) = stmt.kind + && let Block { + stmts: &[], + expr: Some(els), + .. + } = els + && let Some(inner_pat) = pat_and_expr_can_be_question_mark(cx, pat, els) { let mut applicability = Applicability::MaybeIncorrect; let init_expr_str = snippet_with_applicability(cx, init_expr.span, "..", &mut applicability); let receiver_str = snippet_with_applicability(cx, inner_pat.span, "..", &mut applicability); - let sugg = format!( - "let {receiver_str} = {init_expr_str}?;", - ); + let sugg = format!("let {receiver_str} = {init_expr_str}?;",); span_lint_and_sugg( cx, QUESTION_MARK, diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs index 3287675a8..1b3081abc 100644 --- a/src/tools/clippy/clippy_lints/src/ranges.rs +++ b/src/tools/clippy/clippy_lints/src/ranges.rs @@ -1,6 +1,6 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{constant, 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::{snippet, snippet_opt, snippet_with_applicability}; use clippy_utils::sugg::Sugg; use clippy_utils::{get_parent_expr, higher, in_constant, is_integer_const, path_to_local}; @@ -11,7 +11,8 @@ use rustc_hir::{BinOpKind, Expr, ExprKind, HirId}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::source_map::{Span, Spanned}; +use rustc_span::Span; +use rustc_span::source_map::Spanned; use std::cmp::Ordering; declare_clippy_lint! { @@ -39,7 +40,7 @@ declare_clippy_lint! { /// ([#3307](https://github.com/rust-lang/rust-clippy/issues/3307)). /// /// ### Example - /// ```rust + /// ```no_run /// # let x = 0; /// # let y = 1; /// for i in x..(y+1) { @@ -48,7 +49,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let x = 0; /// # let y = 1; /// for i in x..=y { @@ -77,7 +78,7 @@ declare_clippy_lint! { /// ([#3307](https://github.com/rust-lang/rust-clippy/issues/3307)). /// /// ### Example - /// ```rust + /// ```no_run /// # let x = 0; /// # let y = 1; /// for i in x..=(y-1) { @@ -86,7 +87,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let x = 0; /// # let y = 1; /// for i in x..y { @@ -118,7 +119,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn main() { /// (0..=10).rev().for_each(|x| println!("{}", x)); /// @@ -142,14 +143,14 @@ declare_clippy_lint! { /// failure modes (such as fencepost errors or using `||` instead of `&&`). /// /// ### Example - /// ```rust + /// ```no_run /// // given /// let x = 6; /// /// assert!(x >= 3 && x < 8); /// ``` /// Use instead: - /// ```rust + /// ```no_run ///# let x = 6; /// assert!((3..8).contains(&x)); /// ``` diff --git a/src/tools/clippy/clippy_lints/src/raw_strings.rs b/src/tools/clippy/clippy_lints/src/raw_strings.rs index 8a7e48746..391c77dbf 100644 --- a/src/tools/clippy/clippy_lints/src/raw_strings.rs +++ b/src/tools/clippy/clippy_lints/src/raw_strings.rs @@ -20,11 +20,11 @@ declare_clippy_lint! { /// idiomatic than a string literal, so it's opt-in. /// /// ### Example - /// ```rust + /// ```no_run /// let r = r"Hello, world!"; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let r = "Hello, world!"; /// ``` #[clippy::version = "1.72.0"] @@ -41,11 +41,11 @@ declare_clippy_lint! { /// necessary. /// /// ### Example - /// ```rust + /// ```no_run /// let r = r###"Hello, "world"!"###; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let r = r#"Hello, "world"!"#; /// ``` #[clippy::version = "1.72.0"] @@ -75,6 +75,7 @@ impl EarlyLintPass for RawStrings { if !snippet(cx, expr.span, prefix).trim().starts_with(prefix) { return; } + let descr = lit.kind.descr(); if !str.contains(['\\', '"']) { span_lint_and_then( @@ -89,20 +90,17 @@ impl EarlyLintPass for RawStrings { let r_pos = expr.span.lo() + BytePos::from_usize(prefix.len() - 1); let start = start.with_lo(r_pos); - if end.is_empty() { - diag.span_suggestion( - start, - "use a string literal instead", - format!("\"{str}\""), - Applicability::MachineApplicable, - ); - } else { - diag.multipart_suggestion( - "try", - vec![(start, String::new()), (end, String::new())], - Applicability::MachineApplicable, - ); + let mut remove = vec![(start, String::new())]; + // avoid debug ICE from empty suggestions + if !end.is_empty() { + remove.push((end, String::new())); } + + diag.multipart_suggestion_verbose( + format!("use a plain {descr} literal instead"), + remove, + Applicability::MachineApplicable, + ); }, ); if !matches!(cx.get_lint_level(NEEDLESS_RAW_STRINGS), rustc_lint::Allow) { @@ -149,9 +147,9 @@ impl EarlyLintPass for RawStrings { let (start, end) = hash_spans(expr.span, prefix, req, max); let message = match max - req { - _ if req == 0 => "remove all the hashes around the literal".to_string(), - 1 => "remove one hash from both sides of the literal".to_string(), - n => format!("remove {n} hashes from both sides of the literal"), + _ if req == 0 => format!("remove all the hashes around the {descr} literal"), + 1 => format!("remove one hash from both sides of the {descr} literal"), + n => format!("remove {n} hashes from both sides of the {descr} literal"), }; diag.multipart_suggestion( diff --git a/src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs b/src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs index 8e85c55e7..59ce289e7 100644 --- a/src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs +++ b/src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs @@ -1,12 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::VecArgs; +use clippy_utils::last_path_segment; use clippy_utils::macros::root_macro_call_first_node; use clippy_utils::source::{indent_of, snippet}; -use clippy_utils::ty::match_type; -use clippy_utils::{last_path_segment, paths}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{sym, Span, Symbol}; @@ -21,13 +21,13 @@ declare_clippy_lint! { /// than different instances. /// /// ### Example - /// ```rust + /// ```no_run /// let v = vec![std::sync::Arc::new("some data".to_string()); 100]; /// // or /// let v = vec![std::rc::Rc::new("some data".to_string()); 100]; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// // Initialize each value separately: /// let mut data = Vec::with_capacity(100); /// for _ in 0..100 { @@ -133,8 +133,9 @@ fn ref_init(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<(Symbol, Span)> { return Some((symbol, func.span)); } - let ty_path = cx.typeck_results().expr_ty(expr); - if match_type(cx, ty_path, &paths::WEAK_RC) || match_type(cx, ty_path, &paths::WEAK_ARC) { + if let ty::Adt(adt, _) = *cx.typeck_results().expr_ty(expr).kind() + && matches!(cx.tcx.get_diagnostic_name(adt.did()), Some(sym::RcWeak | sym::ArcWeak)) + { return Some((Symbol::intern("Weak"), func.span)); } } diff --git a/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs b/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs index 2bf90815c..b27d4cc6e 100644 --- a/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs +++ b/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs @@ -24,7 +24,7 @@ declare_clippy_lint! { /// a zero-byte read would allocate a `Vec` for it. /// /// ### Example - /// ```rust + /// ```no_run /// use std::io; /// fn foo<F: io::Read>(mut f: F) { /// let mut data = Vec::with_capacity(100); @@ -32,7 +32,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::io; /// fn foo<F: io::Read>(mut f: F) { /// let mut data = Vec::with_capacity(100); @@ -42,7 +42,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.63.0"] pub READ_ZERO_BYTE_VEC, - correctness, + nursery, "checks for reads into a zero-length `Vec`" } declare_lint_pass!(ReadZeroByteVec => [READ_ZERO_BYTE_VEC]); @@ -59,7 +59,10 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec { { let visitor = |expr: &Expr<'_>| { if let ExprKind::MethodCall(path, _, [arg], _) = expr.kind - && let PathSegment { ident: read_or_read_exact, .. } = *path + && let PathSegment { + ident: read_or_read_exact, + .. + } = *path && matches!(read_or_read_exact.as_str(), "read" | "read_exact") && let ExprKind::AddrOf(_, hir::Mutability::Mut, inner) = arg.kind && let ExprKind::Path(QPath::Resolved(None, inner_path)) = inner.kind @@ -72,15 +75,14 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec { } }; - let (read_found, next_stmt_span) = - if let Some(next_stmt) = block.stmts.get(idx + 1) { + let (read_found, next_stmt_span) = if let Some(next_stmt) = block.stmts.get(idx + 1) { // case { .. stmt; stmt; .. } (for_each_expr(next_stmt, visitor).is_some(), next_stmt.span) } else if let Some(e) = block.expr { // case { .. stmt; expr } (for_each_expr(e, visitor).is_some(), e.span) } else { - return + return; }; if read_found && !next_stmt_span.from_expansion() { @@ -93,13 +95,14 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec { next_stmt_span, "reading zero byte data to `Vec`", "try", - format!("{}.resize({len}, 0); {}", + format!( + "{}.resize({len}, 0); {}", ident.as_str(), snippet(cx, next_stmt_span, "..") ), applicability, ); - } + }, VecInitKind::WithExprCapacity(hir_id) => { let e = cx.tcx.hir().expect_expr(hir_id); span_lint_and_sugg( @@ -108,14 +111,15 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec { next_stmt_span, "reading zero byte data to `Vec`", "try", - format!("{}.resize({}, 0); {}", + format!( + "{}.resize({}, 0); {}", ident.as_str(), snippet(cx, e.span, ".."), snippet(cx, next_stmt_span, "..") ), applicability, ); - } + }, _ => { span_lint( cx, @@ -123,8 +127,7 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec { next_stmt_span, "reading zero byte data to `Vec`", ); - - } + }, } } } diff --git a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs index 534b2762b..90297ca8b 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs @@ -5,7 +5,7 @@ use clippy_utils::peel_blocks; use clippy_utils::source::{snippet, walk_span_to_context}; use clippy_utils::visitors::for_each_expr; use rustc_errors::Applicability; -use rustc_hir::{AsyncGeneratorKind, Closure, Expr, ExprKind, GeneratorKind, MatchSource}; +use rustc_hir::{Closure, CoroutineKind, CoroutineSource, Expr, ExprKind, MatchSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::UpvarCapture; @@ -19,7 +19,7 @@ declare_clippy_lint! { /// It is simpler and more efficient to use the future directly. /// /// ### Example - /// ```rust + /// ```no_run /// let f = async { /// 1 + 2 /// }; @@ -28,7 +28,7 @@ declare_clippy_lint! { /// }; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let f = async { /// 1 + 2 /// }; @@ -48,7 +48,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantAsyncBlock { let Some(body_expr) = desugar_async_block(cx, expr) && let Some(expr) = desugar_await(peel_blocks(body_expr)) && // The await prefix must not come from a macro as its content could change in the future. - expr.span.ctxt() == body_expr.span.ctxt() && + expr.span.eq_ctxt(body_expr.span) && // An async block does not have immediate side-effects from a `.await` point-of-view. (!expr.can_have_side_effects() || desugar_async_block(cx, expr).is_some()) && let Some(shortened_span) = walk_span_to_context(expr.span, span.ctxt()) @@ -69,12 +69,11 @@ impl<'tcx> LateLintPass<'tcx> for RedundantAsyncBlock { /// If `expr` is a desugared `async` block, return the original expression if it does not capture /// any variable by ref. fn desugar_async_block<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { - if let ExprKind::Closure(Closure { body, def_id, .. }) = expr.kind && - let body = cx.tcx.hir().body(*body) && - matches!(body.generator_kind, Some(GeneratorKind::Async(AsyncGeneratorKind::Block))) + if let ExprKind::Closure(Closure { body, def_id, .. }) = expr.kind + && let body = cx.tcx.hir().body(*body) + && matches!(body.coroutine_kind, Some(CoroutineKind::Async(CoroutineSource::Block))) { - cx - .typeck_results() + cx.typeck_results() .closure_min_captures .get(def_id) .map_or(true, |m| { @@ -93,12 +92,13 @@ fn desugar_async_block<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Op /// If `expr` is a desugared `.await`, return the original expression if it does not come from a /// macro expansion. fn desugar_await<'tcx>(expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { - if let ExprKind::Match(match_value, _, MatchSource::AwaitDesugar) = expr.kind && - let ExprKind::Call(_, [into_future_arg]) = match_value.kind && - let ctxt = expr.span.ctxt() && - for_each_expr(into_future_arg, |e| - walk_span_to_context(e.span, ctxt) - .map_or(ControlFlow::Break(()), |_| ControlFlow::Continue(()))).is_none() + if let ExprKind::Match(match_value, _, MatchSource::AwaitDesugar) = expr.kind + && let ExprKind::Call(_, [into_future_arg]) = match_value.kind + && let ctxt = expr.span.ctxt() + && for_each_expr(into_future_arg, |e| { + walk_span_to_context(e.span, ctxt).map_or(ControlFlow::Break(()), |_| ControlFlow::Continue(())) + }) + .is_none() { Some(into_future_arg) } else { diff --git a/src/tools/clippy/clippy_lints/src/redundant_clone.rs b/src/tools/clippy/clippy_lints/src/redundant_clone.rs index e36adef55..8daf085a4 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_clone.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_clone.rs @@ -12,8 +12,7 @@ use rustc_middle::mir; use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::def_id::LocalDefId; -use rustc_span::source_map::{BytePos, Span}; -use rustc_span::sym; +use rustc_span::{sym, BytePos, Span}; macro_rules! unwrap_or_continue { ($x:expr) => { @@ -37,7 +36,7 @@ declare_clippy_lint! { /// False-negatives: analysis performed by this lint is conservative and limited. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::path::Path; /// # #[derive(Clone)] /// # struct Foo; @@ -99,8 +98,8 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone { unwrap_or_continue!(is_call_with_ref_arg(cx, mir, &terminator.kind)); let from_borrow = match_def_path(cx, fn_def_id, &paths::CLONE_TRAIT_METHOD) - || match_def_path(cx, fn_def_id, &paths::TO_OWNED_METHOD) - || (match_def_path(cx, fn_def_id, &paths::TO_STRING_METHOD) + || cx.tcx.is_diagnostic_item(sym::to_owned_method, fn_def_id) + || (cx.tcx.is_diagnostic_item(sym::to_string_method, fn_def_id) && is_type_lang_item(cx, arg_ty, LangItem::String)); let from_deref = !from_borrow diff --git a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs index f42836611..e679fab53 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs @@ -23,12 +23,12 @@ declare_clippy_lint! { /// complexity. /// /// ### Example - /// ```rust + /// ```no_run /// let a = (|| 42)(); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let a = 42; /// ``` #[clippy::version = "pre 1.29.0"] @@ -98,11 +98,15 @@ fn find_innermost_closure<'tcx>( && steps > 0 { expr = body.value; - data = Some((body.value, closure.fn_decl, if is_async_closure(body) { - ty::Asyncness::Yes - } else { - ty::Asyncness::No - })); + data = Some(( + body.value, + closure.fn_decl, + if is_async_closure(body) { + ty::Asyncness::Yes + } else { + ty::Asyncness::No + }, + )); steps -= 1; } @@ -144,7 +148,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { // without this check, we'd end up linting twice. && !matches!(recv.kind, hir::ExprKind::Call(..)) && let (full_expr, call_depth) = get_parent_call_exprs(cx, expr) - && let Some((body, fn_decl, generator_kind)) = find_innermost_closure(cx, recv, call_depth) + && let Some((body, fn_decl, coroutine_kind)) = find_innermost_closure(cx, recv, call_depth) { span_lint_and_then( cx, @@ -154,9 +158,10 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { |diag| { if fn_decl.inputs.is_empty() { let mut applicability = Applicability::MachineApplicable; - let mut hint = Sugg::hir_with_context(cx, body, full_expr.span.ctxt(), "..", &mut applicability); + let mut hint = + Sugg::hir_with_context(cx, body, full_expr.span.ctxt(), "..", &mut applicability); - if generator_kind.is_async() + if coroutine_kind.is_async() && let hir::ExprKind::Closure(closure) = body.kind { let async_closure_body = cx.tcx.hir().body(closure.body); @@ -173,10 +178,10 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { full_expr.span, "try doing something like", hint.maybe_par(), - applicability + applicability, ); } - } + }, ); } } diff --git a/src/tools/clippy/clippy_lints/src/redundant_else.rs b/src/tools/clippy/clippy_lints/src/redundant_else.rs index 73088ce1a..221aa317e 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_else.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_else.rs @@ -16,7 +16,7 @@ declare_clippy_lint! { /// Some may prefer to keep the `else` block for clarity. /// /// ### Example - /// ```rust + /// ```no_run /// fn my_func(count: u32) { /// if count == 0 { /// print!("Nothing to do"); @@ -27,7 +27,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn my_func(count: u32) { /// if count == 0 { /// print!("Nothing to do"); diff --git a/src/tools/clippy/clippy_lints/src/redundant_field_names.rs b/src/tools/clippy/clippy_lints/src/redundant_field_names.rs index 61bff4a0e..b8e606df7 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_field_names.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_field_names.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 rustc_ast::ast::{Expr, ExprKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; @@ -16,7 +16,7 @@ declare_clippy_lint! { /// the field name is redundant. /// /// ### Example - /// ```rust + /// ```no_run /// let bar: u8 = 123; /// /// struct Foo { diff --git a/src/tools/clippy/clippy_lints/src/redundant_locals.rs b/src/tools/clippy/clippy_lints/src/redundant_locals.rs index 0c89c7ee4..6bc0d0618 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_locals.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_locals.rs @@ -3,11 +3,9 @@ use clippy_utils::is_from_proc_macro; use clippy_utils::ty::needs_ordered_drop; use rustc_ast::Mutability; use rustc_hir::def::Res; -use rustc_hir::{ - BindingAnnotation, ByRef, Expr, ExprKind, HirId, Local, Node, Pat, PatKind, QPath, -}; +use rustc_hir::{BindingAnnotation, ByRef, ExprKind, HirId, Local, Node, Pat, PatKind, QPath}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::{in_external_macro, is_from_async_await}; +use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::Ident; use rustc_span::DesugaringKind; @@ -22,7 +20,7 @@ declare_clippy_lint! { /// Note that although these bindings do not affect your code's meaning, they _may_ affect `rustc`'s stack allocation. /// /// ### Example - /// ```rust + /// ```no_run /// let a = 0; /// let a = a; /// @@ -31,7 +29,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let a = 0; /// // no redefinition with the same name /// @@ -39,7 +37,7 @@ declare_clippy_lint! { /// // no redefinition with the same name /// } /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub REDUNDANT_LOCALS, correctness, "redundant redefinition of a local binding" @@ -64,25 +62,22 @@ impl<'tcx> LateLintPass<'tcx> for RedundantLocals { if let Res::Local(binding_id) = cx.qpath_res(&qpath, expr.hir_id); if let Node::Pat(binding_pat) = cx.tcx.hir().get(binding_id); // the previous binding has the same mutability - if find_binding(binding_pat, ident).unwrap().1 == mutability; + if find_binding(binding_pat, ident).is_some_and(|bind| bind.1 == mutability); // the local does not change the effect of assignments to the binding. see #11290 if !affects_assignments(cx, mutability, binding_id, local.hir_id); // the local does not affect the code's drop behavior - if !affects_drop_behavior(cx, binding_id, local.hir_id, expr); + if !needs_ordered_drop(cx, cx.typeck_results().expr_ty(expr)); // the local is user-controlled if !in_external_macro(cx.sess(), local.span); if !is_from_proc_macro(cx, expr); - // Async function parameters are lowered into the closure body, so we can't lint them. - // see `lower_maybe_async_body` in `rust_ast_lowering` - if !is_from_async_await(local.span); then { span_lint_and_help( cx, REDUNDANT_LOCALS, - vec![binding_pat.span, local.span], - "redundant redefinition of a binding", - None, - &format!("remove the redefinition of `{ident}`"), + local.span, + &format!("redundant redefinition of a binding `{ident}`"), + Some(binding_pat.span), + &format!("`{ident}` is initially defined here"), ); } } @@ -109,18 +104,3 @@ fn affects_assignments(cx: &LateContext<'_>, mutability: Mutability, bind: HirId // the binding is mutable and the rebinding is in a different scope than the original binding mutability == Mutability::Mut && hir.get_enclosing_scope(bind) != hir.get_enclosing_scope(rebind) } - -/// Check if a rebinding of a local affects the code's drop behavior. -fn affects_drop_behavior<'tcx>( - cx: &LateContext<'tcx>, - bind: HirId, - rebind: HirId, - rebind_expr: &Expr<'tcx>, -) -> bool { - let hir = cx.tcx.hir(); - - // the rebinding is in a different scope than the original binding - // and the type of the binding cares about drop order - hir.get_enclosing_scope(bind) != hir.get_enclosing_scope(rebind) - && needs_ordered_drop(cx, cx.typeck_results().expr_ty(rebind_expr)) -} diff --git a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs index c2a8db7df..03673eb27 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs @@ -18,14 +18,14 @@ declare_clippy_lint! { /// module's visibility. /// /// ### Example - /// ```rust + /// ```no_run /// mod internal { /// pub(crate) fn internal_fn() { } /// } /// ``` /// This function is not visible outside the module and it can be declared with `pub` or /// private visibility - /// ```rust + /// ```no_run /// mod internal { /// pub fn internal_fn() { } /// } diff --git a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs index 4abfa0fc3..7adbd6791 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs @@ -51,12 +51,12 @@ declare_clippy_lint! { /// Some people may prefer to dereference rather than slice. /// /// ### Example - /// ```rust + /// ```no_run /// let vec = vec![1, 2, 3]; /// let slice = &vec[..]; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let vec = vec![1, 2, 3]; /// let slice = &*vec; /// ``` diff --git a/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs b/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs index ed42a422b..a70b831a8 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.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; use rustc_ast::ast::{ConstItem, Item, ItemKind, StaticItem, Ty, TyKind}; use rustc_errors::Applicability; diff --git a/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs b/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs index 1d4fdb43a..f6af9cac3 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs @@ -24,11 +24,11 @@ declare_clippy_lint! { /// - `Path` to anything else than a primitive type. /// /// ### Example - /// ```rust + /// ```no_run /// let foo: String = String::new(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let foo = String::new(); /// ``` #[clippy::version = "1.72.0"] @@ -145,8 +145,8 @@ impl LateLintPass<'_> for RedundantTypeAnnotations { hir::ExprKind::Call(init_call, _) => { if let hir::TyKind::Path(ty_path) = &ty.kind && let hir::QPath::Resolved(_, resolved_path_ty) = ty_path - - && is_redundant_in_func_call(cx, resolved_path_ty.res, init_call) { + && is_redundant_in_func_call(cx, resolved_path_ty.res, init_call) + { span_lint(cx, REDUNDANT_TYPE_ANNOTATIONS, local.span, "redundant type annotation"); } }, @@ -164,11 +164,11 @@ impl LateLintPass<'_> for RedundantTypeAnnotations { && let hir::QPath::Resolved(_, resolved_path_ty) = ty_path && let Some(func_ty) = func_hir_id_to_func_ty(cx, init.hir_id) && let Some(return_type) = func_ty_to_return_type(cx, func_ty) - && is_same_type(cx, resolved_path_ty.res, if is_ref { - return_type.peel_refs() - } else { - return_type - }) + && is_same_type( + cx, + resolved_path_ty.res, + if is_ref { return_type.peel_refs() } else { return_type }, + ) { span_lint(cx, REDUNDANT_TYPE_ANNOTATIONS, local.span, "redundant type annotation"); } @@ -177,10 +177,8 @@ impl LateLintPass<'_> for RedundantTypeAnnotations { hir::ExprKind::Path(init_path) => { // TODO: check for non primty if let Some(primty) = extract_primty(&ty.kind) - && let hir::QPath::TypeRelative(init_ty, _) = init_path && let Some(primty_init) = extract_primty(&init_ty.kind) - && primty == primty_init { span_lint(cx, REDUNDANT_TYPE_ANNOTATIONS, local.span, "redundant type annotation"); @@ -205,8 +203,8 @@ impl LateLintPass<'_> for RedundantTypeAnnotations { }, LitKind::Err => (), } - } - _ => () + }, + _ => (), } }; } diff --git a/src/tools/clippy/clippy_lints/src/ref_patterns.rs b/src/tools/clippy/clippy_lints/src/ref_patterns.rs index b1530eed1..8b3dabde9 100644 --- a/src/tools/clippy/clippy_lints/src/ref_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/ref_patterns.rs @@ -10,12 +10,12 @@ declare_clippy_lint! { /// The `ref` keyword can be confusing for people unfamiliar with it, and often /// it is more concise to use `&` instead. /// ### Example - /// ```rust + /// ```no_run /// let opt = Some(5); /// if let Some(ref foo) = opt {} /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let opt = Some(5); /// if let Some(foo) = &opt {} /// ``` @@ -29,7 +29,7 @@ declare_lint_pass!(RefPatterns => [REF_PATTERNS]); impl EarlyLintPass for RefPatterns { fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &Pat) { if let PatKind::Ident(BindingAnnotation::REF, _, _) = pat.kind - && !pat.span.from_expansion() + && !pat.span.from_expansion() { span_lint_and_help( cx, diff --git a/src/tools/clippy/clippy_lints/src/reference.rs b/src/tools/clippy/clippy_lints/src/reference.rs index db870ec4c..12da29f11 100644 --- a/src/tools/clippy/clippy_lints/src/reference.rs +++ b/src/tools/clippy/clippy_lints/src/reference.rs @@ -50,7 +50,7 @@ impl EarlyLintPass for DerefAddrOf { if_chain! { if let ExprKind::Unary(UnOp::Deref, ref deref_target) = e.kind; if let ExprKind::AddrOf(_, ref mutability, ref addrof_target) = without_parens(deref_target).kind; - if deref_target.span.ctxt() == e.span.ctxt(); + if deref_target.span.eq_ctxt(e.span); if !addrof_target.span.from_expansion(); then { let mut applicability = Applicability::MachineApplicable; diff --git a/src/tools/clippy/clippy_lints/src/regex.rs b/src/tools/clippy/clippy_lints/src/regex.rs index b795e4b15..cb78eec9e 100644 --- a/src/tools/clippy/clippy_lints/src/regex.rs +++ b/src/tools/clippy/clippy_lints/src/regex.rs @@ -9,7 +9,7 @@ use rustc_hir::def_id::DefIdMap; use rustc_hir::{BorrowKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::source_map::{BytePos, Span}; +use rustc_span::{BytePos, Span}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs b/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs index 0c8c904e3..1975946c6 100644 --- a/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs +++ b/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs @@ -18,18 +18,18 @@ declare_clippy_lint! { /// The `Vec::with_capacity` constructor is less complex. /// /// ### Example - /// ```rust + /// ```no_run /// let mut v: Vec<usize> = vec![]; /// v.reserve(10); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let mut v: Vec<usize> = Vec::with_capacity(10); /// ``` #[clippy::version = "1.73.0"] pub RESERVE_AFTER_INITIALIZATION, complexity, - "`reserve` called immediatly after `Vec` creation" + "`reserve` called immediately after `Vec` creation" } impl_lint_pass!(ReserveAfterInitialization => [RESERVE_AFTER_INITIALIZATION]); @@ -74,15 +74,24 @@ impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization { && let PatKind::Binding(BindingAnnotation::MUT, id, _, None) = local.pat.kind && !in_external_macro(cx.sess(), local.span) && let Some(init) = get_vec_init_kind(cx, init_expr) - && !matches!(init, VecInitKind::WithExprCapacity(_) | VecInitKind::WithConstCapacity(_)) + && !matches!( + init, + VecInitKind::WithExprCapacity(_) | VecInitKind::WithConstCapacity(_) + ) { self.searcher = Some(VecReserveSearcher { local_id: id, err_span: local.span, - init_part: snippet(cx, local.span.shrink_to_lo() - .to(init_expr.span.source_callsite().shrink_to_lo()), "..") - .into_owned(), - space_hint: String::new() + init_part: snippet( + cx, + local + .span + .shrink_to_lo() + .to(init_expr.span.source_callsite().shrink_to_lo()), + "..", + ) + .into_owned(), + space_hint: String::new(), }); } } @@ -94,15 +103,21 @@ impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization { && let Res::Local(id) = path.res && !in_external_macro(cx.sess(), expr.span) && let Some(init) = get_vec_init_kind(cx, right) - && !matches!(init, VecInitKind::WithExprCapacity(_) | VecInitKind::WithConstCapacity(_)) + && !matches!( + init, + VecInitKind::WithExprCapacity(_) | VecInitKind::WithConstCapacity(_) + ) { self.searcher = Some(VecReserveSearcher { local_id: id, err_span: expr.span, - init_part: snippet(cx, left.span.shrink_to_lo() - .to(right.span.source_callsite().shrink_to_lo()), "..") - .into_owned(), // see `assign_expression` test - space_hint: String::new() + init_part: snippet( + cx, + left.span.shrink_to_lo().to(right.span.source_callsite().shrink_to_lo()), + "..", + ) + .into_owned(), // see `assign_expression` test + space_hint: String::new(), }); } } @@ -118,7 +133,7 @@ impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization { self.searcher = Some(VecReserveSearcher { err_span: searcher.err_span.to(stmt.span), space_hint: snippet(cx, space_hint.span, "..").into_owned(), - .. searcher + ..searcher }); } else { searcher.display_err(cx); diff --git a/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs b/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs index bccf421e8..245029a06 100644 --- a/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs +++ b/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs @@ -26,7 +26,7 @@ declare_clippy_lint! { /// if it was added on constructors for example. /// /// ### Example - /// ```rust + /// ```no_run /// pub struct Bar; /// impl Bar { /// // Missing attribute @@ -37,7 +37,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # { /// // It's better to have the `#[must_use]` attribute on the method like this: /// pub struct Bar; diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs index d6b9a49d2..f2a3dc509 100644 --- a/src/tools/clippy/clippy_lints/src/returns.rs +++ b/src/tools/clippy/clippy_lints/src/returns.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::source::{snippet_opt, snippet_with_context}; +use clippy_utils::sugg::has_enclosing_paren; use clippy_utils::visitors::{for_each_expr_with_closures, Descend}; use clippy_utils::{fn_def_id, is_from_proc_macro, path_to_local_id, span_find_starting_semi}; use core::ops::ControlFlow; @@ -14,8 +15,7 @@ use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, GenericArgKind, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::def_id::LocalDefId; -use rustc_span::source_map::Span; -use rustc_span::{BytePos, Pos}; +use rustc_span::{BytePos, Pos, Span}; use std::borrow::Cow; declare_clippy_lint! { @@ -34,14 +34,14 @@ declare_clippy_lint! { /// bound without first assigning it to a let-binding. /// /// ### Example - /// ```rust + /// ```no_run /// fn foo() -> String { /// let x = String::new(); /// x /// } /// ``` /// instead, use - /// ``` + /// ```no_run /// fn foo() -> String { /// String::new() /// } @@ -61,13 +61,13 @@ declare_clippy_lint! { /// more rusty. /// /// ### Example - /// ```rust + /// ```no_run /// fn foo(x: usize) -> usize { /// return x; /// } /// ``` /// simplify to - /// ```rust + /// ```no_run /// fn foo(x: usize) -> usize { /// x /// } @@ -213,6 +213,9 @@ impl<'tcx> LateLintPass<'tcx> for Return { if let Some(mut snippet) = snippet_opt(cx, initexpr.span) { if !cx.typeck_results().expr_adjustments(retexpr).is_empty() { + if !has_enclosing_paren(&snippet) { + snippet = format!("({snippet})"); + } snippet.push_str(" as _"); } err.multipart_suggestion( diff --git a/src/tools/clippy/clippy_lints/src/same_name_method.rs b/src/tools/clippy/clippy_lints/src/same_name_method.rs index a37e2772d..fd1f3d390 100644 --- a/src/tools/clippy/clippy_lints/src/same_name_method.rs +++ b/src/tools/clippy/clippy_lints/src/same_name_method.rs @@ -18,7 +18,7 @@ declare_clippy_lint! { /// Confusing. /// /// ### Example - /// ```rust + /// ```no_run /// trait T { /// fn foo(&self) {} /// } @@ -120,9 +120,10 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod { } }; - for impl_item_ref in (*items).iter().filter(|impl_item_ref| { - matches!(impl_item_ref.kind, rustc_hir::AssocItemKind::Fn { .. }) - }) { + for impl_item_ref in (*items) + .iter() + .filter(|impl_item_ref| matches!(impl_item_ref.kind, rustc_hir::AssocItemKind::Fn { .. })) + { let method_name = impl_item_ref.ident.name; methods_in_trait.remove(&method_name); check_trait_method(method_name, impl_item_ref.span); @@ -133,9 +134,10 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod { } }, None => { - for impl_item_ref in (*items).iter().filter(|impl_item_ref| { - matches!(impl_item_ref.kind, rustc_hir::AssocItemKind::Fn { .. }) - }) { + for impl_item_ref in (*items) + .iter() + .filter(|impl_item_ref| matches!(impl_item_ref.kind, rustc_hir::AssocItemKind::Fn { .. })) + { let method_name = impl_item_ref.ident.name; let impl_span = impl_item_ref.span; let hir_id = impl_item_ref.id.hir_id(); diff --git a/src/tools/clippy/clippy_lints/src/semicolon_block.rs b/src/tools/clippy/clippy_lints/src/semicolon_block.rs index 88f295c72..b0601bba4 100644 --- a/src/tools/clippy/clippy_lints/src/semicolon_block.rs +++ b/src/tools/clippy/clippy_lints/src/semicolon_block.rs @@ -19,13 +19,13 @@ declare_clippy_lint! { /// /// ### Example /// - /// ```rust + /// ```no_run /// # fn f(_: u32) {} /// # let x = 0; /// unsafe { f(x) }; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # fn f(_: u32) {} /// # let x = 0; /// unsafe { f(x); } @@ -48,13 +48,13 @@ declare_clippy_lint! { /// /// ### Example /// - /// ```rust + /// ```no_run /// # fn f(_: u32) {} /// # let x = 0; /// unsafe { f(x); } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # fn f(_: u32) {} /// # let x = 0; /// unsafe { f(x) }; diff --git a/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs b/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs index c9547cd95..ccf8b9977 100644 --- a/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs +++ b/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs @@ -17,13 +17,13 @@ declare_clippy_lint! { /// code, it doesn't require a change in previous last line. /// /// ### Example - /// ```rust + /// ```no_run /// fn main() { /// println!("Hello world") /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn main() { /// println!("Hello world"); /// } diff --git a/src/tools/clippy/clippy_lints/src/shadow.rs b/src/tools/clippy/clippy_lints/src/shadow.rs index 78418b223..41c10b34a 100644 --- a/src/tools/clippy/clippy_lints/src/shadow.rs +++ b/src/tools/clippy/clippy_lints/src/shadow.rs @@ -21,13 +21,13 @@ declare_clippy_lint! { /// lint to `Warn`. /// /// ### Example - /// ```rust + /// ```no_run /// # let x = 1; /// let x = &x; /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let x = 1; /// let y = &x; // use different variable name /// ``` @@ -49,12 +49,12 @@ declare_clippy_lint! { /// the code. /// /// ### Example - /// ```rust + /// ```no_run /// let x = 2; /// let x = x + 1; /// ``` /// use different variable name: - /// ```rust + /// ```no_run /// let x = 2; /// let y = x + 1; /// ``` @@ -77,7 +77,7 @@ declare_clippy_lint! { /// names to bindings or introducing more scopes to contain the bindings. /// /// ### Example - /// ```rust + /// ```no_run /// # let y = 1; /// # let z = 2; /// let x = y; @@ -85,7 +85,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let y = 1; /// # let z = 2; /// let x = y; diff --git a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs index 4b248c9c7..57bcee1a8 100644 --- a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs +++ b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs @@ -236,9 +236,13 @@ impl<'ap, 'lc, 'others, 'stmt, 'tcx> StmtsChecker<'ap, 'lc, 'others, 'stmt, 'tcx fn manage_has_expensive_expr_after_last_attr(&mut self) { let has_expensive_stmt = match self.ap.curr_stmt.kind { hir::StmtKind::Expr(expr) if is_inexpensive_expr(expr) => false, - hir::StmtKind::Local(local) if let Some(expr) = local.init - && let hir::ExprKind::Path(_) = expr.kind => false, - _ => true + hir::StmtKind::Local(local) + if let Some(expr) = local.init + && let hir::ExprKind::Path(_) = expr.kind => + { + false + }, + _ => true, }; if has_expensive_stmt { for apa in self.ap.apas.values_mut() { @@ -292,8 +296,7 @@ impl<'ap, 'lc, 'others, 'stmt, 'tcx> Visitor<'tcx> for StmtsChecker<'ap, 'lc, 'o && { if let Some(local_hir_id) = path_to_local(expr) { local_hir_id == hir_id - } - else { + } else { true } } @@ -306,8 +309,7 @@ impl<'ap, 'lc, 'others, 'stmt, 'tcx> Visitor<'tcx> for StmtsChecker<'ap, 'lc, 'o let expr_or_init = expr_or_init(self.cx, expr); if let hir::ExprKind::MethodCall(_, local_expr, _, span) = expr_or_init.kind { local_expr.span.to(span) - } - else { + } else { expr_or_init.span } }, @@ -317,8 +319,12 @@ impl<'ap, 'lc, 'others, 'stmt, 'tcx> Visitor<'tcx> for StmtsChecker<'ap, 'lc, 'o modify_apa_params(&mut apa); let _ = self.ap.apas.insert(hir_id, apa); } else { - let Some(hir_id) = path_to_local(expr) else { return; }; - let Some(apa) = self.ap.apas.get_mut(&hir_id) else { return; }; + let Some(hir_id) = path_to_local(expr) else { + return; + }; + let Some(apa) = self.ap.apas.get_mut(&hir_id) else { + return; + }; match self.ap.curr_stmt.kind { hir::StmtKind::Local(local) => { if let hir::PatKind::Binding(_, _, ident, _) = local.pat.kind { @@ -437,19 +443,20 @@ fn has_drop(expr: &hir::Expr<'_>, first_bind_ident: &Ident, lcx: &LateContext<'_ { let has_ident = |local_expr: &hir::Expr<'_>| { if let hir::ExprKind::Path(hir::QPath::Resolved(_, arg_path)) = &local_expr.kind - && let [first_arg_ps, .. ] = arg_path.segments + && let [first_arg_ps, ..] = arg_path.segments && &first_arg_ps.ident == first_bind_ident { true - } - else { + } else { false } }; if has_ident(first_arg) { return true; } - if let hir::ExprKind::Tup(value) = &first_arg.kind && value.iter().any(has_ident) { + if let hir::ExprKind::Tup(value) = &first_arg.kind + && value.iter().any(has_ident) + { return true; } } diff --git a/src/tools/clippy/clippy_lints/src/single_call_fn.rs b/src/tools/clippy/clippy_lints/src/single_call_fn.rs index 7bbe98e0a..0492df68d 100644 --- a/src/tools/clippy/clippy_lints/src/single_call_fn.rs +++ b/src/tools/clippy/clippy_lints/src/single_call_fn.rs @@ -23,7 +23,7 @@ declare_clippy_lint! { /// Note: If this lint is used, prepare to allow this a lot. /// /// ### Example - /// ```rust + /// ```no_run /// pub fn a<T>(t: &T) /// where /// T: AsRef<str>, @@ -37,7 +37,7 @@ declare_clippy_lint! { /// /// ``` /// Use instead: - /// ```rust + /// ```no_run /// pub fn a<T>(t: &T) /// where /// T: AsRef<str>, @@ -72,8 +72,8 @@ impl<'tcx> LateLintPass<'tcx> for SingleCallFn { ) { if self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(def_id) || in_external_macro(cx.sess(), span) - || is_from_proc_macro(cx, &(&kind, body, cx.tcx.local_def_id_to_hir_id(def_id), span)) || is_in_test_function(cx.tcx, body.value.hir_id) + || is_from_proc_macro(cx, &(&kind, body, cx.tcx.local_def_id_to_hir_id(def_id), span)) { return; } diff --git a/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs b/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs index 3dc995e2f..74ee8ce2d 100644 --- a/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs +++ b/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs @@ -22,13 +22,13 @@ declare_clippy_lint! { /// be obvious or, rarely, expressible in one character. /// /// ### Example - /// ```rust + /// ```no_run /// struct DiagnosticCtx<'a> { /// source: &'a str, /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// struct DiagnosticCtx<'src> { /// source: &'src str, /// } diff --git a/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs b/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs index 321c89889..099743d22 100644 --- a/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs +++ b/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs @@ -21,11 +21,11 @@ declare_clippy_lint! { /// the end of the range to be the length instead. /// /// ### Example - /// ```rust + /// ```no_run /// let x = [0..200]; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// // If it was intended to include every element in the range... /// let x = (0..200).collect::<Vec<i32>>(); /// // ...Or if 200 was meant to be the len diff --git a/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs b/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs index bd783b4e0..b940cac60 100644 --- a/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs +++ b/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs @@ -2,7 +2,6 @@ //! expecting a count of T use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -67,16 +66,6 @@ fn get_pointee_ty_and_count_expr<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, ) -> Option<(Ty<'tcx>, &'tcx Expr<'tcx>)> { - const FUNCTIONS: [&[&str]; 8] = [ - &paths::PTR_COPY_NONOVERLAPPING, - &paths::PTR_COPY, - &paths::PTR_WRITE_BYTES, - &paths::PTR_SWAP_NONOVERLAPPING, - &paths::PTR_SLICE_FROM_RAW_PARTS, - &paths::PTR_SLICE_FROM_RAW_PARTS_MUT, - &paths::SLICE_FROM_RAW_PARTS, - &paths::SLICE_FROM_RAW_PARTS_MUT, - ]; const METHODS: [&str; 11] = [ "write_bytes", "copy_to", @@ -97,7 +86,16 @@ fn get_pointee_ty_and_count_expr<'tcx>( if let ExprKind::Call(func, [.., count]) = expr.kind; if let ExprKind::Path(ref func_qpath) = func.kind; if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id(); - if FUNCTIONS.iter().any(|func_path| match_def_path(cx, def_id, func_path)); + if matches!(cx.tcx.get_diagnostic_name(def_id), Some( + sym::ptr_copy + | sym::ptr_copy_nonoverlapping + | sym::ptr_slice_from_raw_parts + | sym::ptr_slice_from_raw_parts_mut + | sym::ptr_swap_nonoverlapping + | sym::ptr_write_bytes + | sym::slice_from_raw_parts + | sym::slice_from_raw_parts_mut + )); // Get the pointee type if let Some(pointee_ty) = cx.typeck_results().node_args(func.hir_id).types().next(); diff --git a/src/tools/clippy/clippy_lints/src/size_of_ref.rs b/src/tools/clippy/clippy_lints/src/size_of_ref.rs index 89ac8cd8c..7de029b7b 100644 --- a/src/tools/clippy/clippy_lints/src/size_of_ref.rs +++ b/src/tools/clippy/clippy_lints/src/size_of_ref.rs @@ -19,7 +19,7 @@ declare_clippy_lint! { /// the reference. /// /// ### Example - /// ```rust + /// ```no_run /// struct Foo { /// buffer: [u8], /// } @@ -35,7 +35,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// struct Foo { /// buffer: [u8], /// } diff --git a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs index 9db18c297..2244eab96 100644 --- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs +++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs @@ -31,7 +31,7 @@ declare_clippy_lint! { /// The `resize` call first allocates memory (since `Vec::new()` did not), and only *then* zero-initializes it. /// /// ### Example - /// ```rust + /// ```no_run /// # use core::iter::repeat; /// # let len = 4; /// let mut vec1 = Vec::new(); @@ -45,7 +45,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let len = 4; /// let mut vec1 = vec![0; len]; /// let mut vec2 = vec![0; len]; @@ -335,7 +335,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VectorInitializationVisitor<'a, 'tcx> { fn visit_block(&mut self, block: &'tcx Block<'_>) { if self.initialization_found { - if let Some(s) = block.stmts.get(0) { + if let Some(s) = block.stmts.first() { self.visit_stmt(s); } diff --git a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs index 5f54a10d1..d07a44770 100644 --- a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs +++ b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs @@ -1,9 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_from_proc_macro; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::def_id::DefId; use rustc_hir::{HirId, Path, PathSegment}; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::symbol::kw; use rustc_span::{sym, Span}; @@ -20,11 +22,11 @@ declare_clippy_lint! { /// migrating to become `no_std` compatible. /// /// ### Example - /// ```rust + /// ```no_run /// use std::hash::Hasher; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use core::hash::Hasher; /// ``` #[clippy::version = "1.64.0"] @@ -45,11 +47,11 @@ declare_clippy_lint! { /// for crates migrating to become `no_std` compatible. /// /// ### Example - /// ```rust + /// ```no_run /// use std::vec::Vec; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # extern crate alloc; /// use alloc::vec::Vec; /// ``` @@ -71,12 +73,12 @@ declare_clippy_lint! { /// is also useful for crates migrating to become `no_std` compatible. /// /// ### Example - /// ```rust + /// ```no_run /// # extern crate alloc; /// use alloc::slice::from_ref; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use core::slice::from_ref; /// ``` #[clippy::version = "1.64.0"] @@ -99,19 +101,13 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports { if let Res::Def(_, def_id) = path.res && let Some(first_segment) = get_first_segment(path) && is_stable(cx, def_id) + && !in_external_macro(cx.sess(), path.span) + && !is_from_proc_macro(cx, &first_segment.ident) { let (lint, used_mod, replace_with) = match first_segment.ident.name { sym::std => match cx.tcx.crate_name(def_id.krate) { - sym::core => ( - STD_INSTEAD_OF_CORE, - "std", - "core", - ), - sym::alloc => ( - STD_INSTEAD_OF_ALLOC, - "std", - "alloc", - ), + sym::core => (STD_INSTEAD_OF_CORE, "std", "core"), + sym::alloc => (STD_INSTEAD_OF_ALLOC, "std", "alloc"), _ => { self.prev_span = path.span; return; @@ -119,11 +115,7 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports { }, sym::alloc => { if cx.tcx.crate_name(def_id.krate) == sym::core { - ( - ALLOC_INSTEAD_OF_CORE, - "alloc", - "core", - ) + (ALLOC_INSTEAD_OF_CORE, "alloc", "core") } else { self.prev_span = path.span; return; @@ -139,7 +131,8 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports { &format!("used import from `{used_mod}` instead of `{replace_with}`"), &format!("consider importing the item from `{replace_with}`"), replace_with.to_string(), - Applicability::MachineApplicable); + Applicability::MachineApplicable, + ); self.prev_span = path.span; } } diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs index 76f463fff..a44adc938 100644 --- a/src/tools/clippy/clippy_lints/src/strings.rs +++ b/src/tools/clippy/clippy_lints/src/strings.rs @@ -26,7 +26,7 @@ declare_clippy_lint! { /// `.push_str(_)` method is more readable. /// /// ### Example - /// ```rust + /// ```no_run /// let mut x = "Hello".to_owned(); /// x = x + ", World"; /// @@ -58,13 +58,13 @@ declare_clippy_lint! { /// particular lint `allow` by default. /// /// ### Example - /// ```rust + /// ```no_run /// let x = "Hello".to_owned(); /// x + ", World"; /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let mut x = "Hello".to_owned(); /// x.push_str(", World"); /// ``` @@ -106,12 +106,12 @@ declare_clippy_lint! { /// more readable than a function call. /// /// ### Example - /// ```rust + /// ```no_run /// let bstr = "a byte string".as_bytes(); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let bstr = b"a byte string"; /// ``` #[clippy::version = "pre 1.29.0"] @@ -231,12 +231,12 @@ declare_clippy_lint! { /// It's unnecessary, the string can be used directly. /// /// ### Example - /// ```rust + /// ```no_run /// std::str::from_utf8(&"Hello World!".as_bytes()[6..11]).unwrap(); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// &"Hello World!"[6..11]; /// ``` #[clippy::version = "1.50.0"] @@ -387,12 +387,12 @@ declare_clippy_lint! { /// expressed with `.to_owned()`. /// /// ### Example - /// ```rust + /// ```no_run /// // example code where clippy issues a warning /// let _ = "str".to_string(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// // example code which does not raise clippy warning /// let _ = "str".to_owned(); /// ``` @@ -435,13 +435,13 @@ declare_clippy_lint! { /// When called on a `String` it only clones the `String`, which can be better expressed with `.clone()`. /// /// ### Example - /// ```rust + /// ```no_run /// // example code where clippy issues a warning /// let msg = String::from("Hello World"); /// let _ = msg.to_string(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// // example code which does not raise clippy warning /// let msg = String::from("Hello World"); /// let _ = msg.clone(); @@ -483,11 +483,11 @@ declare_clippy_lint! { /// `split_whitespace` already ignores leading and trailing whitespace. /// /// ### Example - /// ```rust + /// ```no_run /// " A B C ".trim().split_whitespace(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// " A B C ".split_whitespace(); /// ``` #[clippy::version = "1.62.0"] diff --git a/src/tools/clippy/clippy_lints/src/suspicious_doc_comments.rs b/src/tools/clippy/clippy_lints/src/suspicious_doc_comments.rs index 8be4ec3dc..0abc199da 100644 --- a/src/tools/clippy/clippy_lints/src/suspicious_doc_comments.rs +++ b/src/tools/clippy/clippy_lints/src/suspicious_doc_comments.rs @@ -32,7 +32,7 @@ declare_clippy_lint! { /// /// ### Example /// In this example, the doc comment is attached to the *function*, rather than the *module*. - /// ```rust + /// ```no_run /// pub mod util { /// ///! This module contains utility functions. /// @@ -41,7 +41,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// pub mod util { /// //! This module contains utility functions. /// diff --git a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs index d10f10ef8..bb8cde5b9 100644 --- a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs +++ b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs @@ -28,7 +28,7 @@ declare_clippy_lint! { /// unusual that happens to look like a typo. /// /// ### Example - /// ```rust + /// ```no_run /// struct Vec3 { /// x: f64, /// y: f64, @@ -45,7 +45,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # struct Vec3 { /// # x: f64, /// # y: f64, @@ -578,7 +578,7 @@ fn ident_difference_expr_with_base_location( | (Assign(_, _, _), Assign(_, _, _)) | (TryBlock(_), TryBlock(_)) | (Await(_, _), Await(_, _)) - | (Async(_, _), Async(_, _)) + | (Gen(_, _, _), Gen(_, _, _)) | (Block(_, _), Block(_, _)) | (Closure(_), Closure(_)) | (Match(_, _), Match(_, _)) diff --git a/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs b/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs index 8e156b882..4340c23f8 100644 --- a/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs +++ b/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs @@ -14,11 +14,11 @@ declare_clippy_lint! { /// ### Why is this bad? /// It's most probably a typo and may lead to unexpected behaviours. /// ### Example - /// ```rust + /// ```no_run /// let x = 3_i32 ^ 4_i32; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let x = 3_i32.pow(4); /// ``` #[clippy::version = "1.67.0"] @@ -33,26 +33,23 @@ impl LateLintPass<'_> for ConfusingXorAndPow { if !in_external_macro(cx.sess(), expr.span) && let ExprKind::Binary(op, left, right) = &expr.kind && op.node == BinOpKind::BitXor - && left.span.ctxt() == right.span.ctxt() + && left.span.eq_ctxt(right.span) && let ExprKind::Lit(lit_left) = &left.kind && let ExprKind::Lit(lit_right) = &right.kind && matches!(lit_right.node, LitKind::Int(..) | LitKind::Float(..)) && matches!(lit_left.node, LitKind::Int(..) | LitKind::Float(..)) - && NumericLiteral::from_lit_kind(&snippet(cx, lit_right.span, ".."), &lit_right.node).is_some_and(|x| x.is_decimal()) - { - span_lint_and_sugg( - cx, - SUSPICIOUS_XOR_USED_AS_POW, - expr.span, - "`^` is not the exponentiation operator", - "did you mean to write", - format!( - "{}.pow({})", - lit_left.node, - lit_right.node - ), - Applicability::MaybeIncorrect, - ); - } + && NumericLiteral::from_lit_kind(&snippet(cx, lit_right.span, ".."), &lit_right.node) + .is_some_and(|x| x.is_decimal()) + { + span_lint_and_sugg( + cx, + SUSPICIOUS_XOR_USED_AS_POW, + expr.span, + "`^` is not the exponentiation operator", + "did you mean to write", + format!("{}.pow({})", lit_left.node, lit_right.node), + Applicability::MaybeIncorrect, + ); + } } } diff --git a/src/tools/clippy/clippy_lints/src/swap.rs b/src/tools/clippy/clippy_lints/src/swap.rs index 548fabb8b..660e6835e 100644 --- a/src/tools/clippy/clippy_lints/src/swap.rs +++ b/src/tools/clippy/clippy_lints/src/swap.rs @@ -25,7 +25,7 @@ declare_clippy_lint! { /// without deinitializing or copying either variable. /// /// ### Example - /// ```rust + /// ```no_run /// let mut a = 42; /// let mut b = 1337; /// @@ -34,7 +34,7 @@ declare_clippy_lint! { /// a = t; /// ``` /// Use std::mem::swap(): - /// ```rust + /// ```no_run /// let mut a = 1; /// let mut b = 2; /// std::mem::swap(&mut a, &mut b); @@ -53,14 +53,14 @@ declare_clippy_lint! { /// This looks like a failed attempt to swap. /// /// ### Example - /// ```rust + /// ```no_run /// # let mut a = 1; /// # let mut b = 2; /// a = b; /// b = a; /// ``` /// If swapping is intended, use `swap()` instead: - /// ```rust + /// ```no_run /// # let mut a = 1; /// # let mut b = 2; /// std::mem::swap(&mut a, &mut b); @@ -232,7 +232,7 @@ fn is_same(cx: &LateContext<'_>, lhs: ExprOrIdent<'_>, rhs: &Expr<'_>) -> bool { } else { false } - } + }, } } diff --git a/src/tools/clippy/clippy_lints/src/swap_ptr_to_ref.rs b/src/tools/clippy/clippy_lints/src/swap_ptr_to_ref.rs index d085dda35..6a6c94425 100644 --- a/src/tools/clippy/clippy_lints/src/swap_ptr_to_ref.rs +++ b/src/tools/clippy/clippy_lints/src/swap_ptr_to_ref.rs @@ -1,11 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::path_def_id; use clippy_utils::source::snippet_with_context; -use clippy_utils::{match_def_path, path_def_id, paths}; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::{Span, SyntaxContext}; +use rustc_span::{sym, Span, SyntaxContext}; declare_clippy_lint! { /// ### What it does @@ -16,7 +16,7 @@ declare_clippy_lint! { /// other. This would then lead to undefined behavior. /// /// ### Example - /// ```rust + /// ```no_run /// unsafe fn swap(x: &[*mut u32], y: &[*mut u32]) { /// for (&x, &y) in x.iter().zip(y) { /// core::mem::swap(&mut *x, &mut *y); @@ -24,7 +24,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// unsafe fn swap(x: &[*mut u32], y: &[*mut u32]) { /// for (&x, &y) in x.iter().zip(y) { /// core::ptr::swap(x, y); @@ -42,7 +42,7 @@ impl LateLintPass<'_> for SwapPtrToRef { fn check_expr(&mut self, cx: &LateContext<'_>, e: &Expr<'_>) { if let ExprKind::Call(fn_expr, [arg1, arg2]) = e.kind && let Some(fn_id) = path_def_id(cx, fn_expr) - && match_def_path(cx, fn_id, &paths::MEM_SWAP) + && cx.tcx.is_diagnostic_item(sym::mem_swap, fn_id) && let ctxt = e.span.ctxt() && let (from_ptr1, arg1_span) = is_ptr_to_ref(cx, arg1, ctxt) && let (from_ptr2, arg2_span) = is_ptr_to_ref(cx, arg2, ctxt) @@ -58,9 +58,14 @@ impl LateLintPass<'_> for SwapPtrToRef { let mut app = Applicability::MachineApplicable; let snip1 = snippet_with_context(cx, arg1_span.unwrap_or(arg1.span), ctxt, "..", &mut app).0; let snip2 = snippet_with_context(cx, arg2_span.unwrap_or(arg2.span), ctxt, "..", &mut app).0; - diag.span_suggestion(e.span, "use ptr::swap", format!("core::ptr::swap({snip1}, {snip2})"), app); + diag.span_suggestion( + e.span, + "use ptr::swap", + format!("core::ptr::swap({snip1}, {snip2})"), + app, + ); } - } + }, ); } } @@ -73,7 +78,10 @@ fn is_ptr_to_ref(cx: &LateContext<'_>, e: &Expr<'_>, ctxt: SyntaxContext) -> (bo && let ExprKind::Unary(UnOp::Deref, derefed_expr) = borrowed_expr.kind && cx.typeck_results().expr_ty(derefed_expr).is_unsafe_ptr() { - (true, (borrowed_expr.span.ctxt() == ctxt || derefed_expr.span.ctxt() == ctxt).then_some(derefed_expr.span)) + ( + true, + (borrowed_expr.span.ctxt() == ctxt || derefed_expr.span.ctxt() == ctxt).then_some(derefed_expr.span), + ) } else { (false, None) } diff --git a/src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs b/src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs index e223aea29..dcf1fac02 100644 --- a/src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs +++ b/src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs @@ -3,7 +3,7 @@ use rustc_ast::ast; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::{BytePos, Span}; +use rustc_span::{BytePos, Span}; declare_clippy_lint! { /// ### What it does @@ -16,7 +16,7 @@ declare_clippy_lint! { /// display settings of the author and reader differ. /// /// ### Example - /// ```rust + /// ```no_run /// /// /// /// Struct to hold two strings: /// /// - first one @@ -34,7 +34,7 @@ declare_clippy_lint! { /// ``` /// /// Will be converted to: - /// ```rust + /// ```no_run /// /// /// /// Struct to hold two strings: /// /// - first one diff --git a/src/tools/clippy/clippy_lints/src/temporary_assignment.rs b/src/tools/clippy/clippy_lints/src/temporary_assignment.rs index b6b653f66..c717ccc35 100644 --- a/src/tools/clippy/clippy_lints/src/temporary_assignment.rs +++ b/src/tools/clippy/clippy_lints/src/temporary_assignment.rs @@ -14,7 +14,7 @@ declare_clippy_lint! { /// updated, why not write the structure you want in the first place? /// /// ### Example - /// ```rust + /// ```no_run /// (0, 0).0 = 1 /// ``` #[clippy::version = "pre 1.29.0"] diff --git a/src/tools/clippy/clippy_lints/src/tests_outside_test_module.rs b/src/tools/clippy/clippy_lints/src/tests_outside_test_module.rs index b356666d8..0cfb1c125 100644 --- a/src/tools/clippy/clippy_lints/src/tests_outside_test_module.rs +++ b/src/tools/clippy/clippy_lints/src/tests_outside_test_module.rs @@ -15,7 +15,7 @@ declare_clippy_lint! { /// The idiomatic (and more performant) way of writing tests is inside a testing module (flagged with `#[cfg(test)]`), /// having test functions outside of this module is confusing and may lead to them being "hidden". /// ### Example - /// ```rust + /// ```no_run /// #[test] /// fn my_cool_test() { /// // [...] @@ -28,7 +28,7 @@ declare_clippy_lint! { /// /// ``` /// Use instead: - /// ```rust + /// ```no_run /// #[cfg(test)] /// mod tests { /// #[test] diff --git a/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs b/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs index f1b703fde..a171d225f 100644 --- a/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs +++ b/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs @@ -17,13 +17,13 @@ declare_clippy_lint! { /// more straight forward to use the dedicated `is_digit` method. /// /// ### Example - /// ```rust + /// ```no_run /// # let c = 'c'; /// # let radix = 10; /// let is_digit = c.to_digit(radix).is_some(); /// ``` /// can be written as: - /// ``` + /// ```no_run /// # let c = 'c'; /// # let radix = 10; /// let is_digit = c.is_digit(radix); diff --git a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs index bb9da3a20..87181adc2 100644 --- a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs +++ b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs @@ -13,7 +13,7 @@ declare_clippy_lint! { /// Zero-sized arrays aren't very useful in Rust itself, so such a struct is likely being created to pass to C code or in some other situation where control over memory layout matters (for example, in conjunction with manual allocation to make it easy to compute the offset of the array). Either way, `#[repr(C)]` (or another `repr` attribute) is needed. /// /// ### Example - /// ```rust + /// ```no_run /// struct RarelyUseful { /// some_field: u32, /// last: [u32; 0], @@ -21,7 +21,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// #[repr(C)] /// struct MoreOftenUseful { /// some_field: usize, diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs index 6db330dfa..f065d215e 100644 --- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs +++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs @@ -1,5 +1,5 @@ +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::{snippet, snippet_opt, snippet_with_applicability}; use clippy_utils::{is_from_proc_macro, SpanlessEq, SpanlessHash}; use core::hash::{Hash, Hasher}; @@ -27,12 +27,12 @@ declare_clippy_lint! { /// less readable than combining the bounds /// /// ### Example - /// ```rust + /// ```no_run /// pub fn foo<T>(t: T) where T: Copy, T: Clone {} /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// pub fn foo<T>(t: T) where T: Copy + Clone {} /// ``` #[clippy::version = "1.38.0"] @@ -51,12 +51,12 @@ declare_clippy_lint! { /// less readable than specifying them only once. /// /// ### Example - /// ```rust + /// ```no_run /// fn func<T: Clone + Default>(arg: T) where T: Clone + Default {} /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # mod hidden { /// fn func<T: Clone + Default>(arg: T) {} /// # } @@ -66,19 +66,19 @@ declare_clippy_lint! { /// fn func<T>(arg: T) where T: Clone + Default {} /// ``` /// - /// ```rust + /// ```no_run /// fn foo<T: Default + Default>(bar: T) {} /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn foo<T: Default>(bar: T) {} /// ``` /// - /// ```rust + /// ```no_run /// fn foo<T>(bar: T) where T: Default + Default {} /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn foo<T>(bar: T) where T: Default {} /// ``` #[clippy::version = "1.47.0"] diff --git a/src/tools/clippy/clippy_lints/src/transmute/mod.rs b/src/tools/clippy/clippy_lints/src/transmute/mod.rs index 0dc30f7a9..6eec40cb5 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/mod.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/mod.rs @@ -17,8 +17,8 @@ mod useless_transmute; mod utils; mod wrong_transmute; +use clippy_config::msrvs::Msrv; use clippy_utils::in_constant; -use clippy_utils::msrvs::Msrv; use if_chain::if_chain; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; @@ -78,12 +78,12 @@ declare_clippy_lint! { /// /// ### Example /// - /// ```rust + /// ```no_run /// # let p: *const [i32] = &[]; /// unsafe { std::mem::transmute::<*const [i32], *const [u16]>(p) }; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # let p: *const [i32] = &[]; /// p as *const [u16]; /// ``` @@ -159,7 +159,7 @@ declare_clippy_lint! { /// [`from_u32_unchecked`]: https://doc.rust-lang.org/std/char/fn.from_u32_unchecked.html /// /// ### Example - /// ```rust + /// ```no_run /// let x = 1_u32; /// unsafe { /// let _: char = std::mem::transmute(x); // where x: u32 @@ -193,7 +193,7 @@ declare_clippy_lint! { /// [`from_utf8_unchecked`]: https://doc.rust-lang.org/std/str/fn.from_utf8_unchecked.html /// /// ### Example - /// ```rust + /// ```no_run /// let b: &[u8] = &[1_u8, 2_u8]; /// unsafe { /// let _: &str = std::mem::transmute(b); // where b: &[u8] @@ -216,7 +216,7 @@ declare_clippy_lint! { /// This might result in an invalid in-memory representation of a `bool`. /// /// ### Example - /// ```rust + /// ```no_run /// let x = 1_u8; /// unsafe { /// let _: bool = std::mem::transmute(x); // where x: u8 @@ -240,7 +240,7 @@ declare_clippy_lint! { /// and safe. /// /// ### Example - /// ```rust + /// ```no_run /// unsafe { /// let _: f32 = std::mem::transmute(1_u32); // where x: u32 /// } @@ -264,12 +264,12 @@ declare_clippy_lint! { /// elsewhere. `new_unchecked` only works for the appropriate types instead. /// /// ### Example - /// ```rust + /// ```no_run /// # use core::num::NonZeroU32; /// let _non_zero: NonZeroU32 = unsafe { std::mem::transmute(123) }; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # use core::num::NonZeroU32; /// let _non_zero = unsafe { NonZeroU32::new_unchecked(123) }; /// ``` @@ -288,7 +288,7 @@ declare_clippy_lint! { /// and safe. /// /// ### Example - /// ```rust + /// ```no_run /// unsafe { /// let _: u32 = std::mem::transmute(1f32); /// } @@ -311,7 +311,7 @@ declare_clippy_lint! { /// is intuitive and safe. /// /// ### Example - /// ```rust + /// ```no_run /// unsafe { /// let x: [u8; 8] = std::mem::transmute(1i64); /// } @@ -335,7 +335,7 @@ declare_clippy_lint! { /// written as casts. /// /// ### Example - /// ```rust + /// ```no_run /// let ptr = &1u32 as *const u32; /// unsafe { /// // pointer-to-pointer transmute @@ -366,7 +366,7 @@ declare_clippy_lint! { /// collection, so we just lint the ones that come with `std`. /// /// ### Example - /// ```rust + /// ```no_run /// // different size, therefore likely out-of-bounds memory access /// // You absolutely do not want this in your code! /// unsafe { @@ -376,7 +376,7 @@ declare_clippy_lint! { /// /// You must always iterate, map and collect the values: /// - /// ```rust + /// ```no_run /// vec![2_u16].into_iter().map(u32::from).collect::<Vec<_>>(); /// ``` #[clippy::version = "1.40.0"] @@ -398,12 +398,12 @@ declare_clippy_lint! { /// [#8496](https://github.com/rust-lang/rust-clippy/issues/8496) for more details. /// /// ### Example - /// ```rust + /// ```no_run /// struct Foo<T>(u32, T); /// let _ = unsafe { core::mem::transmute::<Foo<u32>, Foo<i32>>(Foo(0u32, 0u32)) }; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// #[repr(C)] /// struct Foo<T>(u32, T); /// let _ = unsafe { core::mem::transmute::<Foo<u32>, Foo<i32>>(Foo(0u32, 0u32)) }; @@ -427,7 +427,7 @@ declare_clippy_lint! { /// call, aren't detectable yet. /// /// ### Example - /// ```rust + /// ```no_run /// let null_ref: &u64 = unsafe { std::mem::transmute(0 as *const u64) }; /// ``` #[clippy::version = "1.35.0"] @@ -451,11 +451,11 @@ declare_clippy_lint! { /// call, aren't detectable yet. /// /// ### Example - /// ```rust + /// ```no_run /// let null_fn: fn() = unsafe { std::mem::transmute( std::ptr::null::<()>() ) }; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let null_fn: Option<fn()> = None; /// ``` #[clippy::version = "1.68.0"] diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs index 6bdb9aa5a..4ab3afbe7 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs +++ b/src/tools/clippy/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/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs index c61eb0a93..7c2223ca3 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs @@ -98,17 +98,17 @@ pub(super) fn check<'tcx>( }, (ReducedTy::UnorderedFields(from_ty), ReducedTy::UnorderedFields(to_ty)) if from_ty != to_ty => { - let same_adt_did = if let (ty::Adt(from_def, from_subs), ty::Adt(to_def, to_subs)) - = (from_ty.kind(), to_ty.kind()) - && from_def == to_def - { - if same_except_params(from_subs, to_subs) { - return false; - } - Some(from_def.did()) - } else { - None - }; + let same_adt_did = if let (ty::Adt(from_def, from_subs), ty::Adt(to_def, to_subs)) = + (from_ty.kind(), to_ty.kind()) + && from_def == to_def + { + if same_except_params(from_subs, to_subs) { + return false; + } + Some(from_def.did()) + } else { + None + }; span_lint_and_then( cx, TRANSMUTE_UNDEFINED_REPR, diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs b/src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs index 770914e99..471bd44b5 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs @@ -16,8 +16,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t } // Catching transmute over constants that resolve to `null`. - if let ExprKind::Path(ref _qpath) = arg.kind && - let Some(Constant::RawPtr(0)) = constant(cx, cx.typeck_results(), arg) + if let ExprKind::Path(ref _qpath) = arg.kind + && let Some(Constant::RawPtr(0)) = constant(cx, cx.typeck_results(), arg) { span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG); return true; @@ -25,15 +25,17 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t // Catching: // `std::mem::transmute(0 as *const i32)` - if let ExprKind::Cast(inner_expr, _cast_ty) = arg.kind && is_integer_literal(inner_expr, 0) { + if let ExprKind::Cast(inner_expr, _cast_ty) = arg.kind + && is_integer_literal(inner_expr, 0) + { span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG); return true; } // Catching: // `std::mem::transmute(std::ptr::null::<i32>())` - if let ExprKind::Call(func1, []) = arg.kind && - is_path_diagnostic_item(cx, func1, sym::ptr_null) + if let ExprKind::Call(func1, []) = arg.kind + && is_path_diagnostic_item(cx, func1, sym::ptr_null) { span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG); return true; diff --git a/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs b/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs index c12519d72..642e39e82 100644 --- a/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs +++ b/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs @@ -1,5 +1,5 @@ +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/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs index 71a4b3fba..6a6160c49 100644 --- a/src/tools/clippy/clippy_lints/src/types/mod.rs +++ b/src/tools/clippy/clippy_lints/src/types/mod.rs @@ -18,7 +18,7 @@ use rustc_hir::{ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::def_id::LocalDefId; -use rustc_span::source_map::Span; +use rustc_span::Span; declare_clippy_lint! { /// ### What it does @@ -64,7 +64,7 @@ declare_clippy_lint! { /// 1st comment). /// /// ### Example - /// ```rust + /// ```no_run /// struct X { /// values: Vec<Box<i32>>, /// } @@ -72,7 +72,7 @@ declare_clippy_lint! { /// /// Better: /// - /// ```rust + /// ```no_run /// struct X { /// values: Vec<i32>, /// } @@ -97,7 +97,7 @@ declare_clippy_lint! { /// consider a custom `enum` instead, with clear names for each case. /// /// ### Example - /// ```rust + /// ```no_run /// fn get_data() -> Option<Option<u32>> { /// None /// } @@ -105,7 +105,7 @@ declare_clippy_lint! { /// /// Better: /// - /// ```rust + /// ```no_run /// pub enum Contents { /// Data(Vec<u8>), // Was Some(Some(Vec<u8>)) /// NotYetFetched, // Was Some(None) @@ -152,7 +152,7 @@ declare_clippy_lint! { /// `LinkedList` makes sense are few and far between, but they can still happen. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::collections::LinkedList; /// let x: LinkedList<usize> = LinkedList::new(); /// ``` @@ -197,14 +197,14 @@ declare_clippy_lint! { /// `Arc<Arc<T>>`, `Arc<Box<T>>`, `Box<&T>`, `Box<Rc<T>>`, `Box<Arc<T>>`, `Box<Box<T>>`, add an unnecessary level of indirection. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::rc::Rc; /// fn foo(bar: Rc<&usize>) {} /// ``` /// /// Better: /// - /// ```rust + /// ```no_run /// fn foo(bar: &usize) {} /// ``` #[clippy::version = "1.44.0"] @@ -258,7 +258,7 @@ declare_clippy_lint! { /// using a `type` definition to simplify them. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::rc::Rc; /// struct Foo { /// inner: Rc<Vec<Vec<Box<(u32, u32, u32, u32)>>>>, @@ -578,7 +578,7 @@ impl Types { } } -#[allow(clippy::struct_excessive_bools)] +#[allow(clippy::struct_excessive_bools, clippy::struct_field_names)] #[derive(Clone, Copy, Default)] struct CheckTyContext { is_in_trait_impl: bool, diff --git a/src/tools/clippy/clippy_lints/src/types/utils.rs b/src/tools/clippy/clippy_lints/src/types/utils.rs index a30748db8..39469841b 100644 --- a/src/tools/clippy/clippy_lints/src/types/utils.rs +++ b/src/tools/clippy/clippy_lints/src/types/utils.rs @@ -2,7 +2,7 @@ use clippy_utils::last_path_segment; use if_chain::if_chain; use rustc_hir::{GenericArg, GenericArgsParentheses, QPath, TyKind}; use rustc_lint::LateContext; -use rustc_span::source_map::Span; +use rustc_span::Span; pub(super) fn match_borrows_parameter(_cx: &LateContext<'_>, qpath: &QPath<'_>) -> Option<Span> { let last = last_path_segment(qpath); diff --git a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs index 6193fdeb4..32aebdd8c 100644 --- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -44,14 +44,14 @@ declare_clippy_lint! { /// and bugs. /// /// ### Example - /// ```rust + /// ```no_run /// use std::ptr::NonNull; /// let a = &mut 42; /// /// let ptr = unsafe { NonNull::new_unchecked(a) }; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::ptr::NonNull; /// let a = &mut 42; /// @@ -72,7 +72,7 @@ declare_clippy_lint! { /// describe safety invariants. /// /// ### Example - /// ```rust + /// ```no_run /// use std::ptr::NonNull; /// let a = &mut 42; /// @@ -80,7 +80,7 @@ declare_clippy_lint! { /// let ptr = NonNull::new(a).unwrap(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::ptr::NonNull; /// let a = &mut 42; /// @@ -638,7 +638,9 @@ fn get_body_search_span(cx: &LateContext<'_>) -> Option<Span> { fn span_has_safety_comment(cx: &LateContext<'_>, span: Span) -> bool { let source_map = cx.sess().source_map(); let ctxt = span.ctxt(); - if ctxt.is_root() && let Some(search_span) = get_body_search_span(cx) { + if ctxt.is_root() + && let Some(search_span) = get_body_search_span(cx) + { if let Ok(unsafe_line) = source_map.lookup_line(span.lo()) && let Some(body_span) = walk_span_to_context(search_span, SyntaxContext::root()) && let Ok(body_line) = source_map.lookup_line(body_span.lo()) @@ -648,11 +650,13 @@ fn span_has_safety_comment(cx: &LateContext<'_>, span: Span) -> bool { // Get the text from the start of function body to the unsafe block. // fn foo() { some_stuff; unsafe { stuff }; other_stuff; } // ^-------------^ - body_line.line < unsafe_line.line && text_has_safety_comment( - src, - &unsafe_line.sf.lines()[body_line.line + 1..=unsafe_line.line], - unsafe_line.sf.start_pos, - ).is_some() + body_line.line < unsafe_line.line + && text_has_safety_comment( + src, + &unsafe_line.sf.lines()[body_line.line + 1..=unsafe_line.line], + unsafe_line.sf.start_pos, + ) + .is_some() } else { // Problem getting source text. Pretend a comment was found. true diff --git a/src/tools/clippy/clippy_lints/src/unicode.rs b/src/tools/clippy/clippy_lints/src/unicode.rs index e275bfd37..b824deac2 100644 --- a/src/tools/clippy/clippy_lints/src/unicode.rs +++ b/src/tools/clippy/clippy_lints/src/unicode.rs @@ -7,7 +7,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, HirId}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::Span; +use rustc_span::Span; use unicode_normalization::UnicodeNormalization; declare_clippy_lint! { @@ -39,12 +39,12 @@ declare_clippy_lint! { /// requirements, activating this lint could be useful. /// /// ### Example - /// ```rust + /// ```no_run /// let x = String::from("€"); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let x = String::from("\u{20ac}"); /// ``` #[clippy::version = "pre 1.29.0"] diff --git a/src/tools/clippy/clippy_lints/src/uninit_vec.rs b/src/tools/clippy/clippy_lints/src/uninit_vec.rs index 6756df8e7..72569e10f 100644 --- a/src/tools/clippy/clippy_lints/src/uninit_vec.rs +++ b/src/tools/clippy/clippy_lints/src/uninit_vec.rs @@ -201,7 +201,7 @@ fn extract_set_len_self<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Opt let expr = peel_hir_expr_while(expr, |e| { if let ExprKind::Block(block, _) = e.kind { // Extract the first statement/expression - match (block.stmts.get(0).map(|stmt| &stmt.kind), block.expr) { + match (block.stmts.first().map(|stmt| &stmt.kind), block.expr) { (None, Some(expr)) => Some(expr), (Some(StmtKind::Expr(expr) | StmtKind::Semi(expr)), _) => Some(expr), _ => None, diff --git a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs index de4b8738e..e76cc65fd 100644 --- a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs +++ b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs @@ -25,7 +25,7 @@ declare_clippy_lint! { /// way of specifying this without triggering needless_return lint /// /// ### Example - /// ```rust + /// ```no_run /// let mut twins = vec![(1, 1), (2, 2)]; /// twins.sort_by_key(|x| { x.1; }); /// ``` diff --git a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs index e7915953d..ef67f4b04 100644 --- a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs +++ b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs @@ -24,7 +24,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>) { && expr_needs_inferred_result(cx, init) { if !matches!(local.pat.kind, PatKind::Wild) - && !matches!(local.pat.kind, PatKind::Tuple([], ddpos) if ddpos.as_opt_usize().is_none()) + && !matches!(local.pat.kind, PatKind::Tuple([], ddpos) if ddpos.as_opt_usize().is_none()) { span_lint_and_then( cx, @@ -43,7 +43,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>) { } } else { if let ExprKind::Match(_, _, MatchSource::AwaitDesugar) = init.kind { - return + return; } span_lint_and_then( @@ -55,12 +55,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>) { if let Some(expr) = &local.init { let mut app = Applicability::MachineApplicable; let snip = snippet_with_context(cx, expr.span, local.span.ctxt(), "()", &mut app).0; - diag.span_suggestion( - local.span, - "omit the `let` binding", - format!("{snip};"), - app, - ); + diag.span_suggestion(local.span, "omit the `let` binding", format!("{snip};"), app); } }, ); diff --git a/src/tools/clippy/clippy_lints/src/unit_types/mod.rs b/src/tools/clippy/clippy_lints/src/unit_types/mod.rs index 546242ebd..884c6ca4d 100644 --- a/src/tools/clippy/clippy_lints/src/unit_types/mod.rs +++ b/src/tools/clippy/clippy_lints/src/unit_types/mod.rs @@ -16,7 +16,7 @@ declare_clippy_lint! { /// binding one is kind of pointless. /// /// ### Example - /// ```rust + /// ```no_run /// let x = { /// 1; /// }; @@ -38,7 +38,7 @@ declare_clippy_lint! { /// adds semicolons at the end of the operands. /// /// ### Example - /// ```rust + /// ```no_run /// # fn foo() {}; /// # fn bar() {}; /// # fn baz() {}; @@ -51,7 +51,7 @@ declare_clippy_lint! { /// } /// ``` /// is equal to - /// ```rust + /// ```no_run /// # fn foo() {}; /// # fn bar() {}; /// # fn baz() {}; @@ -63,7 +63,7 @@ declare_clippy_lint! { /// ``` /// /// For asserts: - /// ```rust + /// ```no_run /// # fn foo() {}; /// # fn bar() {}; /// assert_eq!({ foo(); }, { bar(); }); diff --git a/src/tools/clippy/clippy_lints/src/unnamed_address.rs b/src/tools/clippy/clippy_lints/src/unnamed_address.rs index dea8a1e35..e7355f923 100644 --- a/src/tools/clippy/clippy_lints/src/unnamed_address.rs +++ b/src/tools/clippy/clippy_lints/src/unnamed_address.rs @@ -1,10 +1,10 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; -use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -16,7 +16,7 @@ declare_clippy_lint! { /// the same address after being merged together. /// /// ### Example - /// ```rust + /// ```no_run /// type F = fn(); /// fn a() {} /// let f: F = a; @@ -96,7 +96,7 @@ impl LateLintPass<'_> for UnnamedAddress { if let ExprKind::Call(func, [ref _left, ref _right]) = expr.kind; if let ExprKind::Path(ref func_qpath) = func.kind; if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id(); - if match_def_path(cx, def_id, &paths::PTR_EQ); + if cx.tcx.is_diagnostic_item(sym::ptr_eq, def_id); let ty_param = cx.typeck_results().node_args(func.hir_id).type_at(0); if ty_param.is_trait(); then { diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs b/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs index ed2ef5063..ca159eb4d 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs @@ -22,13 +22,13 @@ declare_clippy_lint! { /// `Box<T>` been dropped. /// /// ### Example - /// ```rust + /// ```no_run /// fn foo() -> Box<String> { /// Box::new(String::from("Hello, world!")) /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn foo() -> String { /// String::from("Hello, world!") /// } diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs b/src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs index 5aa057580..9107b2b99 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs @@ -9,18 +9,18 @@ use rustc_span::sym; declare_clippy_lint! { /// ### What it does - /// Suggest removing the use of a may (or map_err) method when an Option or Result is being construted. + /// Suggest removing the use of a may (or map_err) method when an Option or Result is being constructed. /// /// ### Why is this bad? /// It introduces unnecessary complexity. In this case the function can be used directly and /// construct the Option or Result from the output. /// /// ### Example - /// ```rust + /// ```no_run /// Some(4).map(i32::swap_bytes); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// Some(i32::swap_bytes(4)); /// ``` #[clippy::version = "1.73.0"] @@ -36,19 +36,20 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMapOnConstructor { return; } if let hir::ExprKind::MethodCall(path, recv, args, ..) = expr.kind - && let Some(sym::Option | sym::Result) = get_type_diagnostic_name(cx, cx.typeck_results().expr_ty(recv)){ - let (constructor_path, constructor_item) = - if let hir::ExprKind::Call(constructor, constructor_args) = recv.kind - && let hir::ExprKind::Path(constructor_path) = constructor.kind - && let Some(arg) = constructor_args.get(0) - { - if constructor.span.from_expansion() || arg.span.from_expansion() { - return; - } - (constructor_path, arg) - } else { + && let Some(sym::Option | sym::Result) = get_type_diagnostic_name(cx, cx.typeck_results().expr_ty(recv)) + { + let (constructor_path, constructor_item) = if let hir::ExprKind::Call(constructor, constructor_args) = + recv.kind + && let hir::ExprKind::Path(constructor_path) = constructor.kind + && let Some(arg) = constructor_args.first() + { + if constructor.span.from_expansion() || arg.span.from_expansion() { return; - }; + } + (constructor_path, arg) + } else { + return; + }; let constructor_symbol = match constructor_path { hir::QPath::Resolved(_, path) => { if let Some(path_segment) = path.segments.last() { @@ -66,7 +67,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMapOnConstructor { _ => return, } - if let Some(map_arg) = args.get(0) + if let Some(map_arg) = args.first() && let hir::ExprKind::Path(fun) = map_arg.kind { if map_arg.span.from_expansion() { @@ -82,7 +83,10 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMapOnConstructor { cx, UNNECESSARY_MAP_ON_CONSTRUCTOR, expr.span, - &format!("unnecessary {} on constructor {constructor_snippet}(_)", path.ident.name), + &format!( + "unnecessary {} on constructor {constructor_snippet}(_)", + path.ident.name + ), "try", format!("{constructor_snippet}({fun_snippet}({constructor_arg_snippet}))"), applicability, diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs b/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs index 57a4a429e..28ea02e4d 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs @@ -20,11 +20,11 @@ declare_clippy_lint! { /// This results in longer and less readable code /// /// ### Example - /// ```rust + /// ```no_run /// vec!["1", "2", "3"].join(&String::new()); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// vec!["1", "2", "3"].join(""); /// ``` #[clippy::version = "1.62.0"] diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_self_imports.rs b/src/tools/clippy/clippy_lints/src/unnecessary_self_imports.rs index 397633f53..a1083a0a6 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_self_imports.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_self_imports.rs @@ -19,11 +19,11 @@ declare_clippy_lint! { /// to detect this scenario and that is why it is a restriction lint. /// /// ### Example - /// ```rust + /// ```no_run /// use std::io::{self}; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::io; /// ``` #[clippy::version = "1.53.0"] diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_struct_initialization.rs b/src/tools/clippy/clippy_lints/src/unnecessary_struct_initialization.rs index f4111186c..c35a2afab 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_struct_initialization.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_struct_initialization.rs @@ -15,14 +15,14 @@ declare_clippy_lint! { /// Readability suffers from unnecessary struct building. /// /// ### Example - /// ```rust + /// ```no_run /// struct S { s: String } /// /// let a = S { s: String::from("Hello, world!") }; /// let b = S { ..a }; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// struct S { s: String } /// /// let a = S { s: String::from("Hello, world!") }; @@ -42,9 +42,9 @@ declare_lint_pass!(UnnecessaryStruct => [UNNECESSARY_STRUCT_INITIALIZATION]); impl LateLintPass<'_> for UnnecessaryStruct { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { if let ExprKind::Struct(_, &[], Some(base)) = expr.kind { - if let Some(parent) = get_parent_expr(cx, expr) && - let parent_ty = cx.typeck_results().expr_ty_adjusted(parent) && - parent_ty.is_any_ptr() + if let Some(parent) = get_parent_expr(cx, expr) + && let parent_ty = cx.typeck_results().expr_ty_adjusted(parent) + && parent_ty.is_any_ptr() { if is_copy(cx, cx.typeck_results().expr_ty(expr)) && path_to_local(base).is_some() { // When the type implements `Copy`, a reference to the new struct works on the @@ -59,9 +59,9 @@ impl LateLintPass<'_> for UnnecessaryStruct { } // TODO: do not propose to replace *XX if XX is not Copy - if let ExprKind::Unary(UnOp::Deref, target) = base.kind && - matches!(target.kind, ExprKind::Path(..)) && - !is_copy(cx, cx.typeck_results().expr_ty(expr)) + if let ExprKind::Unary(UnOp::Deref, target) = base.kind + && matches!(target.kind, ExprKind::Path(..)) + && !is_copy(cx, cx.typeck_results().expr_ty(expr)) { // `*base` cannot be used instead of the struct in the general case if it is not Copy. return; @@ -81,8 +81,8 @@ impl LateLintPass<'_> for UnnecessaryStruct { } fn is_mutable(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - if let Some(hir_id) = path_to_local(expr) && - let Node::Pat(pat) = cx.tcx.hir().get(hir_id) + if let Some(hir_id) = path_to_local(expr) + && let Node::Pat(pat) = cx.tcx.hir().get(hir_id) { matches!(pat.kind, PatKind::Binding(BindingAnnotation::MUT, ..)) } else { diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs index f34f8d0e3..ab8de17b0 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs @@ -26,7 +26,7 @@ declare_clippy_lint! { /// fit some external requirement. /// /// ### Example - /// ```rust + /// ```no_run /// fn get_cool_number(a: bool, b: bool) -> Option<i32> { /// if a && b { /// return Some(50); @@ -39,7 +39,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn get_cool_number(a: bool, b: bool) -> i32 { /// if a && b { /// return 50; diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs index 766a54814..8ff088a20 100644 --- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs @@ -1,8 +1,8 @@ #![allow(clippy::wildcard_imports, clippy::enum_glob_use)] +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::mut_visit::*; use rustc_ast::ptr::P; @@ -29,13 +29,13 @@ declare_clippy_lint! { /// In the example above, `Some` is repeated, which unnecessarily complicates the pattern. /// /// ### Example - /// ```rust + /// ```no_run /// fn main() { /// if let Some(0) | Some(2) = Some(0) {} /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn main() { /// if let Some(0 | 2) = Some(0) {} /// } diff --git a/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs b/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs index 7ee785804..c43d5dc94 100644 --- a/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs +++ b/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint; use rustc_ast::ast::{Item, ItemKind, UseTree, UseTreeKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::Span; +use rustc_span::Span; use rustc_span::symbol::Ident; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/unused_async.rs b/src/tools/clippy/clippy_lints/src/unused_async.rs index bc7c3897a..aea72c798 100644 --- a/src/tools/clippy/clippy_lints/src/unused_async.rs +++ b/src/tools/clippy/clippy_lints/src/unused_async.rs @@ -19,7 +19,7 @@ declare_clippy_lint! { /// causes runtime overhead and hassle for the caller. /// /// ### Example - /// ```rust + /// ```no_run /// async fn get_random_number() -> i64 { /// 4 // Chosen by fair dice roll. Guaranteed to be random. /// } @@ -27,7 +27,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// fn get_random_number_improved() -> i64 { /// 4 // Chosen by fair dice roll. Guaranteed to be random. /// } @@ -86,7 +86,7 @@ impl<'a, 'tcx> Visitor<'tcx> for AsyncFnVisitor<'a, 'tcx> { } fn visit_body(&mut self, b: &'tcx Body<'tcx>) { - let is_async_block = matches!(b.generator_kind, Some(rustc_hir::GeneratorKind::Async(_))); + let is_async_block = matches!(b.coroutine_kind, Some(rustc_hir::CoroutineKind::Async(_))); if is_async_block { self.async_depth += 1; diff --git a/src/tools/clippy/clippy_lints/src/unused_peekable.rs b/src/tools/clippy/clippy_lints/src/unused_peekable.rs index 4ee16d9a5..0473ecaab 100644 --- a/src/tools/clippy/clippy_lints/src/unused_peekable.rs +++ b/src/tools/clippy/clippy_lints/src/unused_peekable.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::ty::{match_type, peel_mid_ty_refs_is_mutable}; -use clippy_utils::{fn_def_id, is_trait_method, path_to_local_id, paths, peel_ref_operators}; +use clippy_utils::ty::{is_type_diagnostic_item, peel_mid_ty_refs_is_mutable}; +use clippy_utils::{fn_def_id, is_trait_method, path_to_local_id, peel_ref_operators}; use rustc_ast::Mutability; use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{Block, Expr, ExprKind, HirId, Local, Node, PatKind, PathSegment, StmtKind}; @@ -18,7 +18,7 @@ declare_clippy_lint! { /// or just a leftover after a refactor. /// /// ### Example - /// ```rust + /// ```no_run /// let collection = vec![1, 2, 3]; /// let iter = collection.iter().peekable(); /// @@ -28,7 +28,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let collection = vec![1, 2, 3]; /// let iter = collection.iter(); /// @@ -49,7 +49,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedPeekable { // Don't lint `Peekable`s returned from a block if let Some(expr) = block.expr && let Some(ty) = cx.typeck_results().expr_ty_opt(peel_ref_operators(cx, expr)) - && match_type(cx, ty, &paths::PEEKABLE) + && is_type_diagnostic_item(cx, ty, sym::IterPeekable) { return; } @@ -62,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedPeekable { && !init.span.from_expansion() && let Some(ty) = cx.typeck_results().expr_ty_opt(init) && let (ty, _, Mutability::Mut) = peel_mid_ty_refs_is_mutable(ty) - && match_type(cx, ty, &paths::PEEKABLE) + && is_type_diagnostic_item(cx, ty, sym::IterPeekable) { let mut vis = PeekableVisitor::new(cx, binding); @@ -85,8 +85,8 @@ impl<'tcx> LateLintPass<'tcx> for UnusedPeekable { ident.span, "`peek` never called on `Peekable` iterator", None, - "consider removing the call to `peekable`" - ); + "consider removing the call to `peekable`", + ); } } } @@ -131,11 +131,7 @@ impl<'tcx> Visitor<'tcx> for PeekableVisitor<'_, 'tcx> { // If the Peekable is passed to a function, stop ExprKind::Call(_, args) => { if let Some(func_did) = fn_def_id(self.cx, expr) - && let Some(into_iter_did) = self - .cx - .tcx - .lang_items() - .into_iter_fn() + && let Some(into_iter_did) = self.cx.tcx.lang_items().into_iter_fn() && func_did == into_iter_did { // Probably a for loop desugar, stop searching @@ -222,7 +218,7 @@ impl<'tcx> Visitor<'tcx> for PeekableVisitor<'_, 'tcx> { fn arg_is_mut_peekable(cx: &LateContext<'_>, arg: &Expr<'_>) -> bool { if let Some(ty) = cx.typeck_results().expr_ty_opt(arg) && let (ty, _, Mutability::Mut) = peel_mid_ty_refs_is_mutable(ty) - && match_type(cx, ty, &paths::PEEKABLE) + && is_type_diagnostic_item(cx, ty, sym::IterPeekable) { true } else { diff --git a/src/tools/clippy/clippy_lints/src/unused_rounding.rs b/src/tools/clippy/clippy_lints/src/unused_rounding.rs index 097568cd1..fbb36bea0 100644 --- a/src/tools/clippy/clippy_lints/src/unused_rounding.rs +++ b/src/tools/clippy/clippy_lints/src/unused_rounding.rs @@ -16,11 +16,11 @@ declare_clippy_lint! { /// This is unnecessary and confusing to the reader. Doing this is probably a mistake. /// /// ### Example - /// ```rust + /// ```no_run /// let x = 1f32.ceil(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let x = 1f32; /// ``` #[clippy::version = "1.63.0"] @@ -31,18 +31,21 @@ declare_clippy_lint! { declare_lint_pass!(UnusedRounding => [UNUSED_ROUNDING]); fn is_useless_rounding<'a>(cx: &EarlyContext<'_>, expr: &'a Expr) -> Option<(&'a str, String)> { - if let ExprKind::MethodCall(box MethodCall { seg:name_ident, receiver, .. }) = &expr.kind + if let ExprKind::MethodCall(box MethodCall { + seg: name_ident, + receiver, + .. + }) = &expr.kind && let method_name = name_ident.ident.name.as_str() && (method_name == "ceil" || method_name == "round" || method_name == "floor") && let ExprKind::Lit(token_lit) = &receiver.kind && token_lit.is_semantic_float() - && let Ok(f) = token_lit.symbol.as_str().replace('_', "").parse::<f64>() { - (f.fract() == 0.0).then(|| - (method_name, snippet(cx, receiver.span, "..").to_string()) - ) - } else { - None - } + && let Ok(f) = token_lit.symbol.as_str().replace('_', "").parse::<f64>() + { + (f.fract() == 0.0).then(|| (method_name, snippet(cx, receiver.span, "..").to_string())) + } else { + None + } } impl EarlyLintPass for UnusedRounding { diff --git a/src/tools/clippy/clippy_lints/src/unused_unit.rs b/src/tools/clippy/clippy_lints/src/unused_unit.rs index 95e74718d..adbf82813 100644 --- a/src/tools/clippy/clippy_lints/src/unused_unit.rs +++ b/src/tools/clippy/clippy_lints/src/unused_unit.rs @@ -6,8 +6,7 @@ use rustc_ast::{ast, ClosureBinder}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::Span; -use rustc_span::BytePos; +use rustc_span::{BytePos, Span}; declare_clippy_lint! { /// ### What it does @@ -19,13 +18,13 @@ declare_clippy_lint! { /// statement look like a function call. /// /// ### Example - /// ```rust + /// ```no_run /// fn return_unit() -> () { /// () /// } /// ``` /// is equivalent to - /// ```rust + /// ```no_run /// fn return_unit() {} /// ``` #[clippy::version = "1.31.0"] diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs index 9a0d83d83..cdfcb8500 100644 --- a/src/tools/clippy/clippy_lints/src/unwrap.rs +++ b/src/tools/clippy/clippy_lints/src/unwrap.rs @@ -15,8 +15,7 @@ use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::def_id::LocalDefId; -use rustc_span::source_map::Span; -use rustc_span::sym; +use rustc_span::{sym, Span}; declare_clippy_lint! { /// ### What it does @@ -26,7 +25,7 @@ declare_clippy_lint! { /// Using `if let` or `match` is more idiomatic. /// /// ### Example - /// ```rust + /// ```no_run /// # let option = Some(0); /// # fn do_something_with(_x: usize) {} /// if option.is_some() { @@ -36,7 +35,7 @@ declare_clippy_lint! { /// /// Could be written: /// - /// ```rust + /// ```no_run /// # let option = Some(0); /// # fn do_something_with(_x: usize) {} /// if let Some(value) = option { @@ -61,7 +60,7 @@ declare_clippy_lint! { /// So something like `let x: Option<()> = None; x.unwrap();` will not be recognized. /// /// ### Example - /// ```rust + /// ```no_run /// # let option = Some(0); /// # fn do_something_with(_x: usize) {} /// if option.is_none() { diff --git a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs index 3a1845425..21592abbf 100644 --- a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs +++ b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs @@ -22,7 +22,7 @@ declare_clippy_lint! { /// /// ### Example /// Before: - /// ```rust + /// ```no_run /// fn divisible_by_3(i_str: String) -> Result<(), String> { /// let i = i_str /// .parse::<i32>() @@ -37,7 +37,7 @@ declare_clippy_lint! { /// ``` /// /// After: - /// ```rust + /// ```no_run /// fn divisible_by_3(i_str: String) -> Result<(), String> { /// let i = i_str /// .parse::<i32>() diff --git a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs index 4df1e3299..de6a75b79 100644 --- a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs +++ b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs @@ -26,11 +26,11 @@ declare_clippy_lint! { /// the letters in the second acronym. /// /// ### Example - /// ```rust + /// ```no_run /// struct HTTPResponse; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// struct HttpResponse; /// ``` #[clippy::version = "1.51.0"] diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs index 50231d930..c3fe16ad5 100644 --- a/src/tools/clippy/clippy_lints/src/use_self.rs +++ b/src/tools/clippy/clippy_lints/src/use_self.rs @@ -1,6 +1,6 @@ +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 if_chain::if_chain; use rustc_data_structures::fx::FxHashSet; @@ -31,7 +31,7 @@ declare_clippy_lint! { /// - Unaddressed false negative in fn bodies of trait implementations /// /// ### Example - /// ```rust + /// ```no_run /// struct Foo; /// impl Foo { /// fn new() -> Foo { @@ -40,7 +40,7 @@ declare_clippy_lint! { /// } /// ``` /// could be - /// ```rust + /// ```no_run /// struct Foo; /// impl Foo { /// fn new() -> Self { @@ -54,7 +54,6 @@ declare_clippy_lint! { "unnecessary structure name repetition whereas `Self` is applicable" } -#[derive(Default)] pub struct UseSelf { msrv: Msrv, stack: Vec<StackItem>, @@ -65,7 +64,7 @@ impl UseSelf { pub fn new(msrv: Msrv) -> Self { Self { msrv, - ..Self::default() + stack: Vec::new(), } } } diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs index f32e7edad..28f1d487e 100644 --- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs +++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lin use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_context}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{is_copy, is_type_diagnostic_item, same_type_and_consts}; -use clippy_utils::{get_parent_expr, is_trait_method, is_ty_alias, match_def_path, path_to_local, paths}; +use clippy_utils::{get_parent_expr, is_trait_method, is_ty_alias, path_to_local}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def::DefKind; @@ -26,13 +26,13 @@ declare_clippy_lint! { /// Redundant code. /// /// ### Example - /// ```rust + /// ```no_run /// // format!() returns a `String` /// let s: String = format!("hello").into(); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let s: String = format!("hello"); /// ``` #[clippy::version = "1.45.0"] @@ -215,20 +215,19 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { did, args, cx.typeck_results().node_args(recv.hir_id), - MethodOrFunction::Function + MethodOrFunction::Function, )) - } + }, ExprKind::MethodCall(.., args, _) => { - cx.typeck_results().type_dependent_def_id(parent.hir_id) - .map(|did| { - return ( - did, - args, - cx.typeck_results().node_args(parent.hir_id), - MethodOrFunction::Method - ); - }) - } + cx.typeck_results().type_dependent_def_id(parent.hir_id).map(|did| { + return ( + did, + args, + cx.typeck_results().node_args(parent.hir_id), + MethodOrFunction::Method, + ); + }) + }, _ => None, }; @@ -244,7 +243,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { into_iter_did, cx.typeck_results().expr_ty(into_iter_recv), param.index, - node_args + node_args, ) && self.expn_depth == 0 { @@ -255,26 +254,38 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { let plural = if depth == 0 { "" } else { "s" }; let mut applicability = Applicability::MachineApplicable; - let sugg = snippet_with_applicability(cx, into_iter_recv.span.source_callsite(), "<expr>", &mut applicability).into_owned(); - span_lint_and_then(cx, USELESS_CONVERSION, e.span, "explicit call to `.into_iter()` in function argument accepting `IntoIterator`", |diag| { - diag.span_suggestion( - e.span, - format!("consider removing the `.into_iter()`{plural}"), - sugg, - applicability, - ); - diag.span_note(span, "this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`"); - }); + let sugg = snippet_with_applicability( + cx, + into_iter_recv.span.source_callsite(), + "<expr>", + &mut applicability, + ) + .into_owned(); + span_lint_and_then( + cx, + USELESS_CONVERSION, + e.span, + "explicit call to `.into_iter()` in function argument accepting `IntoIterator`", + |diag| { + diag.span_suggestion( + e.span, + format!("consider removing the `.into_iter()`{plural}"), + sugg, + applicability, + ); + diag.span_note(span, "this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`"); + }, + ); // Early return to avoid linting again with contradicting suggestions return; } } - if let Some(id) = path_to_local(recv) && - let Node::Pat(pat) = cx.tcx.hir().get(id) && - let PatKind::Binding(ann, ..) = pat.kind && - ann != BindingAnnotation::MUT + if let Some(id) = path_to_local(recv) + && let Node::Pat(pat) = cx.tcx.hir().get(id) + && let PatKind::Binding(ann, ..) = pat.kind + && ann != BindingAnnotation::MUT { // Do not remove .into_iter() applied to a non-mutable local variable used in // a larger expression context as it would differ in mutability. @@ -331,7 +342,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { let a = cx.typeck_results().expr_ty(e); let b = cx.typeck_results().expr_ty(arg); if_chain! { - if match_def_path(cx, def_id, &paths::TRY_FROM); + if cx.tcx.is_diagnostic_item(sym::try_from_fn, def_id); if is_type_diagnostic_item(cx, a, sym::Result); if let ty::Adt(_, args) = a.kind(); if let Some(a_type) = args.types().next(); diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index f02c33cc6..152248afc 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -7,15 +7,15 @@ use rustc_ast::LitIntType; use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; use rustc_hir::{ - ArrayLen, BindingAnnotation, Closure, ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind, + ArrayLen, BindingAnnotation, Closure, ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind, CaptureBy }; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::{Ident, Symbol}; use std::cell::Cell; use std::fmt::{Display, Formatter, Write as _}; -declare_clippy_lint! { +declare_lint_pass!( /// ### What it does /// Generates clippy code that detects the offending pattern /// @@ -47,12 +47,8 @@ declare_clippy_lint! { /// // report your lint here /// } /// ``` - pub LINT_AUTHOR, - internal_warn, - "helper for writing lints" -} - -declare_lint_pass!(Author => [LINT_AUTHOR]); + Author => [] +); /// Writes a line of output with indentation added macro_rules! out { @@ -268,8 +264,8 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { fn qpath(&self, qpath: &Binding<&QPath<'_>>) { if let QPath::LangItem(lang_item, ..) = *qpath.value { chain!(self, "matches!({qpath}, QPath::LangItem(LangItem::{lang_item:?}, _))"); - } else { - chain!(self, "match_qpath({qpath}, &[{}])", path_to_string(qpath.value)); + } else if let Ok(path) = path_to_string(qpath.value) { + chain!(self, "match_qpath({qpath}, &[{}])", path); } } @@ -483,6 +479,11 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { movability, .. }) => { + let capture_clause = match capture_clause { + CaptureBy::Value { .. } => "Value { .. }", + CaptureBy::Ref => "Ref", + }; + let movability = OptionPat::new(movability.map(|m| format!("Movability::{m:?}"))); let ret_ty = match fn_decl.output { @@ -491,7 +492,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { }; bind!(self, fn_decl, body_id); - kind!("Closure(CaptureBy::{capture_clause:?}, {fn_decl}, {body_id}, _, {movability})"); + kind!("Closure(CaptureBy::{capture_clause}, {fn_decl}, {body_id}, _, {movability})"); chain!(self, "let {ret_ty} = {fn_decl}.output"); self.body(body_id); }, @@ -738,8 +739,8 @@ fn has_attr(cx: &LateContext<'_>, hir_id: hir::HirId) -> bool { get_attr(cx.sess(), attrs, "author").count() > 0 } -fn path_to_string(path: &QPath<'_>) -> String { - fn inner(s: &mut String, path: &QPath<'_>) { +fn path_to_string(path: &QPath<'_>) -> Result<String, ()> { + fn inner(s: &mut String, path: &QPath<'_>) -> Result<(), ()> { match *path { QPath::Resolved(_, path) => { for (i, segment) in path.segments.iter().enumerate() { @@ -751,16 +752,18 @@ fn path_to_string(path: &QPath<'_>) -> String { }, QPath::TypeRelative(ty, segment) => match &ty.kind { hir::TyKind::Path(inner_path) => { - inner(s, inner_path); + inner(s, inner_path)?; *s += ", "; write!(s, "{:?}", segment.ident.as_str()).unwrap(); }, other => write!(s, "/* unimplemented: {other:?}*/").unwrap(), }, - QPath::LangItem(..) => panic!("path_to_string: called for lang item qpath"), + QPath::LangItem(..) => return Err(()), } + + Ok(()) } let mut s = String::new(); - inner(&mut s, path); - s + inner(&mut s, path)?; + Ok(s) } diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs deleted file mode 100644 index 75c3c7a95..000000000 --- a/src/tools/clippy/clippy_lints/src/utils/conf.rs +++ /dev/null @@ -1,746 +0,0 @@ -//! Read configurations files. - -#![allow(clippy::module_name_repetitions)] - -use rustc_session::Session; -use rustc_span::{BytePos, Pos, SourceFile, Span, SyntaxContext}; -use serde::de::{Deserializer, IgnoredAny, IntoDeserializer, MapAccess, Visitor}; -use serde::Deserialize; -use std::fmt::{Debug, Display, Formatter}; -use std::ops::Range; -use std::path::{Path, PathBuf}; -use std::str::FromStr; -use std::{cmp, env, fmt, fs, io}; - -#[rustfmt::skip] -const DEFAULT_DOC_VALID_IDENTS: &[&str] = &[ - "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", - "DirectX", - "ECMAScript", - "GPLv2", "GPLv3", - "GitHub", "GitLab", - "IPv4", "IPv6", - "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", - "WebAssembly", - "NaN", "NaNs", - "OAuth", "GraphQL", - "OCaml", - "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenDNS", - "WebGL", - "TensorFlow", - "TrueType", - "iOS", "macOS", "FreeBSD", - "TeX", "LaTeX", "BibTeX", "BibLaTeX", - "MinGW", - "CamelCase", -]; -const DEFAULT_DISALLOWED_NAMES: &[&str] = &["foo", "baz", "quux"]; -const DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS: &[&str] = &["i", "j", "x", "y", "z", "w", "n"]; - -/// Holds information used by `MISSING_ENFORCED_IMPORT_RENAMES` lint. -#[derive(Clone, Debug, Deserialize)] -pub struct Rename { - pub path: String, - pub rename: String, -} - -#[derive(Clone, Debug, Deserialize)] -#[serde(untagged)] -pub enum DisallowedPath { - Simple(String), - WithReason { path: String, reason: Option<String> }, -} - -impl DisallowedPath { - pub fn path(&self) -> &str { - let (Self::Simple(path) | Self::WithReason { path, .. }) = self; - - path - } - - pub fn reason(&self) -> Option<String> { - match self { - Self::WithReason { - reason: Some(reason), .. - } => Some(format!("{reason} (from clippy.toml)")), - _ => None, - } - } -} - -/// Conf with parse errors -#[derive(Default)] -pub struct TryConf { - pub conf: Conf, - pub errors: Vec<ConfError>, - pub warnings: Vec<ConfError>, -} - -impl TryConf { - fn from_toml_error(file: &SourceFile, error: &toml::de::Error) -> Self { - ConfError::from_toml(file, error).into() - } -} - -impl From<ConfError> for TryConf { - fn from(value: ConfError) -> Self { - Self { - conf: Conf::default(), - errors: vec![value], - warnings: vec![], - } - } -} - -impl From<io::Error> for TryConf { - fn from(value: io::Error) -> Self { - ConfError::from(value).into() - } -} - -#[derive(Debug)] -pub struct ConfError { - pub message: String, - pub span: Option<Span>, -} - -impl ConfError { - fn from_toml(file: &SourceFile, error: &toml::de::Error) -> Self { - if let Some(span) = error.span() { - Self::spanned(file, error.message(), span) - } else { - Self { - message: error.message().to_string(), - span: None, - } - } - } - - fn spanned(file: &SourceFile, message: impl Into<String>, span: Range<usize>) -> Self { - Self { - message: message.into(), - span: Some(Span::new( - file.start_pos + BytePos::from_usize(span.start), - file.start_pos + BytePos::from_usize(span.end), - SyntaxContext::root(), - None, - )), - } - } -} - -impl From<io::Error> for ConfError { - fn from(value: io::Error) -> Self { - Self { - message: value.to_string(), - span: None, - } - } -} - -macro_rules! define_Conf { - ($( - $(#[doc = $doc:literal])+ - $(#[conf_deprecated($dep:literal, $new_conf:ident)])? - ($name:ident: $ty:ty = $default:expr), - )*) => { - /// Clippy lint configuration - pub struct Conf { - $($(#[doc = $doc])+ pub $name: $ty,)* - } - - mod defaults { - $(pub fn $name() -> $ty { $default })* - } - - impl Default for Conf { - fn default() -> Self { - Self { $($name: defaults::$name(),)* } - } - } - - #[derive(Deserialize)] - #[serde(field_identifier, rename_all = "kebab-case")] - #[allow(non_camel_case_types)] - enum Field { $($name,)* third_party, } - - struct ConfVisitor<'a>(&'a SourceFile); - - impl<'de> Visitor<'de> for ConfVisitor<'_> { - type Value = TryConf; - - fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - formatter.write_str("Conf") - } - - fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error> where V: MapAccess<'de> { - let mut errors = Vec::new(); - let mut warnings = Vec::new(); - $(let mut $name = None;)* - // could get `Field` here directly, but get `String` first for diagnostics - while let Some(name) = map.next_key::<toml::Spanned<String>>()? { - match Field::deserialize(name.get_ref().as_str().into_deserializer()) { - Err(e) => { - let e: FieldError = e; - errors.push(ConfError::spanned(self.0, e.0, name.span())); - } - $(Ok(Field::$name) => { - $(warnings.push(ConfError::spanned(self.0, format!("deprecated field `{}`. {}", name.get_ref(), $dep), name.span()));)? - let raw_value = map.next_value::<toml::Spanned<toml::Value>>()?; - let value_span = raw_value.span(); - match <$ty>::deserialize(raw_value.into_inner()) { - Err(e) => errors.push(ConfError::spanned(self.0, e.to_string().replace('\n', " ").trim(), value_span)), - Ok(value) => match $name { - Some(_) => errors.push(ConfError::spanned(self.0, format!("duplicate field `{}`", name.get_ref()), name.span())), - None => { - $name = Some(value); - // $new_conf is the same as one of the defined `$name`s, so - // this variable is defined in line 2 of this function. - $(match $new_conf { - Some(_) => errors.push(ConfError::spanned(self.0, concat!( - "duplicate field `", stringify!($new_conf), - "` (provided as `", stringify!($name), "`)" - ), name.span())), - None => $new_conf = $name.clone(), - })? - }, - } - } - })* - // ignore contents of the third_party key - Ok(Field::third_party) => drop(map.next_value::<IgnoredAny>()) - } - } - let conf = Conf { $($name: $name.unwrap_or_else(defaults::$name),)* }; - Ok(TryConf { conf, errors, warnings }) - } - } - - pub mod metadata { - use crate::utils::ClippyConfiguration; - - macro_rules! wrap_option { - () => (None); - ($x:literal) => (Some($x)); - } - - pub fn get_configuration_metadata() -> Vec<ClippyConfiguration> { - vec![ - $( - { - let deprecation_reason = wrap_option!($($dep)?); - - ClippyConfiguration::new( - stringify!($name), - stringify!($ty), - format!("{:?}", super::defaults::$name()), - concat!($($doc, '\n',)*), - deprecation_reason, - ) - }, - )+ - ] - } - } - }; -} - -define_Conf! { - /// Lint: ARITHMETIC_SIDE_EFFECTS. - /// - /// Suppress checking of the passed type names in all types of operations. - /// - /// If a specific operation is desired, consider using `arithmetic_side_effects_allowed_binary` or `arithmetic_side_effects_allowed_unary` instead. - /// - /// #### Example - /// - /// ```toml - /// arithmetic-side-effects-allowed = ["SomeType", "AnotherType"] - /// ``` - /// - /// #### Noteworthy - /// - /// A type, say `SomeType`, listed in this configuration has the same behavior of - /// `["SomeType" , "*"], ["*", "SomeType"]` in `arithmetic_side_effects_allowed_binary`. - (arithmetic_side_effects_allowed: rustc_data_structures::fx::FxHashSet<String> = <_>::default()), - /// Lint: ARITHMETIC_SIDE_EFFECTS. - /// - /// Suppress checking of the passed type pair names in binary operations like addition or - /// multiplication. - /// - /// Supports the "*" wildcard to indicate that a certain type won't trigger the lint regardless - /// of the involved counterpart. For example, `["SomeType", "*"]` or `["*", "AnotherType"]`. - /// - /// Pairs are asymmetric, which means that `["SomeType", "AnotherType"]` is not the same as - /// `["AnotherType", "SomeType"]`. - /// - /// #### Example - /// - /// ```toml - /// arithmetic-side-effects-allowed-binary = [["SomeType" , "f32"], ["AnotherType", "*"]] - /// ``` - (arithmetic_side_effects_allowed_binary: Vec<[String; 2]> = <_>::default()), - /// Lint: ARITHMETIC_SIDE_EFFECTS. - /// - /// Suppress checking of the passed type names in unary operations like "negation" (`-`). - /// - /// #### Example - /// - /// ```toml - /// arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"] - /// ``` - (arithmetic_side_effects_allowed_unary: rustc_data_structures::fx::FxHashSet<String> = <_>::default()), - /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UNUSED_SELF, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX, UNNECESSARY_BOX_RETURNS, SINGLE_CALL_FN. - /// - /// Suppress lints whenever the suggested change would cause breakage for other crates. - (avoid_breaking_exported_api: bool = true), - /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD. - /// - /// The minimum rust version that the project supports - (msrv: Option<String> = None), - /// DEPRECATED LINT: BLACKLISTED_NAME. - /// - /// Use the Disallowed Names lint instead - #[conf_deprecated("Please use `disallowed-names` instead", disallowed_names)] - (blacklisted_names: Vec<String> = Vec::new()), - /// Lint: COGNITIVE_COMPLEXITY. - /// - /// The maximum cognitive complexity a function can have - (cognitive_complexity_threshold: u64 = 25), - /// Lint: EXCESSIVE_NESTING. - /// - /// The maximum amount of nesting a block can reside in - (excessive_nesting_threshold: u64 = 0), - /// DEPRECATED LINT: CYCLOMATIC_COMPLEXITY. - /// - /// Use the Cognitive Complexity lint instead. - #[conf_deprecated("Please use `cognitive-complexity-threshold` instead", cognitive_complexity_threshold)] - (cyclomatic_complexity_threshold: u64 = 25), - /// Lint: DISALLOWED_NAMES. - /// - /// The list of disallowed names to lint about. NB: `bar` is not here since it has legitimate uses. The value - /// `".."` can be used as part of the list to indicate that the configured values should be appended to the - /// default configuration of Clippy. By default, any configuration will replace the default value. - (disallowed_names: Vec<String> = super::DEFAULT_DISALLOWED_NAMES.iter().map(ToString::to_string).collect()), - /// Lint: SEMICOLON_INSIDE_BLOCK. - /// - /// Whether to lint only if it's multiline. - (semicolon_inside_block_ignore_singleline: bool = false), - /// Lint: SEMICOLON_OUTSIDE_BLOCK. - /// - /// Whether to lint only if it's singleline. - (semicolon_outside_block_ignore_multiline: bool = false), - /// Lint: DOC_MARKDOWN. - /// - /// The list of words this lint should not consider as identifiers needing ticks. The value - /// `".."` can be used as part of the list to indicate, that the configured values should be appended to the - /// default configuration of Clippy. By default, any configuration will replace the default value. For example: - /// * `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`. - /// * `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list. - /// - /// Default list: - (doc_valid_idents: Vec<String> = super::DEFAULT_DOC_VALID_IDENTS.iter().map(ToString::to_string).collect()), - /// Lint: TOO_MANY_ARGUMENTS. - /// - /// The maximum number of argument a function or method can have - (too_many_arguments_threshold: u64 = 7), - /// Lint: TYPE_COMPLEXITY. - /// - /// The maximum complexity a type can have - (type_complexity_threshold: u64 = 250), - /// Lint: MANY_SINGLE_CHAR_NAMES. - /// - /// The maximum number of single char bindings a scope may have - (single_char_binding_names_threshold: u64 = 4), - /// Lint: BOXED_LOCAL, USELESS_VEC. - /// - /// The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap - (too_large_for_stack: u64 = 200), - /// Lint: ENUM_VARIANT_NAMES. - /// - /// The minimum number of enum variants for the lints about variant names to trigger - (enum_variant_name_threshold: u64 = 3), - /// Lint: LARGE_ENUM_VARIANT. - /// - /// The maximum size of an enum's variant to avoid box suggestion - (enum_variant_size_threshold: u64 = 200), - /// Lint: VERBOSE_BIT_MASK. - /// - /// The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros' - (verbose_bit_mask_threshold: u64 = 1), - /// Lint: DECIMAL_LITERAL_REPRESENTATION. - /// - /// The lower bound for linting decimal literals - (literal_representation_threshold: u64 = 16384), - /// Lint: TRIVIALLY_COPY_PASS_BY_REF. - /// - /// The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by reference. - (trivial_copy_size_limit: Option<u64> = None), - /// Lint: LARGE_TYPES_PASSED_BY_VALUE. - /// - /// The minimum size (in bytes) to consider a type for passing by reference instead of by value. - (pass_by_value_size_limit: u64 = 256), - /// Lint: TOO_MANY_LINES. - /// - /// The maximum number of lines a function or method can have - (too_many_lines_threshold: u64 = 100), - /// Lint: LARGE_STACK_ARRAYS, LARGE_CONST_ARRAYS. - /// - /// The maximum allowed size for arrays on the stack - (array_size_threshold: u64 = 512_000), - /// Lint: LARGE_STACK_FRAMES. - /// - /// The maximum allowed stack size for functions in bytes - (stack_size_threshold: u64 = 512_000), - /// Lint: VEC_BOX. - /// - /// The size of the boxed type in bytes, where boxing in a `Vec` is allowed - (vec_box_size_threshold: u64 = 4096), - /// Lint: TYPE_REPETITION_IN_BOUNDS. - /// - /// The maximum number of bounds a trait can have to be linted - (max_trait_bounds: u64 = 3), - /// Lint: STRUCT_EXCESSIVE_BOOLS. - /// - /// The maximum number of bool fields a struct can have - (max_struct_bools: u64 = 3), - /// Lint: FN_PARAMS_EXCESSIVE_BOOLS. - /// - /// The maximum number of bool parameters a function can have - (max_fn_params_bools: u64 = 3), - /// Lint: WILDCARD_IMPORTS. - /// - /// Whether to allow certain wildcard imports (prelude, super in tests). - (warn_on_all_wildcard_imports: bool = false), - /// Lint: DISALLOWED_MACROS. - /// - /// The list of disallowed macros, written as fully qualified paths. - (disallowed_macros: Vec<crate::utils::conf::DisallowedPath> = Vec::new()), - /// Lint: DISALLOWED_METHODS. - /// - /// The list of disallowed methods, written as fully qualified paths. - (disallowed_methods: Vec<crate::utils::conf::DisallowedPath> = Vec::new()), - /// Lint: DISALLOWED_TYPES. - /// - /// The list of disallowed types, written as fully qualified paths. - (disallowed_types: Vec<crate::utils::conf::DisallowedPath> = Vec::new()), - /// Lint: UNREADABLE_LITERAL. - /// - /// Should the fraction of a decimal be linted to include separators. - (unreadable_literal_lint_fractions: bool = true), - /// Lint: UPPER_CASE_ACRONYMS. - /// - /// Enables verbose mode. Triggers if there is more than one uppercase char next to each other - (upper_case_acronyms_aggressive: bool = false), - /// Lint: MANUAL_LET_ELSE. - /// - /// Whether the matches should be considered by the lint, and whether there should - /// be filtering for common types. - (matches_for_let_else: crate::manual_let_else::MatchLintBehaviour = - crate::manual_let_else::MatchLintBehaviour::WellKnownTypes), - /// Lint: _CARGO_COMMON_METADATA. - /// - /// For internal testing only, ignores the current `publish` settings in the Cargo manifest. - (cargo_ignore_publish: bool = false), - /// Lint: NONSTANDARD_MACRO_BRACES. - /// - /// Enforce the named macros always use the braces specified. - /// - /// A `MacroMatcher` can be added like so `{ name = "macro_name", brace = "(" }`. If the macro - /// could be used with a full path two `MacroMatcher`s have to be added one with the full path - /// `crate_name::macro_name` and one with just the macro name. - (standard_macro_braces: Vec<crate::nonstandard_macro_braces::MacroMatcher> = Vec::new()), - /// Lint: MISSING_ENFORCED_IMPORT_RENAMES. - /// - /// The list of imports to always rename, a fully qualified path followed by the rename. - (enforced_import_renames: Vec<crate::utils::conf::Rename> = Vec::new()), - /// Lint: DISALLOWED_SCRIPT_IDENTS. - /// - /// The list of unicode scripts allowed to be used in the scope. - (allowed_scripts: Vec<String> = vec!["Latin".to_string()]), - /// Lint: NON_SEND_FIELDS_IN_SEND_TY. - /// - /// Whether to apply the raw pointer heuristic to determine if a type is `Send`. - (enable_raw_pointer_heuristic_for_send: bool = true), - /// Lint: INDEX_REFUTABLE_SLICE. - /// - /// When Clippy suggests using a slice pattern, this is the maximum number of elements allowed in - /// the slice pattern that is suggested. If more elements are necessary, the lint is suppressed. - /// For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements. - (max_suggested_slice_pattern_length: u64 = 3), - /// Lint: AWAIT_HOLDING_INVALID_TYPE. - (await_holding_invalid_types: Vec<crate::utils::conf::DisallowedPath> = Vec::new()), - /// Lint: LARGE_INCLUDE_FILE. - /// - /// The maximum size of a file included via `include_bytes!()` or `include_str!()`, in bytes - (max_include_file_size: u64 = 1_000_000), - /// Lint: EXPECT_USED. - /// - /// Whether `expect` should be allowed in test functions or `#[cfg(test)]` - (allow_expect_in_tests: bool = false), - /// Lint: UNWRAP_USED. - /// - /// Whether `unwrap` should be allowed in test functions or `#[cfg(test)]` - (allow_unwrap_in_tests: bool = false), - /// Lint: DBG_MACRO. - /// - /// Whether `dbg!` should be allowed in test functions or `#[cfg(test)]` - (allow_dbg_in_tests: bool = false), - /// Lint: PRINT_STDOUT, PRINT_STDERR. - /// - /// Whether print macros (ex. `println!`) should be allowed in test functions or `#[cfg(test)]` - (allow_print_in_tests: bool = false), - /// Lint: RESULT_LARGE_ERR. - /// - /// The maximum size of the `Err`-variant in a `Result` returned from a function - (large_error_threshold: u64 = 128), - /// Lint: MUTABLE_KEY_TYPE, IFS_SAME_COND. - /// - /// A list of paths to types that should be treated like `Arc`, i.e. ignored but - /// for the generic parameters for determining interior mutability - (ignore_interior_mutability: Vec<String> = Vec::from(["bytes::Bytes".into()])), - /// Lint: UNINLINED_FORMAT_ARGS. - /// - /// Whether to allow mixed uninlined format args, e.g. `format!("{} {}", a, foo.bar)` - (allow_mixed_uninlined_format_args: bool = true), - /// Lint: INDEXING_SLICING. - /// - /// Whether to suppress a restriction lint in constant code. In same - /// cases the restructured operation might not be unavoidable, as the - /// suggested counterparts are unavailable in constant code. This - /// configuration will cause restriction lints to trigger even - /// if no suggestion can be made. - (suppress_restriction_lint_in_const: bool = false), - /// Lint: MISSING_DOCS_IN_PRIVATE_ITEMS. - /// - /// Whether to **only** check for missing documentation in items visible within the current - /// crate. For example, `pub(crate)` items. - (missing_docs_in_crate_items: bool = false), - /// Lint: LARGE_FUTURES. - /// - /// The maximum byte size a `Future` can have, before it triggers the `clippy::large_futures` lint - (future_size_threshold: u64 = 16 * 1024), - /// Lint: UNNECESSARY_BOX_RETURNS. - /// - /// The byte size a `T` in `Box<T>` can have, below which it triggers the `clippy::unnecessary_box` lint - (unnecessary_box_size: u64 = 128), - /// Lint: MODULE_INCEPTION. - /// - /// Whether to allow module inception if it's not public. - (allow_private_module_inception: bool = false), - /// Lint: MIN_IDENT_CHARS. - /// - /// Allowed names below the minimum allowed characters. The value `".."` can be used as part of - /// the list to indicate, that the configured values should be appended to the default - /// configuration of Clippy. By default, any configuration will replace the default value. - (allowed_idents_below_min_chars: rustc_data_structures::fx::FxHashSet<String> = - super::DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS.iter().map(ToString::to_string).collect()), - /// Lint: MIN_IDENT_CHARS. - /// - /// Minimum chars an ident can have, anything below or equal to this will be linted. - (min_ident_chars_threshold: u64 = 1), - /// Lint: UNDOCUMENTED_UNSAFE_BLOCKS. - /// - /// Whether to accept a safety comment to be placed above the statement containing the `unsafe` block - (accept_comment_above_statement: bool = true), - /// Lint: UNDOCUMENTED_UNSAFE_BLOCKS. - /// - /// Whether to accept a safety comment to be placed above the attributes for the `unsafe` block - (accept_comment_above_attributes: bool = true), - /// Lint: UNNECESSARY_RAW_STRING_HASHES. - /// - /// Whether to allow `r#""#` when `r""` can be used - (allow_one_hash_in_raw_strings: bool = false), - /// Lint: ABSOLUTE_PATHS. - /// - /// The maximum number of segments a path can have before being linted, anything above this will - /// be linted. - (absolute_paths_max_segments: u64 = 2), - /// Lint: ABSOLUTE_PATHS. - /// - /// Which crates to allow absolute paths from - (absolute_paths_allowed_crates: rustc_data_structures::fx::FxHashSet<String> = - rustc_data_structures::fx::FxHashSet::default()), - /// Lint: PATH_ENDS_WITH_EXT. - /// - /// Additional dotfiles (files or directories starting with a dot) to allow - (allowed_dotfiles: rustc_data_structures::fx::FxHashSet<String> = - rustc_data_structures::fx::FxHashSet::default()), - /// Lint: EXPLICIT_ITER_LOOP - /// - /// Whether to recommend using implicit into iter for reborrowed values. - /// - /// #### Example - /// ``` - /// let mut vec = vec![1, 2, 3]; - /// let rmvec = &mut vec; - /// for _ in rmvec.iter() {} - /// for _ in rmvec.iter_mut() {} - /// ``` - /// - /// Use instead: - /// ``` - /// let mut vec = vec![1, 2, 3]; - /// let rmvec = &mut vec; - /// for _ in &*rmvec {} - /// for _ in &mut *rmvec {} - /// ``` - (enforce_iter_loop_reborrow: bool = false), -} - -/// Search for the configuration file. -/// -/// # Errors -/// -/// Returns any unexpected filesystem error encountered when searching for the config file -pub fn lookup_conf_file() -> io::Result<(Option<PathBuf>, Vec<String>)> { - /// Possible filename to search for. - const CONFIG_FILE_NAMES: [&str; 2] = [".clippy.toml", "clippy.toml"]; - - // Start looking for a config file in CLIPPY_CONF_DIR, or failing that, CARGO_MANIFEST_DIR. - // If neither of those exist, use ".". (Update documentation if this priority changes) - let mut current = env::var_os("CLIPPY_CONF_DIR") - .or_else(|| env::var_os("CARGO_MANIFEST_DIR")) - .map_or_else(|| PathBuf::from("."), PathBuf::from) - .canonicalize()?; - - let mut found_config: Option<PathBuf> = None; - let mut warnings = vec![]; - - loop { - for config_file_name in &CONFIG_FILE_NAMES { - if let Ok(config_file) = current.join(config_file_name).canonicalize() { - match fs::metadata(&config_file) { - Err(e) if e.kind() == io::ErrorKind::NotFound => {}, - Err(e) => return Err(e), - Ok(md) if md.is_dir() => {}, - Ok(_) => { - // warn if we happen to find two config files #8323 - if let Some(ref found_config) = found_config { - warnings.push(format!( - "using config file `{}`, `{}` will be ignored", - found_config.display(), - config_file.display() - )); - } else { - found_config = Some(config_file); - } - }, - } - } - } - - if found_config.is_some() { - return Ok((found_config, warnings)); - } - - // If the current directory has no parent, we're done searching. - if !current.pop() { - return Ok((None, warnings)); - } - } -} - -/// Read the `toml` configuration file. -/// -/// In case of error, the function tries to continue as much as possible. -pub fn read(sess: &Session, path: &Path) -> TryConf { - let file = match sess.source_map().load_file(path) { - Err(e) => return e.into(), - Ok(file) => file, - }; - match toml::de::Deserializer::new(file.src.as_ref().unwrap()).deserialize_map(ConfVisitor(&file)) { - Ok(mut conf) => { - extend_vec_if_indicator_present(&mut conf.conf.doc_valid_idents, DEFAULT_DOC_VALID_IDENTS); - extend_vec_if_indicator_present(&mut conf.conf.disallowed_names, DEFAULT_DISALLOWED_NAMES); - // TODO: THIS SHOULD BE TESTED, this comment will be gone soon - if conf.conf.allowed_idents_below_min_chars.contains(&"..".to_owned()) { - conf.conf - .allowed_idents_below_min_chars - .extend(DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS.iter().map(ToString::to_string)); - } - - conf - }, - Err(e) => TryConf::from_toml_error(&file, &e), - } -} - -fn extend_vec_if_indicator_present(vec: &mut Vec<String>, default: &[&str]) { - if vec.contains(&"..".to_string()) { - vec.extend(default.iter().map(ToString::to_string)); - } -} - -const SEPARATOR_WIDTH: usize = 4; - -#[derive(Debug)] -struct FieldError(String); - -impl std::error::Error for FieldError {} - -impl Display for FieldError { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.pad(&self.0) - } -} - -impl serde::de::Error for FieldError { - fn custom<T: Display>(msg: T) -> Self { - Self(msg.to_string()) - } - - fn unknown_field(field: &str, expected: &'static [&'static str]) -> Self { - // List the available fields sorted and at least one per line, more if `CLIPPY_TERMINAL_WIDTH` is - // set and allows it. - use fmt::Write; - - let mut expected = expected.to_vec(); - expected.sort_unstable(); - - let (rows, column_widths) = calculate_dimensions(&expected); - - let mut msg = format!("unknown field `{field}`, expected one of"); - for row in 0..rows { - writeln!(msg).unwrap(); - for (column, column_width) in column_widths.iter().copied().enumerate() { - let index = column * rows + row; - let field = expected.get(index).copied().unwrap_or_default(); - write!(msg, "{:SEPARATOR_WIDTH$}{field:column_width$}", " ").unwrap(); - } - } - Self(msg) - } -} - -fn calculate_dimensions(fields: &[&str]) -> (usize, Vec<usize>) { - let columns = env::var("CLIPPY_TERMINAL_WIDTH") - .ok() - .and_then(|s| <usize as FromStr>::from_str(&s).ok()) - .map_or(1, |terminal_width| { - let max_field_width = fields.iter().map(|field| field.len()).max().unwrap(); - cmp::max(1, terminal_width / (SEPARATOR_WIDTH + max_field_width)) - }); - - let rows = (fields.len() + (columns - 1)) / columns; - - let column_widths = (0..columns) - .map(|column| { - if column < columns - 1 { - (0..rows) - .map(|row| { - let index = column * rows + row; - let field = fields.get(index).copied().unwrap_or_default(); - field.len() - }) - .max() - .unwrap() - } else { - // Avoid adding extra space to the last column. - 0 - } - }) - .collect::<Vec<_>>(); - - (rows, column_widths) -} diff --git a/src/tools/clippy/clippy_lints/src/utils/dump_hir.rs b/src/tools/clippy/clippy_lints/src/utils/dump_hir.rs index 092041aec..b10895197 100644 --- a/src/tools/clippy/clippy_lints/src/utils/dump_hir.rs +++ b/src/tools/clippy/clippy_lints/src/utils/dump_hir.rs @@ -2,9 +2,9 @@ use clippy_utils::get_attr; use hir::TraitItem; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; -declare_clippy_lint! { +declare_lint_pass!( /// ### What it does /// It formats the attached node with `{:#?}` and writes the result to the /// standard output. This is intended for debugging. @@ -19,12 +19,8 @@ declare_clippy_lint! { /// input as u64 /// } /// ``` - pub DUMP_HIR, - internal_warn, - "helper to dump info about code" -} - -declare_lint_pass!(DumpHir => [DUMP_HIR]); + DumpHir => [] +); impl<'tcx> LateLintPass<'tcx> for DumpHir { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { diff --git a/src/tools/clippy/clippy_lints/src/utils/format_args_collector.rs b/src/tools/clippy/clippy_lints/src/utils/format_args_collector.rs index 94a9a7c24..58e66c9f9 100644 --- a/src/tools/clippy/clippy_lints/src/utils/format_args_collector.rs +++ b/src/tools/clippy/clippy_lints/src/utils/format_args_collector.rs @@ -5,27 +5,20 @@ use rustc_ast::{Crate, Expr, ExprKind, FormatArgs}; use rustc_data_structures::fx::FxHashMap; use rustc_lexer::{tokenize, TokenKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{hygiene, Span}; use std::iter::once; use std::mem; use std::rc::Rc; -declare_clippy_lint! { - /// ### What it does - /// Collects [`rustc_ast::FormatArgs`] so that future late passes can call - /// [`clippy_utils::macros::find_format_args`] - pub FORMAT_ARGS_COLLECTOR, - internal_warn, - "collects `format_args` AST nodes for use in later lints" -} - +/// Collects [`rustc_ast::FormatArgs`] so that future late passes can call +/// [`clippy_utils::macros::find_format_args`] #[derive(Default)] pub struct FormatArgsCollector { format_args: FxHashMap<Span, Rc<FormatArgs>>, } -impl_lint_pass!(FormatArgsCollector => [FORMAT_ARGS_COLLECTOR]); +impl_lint_pass!(FormatArgsCollector => []); impl EarlyLintPass for FormatArgsCollector { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs index e222a5448..ddcb9f27c 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs @@ -1,5 +1,4 @@ pub mod almost_standard_lint_formulation; -pub mod clippy_lints_internal; pub mod collapsible_calls; pub mod compiler_lint_functions; pub mod if_chain_style; @@ -11,3 +10,4 @@ pub mod msrv_attr_impl; pub mod outer_expn_data_pass; pub mod produce_ice; pub mod unnecessary_def_path; +pub mod unsorted_clippy_utils_paths; diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs index 570a88a0e..d78f67c05 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs @@ -11,7 +11,7 @@ declare_clippy_lint! { /// Checks if lint formulations have a standardized format. /// /// ### Why is this bad? - /// It's not neccessarily bad, but we try to enforce a standard in Clippy. + /// It's not necessarily bad, but we try to enforce a standard in Clippy. /// /// ### Example /// `Checks for use...` can be written as `Checks for usage...` . diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/if_chain_style.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/if_chain_style.rs index fe2f12fe8..8cdd5ea89 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/if_chain_style.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/if_chain_style.rs @@ -30,7 +30,7 @@ impl<'tcx> LateLintPass<'tcx> for IfChainStyle { if_chain_local_span(cx, local, if_chain_span), "`let` expression should be above the `if_chain!`", ); - } else if local.span.ctxt() == block.span.ctxt() && is_if_chain_then(after, block.expr, if_chain_span) { + } else if local.span.eq_ctxt(block.span) && is_if_chain_then(after, block.expr, if_chain_span) { span_lint( cx, IF_CHAIN_STYLE, diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs index 82f9d4e41..fc9afe5ca 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs @@ -13,6 +13,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::ConstValue; use rustc_middle::ty; use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::sym; use rustc_span::symbol::Symbol; use std::borrow::Cow; @@ -160,12 +161,8 @@ impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol { impl InterningDefinedSymbol { fn symbol_str_expr<'tcx>(&self, expr: &'tcx Expr<'tcx>, cx: &LateContext<'tcx>) -> Option<SymbolStrExpr<'tcx>> { - static IDENT_STR_PATHS: &[&[&str]] = &[&paths::IDENT_AS_STR, &paths::TO_STRING_METHOD]; - static SYMBOL_STR_PATHS: &[&[&str]] = &[ - &paths::SYMBOL_AS_STR, - &paths::SYMBOL_TO_IDENT_STRING, - &paths::TO_STRING_METHOD, - ]; + static IDENT_STR_PATHS: &[&[&str]] = &[&paths::IDENT_AS_STR]; + static SYMBOL_STR_PATHS: &[&[&str]] = &[&paths::SYMBOL_AS_STR, &paths::SYMBOL_TO_IDENT_STRING]; let call = if_chain! { if let ExprKind::AddrOf(_, _, e) = expr.kind; if let ExprKind::Unary(UnOp::Deref, e) = e.kind; @@ -186,9 +183,19 @@ impl InterningDefinedSymbol { }; // ...which converts it to a string let paths = if is_ident { IDENT_STR_PATHS } else { SYMBOL_STR_PATHS }; - if let Some(path) = paths.iter().find(|path| match_def_path(cx, did, path)); + if let Some(is_to_owned) = paths + .iter() + .find_map(|path| if match_def_path(cx, did, path) { + Some(path == &paths::SYMBOL_TO_IDENT_STRING) + } else { + None + }) + .or_else(|| if cx.tcx.is_diagnostic_item(sym::to_string_method, did) { + Some(true) + } else { + None + }); then { - let is_to_owned = path.last().unwrap().ends_with("string"); return Some(SymbolStrExpr::Expr { item, is_ident, diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs index bbb5ade8b..00e352961 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs @@ -153,8 +153,9 @@ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass { let fields; if is_lint_ref_ty { if let ExprKind::AddrOf(_, _, inner_exp) = expr.kind - && let ExprKind::Struct(_, struct_fields, _) = inner_exp.kind { - fields = struct_fields; + && let ExprKind::Struct(_, struct_fields, _) = inner_exp.kind + { + fields = struct_fields; } else { return; } diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs index c38a3e81b..51abe0c1d 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs @@ -9,7 +9,7 @@ use crate::renamed_lints::RENAMED_LINTS; use crate::utils::internal_lints::lint_without_lint_pass::{extract_clippy_version_value, is_lint_ref_type}; -use crate::utils::{collect_configs, ClippyConfiguration}; +use clippy_config::{get_configuration_metadata, ClippyConfiguration}; use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::{match_type, walk_ptrs_ty_depth}; @@ -40,8 +40,6 @@ use std::process::Command; const JSON_OUTPUT_FILE: &str = "../util/gh-pages/lints.json"; /// This is the markdown output file of the lint collector. const MARKDOWN_OUTPUT_FILE: &str = "../book/src/lint_configuration.md"; -/// These lints are excluded from the export. -const BLACK_LISTED_LINTS: &[&str] = &["lint_author", "dump_hir", "internal_metadata_collector"]; /// These groups will be ignored by the lint group matcher. This is useful for collections like /// `clippy::all` const IGNORED_LINT_GROUPS: [&str; 1] = ["clippy::all"]; @@ -121,7 +119,7 @@ declare_clippy_lint! { /// ### Example output /// ```json,ignore /// { - /// "id": "internal_metadata_collector", + /// "id": "metadata_collector", /// "id_span": { /// "path": "clippy_lints/src/utils/internal_lints/metadata_collector.rs", /// "line": 1 @@ -131,12 +129,12 @@ declare_clippy_lint! { /// } /// ``` #[clippy::version = "1.56.0"] - pub INTERNAL_METADATA_COLLECTOR, - internal_warn, + pub METADATA_COLLECTOR, + internal, "A busy bee collection metadata about lints" } -impl_lint_pass!(MetadataCollector => [INTERNAL_METADATA_COLLECTOR]); +impl_lint_pass!(MetadataCollector => [METADATA_COLLECTOR]); #[allow(clippy::module_name_repetitions)] #[derive(Debug, Clone)] @@ -155,7 +153,7 @@ impl MetadataCollector { Self { lints: BinaryHeap::<LintMetadata>::default(), applicability_info: FxHashMap::<String, ApplicabilityInfo>::default(), - config: collect_configs(), + config: get_configuration_metadata(), clippy_project_root: std::env::current_dir() .expect("failed to get current dir") .ancestors() @@ -494,7 +492,7 @@ impl SerializableSpan { let loc: Loc = cx.sess().source_map().lookup_char_pos(span.lo()); Self { - path: format!("{}", loc.file.name.prefer_remapped()), + path: format!("{}", loc.file.name.prefer_remapped_unconditionaly()), line: loc.line, } } @@ -528,16 +526,6 @@ impl Serialize for ApplicabilityInfo { } } -impl fmt::Display for ClippyConfiguration { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> fmt::Result { - writeln!( - f, - "* `{}`: `{}`(defaults to `{}`): {}", - self.name, self.config_type, self.default, self.doc - ) - } -} - // ================================================================== // Lint pass // ================================================================== @@ -560,7 +548,6 @@ impl<'hir> LateLintPass<'hir> for MetadataCollector { if is_lint_ref_type(cx, ty); // disallow check let lint_name = sym_to_string(item.ident.name).to_ascii_lowercase(); - if !BLACK_LISTED_LINTS.contains(&lint_name.as_str()); // metadata extraction if let Some((group, level)) = get_lint_group_and_level_or_lint(cx, &lint_name, item); if let Some(mut raw_docs) = extract_attr_docs_or_lint(cx, item); @@ -585,7 +572,6 @@ impl<'hir> LateLintPass<'hir> for MetadataCollector { if is_deprecated_lint(cx, ty); // disallow check let lint_name = sym_to_string(item.ident.name).to_ascii_lowercase(); - if !BLACK_LISTED_LINTS.contains(&lint_name.as_str()); // Metadata the little we can get from a deprecated lint if let Some(raw_docs) = extract_attr_docs_or_lint(cx, item); then { @@ -841,7 +827,7 @@ fn collect_renames(lints: &mut Vec<LintMetadata>) { fn lint_collection_error_item(cx: &LateContext<'_>, item: &Item<'_>, message: &str) { span_lint( cx, - INTERNAL_METADATA_COLLECTOR, + METADATA_COLLECTOR, item.ident.span, &format!("metadata collection error for `{}`: {message}", item.ident.name), ); diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs index a3acb8f17..81be04659 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs @@ -270,7 +270,8 @@ fn read_mir_alloc_def_path<'tcx>(cx: &LateContext<'tcx>, alloc: &'tcx Allocation if let GlobalAlloc::Memory(alloc) = cx.tcx.global_alloc(alloc) { let alloc = alloc.inner(); str::from_utf8(alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len())) - .ok().map(ToOwned::to_owned) + .ok() + .map(ToOwned::to_owned) } else { None } diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/clippy_lints_internal.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unsorted_clippy_utils_paths.rs index da9514dd1..fd51bca9e 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/clippy_lints_internal.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unsorted_clippy_utils_paths.rs @@ -5,21 +5,21 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { /// ### What it does - /// Checks for various things we like to keep tidy in clippy. + /// Checks that [`clippy_utils::paths`] is sorted lexically /// /// ### Why is this bad? /// We like to pretend we're an example of tidy code. /// /// ### Example /// Wrong ordering of the util::paths constants. - pub CLIPPY_LINTS_INTERNAL, + pub UNSORTED_CLIPPY_UTILS_PATHS, internal, "various things that will negatively affect your clippy experience" } -declare_lint_pass!(ClippyLintsInternal => [CLIPPY_LINTS_INTERNAL]); +declare_lint_pass!(UnsortedClippyUtilsPaths => [UNSORTED_CLIPPY_UTILS_PATHS]); -impl EarlyLintPass for ClippyLintsInternal { +impl EarlyLintPass for UnsortedClippyUtilsPaths { fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &Crate) { if let Some(utils) = krate.items.iter().find(|item| item.ident.name.as_str() == "utils") { if let ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) = utils.kind { @@ -32,7 +32,7 @@ impl EarlyLintPass for ClippyLintsInternal { if *last_name > *name { span_lint( cx, - CLIPPY_LINTS_INTERNAL, + UNSORTED_CLIPPY_UTILS_PATHS, item.span, "this constant should be before the previous constant due to lexical \ ordering", diff --git a/src/tools/clippy/clippy_lints/src/utils/mod.rs b/src/tools/clippy/clippy_lints/src/utils/mod.rs index 4fef8c071..13e9ead9a 100644 --- a/src/tools/clippy/clippy_lints/src/utils/mod.rs +++ b/src/tools/clippy/clippy_lints/src/utils/mod.rs @@ -1,148 +1,5 @@ pub mod author; -pub mod conf; pub mod dump_hir; pub mod format_args_collector; #[cfg(feature = "internal")] pub mod internal_lints; -#[cfg(feature = "internal")] -use itertools::Itertools; - -/// Transforms a given `snake_case_string` to a tasty `kebab-case-string` -fn to_kebab(config_name: &str) -> String { - config_name.replace('_', "-") -} - -#[cfg(feature = "internal")] -const BOOK_CONFIGS_PATH: &str = "https://doc.rust-lang.org/clippy/lint_configuration.html"; - -// ================================================================== -// Configuration -// ================================================================== -#[derive(Debug, Clone, Default)] -pub struct ClippyConfiguration { - pub name: String, - #[allow(dead_code)] - config_type: &'static str, - pub default: String, - pub lints: Vec<String>, - pub doc: String, - #[allow(dead_code)] - deprecation_reason: Option<&'static str>, -} - -impl ClippyConfiguration { - pub fn new( - name: &'static str, - config_type: &'static str, - default: String, - doc_comment: &'static str, - deprecation_reason: Option<&'static str>, - ) -> Self { - let (lints, doc) = parse_config_field_doc(doc_comment) - .unwrap_or_else(|| (vec![], "[ERROR] MALFORMED DOC COMMENT".to_string())); - - Self { - name: to_kebab(name), - lints, - doc, - config_type, - default, - deprecation_reason, - } - } - - #[cfg(feature = "internal")] - fn to_markdown_paragraph(&self) -> String { - format!( - "## `{}`\n{}\n\n**Default Value:** `{}` (`{}`)\n\n---\n**Affected lints:**\n{}\n\n", - self.name, - self.doc - .lines() - .map(|line| line.strip_prefix(" ").unwrap_or(line)) - .join("\n"), - self.default, - self.config_type, - self.lints - .iter() - .map(|name| name.to_string().split_whitespace().next().unwrap().to_string()) - .map(|name| format!("* [`{name}`](https://rust-lang.github.io/rust-clippy/master/index.html#{name})")) - .join("\n"), - ) - } - #[cfg(feature = "internal")] - fn to_markdown_link(&self) -> String { - format!("[`{}`]: {BOOK_CONFIGS_PATH}#{}", self.name, self.name) - } -} - -#[cfg(feature = "internal")] -fn collect_configs() -> Vec<ClippyConfiguration> { - crate::utils::conf::metadata::get_configuration_metadata() -} - -/// This parses the field documentation of the config struct. -/// -/// ```rust, ignore -/// parse_config_field_doc(cx, "Lint: LINT_NAME_1, LINT_NAME_2. Papa penguin, papa penguin") -/// ``` -/// -/// Would yield: -/// ```rust, ignore -/// Some(["lint_name_1", "lint_name_2"], "Papa penguin, papa penguin") -/// ``` -fn parse_config_field_doc(doc_comment: &str) -> Option<(Vec<String>, String)> { - const DOC_START: &str = " Lint: "; - if_chain! { - if doc_comment.starts_with(DOC_START); - if let Some(split_pos) = doc_comment.find('.'); - then { - let mut doc_comment = doc_comment.to_string(); - let mut documentation = doc_comment.split_off(split_pos); - - // Extract lints - doc_comment.make_ascii_lowercase(); - let lints: Vec<String> = doc_comment - .split_off(DOC_START.len()) - .split(", ") - .map(str::to_string) - .collect(); - - // Format documentation correctly - // split off leading `.` from lint name list and indent for correct formatting - documentation = documentation.trim_start_matches('.').trim().replace("\n ", "\n "); - - Some((lints, documentation)) - } else { - None - } - } -} - -// Shamelessly stolen from find_all (https://github.com/nectariner/find_all) -pub trait FindAll: Iterator + Sized { - fn find_all<P>(&mut self, predicate: P) -> Option<Vec<usize>> - where - P: FnMut(&Self::Item) -> bool; -} - -impl<I> FindAll for I -where - I: Iterator, -{ - fn find_all<P>(&mut self, mut predicate: P) -> Option<Vec<usize>> - where - P: FnMut(&Self::Item) -> bool, - { - let mut occurences = Vec::<usize>::default(); - for (index, element) in self.enumerate() { - if predicate(&element) { - occurences.push(index); - } - } - - match occurences.len() { - 0 => None, - _ => Some(occurences), - } - } -} diff --git a/src/tools/clippy/clippy_lints/src/vec.rs b/src/tools/clippy/clippy_lints/src/vec.rs index fc17e7c6d..a9a3aaad3 100644 --- a/src/tools/clippy/clippy_lints/src/vec.rs +++ b/src/tools/clippy/clippy_lints/src/vec.rs @@ -1,8 +1,8 @@ use std::ops::ControlFlow; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{constant, Constant}; 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; use clippy_utils::visitors::for_each_local_use_after_expr; @@ -14,8 +14,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::source_map::Span; -use rustc_span::sym; +use rustc_span::{sym, Span}; #[expect(clippy::module_name_repetitions)] #[derive(Clone)] @@ -33,14 +32,14 @@ declare_clippy_lint! { /// This is less efficient. /// /// ### Example - /// ```rust + /// ```no_run /// fn foo(_x: &[u8]) {} /// /// foo(&vec![1, 2]); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # fn foo(_x: &[u8]) {} /// foo(&[1, 2]); /// ``` @@ -110,14 +109,15 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec { } else { ControlFlow::Break(()) } - }).is_continue(); + }) + .is_continue(); if only_slice_uses { self.check_vec_macro( cx, &vec_args, expr.span.ctxt().outer_expn_data().call_site, - SuggestedType::Array + SuggestedType::Array, ); } } diff --git a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs index 3fa51216c..c8b9402f1 100644 --- a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs +++ b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs @@ -30,13 +30,15 @@ declare_clippy_lint! { /// multiple `push` calls. /// /// ### Example - /// ```rust + /// ```no_run /// let mut v = Vec::new(); /// v.push(0); + /// v.push(1); + /// v.push(2); /// ``` /// Use instead: - /// ```rust - /// let v = vec![0]; + /// ```no_run + /// let v = vec![0, 1, 2]; /// ``` #[clippy::version = "1.51.0"] pub VEC_INIT_THEN_PUSH, @@ -209,7 +211,7 @@ impl<'tcx> LateLintPass<'tcx> for VecInitThenPush { found: searcher.found + 1, err_span: searcher.err_span.to(stmt.span), last_push_expr: expr.hir_id, - .. searcher + ..searcher }); } else { searcher.display_err(cx); diff --git a/src/tools/clippy/clippy_lints/src/visibility.rs b/src/tools/clippy/clippy_lints/src/visibility.rs index 496376520..8abcc964b 100644 --- a/src/tools/clippy/clippy_lints/src/visibility.rs +++ b/src/tools/clippy/clippy_lints/src/visibility.rs @@ -82,7 +82,9 @@ impl EarlyLintPass for Visibility { if !in_external_macro(cx.sess(), item.span) && let VisibilityKind::Restricted { path, shorthand, .. } = &item.vis.kind { - if **path == kw::SelfLower && let Some(false) = is_from_proc_macro(cx, item.vis.span) { + if **path == kw::SelfLower + && let Some(false) = is_from_proc_macro(cx, item.vis.span) + { span_lint_and_sugg( cx, NEEDLESS_PUB_SELF, diff --git a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs index d09d02a7d..d88ede763 100644 --- a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs +++ b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs @@ -24,7 +24,7 @@ declare_clippy_lint! { /// still around. /// /// ### Example - /// ```rust + /// ```no_run /// use std::cmp::Ordering::*; /// /// # fn foo(_: std::cmp::Ordering) {} @@ -32,7 +32,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// use std::cmp::Ordering; /// /// # fn foo(_: Ordering) {} @@ -132,6 +132,7 @@ impl LateLintPass<'_> for WildcardImports { if self.warn_on_all || !self.check_exceptions(item, use_path.segments); let used_imports = cx.tcx.names_imported_by_glob_use(item.owner_id.def_id); if !used_imports.is_empty(); // Already handled by `unused_imports` + if !used_imports.contains(&kw::Underscore); then { let mut applicability = Applicability::MachineApplicable; let import_source_snippet = snippet_with_applicability(cx, use_path.span, "..", &mut applicability); diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs index da083fb14..b6f942a90 100644 --- a/src/tools/clippy/clippy_lints/src/write.rs +++ b/src/tools/clippy/clippy_lints/src/write.rs @@ -3,12 +3,15 @@ use clippy_utils::macros::{find_format_args, format_arg_removal_span, root_macro use clippy_utils::source::{expand_past_previous_comma, snippet_opt}; use clippy_utils::{is_in_cfg_test, is_in_test_function}; use rustc_ast::token::LitKind; -use rustc_ast::{FormatArgPosition, FormatArgs, FormatArgsPiece, FormatOptions, FormatPlaceholder, FormatTrait}; +use rustc_ast::{ + FormatArgPosition, FormatArgPositionKind, FormatArgs, FormatArgsPiece, FormatOptions, FormatPlaceholder, + FormatTrait, +}; use rustc_errors::Applicability; use rustc_hir::{Expr, Impl, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::{sym, BytePos}; +use rustc_span::{sym, BytePos, Span}; declare_clippy_lint! { /// ### What it does @@ -19,12 +22,12 @@ declare_clippy_lint! { /// You should use `println!()`, which is simpler. /// /// ### Example - /// ```rust + /// ```no_run /// println!(""); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// println!(); /// ``` #[clippy::version = "pre 1.29.0"] @@ -43,12 +46,12 @@ declare_clippy_lint! { /// newline. /// /// ### Example - /// ```rust + /// ```no_run /// # let name = "World"; /// print!("Hello {}!\n", name); /// ``` /// use println!() instead - /// ```rust + /// ```no_run /// # let name = "World"; /// println!("Hello {}!", name); /// ``` @@ -71,7 +74,7 @@ declare_clippy_lint! { /// Only catches `print!` and `println!` calls. /// /// ### Example - /// ```rust + /// ```no_run /// println!("Hello world!"); /// ``` #[clippy::version = "pre 1.29.0"] @@ -93,7 +96,7 @@ declare_clippy_lint! { /// Only catches `eprint!` and `eprintln!` calls. /// /// ### Example - /// ```rust + /// ```no_run /// eprintln!("Hello world!"); /// ``` #[clippy::version = "1.50.0"] @@ -112,7 +115,7 @@ declare_clippy_lint! { /// debugging Rust code. It should not be used in user-facing output. /// /// ### Example - /// ```rust + /// ```no_run /// # let foo = "bar"; /// println!("{:?}", foo); /// ``` @@ -132,11 +135,11 @@ declare_clippy_lint! { /// (i.e., just put the literal in the format string) /// /// ### Example - /// ```rust + /// ```no_run /// println!("{}", "foo"); /// ``` /// use the literal without formatting: - /// ```rust + /// ```no_run /// println!("foo"); /// ``` #[clippy::version = "pre 1.29.0"] @@ -154,14 +157,14 @@ declare_clippy_lint! { /// You should use `writeln!(buf)`, which is simpler. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::fmt::Write; /// # let mut buf = String::new(); /// writeln!(buf, ""); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # use std::fmt::Write; /// # let mut buf = String::new(); /// writeln!(buf); @@ -183,7 +186,7 @@ declare_clippy_lint! { /// newline. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::fmt::Write; /// # let mut buf = String::new(); /// # let name = "World"; @@ -191,7 +194,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # use std::fmt::Write; /// # let mut buf = String::new(); /// # let name = "World"; @@ -213,14 +216,14 @@ declare_clippy_lint! { /// (i.e., just put the literal in the format string) /// /// ### Example - /// ```rust + /// ```no_run /// # use std::fmt::Write; /// # let mut buf = String::new(); /// writeln!(buf, "{}", "foo"); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # use std::fmt::Write; /// # let mut buf = String::new(); /// writeln!(buf, "foo"); @@ -339,7 +342,10 @@ impl<'tcx> LateLintPass<'tcx> for Write { } fn is_debug_impl(cx: &LateContext<'_>, item: &Item<'_>) -> bool { - if let ItemKind::Impl(Impl { of_trait: Some(trait_ref), .. }) = &item.kind + if let ItemKind::Impl(Impl { + of_trait: Some(trait_ref), + .. + }) = &item.kind && let Some(trait_id) = trait_ref.trait_def_id() { cx.tcx.is_diagnostic_item(sym::Debug, trait_id) @@ -450,6 +456,12 @@ fn check_empty_string(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) { let arg_index = |argument: &FormatArgPosition| argument.index.unwrap_or_else(|pos| pos); + let lint_name = if name.starts_with("write") { + WRITE_LITERAL + } else { + PRINT_LITERAL + }; + let mut counts = vec![0u32; format_args.arguments.all_args().len()]; for piece in &format_args.template { if let FormatArgsPiece::Placeholder(placeholder) = piece { @@ -457,6 +469,12 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) { } } + let mut suggestion: Vec<(Span, String)> = vec![]; + // holds index of replaced positional arguments; used to decrement the index of the remaining + // positional arguments. + let mut replaced_position: Vec<usize> = vec![]; + let mut sug_span: Option<Span> = None; + for piece in &format_args.template { if let FormatArgsPiece::Placeholder(FormatPlaceholder { argument, @@ -471,9 +489,9 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) { && let rustc_ast::ExprKind::Lit(lit) = &arg.expr.kind && !arg.expr.span.from_expansion() && let Some(value_string) = snippet_opt(cx, arg.expr.span) - { + { let (replacement, replace_raw) = match lit.kind { - LitKind::Str | LitKind::StrRaw(_) => match extract_str_literal(&value_string) { + LitKind::Str | LitKind::StrRaw(_) => match extract_str_literal(&value_string) { Some(extracted) => extracted, None => return, }, @@ -493,13 +511,9 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) { _ => continue, }; - let lint = if name.starts_with("write") { - WRITE_LITERAL - } else { - PRINT_LITERAL + let Some(format_string_snippet) = snippet_opt(cx, format_args.span) else { + continue; }; - - let Some(format_string_snippet) = snippet_opt(cx, format_args.span) else { continue }; let format_string_is_raw = format_string_snippet.starts_with('r'); let replacement = match (format_string_is_raw, replace_raw) { @@ -519,29 +533,60 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) { }, }; - span_lint_and_then( - cx, - lint, - arg.expr.span, - "literal with an empty format string", - |diag| { - if let Some(replacement) = replacement - // `format!("{}", "a")`, `format!("{named}", named = "b") - // ~~~~~ ~~~~~~~~~~~~~ - && let Some(removal_span) = format_arg_removal_span(format_args, index) - { - let replacement = replacement.replace('{', "{{").replace('}', "}}"); - diag.multipart_suggestion( - "try", - vec![(*placeholder_span, replacement), (removal_span, String::new())], - Applicability::MachineApplicable, - ); - } - }, - ); + sug_span = Some(sug_span.unwrap_or(arg.expr.span).to(arg.expr.span)); + if let Some((_, index)) = positional_arg_piece_span(piece) { + replaced_position.push(index); + } + + if let Some(replacement) = replacement + // `format!("{}", "a")`, `format!("{named}", named = "b") + // ~~~~~ ~~~~~~~~~~~~~ + && let Some(removal_span) = format_arg_removal_span(format_args, index) + { + let replacement = escape_braces(&replacement, !format_string_is_raw && !replace_raw); + suggestion.push((*placeholder_span, replacement)); + suggestion.push((removal_span, String::new())); + } + } + } + + // Decrement the index of the remaining by the number of replaced positional arguments + if !suggestion.is_empty() { + for piece in &format_args.template { + if let Some((span, index)) = positional_arg_piece_span(piece) + && suggestion.iter().all(|(s, _)| *s != span) + { + let decrement = replaced_position.iter().filter(|i| **i < index).count(); + suggestion.push((span, format!("{{{}}}", index.saturating_sub(decrement)))); + } } } + + if let Some(span) = sug_span { + span_lint_and_then(cx, lint_name, span, "literal with an empty format string", |diag| { + if !suggestion.is_empty() { + diag.multipart_suggestion("try", suggestion, Applicability::MachineApplicable); + } + }); + } +} + +/// Extract Span and its index from the given `piece`, iff it's positional argument. +fn positional_arg_piece_span(piece: &FormatArgsPiece) -> Option<(Span, usize)> { + match piece { + FormatArgsPiece::Placeholder(FormatPlaceholder { + argument: + FormatArgPosition { + index: Ok(index), + kind: FormatArgPositionKind::Number, + .. + }, + span: Some(span), + .. + }) => Some((*span, *index)), + _ => None, + } } /// Removes the raw marker, `#`s and quotes from a str, and returns if the literal is raw @@ -593,3 +638,47 @@ fn conservative_unescape(literal: &str) -> Result<String, UnescapeErr> { if err { Err(UnescapeErr::Lint) } else { Ok(unescaped) } } + +/// Replaces `{` with `{{` and `}` with `}}`. If `preserve_unicode_escapes` is `true` the braces in +/// `\u{xxxx}` are left unmodified +#[expect(clippy::match_same_arms)] +fn escape_braces(literal: &str, preserve_unicode_escapes: bool) -> String { + #[derive(Clone, Copy)] + enum State { + Normal, + Backslash, + UnicodeEscape, + } + + let mut escaped = String::with_capacity(literal.len()); + let mut state = State::Normal; + + for ch in literal.chars() { + state = match (ch, state) { + // Escape braces outside of unicode escapes by doubling them up + ('{' | '}', State::Normal) => { + escaped.push(ch); + State::Normal + }, + // If `preserve_unicode_escapes` isn't enabled stay in `State::Normal`, otherwise: + // + // \u{aaaa} \\ \x01 + // ^ ^ ^ + ('\\', State::Normal) if preserve_unicode_escapes => State::Backslash, + // \u{aaaa} + // ^ + ('u', State::Backslash) => State::UnicodeEscape, + // \xAA \\ + // ^ ^ + (_, State::Backslash) => State::Normal, + // \u{aaaa} + // ^ + ('}', State::UnicodeEscape) => State::Normal, + _ => state, + }; + + escaped.push(ch); + } + + escaped +} diff --git a/src/tools/clippy/clippy_lints/src/zero_div_zero.rs b/src/tools/clippy/clippy_lints/src/zero_div_zero.rs index 9b3de35db..f2f0699ef 100644 --- a/src/tools/clippy/clippy_lints/src/zero_div_zero.rs +++ b/src/tools/clippy/clippy_lints/src/zero_div_zero.rs @@ -13,12 +13,12 @@ declare_clippy_lint! { /// It's less readable than `f32::NAN` or `f64::NAN`. /// /// ### Example - /// ```rust + /// ```no_run /// let nan = 0.0f32 / 0.0; /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let nan = f32::NAN; /// ``` #[clippy::version = "pre 1.29.0"] diff --git a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs index 002304f88..fee100fe1 100644 --- a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs +++ b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs @@ -23,14 +23,14 @@ declare_clippy_lint! { /// * This lints the signature of public items /// /// ### Example - /// ```rust + /// ```no_run /// # use std::collections::HashMap; /// fn unique_words(text: &str) -> HashMap<&str, ()> { /// todo!(); /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # use std::collections::HashSet; /// fn unique_words(text: &str) -> HashSet<&str> { /// todo!(); |