Auto merge of #125764 - flip1995:clippy-subtree-update, r=Manishearth

Clippy subtree update

r? `@Manishearth`
This commit is contained in:
bors 2024-05-30 16:46:31 +00:00
commit 51347ba3c7
128 changed files with 1430 additions and 684 deletions

View file

@ -12,7 +12,7 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for usage of items through absolute paths, like `std::env::current_dir`.
///
/// ### Why is this bad?
/// ### Why restrict this?
/// Many codebases have their own style when it comes to importing, but one that is seldom used
/// is using absolute paths *everywhere*. This is generally considered unidiomatic, and you
/// should add a `use` statement.

View file

@ -19,10 +19,11 @@ declare_clippy_lint! {
/// This lint only warns outer attributes (`#[allow]`), as inner attributes
/// (`#![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
/// ### Why restrict this?
/// `#[allow]` attributes can linger after their reason for existence is gone.
/// `#[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.
/// lint is no longer triggered, which may indicate the attribute can be removed.
///
/// ### Example
/// ```rust,ignore

View file

@ -17,7 +17,7 @@ declare_clippy_lint! {
/// There is a good explanation the reason why this lint should work in this way and how it is useful
/// [in this issue](https://github.com/rust-lang/rust-clippy/issues/5122).
///
/// ### Why is this bad?
/// ### Why restrict this?
/// `as` conversions will perform many kinds of
/// conversions, including silently lossy conversions and dangerous coercions.
/// There are cases when it makes sense to use `as`, so the lint is

View file

@ -65,9 +65,8 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for usage of Intel x86 assembly syntax.
///
/// ### Why is this bad?
/// The lint has been enabled to indicate a preference
/// for AT&T x86 assembly syntax.
/// ### Why restrict this?
/// To enforce consistent use of AT&T x86 assembly syntax.
///
/// ### Example
///
@ -114,9 +113,8 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for usage of AT&T x86 assembly syntax.
///
/// ### Why is this bad?
/// The lint has been enabled to indicate a preference
/// for Intel x86 assembly syntax.
/// ### Why restrict this?
/// To enforce consistent use of Intel x86 assembly syntax.
///
/// ### Example
///

View file

@ -16,23 +16,33 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for `assert!(r.is_ok())` or `assert!(r.is_err())` calls.
///
/// ### Why is this bad?
/// An assertion failure cannot output an useful message of the error.
/// ### Why restrict this?
/// This form of assertion does not show any of the information present in the `Result`
/// other than which variant it isnt.
///
/// ### Known problems
/// The suggested replacement decreases the readability of code and log output.
///
/// ### Example
/// ```rust,ignore
/// ```rust,no_run
/// # let r = Ok::<_, ()>(());
/// assert!(r.is_ok());
/// # let r = Err::<_, ()>(());
/// # let r = Err::<(), _>(());
/// assert!(r.is_err());
/// ```
///
/// Use instead:
///
/// ```rust,no_run
/// # let r = Ok::<_, ()>(());
/// r.unwrap();
/// # let r = Err::<(), _>(());
/// r.unwrap_err();
/// ```
#[clippy::version = "1.64.0"]
pub ASSERTIONS_ON_RESULT_STATES,
restriction,
"`assert!(r.is_ok())`/`assert!(r.is_err())` gives worse error message than directly calling `r.unwrap()`/`r.unwrap_err()`"
"`assert!(r.is_ok())` or `assert!(r.is_err())` gives worse panic messages than directly calling `r.unwrap()` or `r.unwrap_err()`"
}
declare_lint_pass!(AssertionsOnResultStates => [ASSERTIONS_ON_RESULT_STATES]);

View file

@ -309,9 +309,9 @@ declare_clippy_lint! {
///
/// (This requires the `lint_reasons` feature)
///
/// ### Why is this bad?
/// Allowing a lint should always have a reason. This reason should be documented to
/// ensure that others understand the reasoning
/// ### Why restrict this?
/// Justifying each `allow` helps readers understand the reasoning,
/// and may allow removing `allow` attributes if their purpose is obsolete.
///
/// ### Example
/// ```no_run

View file

@ -303,7 +303,7 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for casts of a function pointer to any integer type.
///
/// ### Why is this bad?
/// ### Why restrict this?
/// Casting a function pointer to an integer can have surprising results and can occur
/// accidentally if parentheses are omitted from a function call. If you aren't doing anything
/// low-level with function pointers then you can opt-out of casting functions to integers in
@ -535,8 +535,8 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for the usage of `as _` conversion using inferred type.
///
/// ### Why is this bad?
/// The conversion might include lossy conversion and dangerous cast that might go
/// ### Why restrict this?
/// The conversion might include lossy conversion or a dangerous cast that might go
/// undetected due to the type being inferred.
///
/// The lint is allowed by default as using `_` is less wordy than always specifying the type.

View file

@ -10,8 +10,10 @@ declare_clippy_lint! {
/// ### What it does
/// Checks usage of `std::fs::create_dir` and suggest using `std::fs::create_dir_all` instead.
///
/// ### Why is this bad?
/// Sometimes `std::fs::create_dir` is mistakenly chosen over `std::fs::create_dir_all`.
/// ### Why restrict this?
/// Sometimes `std::fs::create_dir` is mistakenly chosen over `std::fs::create_dir_all`,
/// resulting in failure when more than one directory needs to be created or when the directory already exists.
/// Crates which never need to specifically create a single directory may wish to prevent this mistake.
///
/// ### Example
/// ```rust,ignore

View file

@ -14,7 +14,7 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for usage of the [`dbg!`](https://doc.rust-lang.org/std/macro.dbg.html) macro.
///
/// ### Why is this bad?
/// ### Why restrict this?
/// The `dbg!` macro is intended as a debugging tool. It should not be present in released
/// software or committed to a version control system.
///

View file

@ -22,9 +22,8 @@ declare_clippy_lint! {
///
/// See [RFC0212](https://github.com/rust-lang/rfcs/blob/master/text/0212-restore-int-fallback.md) for more information about the fallback.
///
/// ### Why is this bad?
/// For those who are very careful about types, default numeric fallback
/// can be a pitfall that cause unexpected runtime behavior.
/// ### Why restrict this?
/// To ensure that every numeric type is chosen explicitly rather than implicitly.
///
/// ### Known problems
/// This lint can only be allowed at the function level or above.

View file

@ -10,7 +10,7 @@ declare_clippy_lint! {
/// ### What it does
/// Displays a warning when a union is declared with the default representation (without a `#[repr(C)]` attribute).
///
/// ### Why is this bad?
/// ### Why restrict this?
/// Unions in Rust have unspecified layout by default, despite many people thinking that they
/// lay out each field at the start of the union (like C does). That is, there are no guarantees
/// about the offset of the fields for unions with multiple non-ZST fields without an explicitly

View file

@ -2,7 +2,9 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
use clippy_utils::sugg::has_enclosing_paren;
use clippy_utils::ty::{implements_trait, is_manually_drop, peel_mid_ty_refs};
use clippy_utils::{expr_use_ctxt, get_parent_expr, is_lint_allowed, path_to_local, DefinedTy, ExprUseNode};
use clippy_utils::{
expr_use_ctxt, get_parent_expr, is_block_like, is_lint_allowed, path_to_local, DefinedTy, ExprUseNode,
};
use core::mem;
use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX};
use rustc_data_structures::fx::FxIndexMap;
@ -1038,14 +1040,8 @@ fn report<'tcx>(
);
},
State::ExplicitDeref { mutability } => {
if matches!(
expr.kind,
ExprKind::Block(..)
| ExprKind::ConstBlock(_)
| ExprKind::If(..)
| ExprKind::Loop(..)
| ExprKind::Match(..)
) && let ty::Ref(_, ty, _) = data.adjusted_ty.kind()
if is_block_like(expr)
&& let ty::Ref(_, ty, _) = data.adjusted_ty.kind()
&& ty.is_sized(cx.tcx, cx.param_env)
{
// Rustc bug: auto deref doesn't work on block expression when targeting sized types.

View file

@ -1,17 +1,17 @@
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then};
use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_then, span_lint_hir_and_then};
use clippy_utils::ty::{implements_trait, implements_trait_with_env, is_copy};
use clippy_utils::{has_non_exhaustive_attr, is_lint_allowed, match_def_path, paths};
use rustc_errors::Applicability;
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, Visitor};
use rustc_hir::{
self as hir, BlockCheckMode, BodyId, Expr, ExprKind, FnDecl, Safety, Impl, Item, ItemKind, UnsafeSource,
self as hir, BlockCheckMode, BodyId, Expr, ExprKind, FnDecl, Impl, Item, ItemKind, Safety, UnsafeSource,
};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter;
use rustc_middle::traits::Reveal;
use rustc_middle::ty::{
self, ClauseKind, GenericArgKind, GenericParamDefKind, ParamEnv, Upcast, TraitPredicate, Ty, TyCtxt,
self, ClauseKind, GenericArgKind, GenericParamDefKind, ParamEnv, TraitPredicate, Ty, TyCtxt, Upcast,
};
use rustc_session::declare_lint_pass;
use rustc_span::def_id::LocalDefId;
@ -390,13 +390,17 @@ fn check_unsafe_derive_deserialize<'tcx>(
.map(|imp_did| cx.tcx.hir().expect_item(imp_did.expect_local()))
.any(|imp| has_unsafe(cx, imp))
{
span_lint_and_help(
span_lint_hir_and_then(
cx,
UNSAFE_DERIVE_DESERIALIZE,
adt_hir_id,
item.span,
"you are deriving `serde::Deserialize` on a type that has methods using `unsafe`",
None,
"consider implementing `serde::Deserialize` manually. See https://serde.rs/impl-deserialize.html",
|diag| {
diag.help(
"consider implementing `serde::Deserialize` manually. See https://serde.rs/impl-deserialize.html",
);
},
);
}
}
@ -452,20 +456,27 @@ fn check_partial_eq_without_eq<'tcx>(cx: &LateContext<'tcx>, span: Span, trait_r
&& !has_non_exhaustive_attr(cx.tcx, *adt)
&& !ty_implements_eq_trait(cx.tcx, ty, eq_trait_def_id)
&& let param_env = param_env_for_derived_eq(cx.tcx, adt.did(), eq_trait_def_id)
&& let Some(local_def_id) = adt.did().as_local()
// If all of our fields implement `Eq`, we can implement `Eq` too
&& adt
.all_fields()
.map(|f| f.ty(cx.tcx, args))
.all(|ty| implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, None, &[]))
{
span_lint_and_sugg(
span_lint_hir_and_then(
cx,
DERIVE_PARTIAL_EQ_WITHOUT_EQ,
cx.tcx.local_def_id_to_hir_id(local_def_id),
span.ctxt().outer_expn_data().call_site,
"you are deriving `PartialEq` and can implement `Eq`",
"consider deriving `Eq` as well",
"PartialEq, Eq".to_string(),
Applicability::MachineApplicable,
|diag| {
diag.span_suggestion(
span.ctxt().outer_expn_data().call_site,
"consider deriving `Eq` as well",
"PartialEq, Eq",
Applicability::MachineApplicable,
);
},
);
}
}

View file

@ -20,11 +20,11 @@ declare_clippy_lint! {
/// [aliases]: http://www.unicode.org/reports/tr24/tr24-31.html#Script_Value_Aliases
/// [supported_scripts]: https://www.unicode.org/iso15924/iso15924-codes.html
///
/// ### Why is this bad?
/// ### Why restrict this?
/// It may be not desired to have many different scripts for
/// identifiers in the codebase.
///
/// Note that if you only want to allow plain English, you might want to use
/// Note that if you only want to allow typical English, you might want to use
/// built-in [`non_ascii_idents`] lint instead.
///
/// [`non_ascii_idents`]: https://doc.rust-lang.org/rustc/lints/listing/allowed-by-default.html#non-ascii-idents

View file

@ -1,4 +1,4 @@
use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
use clippy_utils::source::snippet_with_applicability;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{Applicability, SuggestionStyle};
@ -30,6 +30,7 @@ pub fn check(
word = tmp_word;
}
let original_len = word.len();
word = word.trim_start_matches(trim_pattern);
// Remove leading or trailing single `:` which may be part of a sentence.
@ -44,6 +45,25 @@ pub fn check(
continue;
}
// Ensure that all reachable matching closing parens are included as well.
let size_diff = original_len - word.len();
let mut open_parens = 0;
let mut close_parens = 0;
for c in word.chars() {
if c == '(' {
open_parens += 1;
} else if c == ')' {
close_parens += 1;
}
}
while close_parens < open_parens
&& let Some(tmp_word) = orig_word.get(size_diff..=(word.len() + size_diff))
&& tmp_word.ends_with(')')
{
word = tmp_word;
close_parens += 1;
}
// Adjust for the current word
let offset = word.as_ptr() as usize - text.as_ptr() as usize;
let span = Span::new(
@ -92,13 +112,15 @@ fn check_word(cx: &LateContext<'_>, word: &str, span: Span, code_level: isize, b
if let Ok(url) = Url::parse(word) {
// try to get around the fact that `foo::bar` parses as a valid URL
if !url.cannot_be_a_base() {
span_lint(
span_lint_and_sugg(
cx,
DOC_MARKDOWN,
span,
"you should put bare URLs between `<`/`>` or make a proper Markdown link",
"try",
format!("<{word}>"),
Applicability::MachineApplicable,
);
return;
}
}

View file

@ -261,7 +261,7 @@ declare_clippy_lint! {
/// Checks for the doc comments of publicly visible
/// safe functions and traits and warns if there is a `# Safety` section.
///
/// ### Why is this bad?
/// ### Why restrict this?
/// Safe functions and traits are safe to implement and therefore do not
/// need to describe safety preconditions that users are required to uphold.
///

View file

@ -52,9 +52,10 @@ declare_clippy_lint! {
/// Checks for usage of `std::mem::forget(t)` where `t` is
/// `Drop` or has a field that implements `Drop`.
///
/// ### Why is this bad?
/// `std::mem::forget(t)` prevents `t` from running its
/// destructor, possibly causing leaks.
/// ### Why restrict this?
/// `std::mem::forget(t)` prevents `t` from running its destructor, possibly causing leaks.
/// It is not possible to detect all means of creating leaks, but it may be desirable to
/// prohibit the simple ones.
///
/// ### Example
/// ```no_run

View file

@ -11,7 +11,7 @@ declare_clippy_lint! {
/// Checks for usage of if expressions with an `else if` branch,
/// but without a final `else` branch.
///
/// ### Why is this bad?
/// ### Why restrict this?
/// Some coding guidelines require this (e.g., MISRA-C:2004 Rule 14.10).
///
/// ### Example

View file

@ -9,7 +9,7 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for empty `Drop` implementations.
///
/// ### Why is this bad?
/// ### Why restrict this?
/// Empty `Drop` implementations have no effect when dropping an instance of the type. They are
/// most likely useless. However, an empty `Drop` implementation prevents a type from being
/// destructured, which might be the intention behind adding the implementation as a marker.

View file

@ -7,32 +7,53 @@ use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
/// Checks for `enum`s with no variants.
/// Checks for `enum`s with no variants, which therefore are uninhabited types
/// (cannot be instantiated).
///
/// As of this writing, the `never_type` is still a
/// nightly-only experimental API. Therefore, this lint is only triggered
/// if the `never_type` is enabled.
/// As of this writing, the `never_type` is still a nightly-only experimental API.
/// Therefore, this lint is only triggered if `#![feature(never_type)]` is enabled.
///
/// ### Why is this bad?
/// If you want to introduce a type which
/// can't be instantiated, you should use `!` (the primitive type "never"),
/// or a wrapper around it, because `!` has more extensive
/// compiler support (type inference, etc...) and wrappers
/// around it are the conventional way to define an uninhabited type.
/// For further information visit [never type documentation](https://doc.rust-lang.org/std/primitive.never.html)
/// * If you only want a type which cant be instantiated, you should use [`!`]
/// (the primitive type "never"), because [`!`] has more extensive compiler support
/// (type inference, etc.) and implementations of common traits.
///
/// * If you need to introduce a distinct type, consider using a [newtype] `struct`
/// containing [`!`] instead (`struct MyType(pub !)`), because it is more idiomatic
/// to use a `struct` rather than an `enum` when an `enum` is unnecessary.
///
/// If you do this, note that the [visibility] of the [`!`] field determines whether
/// the uninhabitedness is visible in documentation, and whether it can be pattern
/// matched to mark code unreachable. If the field is not visible, then the struct
/// acts like any other struct with private fields.
///
/// * If the enum has no variants only because all variants happen to be
/// [disabled by conditional compilation][cfg], then it would be appropriate
/// to allow the lint, with `#[allow(empty_enum)]`.
///
/// For further information, visit
/// [the never types documentation][`!`].
///
/// ### Example
/// ```no_run
/// enum Test {}
/// enum CannotExist {}
/// ```
///
/// Use instead:
/// ```no_run
/// #![feature(never_type)]
///
/// struct Test(!);
/// /// Use the `!` type directly...
/// type CannotExist = !;
///
/// /// ...or define a newtype which is distinct.
/// struct CannotExist2(pub !);
/// ```
///
/// [`!`]: https://doc.rust-lang.org/std/primitive.never.html
/// [cfg]: https://doc.rust-lang.org/reference/conditional-compilation.html
/// [newtype]: https://doc.rust-lang.org/book/ch19-04-advanced-types.html#using-the-newtype-pattern-for-type-safety-and-abstraction
/// [visibility]: https://doc.rust-lang.org/reference/visibility-and-privacy.html
#[clippy::version = "pre 1.29.0"]
pub EMPTY_ENUM,
pedantic,

View file

@ -11,16 +11,23 @@ declare_clippy_lint! {
/// ### What it does
/// Finds structs without fields (a so-called "empty struct") that are declared with brackets.
///
/// ### Why is this bad?
/// Empty brackets after a struct declaration can be omitted.
/// ### Why restrict this?
/// Empty brackets after a struct declaration can be omitted,
/// and it may be desirable to do so consistently for style.
///
/// However, removing the brackets also introduces a public constant named after the struct,
/// so this is not just a syntactic simplification but an an API change, and adding them back
/// is a *breaking* API change.
///
/// ### Example
/// ```no_run
/// struct Cookie {}
/// struct Biscuit();
/// ```
/// Use instead:
/// ```no_run
/// struct Cookie;
/// struct Biscuit;
/// ```
#[clippy::version = "1.62.0"]
pub EMPTY_STRUCTS_WITH_BRACKETS,
@ -32,14 +39,20 @@ declare_clippy_lint! {
/// ### What it does
/// Finds enum variants without fields that are declared with empty brackets.
///
/// ### Why is this bad?
/// Empty brackets while defining enum variants are redundant and can be omitted.
/// ### Why restrict this?
/// Empty brackets after a enum variant declaration are redundant and can be omitted,
/// and it may be desirable to do so consistently for style.
///
/// However, removing the brackets also introduces a public constant named after the variant,
/// so this is not just a syntactic simplification but an an API change, and adding them back
/// is a *breaking* API change.
///
/// ### Example
/// ```no_run
/// enum MyEnum {
/// HasData(u8),
/// HasNoData(), // redundant parentheses
/// HasNoData(), // redundant parentheses
/// NoneHereEither {}, // redundant braces
/// }
/// ```
///
@ -48,6 +61,7 @@ declare_clippy_lint! {
/// enum MyEnum {
/// HasData(u8),
/// HasNoData,
/// NoneHereEither,
/// }
/// ```
#[clippy::version = "1.77.0"]

View file

@ -13,8 +13,9 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for the usage of the `to_ne_bytes` method and/or the function `from_ne_bytes`.
///
/// ### Why is this bad?
/// It's not, but some may prefer to specify the target endianness explicitly.
/// ### Why restrict this?
/// To ensure use of explicitly chosen endianness rather than the targets endianness,
/// such as when implementing network protocols or file formats rather than FFI.
///
/// ### Example
/// ```rust,ignore
@ -31,9 +32,8 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for the usage of the `to_le_bytes` method and/or the function `from_le_bytes`.
///
/// ### Why is this bad?
/// It's not, but some may wish to lint usage of this method, either to suggest using the host
/// endianness or big endian.
/// ### Why restrict this?
/// To ensure use of big endian or the targets endianness rather than little endian.
///
/// ### Example
/// ```rust,ignore
@ -50,9 +50,8 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for the usage of the `to_be_bytes` method and/or the function `from_be_bytes`.
///
/// ### Why is this bad?
/// It's not, but some may wish to lint usage of this method, either to suggest using the host
/// endianness or little endian.
/// ### Why restrict this?
/// To ensure use of little endian or the targets endianness rather than big endian.
///
/// ### Example
/// ```rust,ignore

View file

@ -12,7 +12,7 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for types named `Error` that implement `Error`.
///
/// ### Why is this bad?
/// ### Why restrict this?
/// It can become confusing when a codebase has 20 types all named `Error`, requiring either
/// aliasing them in the `use` statement or qualifying them like `my_module::Error`. This
/// hinders comprehension, as it requires you to memorize every variation of importing `Error`

View file

@ -10,10 +10,10 @@ declare_clippy_lint! {
/// ### What it does
/// Warns on any exported `enum`s that are not tagged `#[non_exhaustive]`
///
/// ### Why is this bad?
/// Exhaustive enums are typically fine, but a project which does
/// not wish to make a stability commitment around exported enums may wish to
/// disable them by default.
/// ### Why restrict this?
/// Making an `enum` exhaustive is a stability commitment: adding a variant is a breaking change.
/// A project may wish to ensure that there are no exhaustive enums or that every exhaustive
/// `enum` is explicitly `#[allow]`ed.
///
/// ### Example
/// ```no_run
@ -40,10 +40,10 @@ declare_clippy_lint! {
/// ### What it does
/// Warns on any exported `struct`s that are not tagged `#[non_exhaustive]`
///
/// ### Why is this bad?
/// Exhaustive structs are typically fine, but a project which does
/// not wish to make a stability commitment around exported structs may wish to
/// disable them by default.
/// ### Why restrict this?
/// Making a `struct` exhaustive is a stability commitment: adding a field is a breaking change.
/// A project may wish to ensure that there are no exhaustive structs or that every exhaustive
/// `struct` is explicitly `#[allow]`ed.
///
/// ### Example
/// ```no_run

View file

@ -9,11 +9,13 @@ declare_clippy_lint! {
/// ### What it does
/// Detects calls to the `exit()` function which terminates the program.
///
/// ### Why is this bad?
/// Exit terminates the program at the location it is called. For unrecoverable
/// errors `panics` should be used to provide a stacktrace and potentially other
/// information. A normal termination or one with an error code should happen in
/// the main function.
/// ### Why restrict this?
/// `exit()` immediately terminates the program with no information other than an exit code.
/// This provides no means to troubleshoot a problem, and may be an unexpected side effect.
///
/// Codebases may use this lint to require that all exits are performed either by panicking
/// (which produces a message, a code location, and optionally a backtrace)
/// or by returning from `main()` (which is a single place to look).
///
/// ### Example
/// ```no_run

View file

@ -38,9 +38,9 @@ declare_clippy_lint! {
/// Checks for whole number float literals that
/// cannot be represented as the underlying type without loss.
///
/// ### Why is this bad?
/// Rust will silently lose precision during
/// conversion to a float.
/// ### Why restrict this?
/// If the value was intended to be exact, it will not be.
/// This may be especially surprising when the lost precision is to the left of the decimal point.
///
/// ### Example
/// ```no_run

View file

@ -11,7 +11,7 @@ declare_clippy_lint! {
/// Detects cases where the result of a `format!` call is
/// appended to an existing `String`.
///
/// ### Why is this bad?
/// ### Why restrict this?
/// Introduces an extra, avoidable heap allocation.
///
/// ### Known problems

View file

@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet;
use rustc_errors::Applicability;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{Body, ExprKind, FnDecl, Safety, ImplicitSelfKind};
use rustc_hir::{Body, ExprKind, FnDecl, ImplicitSelfKind, Safety};
use rustc_lint::LateContext;
use rustc_middle::ty;
use rustc_span::Span;

View file

@ -338,8 +338,10 @@ declare_clippy_lint! {
declare_clippy_lint! {
/// ### What it does
/// Lints when `impl Trait` is being used in a function's parameters.
/// ### Why is this bad?
/// Turbofish syntax (`::<>`) cannot be used when `impl Trait` is being used, making `impl Trait` less powerful. Readability may also be a factor.
///
/// ### Why restrict this?
/// Turbofish syntax (`::<>`) cannot be used to specify the type of an `impl Trait` parameter,
/// making `impl Trait` less powerful. Readability may also be a factor.
///
/// ### Example
/// ```no_run
@ -366,9 +368,8 @@ declare_clippy_lint! {
/// Lints when the name of function parameters from trait impl is
/// different than its default implementation.
///
/// ### Why is this bad?
/// Using the default name for parameters of a trait method is often
/// more desirable for consistency's sake.
/// ### Why restrict this?
/// Using the default name for parameters of a trait method is more consistent.
///
/// ### Example
/// ```rust

View file

@ -15,7 +15,7 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for if-else that could be written using either `bool::then` or `bool::then_some`.
///
/// ### Why is this bad?
/// ### Why restrict this?
/// Looks a little redundant. Using `bool::then` is more concise and incurs no loss of clarity.
/// For simple calculations and known values, use `bool::then_some`, which is eagerly evaluated
/// in comparison to `bool::then`.

View file

@ -16,12 +16,13 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for missing return statements at the end of a block.
///
/// ### Why is this bad?
/// Actually omitting the return keyword is idiomatic Rust code. Programmers
/// coming from other languages might prefer the expressiveness of `return`. It's possible to miss
/// the last returning statement because the only difference is a missing `;`. Especially in bigger
/// code with multiple return paths having a `return` keyword makes it easier to find the
/// corresponding statements.
/// ### Why restrict this?
/// Omitting the return keyword whenever possible is idiomatic Rust code, but:
///
/// * Programmers coming from other languages might prefer the expressiveness of `return`.
/// * It's possible to miss the last returning statement because the only difference is a missing `;`.
/// * Especially in bigger code with multiple return paths, having a `return` keyword makes it easier to find the
/// corresponding statements.
///
/// ### Example
/// ```no_run

View file

@ -45,9 +45,10 @@ declare_clippy_lint! {
/// does report on arrays if we can tell that slicing operations are in bounds and does not
/// lint on constant `usize` indexing on arrays because that is handled by rustc's `const_err` lint.
///
/// ### Why is this bad?
/// Indexing and slicing can panic at runtime and there are
/// safe alternatives.
/// ### Why restrict this?
/// To avoid implicit panics from indexing and slicing.
/// There are “checked” alternatives which do not panic, and can be used with `unwrap()` to make
/// an explicit panic when it is desired.
///
/// ### Example
/// ```rust,no_run

View file

@ -14,7 +14,7 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for multiple inherent implementations of a struct
///
/// ### Why is this bad?
/// ### Why restrict this?
/// Splitting the implementation of a type makes the code harder to navigate.
///
/// ### Example

View file

@ -1,5 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
use rustc_errors::Applicability;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::{Expr, ExprKind};
@ -62,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for NumberedFields {
snippet_with_applicability(cx, path.span(), "..", &mut appl),
expr_spans
.into_iter_sorted()
.map(|(_, span)| snippet_with_applicability(cx, span, "..", &mut appl))
.map(|(_, span)| snippet_with_context(cx, span, path.span().ctxt(), "..", &mut appl).0)
.intersperse(Cow::Borrowed(", "))
.collect::<String>()
);

View file

@ -7,10 +7,10 @@ use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
/// Checks for the usage of division (/) and remainder (%) operations
/// when performed on any integer types using the default Div and Rem trait implementations.
/// Checks for the usage of division (`/`) and remainder (`%`) operations
/// when performed on any integer types using the default `Div` and `Rem` trait implementations.
///
/// ### Why is this bad?
/// ### Why restrict this?
/// In cryptographic contexts, division can result in timing sidechannel vulnerabilities,
/// and needs to be replaced with constant-time code instead (e.g. Barrett reduction).
///

View file

@ -14,8 +14,8 @@ declare_clippy_lint! {
/// ### What it does
/// This is a restriction lint which prevents the use of hash types (i.e., `HashSet` and `HashMap`) in for loops.
///
/// ### Why is this bad?
/// Because hash types are unordered, when iterated through such as in a for loop, the values are returned in
/// ### Why restrict this?
/// Because hash types are unordered, when iterated through such as in a `for` loop, the values are returned in
/// an undefined order. As a result, on redundant systems this may cause inconsistencies and anomalies.
/// In addition, the unknown order of the elements may reduce readability or introduce other undesired
/// side effects.

View file

@ -10,10 +10,12 @@ use rustc_span::sym;
declare_clippy_lint! {
/// ### What it does
/// Checks for the inclusion of large files via `include_bytes!()`
/// and `include_str!()`
/// or `include_str!()`.
///
/// ### Why is this bad?
/// Including large files can increase the size of the binary
/// ### Why restrict this?
/// Including large files can undesirably increase the size of the binary produced by the compiler.
/// This lint may be used to catch mistakes where an unexpectedly large file is included, or
/// temporarily to obtain a list of all large files.
///
/// ### Example
/// ```rust,ignore

View file

@ -12,9 +12,8 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for `let _ = <expr>` where expr is `#[must_use]`
///
/// ### Why is this bad?
/// It's better to explicitly handle the value of a `#[must_use]`
/// expr
/// ### Why restrict this?
/// To ensure that all `#[must_use]` types are used rather than ignored.
///
/// ### Example
/// ```no_run
@ -96,8 +95,8 @@ declare_clippy_lint! {
/// Checks for `let _ = <expr>` without a type annotation, and suggests to either provide one,
/// or remove the `let` keyword altogether.
///
/// ### Why is this bad?
/// The `let _ = <expr>` expression ignores the value of `<expr>` but will remain doing so even
/// ### Why restrict this?
/// The `let _ = <expr>` expression ignores the value of `<expr>`, but will continue to do so even
/// if the type were to change, thus potentially introducing subtle bugs. By supplying a type
/// annotation, one will be forced to re-visit the decision to ignore the value in such cases.
///

View file

@ -132,8 +132,8 @@ declare_clippy_lint! {
/// ### What it does
/// Warns if there is a better representation for a numeric literal.
///
/// ### Why is this bad?
/// Especially for big powers of 2 a hexadecimal representation is more
/// ### Why restrict this?
/// Especially for big powers of 2, a hexadecimal representation is usually more
/// readable than a decimal representation.
///
/// ### Example

View file

@ -675,9 +675,9 @@ declare_clippy_lint! {
/// Checks for infinite loops in a function where the return type is not `!`
/// and lint accordingly.
///
/// ### Why is this bad?
/// A loop should be gently exited somewhere, or at least mark its parent function as
/// never return (`!`).
/// ### Why restrict this?
/// Making the return type `!` serves as documentation that the function does not return.
/// If the function is not intended to loop infinitely, then this lint may detect a bug.
///
/// ### Example
/// ```no_run,ignore

View file

@ -260,7 +260,7 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for wildcard enum matches using `_`.
///
/// ### Why is this bad?
/// ### Why restrict this?
/// New enum variants added by library updates can be missed.
///
/// ### Known problems
@ -435,7 +435,7 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for unnecessary '..' pattern binding on struct when all fields are explicitly matched.
///
/// ### Why is this bad?
/// ### Why restrict this?
/// Correctness and readability. It's like having a wildcard pattern after
/// matching all enum variants explicitly.
///
@ -861,7 +861,7 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for usage of `Err(x)?`.
///
/// ### Why is this bad?
/// ### Why restrict this?
/// The `?` operator is designed to allow calls that
/// can fail to be easily chained. For example, `foo()?.bar()` or
/// `foo(bar()?)`. Because `Err(x)?` can't be used that way (it will

View file

@ -1,12 +1,17 @@
use std::ops::ControlFlow;
use crate::FxHashSet;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::{indent_of, snippet};
use clippy_utils::ty::{for_each_top_level_late_bound_region, is_copy};
use clippy_utils::{get_attr, is_lint_allowed};
use itertools::Itertools;
use rustc_ast::Mutability;
use rustc_errors::{Applicability, Diag};
use rustc_hir::intravisit::{walk_expr, Visitor};
use rustc_hir::{Arm, Expr, ExprKind, MatchSource};
use rustc_lint::{LateContext, LintContext};
use rustc_middle::ty::{GenericArgKind, Ty};
use rustc_middle::ty::{GenericArgKind, Region, RegionKind, Ty, TyCtxt, TypeVisitable, TypeVisitor};
use rustc_span::Span;
use super::SIGNIFICANT_DROP_IN_SCRUTINEE;
@ -22,43 +27,34 @@ pub(super) fn check<'tcx>(
return;
}
if let Some((suggestions, message)) = has_significant_drop_in_scrutinee(cx, scrutinee, source) {
for found in suggestions {
span_lint_and_then(cx, SIGNIFICANT_DROP_IN_SCRUTINEE, found.found_span, message, |diag| {
set_diagnostic(diag, cx, expr, found);
let s = Span::new(expr.span.hi(), expr.span.hi(), expr.span.ctxt(), None);
diag.span_label(s, "temporary lives until here");
for span in has_significant_drop_in_arms(cx, arms) {
diag.span_label(span, "another value with significant `Drop` created here");
}
diag.note("this might lead to deadlocks or other unexpected behavior");
});
}
let (suggestions, message) = has_significant_drop_in_scrutinee(cx, scrutinee, source);
for found in suggestions {
span_lint_and_then(cx, SIGNIFICANT_DROP_IN_SCRUTINEE, found.found_span, message, |diag| {
set_diagnostic(diag, cx, expr, found);
let s = Span::new(expr.span.hi(), expr.span.hi(), expr.span.ctxt(), None);
diag.span_label(s, "temporary lives until here");
for span in has_significant_drop_in_arms(cx, arms) {
diag.span_label(span, "another value with significant `Drop` created here");
}
diag.note("this might lead to deadlocks or other unexpected behavior");
});
}
}
fn set_diagnostic<'tcx>(diag: &mut Diag<'_, ()>, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, found: FoundSigDrop) {
if found.lint_suggestion == LintSuggestion::MoveAndClone {
// If our suggestion is to move and clone, then we want to leave it to the user to
// decide how to address this lint, since it may be that cloning is inappropriate.
// Therefore, we won't to emit a suggestion.
return;
}
let original = snippet(cx, found.found_span, "..");
let trailing_indent = " ".repeat(indent_of(cx, found.found_span).unwrap_or(0));
let replacement = if found.lint_suggestion == LintSuggestion::MoveAndDerefToCopy {
format!("let value = *{original};\n{trailing_indent}")
} else if found.is_unit_return_val {
// If the return value of the expression to be moved is unit, then we don't need to
// capture the result in a temporary -- we can just replace it completely with `()`.
format!("{original};\n{trailing_indent}")
} else {
format!("let value = {original};\n{trailing_indent}")
let replacement = {
let (def_part, deref_part) = if found.is_unit_return_val {
("", String::new())
} else {
("let value = ", "*".repeat(found.peel_ref_times))
};
format!("{def_part}{deref_part}{original};\n{trailing_indent}")
};
let suggestion_message = if found.lint_suggestion == LintSuggestion::MoveOnly {
let suggestion_message = if found.peel_ref_times == 0 {
"try moving the temporary above the match"
} else {
"try moving the temporary above the match and create a copy"
@ -66,8 +62,11 @@ fn set_diagnostic<'tcx>(diag: &mut Diag<'_, ()>, cx: &LateContext<'tcx>, expr: &
let scrutinee_replacement = if found.is_unit_return_val {
"()".to_owned()
} else {
} else if found.peel_ref_times == 0 {
"value".to_owned()
} else {
let ref_part = "&".repeat(found.peel_ref_times);
format!("({ref_part}value)")
};
diag.multipart_suggestion(
@ -86,20 +85,18 @@ fn has_significant_drop_in_scrutinee<'tcx>(
cx: &LateContext<'tcx>,
scrutinee: &'tcx Expr<'tcx>,
source: MatchSource,
) -> Option<(Vec<FoundSigDrop>, &'static str)> {
) -> (Vec<FoundSigDrop>, &'static str) {
let mut helper = SigDropHelper::new(cx);
let scrutinee = match (source, &scrutinee.kind) {
(MatchSource::ForLoopDesugar, ExprKind::Call(_, [e])) => e,
_ => scrutinee,
};
helper.find_sig_drop(scrutinee).map(|drops| {
let message = if source == MatchSource::Normal {
"temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression"
} else {
"temporary with significant `Drop` in `for` loop condition will live until the end of the `for` expression"
};
(drops, message)
})
let message = if source == MatchSource::Normal {
"temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression"
} else {
"temporary with significant `Drop` in `for` loop condition will live until the end of the `for` expression"
};
(helper.find_sig_drop(scrutinee), message)
}
struct SigDropChecker<'a, 'tcx> {
@ -172,205 +169,248 @@ impl<'a, 'tcx> SigDropChecker<'a, 'tcx> {
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
enum SigDropHolder {
/// No values with significant drop present in this expression.
///
/// Expressions that we've emited lints do not count.
None,
/// Some field in this expression references to values with significant drop.
///
/// Example: `(1, &data.lock().field)`.
PackedRef,
/// The value of this expression references to values with significant drop.
///
/// Example: `data.lock().field`.
DirectRef,
/// This expression should be moved out to avoid significant drop in scrutinee.
Moved,
}
impl Default for SigDropHolder {
fn default() -> Self {
Self::None
}
}
struct SigDropHelper<'a, 'tcx> {
cx: &'a LateContext<'tcx>,
is_chain_end: bool,
has_significant_drop: bool,
current_sig_drop: Option<FoundSigDrop>,
sig_drop_spans: Option<Vec<FoundSigDrop>>,
special_handling_for_binary_op: bool,
parent_expr: Option<&'tcx Expr<'tcx>>,
sig_drop_holder: SigDropHolder,
sig_drop_spans: Vec<FoundSigDrop>,
sig_drop_checker: SigDropChecker<'a, 'tcx>,
}
#[expect(clippy::enum_variant_names)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
enum LintSuggestion {
MoveOnly,
MoveAndDerefToCopy,
MoveAndClone,
}
#[derive(Clone, Copy)]
#[derive(Clone, Copy, Debug)]
struct FoundSigDrop {
found_span: Span,
is_unit_return_val: bool,
lint_suggestion: LintSuggestion,
peel_ref_times: usize,
}
impl<'a, 'tcx> SigDropHelper<'a, 'tcx> {
fn new(cx: &'a LateContext<'tcx>) -> SigDropHelper<'a, 'tcx> {
SigDropHelper {
cx,
is_chain_end: true,
has_significant_drop: false,
current_sig_drop: None,
sig_drop_spans: None,
special_handling_for_binary_op: false,
parent_expr: None,
sig_drop_holder: SigDropHolder::None,
sig_drop_spans: Vec::new(),
sig_drop_checker: SigDropChecker::new(cx),
}
}
fn find_sig_drop(&mut self, match_expr: &'tcx Expr<'_>) -> Option<Vec<FoundSigDrop>> {
fn find_sig_drop(&mut self, match_expr: &'tcx Expr<'_>) -> Vec<FoundSigDrop> {
self.visit_expr(match_expr);
// If sig drop spans is empty but we found a significant drop, it means that we didn't find
// a type that was trivially copyable as we moved up the chain after finding a significant
// drop, so move the entire scrutinee.
if self.has_significant_drop && self.sig_drop_spans.is_none() {
self.try_setting_current_suggestion(match_expr, true);
self.move_current_suggestion();
}
self.sig_drop_spans.take()
core::mem::take(&mut self.sig_drop_spans)
}
fn replace_current_sig_drop(
&mut self,
found_span: Span,
is_unit_return_val: bool,
lint_suggestion: LintSuggestion,
) {
self.current_sig_drop.replace(FoundSigDrop {
fn replace_current_sig_drop(&mut self, found_span: Span, is_unit_return_val: bool, peel_ref_times: usize) {
self.sig_drop_spans.clear();
self.sig_drop_spans.push(FoundSigDrop {
found_span,
is_unit_return_val,
lint_suggestion,
peel_ref_times,
});
}
/// This will try to set the current suggestion (so it can be moved into the suggestions vec
/// later). If `allow_move_and_clone` is false, the suggestion *won't* be set -- this gives us
/// an opportunity to look for another type in the chain that will be trivially copyable.
/// However, if we are at the end of the chain, we want to accept whatever is there. (The
/// suggestion won't actually be output, but the diagnostic message will be output, so the user
/// can determine the best way to handle the lint.)
fn try_setting_current_suggestion(&mut self, expr: &'tcx Expr<'_>, allow_move_and_clone: bool) {
if self.current_sig_drop.is_some() {
return;
fn try_move_sig_drop(&mut self, expr: &'tcx Expr<'_>, parent_expr: &'tcx Expr<'_>) {
if self.sig_drop_holder == SigDropHolder::Moved {
self.sig_drop_holder = SigDropHolder::None;
}
let ty = self.cx.typeck_results().expr_ty(expr);
if ty.is_ref() {
// We checked that the type was ref, so builtin_deref will return Some,
// but let's avoid any chance of an ICE.
if let Some(ty) = ty.builtin_deref(true) {
if ty.is_trivially_pure_clone_copy() {
self.replace_current_sig_drop(expr.span, false, LintSuggestion::MoveAndDerefToCopy);
} else if allow_move_and_clone {
self.replace_current_sig_drop(expr.span, false, LintSuggestion::MoveAndClone);
}
if self.sig_drop_holder == SigDropHolder::DirectRef {
self.sig_drop_holder = SigDropHolder::PackedRef;
self.try_move_sig_drop_direct_ref(expr, parent_expr);
} else if self.sig_drop_checker.is_sig_drop_expr(expr) {
// The values with significant drop can be moved to some other functions. For example, consider
// `drop(data.lock())`. We use `SigDropHolder::None` here to avoid emitting lints in such scenarios.
self.sig_drop_holder = SigDropHolder::None;
self.try_move_sig_drop_direct_ref(expr, parent_expr);
}
if self.sig_drop_holder != SigDropHolder::None {
let parent_ty = self.cx.typeck_results().expr_ty(parent_expr);
if !ty_has_erased_regions(parent_ty) && !parent_expr.is_syntactic_place_expr() {
self.replace_current_sig_drop(parent_expr.span, parent_ty.is_unit(), 0);
self.sig_drop_holder = SigDropHolder::Moved;
}
let (peel_ref_ty, peel_ref_times) = ty_peel_refs(parent_ty);
if !ty_has_erased_regions(peel_ref_ty) && is_copy(self.cx, peel_ref_ty) {
self.replace_current_sig_drop(parent_expr.span, peel_ref_ty.is_unit(), peel_ref_times);
self.sig_drop_holder = SigDropHolder::Moved;
}
} else if ty.is_trivially_pure_clone_copy() {
self.replace_current_sig_drop(expr.span, false, LintSuggestion::MoveOnly);
} else if allow_move_and_clone {
self.replace_current_sig_drop(expr.span, false, LintSuggestion::MoveAndClone);
}
}
fn move_current_suggestion(&mut self) {
if let Some(current) = self.current_sig_drop.take() {
self.sig_drop_spans.get_or_insert_with(Vec::new).push(current);
fn try_move_sig_drop_direct_ref(&mut self, expr: &'tcx Expr<'_>, parent_expr: &'tcx Expr<'_>) {
let arg_idx = match parent_expr.kind {
ExprKind::MethodCall(_, receiver, exprs, _) => std::iter::once(receiver)
.chain(exprs.iter())
.find_position(|ex| ex.hir_id == expr.hir_id)
.map(|(idx, _)| idx),
ExprKind::Call(_, exprs) => exprs
.iter()
.find_position(|ex| ex.hir_id == expr.hir_id)
.map(|(idx, _)| idx),
ExprKind::Binary(_, lhs, rhs) | ExprKind::AssignOp(_, lhs, rhs) => [lhs, rhs]
.iter()
.find_position(|ex| ex.hir_id == expr.hir_id)
.map(|(idx, _)| idx),
ExprKind::Unary(_, ex) => (ex.hir_id == expr.hir_id).then_some(0),
_ => {
// Here we assume that all other expressions create or propagate the reference to the value with
// significant drop.
self.sig_drop_holder = SigDropHolder::DirectRef;
return;
},
};
let Some(arg_idx) = arg_idx else {
return;
};
let fn_sig = if let Some(def_id) = self.cx.typeck_results().type_dependent_def_id(parent_expr.hir_id) {
self.cx.tcx.fn_sig(def_id).instantiate_identity()
} else {
return;
};
let input_re = if let Some(input_ty) = fn_sig.skip_binder().inputs().get(arg_idx)
&& let rustc_middle::ty::Ref(input_re, _, _) = input_ty.kind()
{
input_re
} else {
return;
};
// Late bound lifetime parameters are not related to any constraints, so we can track them in a very
// simple manner. For other lifetime parameters, we give up and update the state to `PackedRef`.
let RegionKind::ReBound(_, input_re_bound) = input_re.kind() else {
self.sig_drop_holder = SigDropHolder::PackedRef;
return;
};
let contains_input_re = |re_bound| {
if re_bound == input_re_bound {
ControlFlow::Break(())
} else {
ControlFlow::Continue(())
}
};
let output_ty = fn_sig.skip_binder().output();
if let rustc_middle::ty::Ref(output_re, peel_ref_ty, _) = output_ty.kind()
&& input_re == output_re
&& for_each_top_level_late_bound_region(*peel_ref_ty, contains_input_re).is_continue()
{
// We're lucky! The output type is still a direct reference to the value with significant drop.
self.sig_drop_holder = SigDropHolder::DirectRef;
} else if for_each_top_level_late_bound_region(output_ty, contains_input_re).is_continue() {
// The lifetime to the value with significant drop goes away. So we can emit a lint that suggests to
// move the expression out.
self.replace_current_sig_drop(parent_expr.span, output_ty.is_unit(), 0);
self.sig_drop_holder = SigDropHolder::Moved;
} else {
// TODO: The lifetime is still there but it's for a inner type. For instance, consider
// `Some(&mutex.lock().field)`, which has a type of `Option<&u32>`. How to address this scenario?
self.sig_drop_holder = SigDropHolder::PackedRef;
}
}
}
fn ty_peel_refs(mut ty: Ty<'_>) -> (Ty<'_>, usize) {
let mut n = 0;
while let rustc_middle::ty::Ref(_, new_ty, Mutability::Not) = ty.kind() {
ty = *new_ty;
n += 1;
}
(ty, n)
}
fn ty_has_erased_regions(ty: Ty<'_>) -> bool {
struct V;
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for V {
type Result = ControlFlow<()>;
fn visit_region(&mut self, region: Region<'tcx>) -> Self::Result {
if region.is_erased() {
ControlFlow::Break(())
} else {
ControlFlow::Continue(())
}
}
}
fn visit_exprs_for_binary_ops(
&mut self,
left: &'tcx Expr<'_>,
right: &'tcx Expr<'_>,
is_unit_return_val: bool,
span: Span,
) {
self.special_handling_for_binary_op = true;
self.visit_expr(left);
self.visit_expr(right);
// If either side had a significant drop, suggest moving the entire scrutinee to avoid
// unnecessary copies and to simplify cases where both sides have significant drops.
if self.has_significant_drop {
self.replace_current_sig_drop(span, is_unit_return_val, LintSuggestion::MoveOnly);
}
self.special_handling_for_binary_op = false;
}
ty.visit_with(&mut V).is_break()
}
impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> {
fn visit_expr(&mut self, ex: &'tcx Expr<'_>) {
if !self.is_chain_end && self.sig_drop_checker.is_sig_drop_expr(ex) {
self.has_significant_drop = true;
// We've emited a lint on some neighborhood expression. That lint will suggest to move out the
// _parent_ expression (not the expression itself). Since we decide to move out the parent
// expression, it is pointless to continue to process the current expression.
if self.sig_drop_holder == SigDropHolder::Moved {
return;
}
self.is_chain_end = false;
// These states are of neighborhood expressions. We save and clear them here, and we'll later merge
// the states of the current expression with them at the end of the method.
let sig_drop_holder_before = core::mem::take(&mut self.sig_drop_holder);
let sig_drop_spans_before = core::mem::take(&mut self.sig_drop_spans);
let parent_expr_before = self.parent_expr.replace(ex);
match ex.kind {
ExprKind::MethodCall(_, expr, ..) => {
self.visit_expr(expr);
}
ExprKind::Binary(_, left, right) => {
self.visit_exprs_for_binary_ops(left, right, false, ex.span);
}
ExprKind::Assign(left, right, _) | ExprKind::AssignOp(_, left, right) => {
self.visit_exprs_for_binary_ops(left, right, true, ex.span);
}
ExprKind::Tup(exprs) => {
for expr in exprs {
self.visit_expr(expr);
if self.has_significant_drop {
// We may have not have set current_sig_drop if all the suggestions were
// MoveAndClone, so add this tuple item's full expression in that case.
if self.current_sig_drop.is_none() {
self.try_setting_current_suggestion(expr, true);
}
// Skip blocks because values in blocks will be dropped as usual.
ExprKind::Block(..) => (),
_ => walk_expr(self, ex),
}
// Now we are guaranteed to have something, so add it to the final vec.
self.move_current_suggestion();
}
// Reset `has_significant_drop` after each tuple expression so we can look for
// additional cases.
self.has_significant_drop = false;
}
if self.sig_drop_spans.is_some() {
self.has_significant_drop = true;
}
}
ExprKind::Array(..) |
ExprKind::Call(..) |
ExprKind::Unary(..) |
ExprKind::If(..) |
ExprKind::Match(..) |
ExprKind::Field(..) |
ExprKind::Index(..) |
ExprKind::Ret(..) |
ExprKind::Become(..) |
ExprKind::Repeat(..) |
ExprKind::Yield(..) => walk_expr(self, ex),
ExprKind::AddrOf(_, _, _) |
ExprKind::Block(_, _) |
ExprKind::Break(_, _) |
ExprKind::Cast(_, _) |
// Don't want to check the closure itself, only invocation, which is covered by MethodCall
ExprKind::Closure { .. } |
ExprKind::ConstBlock(_) |
ExprKind::Continue(_) |
ExprKind::DropTemps(_) |
ExprKind::Err(_) |
ExprKind::InlineAsm(_) |
ExprKind::OffsetOf(_, _) |
ExprKind::Let(_) |
ExprKind::Lit(_) |
ExprKind::Loop(_, _, _, _) |
ExprKind::Path(_) |
ExprKind::Struct(_, _, _) |
ExprKind::Type(_, _) => {
return;
if let Some(parent_ex) = parent_expr_before {
match parent_ex.kind {
ExprKind::Assign(lhs, _, _) | ExprKind::AssignOp(_, lhs, _)
if lhs.hir_id == ex.hir_id && self.sig_drop_holder == SigDropHolder::Moved =>
{
// Never move out only the assignee. Instead, we should always move out the whole assigment.
self.replace_current_sig_drop(parent_ex.span, true, 0);
},
_ => {
self.try_move_sig_drop(ex, parent_ex);
},
}
}
// Once a significant temporary has been found, we need to go back up at least 1 level to
// find the span to extract for replacement, so the temporary gets dropped. However, for
// binary ops, we want to move the whole scrutinee so we avoid unnecessary copies and to
// simplify cases where both sides have significant drops.
if self.has_significant_drop && !self.special_handling_for_binary_op {
self.try_setting_current_suggestion(ex, false);
self.sig_drop_holder = std::cmp::max(self.sig_drop_holder, sig_drop_holder_before);
// We do not need those old spans in neighborhood expressions if we emit a lint that suggests to
// move out the _parent_ expression (i.e., `self.sig_drop_holder == SigDropHolder::Moved`).
if self.sig_drop_holder != SigDropHolder::Moved {
let mut sig_drop_spans = sig_drop_spans_before;
sig_drop_spans.append(&mut self.sig_drop_spans);
self.sig_drop_spans = sig_drop_spans;
}
self.parent_expr = parent_expr_before;
}
}

View file

@ -1,8 +1,12 @@
use std::iter::once;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet;
use clippy_utils::{get_expr_use_or_unification_node, is_res_lang_ctor, path_res, std_or_core};
use rustc_errors::Applicability;
use rustc_hir::def_id::DefId;
use rustc_hir::hir_id::HirId;
use rustc_hir::LangItem::{OptionNone, OptionSome};
use rustc_hir::{Expr, ExprKind, Node};
use rustc_lint::LateContext;
@ -25,7 +29,29 @@ impl IterType {
}
}
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: &str, recv: &Expr<'_>) {
fn is_arg_ty_unified_in_fn<'tcx>(
cx: &LateContext<'tcx>,
fn_id: DefId,
arg_id: HirId,
args: impl IntoIterator<Item = &'tcx Expr<'tcx>>,
) -> bool {
let fn_sig = cx.tcx.fn_sig(fn_id).instantiate_identity();
let arg_id_in_args = args.into_iter().position(|e| e.hir_id == arg_id).unwrap();
let arg_ty_in_args = fn_sig.input(arg_id_in_args).skip_binder();
cx.tcx.predicates_of(fn_id).predicates.iter().any(|(clause, _)| {
clause
.as_projection_clause()
.and_then(|p| p.map_bound(|p| p.term.ty()).transpose())
.is_some_and(|ty| ty.skip_binder() == arg_ty_in_args)
}) || fn_sig
.inputs()
.iter()
.enumerate()
.any(|(i, ty)| i != arg_id_in_args && ty.skip_binder().walk().any(|arg| arg.as_type() == Some(arg_ty_in_args)))
}
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: &str, recv: &'tcx Expr<'tcx>) {
let item = match recv.kind {
ExprKind::Array([]) => None,
ExprKind::Array([e]) => Some(e),
@ -43,6 +69,25 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: &str, re
let is_unified = match get_expr_use_or_unification_node(cx.tcx, expr) {
Some((Node::Expr(parent), child_id)) => match parent.kind {
ExprKind::If(e, _, _) | ExprKind::Match(e, _, _) if e.hir_id == child_id => false,
ExprKind::Call(
Expr {
kind: ExprKind::Path(path),
hir_id,
..
},
args,
) => cx
.typeck_results()
.qpath_res(path, *hir_id)
.opt_def_id()
.filter(|fn_id| cx.tcx.def_kind(fn_id).is_fn_like())
.is_some_and(|fn_id| is_arg_ty_unified_in_fn(cx, fn_id, child_id, args)),
ExprKind::MethodCall(_name, recv, args, _span) => is_arg_ty_unified_in_fn(
cx,
cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap(),
child_id,
once(recv).chain(args.iter()),
),
ExprKind::If(_, _, _)
| ExprKind::Match(_, _, _)
| ExprKind::Closure(_)

View file

@ -257,7 +257,7 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for `.unwrap()` or `.unwrap_err()` calls on `Result`s and `.unwrap()` call on `Option`s.
///
/// ### Why is this bad?
/// ### Why restrict this?
/// It is better to handle the `None` or `Err` case,
/// or at least call `.expect(_)` with a more helpful message. Still, for a lot of
/// quick-and-dirty code, `unwrap` is a good choice, which is why this lint is
@ -333,7 +333,7 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for `.expect()` or `.expect_err()` calls on `Result`s and `.expect()` call on `Option`s.
///
/// ### Why is this bad?
/// ### Why restrict this?
/// Usually it is better to handle the `None` or `Err` case.
/// Still, for a lot of quick-and-dirty code, `expect` is a good choice, which is why
/// this lint is `Allow` by default.
@ -1029,8 +1029,8 @@ declare_clippy_lint! {
/// (`Rc`, `Arc`, `rc::Weak`, or `sync::Weak`), and suggests calling Clone via unified
/// function syntax instead (e.g., `Rc::clone(foo)`).
///
/// ### Why is this bad?
/// Calling '.clone()' on an Rc, Arc, or Weak
/// ### Why restrict this?
/// Calling `.clone()` on an `Rc`, `Arc`, or `Weak`
/// can obscure the fact that only the pointer is being cloned, not the underlying
/// data.
///
@ -1051,7 +1051,7 @@ declare_clippy_lint! {
#[clippy::version = "pre 1.29.0"]
pub CLONE_ON_REF_PTR,
restriction,
"using 'clone' on a ref-counted pointer"
"using `clone` on a ref-counted pointer"
}
declare_clippy_lint! {
@ -1359,7 +1359,7 @@ declare_clippy_lint! {
/// Checks for usage of `.get().unwrap()` (or
/// `.get_mut().unwrap`) on a standard library type which implements `Index`
///
/// ### Why is this bad?
/// ### Why restrict this?
/// Using the Index trait (`[]`) is more clear and more
/// concise.
///
@ -1743,7 +1743,7 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for `FileType::is_file()`.
///
/// ### Why is this bad?
/// ### Why restrict this?
/// When people testing a file type with `FileType::is_file`
/// they are testing whether a path is something they can get bytes from. But
/// `is_file` doesn't cover special file types in unix-like systems, and doesn't cover
@ -2688,8 +2688,9 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for instances of `map_err(|_| Some::Enum)`
///
/// ### Why is this bad?
/// This `map_err` throws away the original error rather than allowing the enum to contain and report the cause of the error
/// ### Why restrict this?
/// This `map_err` throws away the original error rather than allowing the enum to
/// contain and report the cause of the error.
///
/// ### Example
/// Before:
@ -3145,7 +3146,7 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for usage of File::read_to_end and File::read_to_string.
///
/// ### Why is this bad?
/// ### Why restrict this?
/// `fs::{read, read_to_string}` provide the same functionality when `buf` is empty with fewer imports and no intermediate values.
/// See also: [fs::read docs](https://doc.rust-lang.org/std/fs/fn.read.html), [fs::read_to_string docs](https://doc.rust-lang.org/std/fs/fn.read_to_string.html)
///

View file

@ -38,7 +38,7 @@ pub fn check_for_loop_iter(
) -> bool {
if let Some(grandparent) = get_parent_expr(cx, expr).and_then(|parent| get_parent_expr(cx, parent))
&& let Some(ForLoop { pat, body, .. }) = ForLoop::hir(grandparent)
&& let (clone_or_copy_needed, addr_of_exprs) = clone_or_copy_needed(cx, pat, body)
&& let (clone_or_copy_needed, references_to_binding) = clone_or_copy_needed(cx, pat, body)
&& !clone_or_copy_needed
&& let Some(receiver_snippet) = snippet_opt(cx, receiver.span)
{
@ -123,14 +123,12 @@ pub fn check_for_loop_iter(
Applicability::MachineApplicable
};
diag.span_suggestion(expr.span, "use", snippet, applicability);
for addr_of_expr in addr_of_exprs {
match addr_of_expr.kind {
ExprKind::AddrOf(_, _, referent) => {
let span = addr_of_expr.span.with_hi(referent.span.lo());
diag.span_suggestion(span, "remove this `&`", "", applicability);
},
_ => unreachable!(),
}
if !references_to_binding.is_empty() {
diag.multipart_suggestion(
"remove any references to the binding",
references_to_binding,
applicability,
);
}
},
);

View file

@ -9,6 +9,7 @@ use rustc_lint::LateContext;
use rustc_middle::hir::nested_filter;
use rustc_middle::ty::{self, Ty};
use rustc_span::symbol::sym;
use rustc_span::Span;
pub(super) fn derefs_to_slice<'tcx>(
cx: &LateContext<'tcx>,
@ -96,15 +97,15 @@ pub(super) fn clone_or_copy_needed<'tcx>(
cx: &LateContext<'tcx>,
pat: &Pat<'tcx>,
body: &'tcx Expr<'tcx>,
) -> (bool, Vec<&'tcx Expr<'tcx>>) {
) -> (bool, Vec<(Span, String)>) {
let mut visitor = CloneOrCopyVisitor {
cx,
binding_hir_ids: pat_bindings(pat),
clone_or_copy_needed: false,
addr_of_exprs: Vec::new(),
references_to_binding: Vec::new(),
};
visitor.visit_expr(body);
(visitor.clone_or_copy_needed, visitor.addr_of_exprs)
(visitor.clone_or_copy_needed, visitor.references_to_binding)
}
/// Returns a vector of all `HirId`s bound by the pattern.
@ -127,7 +128,7 @@ struct CloneOrCopyVisitor<'cx, 'tcx> {
cx: &'cx LateContext<'tcx>,
binding_hir_ids: Vec<HirId>,
clone_or_copy_needed: bool,
addr_of_exprs: Vec<&'tcx Expr<'tcx>>,
references_to_binding: Vec<(Span, String)>,
}
impl<'cx, 'tcx> Visitor<'tcx> for CloneOrCopyVisitor<'cx, 'tcx> {
@ -142,8 +143,11 @@ impl<'cx, 'tcx> Visitor<'tcx> for CloneOrCopyVisitor<'cx, 'tcx> {
if self.is_binding(expr) {
if let Some(parent) = get_parent_expr(self.cx, expr) {
match parent.kind {
ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, _) => {
self.addr_of_exprs.push(parent);
ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, referent) => {
if !parent.span.from_expansion() {
self.references_to_binding
.push((parent.span.until(referent.span), String::new()));
}
return;
},
ExprKind::MethodCall(.., args, _) => {

View file

@ -12,14 +12,13 @@ use std::borrow::Cow;
declare_clippy_lint! {
/// ### What it does
/// Checks for idents which comprise of a single letter.
/// Checks for identifiers which consist of a single character (or fewer than the configured threshold).
///
/// Note: This lint can be very noisy when enabled; it may be desirable to only enable it
/// temporarily.
///
/// ### Why is this bad?
/// In many cases it's not, but at times it can severely hinder readability. Some codebases may
/// wish to disallow this to improve readability.
/// ### Why restrict this?
/// To improve readability by requiring that every variable has a name more specific than a single letter can be.
///
/// ### Example
/// ```rust,ignore

View file

@ -23,7 +23,7 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for structure field patterns bound to wildcards.
///
/// ### Why is this bad?
/// ### Why restrict this?
/// Using `..` instead is shorter and leaves the focus on
/// the fields that are actually bound.
///
@ -138,7 +138,7 @@ declare_clippy_lint! {
/// To enforce unseparated literal suffix style,
/// see the `separated_literal_suffix` lint.
///
/// ### Why is this bad?
/// ### Why restrict this?
/// Suffix style should be consistent.
///
/// ### Example
@ -166,7 +166,7 @@ declare_clippy_lint! {
/// To enforce separated literal suffix style,
/// see the `unseparated_literal_suffix` lint.
///
/// ### Why is this bad?
/// ### Why restrict this?
/// Suffix style should be consistent.
///
/// ### Example

View file

@ -10,7 +10,7 @@ declare_clippy_lint! {
/// ### What it does
/// Checks assertions without a custom panic message.
///
/// ### Why is this bad?
/// ### Why restrict this?
/// Without a good custom message, it'd be hard to understand what went wrong when the assertion fails.
/// 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.

View file

@ -21,7 +21,7 @@ declare_clippy_lint! {
/// Checks for repeated slice indexing without asserting beforehand that the length
/// is greater than the largest index used to index into the slice.
///
/// ### Why is this bad?
/// ### Why restrict this?
/// In the general case where the compiler does not have a lot of information
/// about the length of a slice, indexing it repeatedly will generate a bounds check
/// for every single index.

View file

@ -20,9 +20,9 @@ use rustc_span::{sym, Span};
declare_clippy_lint! {
/// ### What it does
/// Warns if there is missing doc for any private documentable item
/// Warns if there is missing documentation for any private documentable item.
///
/// ### Why is this bad?
/// ### Why restrict this?
/// Doc is good. *rustc* has a `MISSING_DOCS`
/// allowed-by-default lint for
/// public members, but has no way to enforce documentation of private items.

View file

@ -10,13 +10,16 @@ declare_clippy_lint! {
/// It lints if an exported function, method, trait method with default impl,
/// or trait method impl is not `#[inline]`.
///
/// ### Why is this bad?
/// In general, it is not. Functions can be inlined across
/// crates when that's profitable as long as any form of LTO is used. When LTO is disabled,
/// functions that are not `#[inline]` cannot be inlined across crates. Certain types of crates
/// might intend for most of the methods in their public API to be able to be inlined across
/// crates even when LTO is disabled. For these types of crates, enabling this lint might make
/// sense. It allows the crate to require all exported methods to be `#[inline]` by default, and
/// ### Why restrict this?
/// When a function is not marked `#[inline]`, it is not
/// [a “small” candidate for automatic inlining][small], and LTO is not in use, then it is not
/// possible for the function to be inlined into the code of any crate other than the one in
/// which it is defined. Depending on the role of the function and the relationship of the crates,
/// this could significantly reduce performance.
///
/// Certain types of crates might intend for most of the methods in their public API to be able
/// to be inlined across crates even when LTO is disabled.
/// This lint allows those crates to require all exported methods to be `#[inline]` by default, and
/// then opt out for specific methods where this might not make sense.
///
/// ### Example
@ -51,6 +54,8 @@ declare_clippy_lint! {
/// fn def_bar() {} // missing #[inline]
/// }
/// ```
///
/// [small]: https://github.com/rust-lang/rust/pull/116505
#[clippy::version = "pre 1.29.0"]
pub MISSING_INLINE_IN_PUBLIC_ITEMS,
restriction,

View file

@ -10,16 +10,16 @@ use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
/// Checks if a provided method is used implicitly by a trait
/// implementation. A usage example would be a wrapper where every method
/// should perform some operation before delegating to the inner type's
/// implementation.
///
/// ### Why restrict this?
/// To ensure that a certain implementation implements every method; for example,
/// a wrapper type where every method should delegate to the corresponding method of
/// the inner type's implementation.
///
/// This lint should typically be enabled on a specific trait `impl` item
/// rather than globally.
///
/// ### Why is this bad?
/// Indicates that a method is missing.
///
/// ### Example
/// ```no_run
/// trait Trait {

View file

@ -12,9 +12,10 @@ declare_clippy_lint! {
/// whether the read occurs before or after the write depends on the evaluation
/// order of sub-expressions.
///
/// ### Why is this bad?
/// It is often confusing to read. As described [here](https://doc.rust-lang.org/reference/expressions.html?highlight=subexpression#evaluation-order-of-operands),
/// the operands of these expressions are evaluated before applying the effects of the expression.
/// ### Why restrict this?
/// While [the evaluation order of sub-expressions] is fully specified in Rust,
/// it still may be confusing to read an expression where the evaluation order
/// affects its behavior.
///
/// ### Known problems
/// Code which intentionally depends on the evaluation
@ -40,6 +41,8 @@ declare_clippy_lint! {
/// };
/// let a = tmp + x;
/// ```
///
/// [order]: (https://doc.rust-lang.org/reference/expressions.html?highlight=subexpression#evaluation-order-of-operands)
#[clippy::version = "pre 1.29.0"]
pub MIXED_READ_WRITE_IN_EXPRESSION,
restriction,

View file

@ -10,9 +10,9 @@ use std::path::{Component, Path};
declare_clippy_lint! {
/// ### What it does
/// Checks that module layout uses only self named module files, bans `mod.rs` files.
/// Checks that module layout uses only self named module files; bans `mod.rs` files.
///
/// ### Why is this bad?
/// ### Why restrict this?
/// Having multiple module layout styles in a project can be confusing.
///
/// ### Example
@ -41,7 +41,7 @@ declare_clippy_lint! {
/// ### What it does
/// Checks that module layout uses only `mod.rs` files.
///
/// ### Why is this bad?
/// ### Why restrict this?
/// Having multiple module layout styles in a project can be confusing.
///
/// ### Example

View file

@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::visitors::{for_each_expr_with_closures, Descend, Visitable};
use core::ops::ControlFlow::Continue;
use hir::def::{DefKind, Res};
use hir::{BlockCheckMode, ExprKind, Safety, QPath, UnOp};
use hir::{BlockCheckMode, ExprKind, QPath, Safety, UnOp};
use rustc_ast::Mutability;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
@ -15,7 +15,7 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for `unsafe` blocks that contain more than one unsafe operation.
///
/// ### Why is this bad?
/// ### Why restrict this?
/// Combined with `undocumented_unsafe_blocks`,
/// this lint ensures that each unsafe operation must be independently justified.
/// Combined with `unused_unsafe`, this lint also ensures

View file

@ -14,7 +14,7 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for usage of `Mutex<X>` where an atomic will do.
///
/// ### Why is this bad?
/// ### Why restrict this?
/// Using a mutex just to make access to a plain bool or
/// reference sequential is shooting flies with cannons.
/// `std::sync::atomic::AtomicBool` and `std::sync::atomic::AtomicPtr` are leaner and

View file

@ -6,8 +6,8 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::sugg::Sugg;
use clippy_utils::{
higher, is_else_clause, is_expn_of, is_parent_stmt, peel_blocks, peel_blocks_with_stmt, span_extract_comment,
SpanlessEq,
higher, is_block_like, is_else_clause, is_expn_of, is_parent_stmt, peel_blocks, peel_blocks_with_stmt,
span_extract_comment, SpanlessEq,
};
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
@ -121,14 +121,7 @@ fn condition_needs_parentheses(e: &Expr<'_>) -> bool {
| ExprKind::Type(i, _)
| ExprKind::Index(i, _, _) = inner.kind
{
if matches!(
i.kind,
ExprKind::Block(..)
| ExprKind::ConstBlock(..)
| ExprKind::If(..)
| ExprKind::Loop(..)
| ExprKind::Match(..)
) {
if is_block_like(i) {
return true;
}
inner = i;

View file

@ -98,6 +98,10 @@ struct SimilarNamesLocalVisitor<'a, 'tcx> {
impl<'a, 'tcx> SimilarNamesLocalVisitor<'a, 'tcx> {
fn check_single_char_names(&self) {
if self.single_char_names.last().map(Vec::len) == Some(0) {
return;
}
let num_single_char_names = self.single_char_names.iter().flatten().count();
let threshold = self.lint.single_char_binding_names_threshold;
if num_single_char_names as u64 > threshold {

View file

@ -70,7 +70,7 @@ declare_clippy_lint! {
/// Known safe built-in types like `Wrapping` or `Saturating`, floats, operations in constant
/// environments, allowed types and non-constant operations that won't overflow are ignored.
///
/// ### Why is this bad?
/// ### Why restrict this?
/// For integers, overflow will trigger a panic in debug builds or wrap the result in
/// release mode; division by zero will cause a panic in either mode. As a result, it is
/// desirable to explicitly call checked, wrapping or saturating arithmetic methods.
@ -100,7 +100,7 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for float arithmetic.
///
/// ### Why is this bad?
/// ### Why restrict this?
/// For some embedded systems or kernel development, it
/// can be useful to rule out floating-point numbers.
///
@ -502,7 +502,7 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for division of integers
///
/// ### Why is this bad?
/// ### Why restrict this?
/// When outside of some very specific algorithms,
/// integer division is very often a mistake because it discards the
/// remainder.
@ -596,7 +596,7 @@ declare_clippy_lint! {
/// value and constant, except in functions called `*eq*` (which probably
/// implement equality for a type involving floats).
///
/// ### Why is this bad?
/// ### Why restrict this?
/// Floating point calculations are usually imprecise, so
/// asking if two values are *exactly* equal is asking for trouble. For a good
/// guide on what to do, see [the floating point
@ -653,8 +653,8 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for modulo arithmetic.
///
/// ### Why is this bad?
/// The results of modulo (%) operation might differ
/// ### Why restrict this?
/// The results of modulo (`%`) operation might differ
/// depending on the language, when negative numbers are involved.
/// If you interop with different languages it might be beneficial
/// to double check all places that use modulo arithmetic.

View file

@ -13,9 +13,9 @@ use rustc_span::{sym, Span};
declare_clippy_lint! {
/// ### What it does
/// Checks for usage of `panic!` or assertions in a function of type result.
/// Checks for usage of `panic!` or assertions in a function whose return type is `Result`.
///
/// ### Why is this bad?
/// ### Why restrict this?
/// For some codebases, it is desirable for functions of type result to return an error instead of crashing. Hence panicking macros should be avoided.
///
/// ### Known problems

View file

@ -14,8 +14,8 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for usage of `panic!`.
///
/// ### Why is this bad?
/// `panic!` will stop the execution of the executable.
/// ### Why restrict this?
/// This macro, or panics in general, may be unwanted in production code.
///
/// ### Example
/// ```no_run
@ -31,8 +31,8 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for usage of `unimplemented!`.
///
/// ### Why is this bad?
/// This macro should not be present in production code.
/// ### Why restrict this?
/// This macro, or panics in general, may be unwanted in production code.
///
/// ### Example
/// ```no_run
@ -48,9 +48,9 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for usage of `todo!`.
///
/// ### Why is this bad?
/// The `todo!` macro is often used for unfinished code, and it causes
/// code to panic. It should not be present in production code.
/// ### Why restrict this?
/// The `todo!` macro indicates the presence of unfinished code,
/// so it should not be present in production code.
///
/// ### Example
/// ```no_run
@ -70,8 +70,8 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for usage of `unreachable!`.
///
/// ### Why is this bad?
/// This macro can cause code to panic.
/// ### Why restrict this?
/// This macro, or panics in general, may be unwanted in production code.
///
/// ### Example
/// ```no_run

View file

@ -5,15 +5,16 @@ use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
/// Checks whether partial fields of a struct are public.
/// Checks whether some but not all fields of a `struct` are public.
///
/// Either make all fields of a type public, or make none of them public
///
/// ### Why is this bad?
/// ### Why restrict this?
/// Most types should either be:
/// * Abstract data types: complex objects with opaque implementation which guard
/// interior invariants and expose intentionally limited API to the outside world.
/// * Data:relatively simple objects which group a bunch of related attributes together.
/// interior invariants and expose intentionally limited API to the outside world.
/// * Data:relatively simple objects which group a bunch of related attributes together,
/// but have no invariants.
///
/// ### Example
/// ```no_run

View file

@ -30,9 +30,8 @@ declare_clippy_lint! {
/// this lint can still be used to highlight areas of interest and ensure a good understanding
/// of ownership semantics.
///
/// ### Why is this bad?
/// It isn't bad in general. But in some contexts it can be desirable
/// because it increases ownership hints in the code, and will guard against some changes
/// ### Why restrict this?
/// It increases ownership hints in the code, and will guard against some changes
/// in ownership.
///
/// ### Example

View file

@ -5,13 +5,11 @@ use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
///
/// Restricts the usage of `pub use ...`
///
/// ### Why is this bad?
///
/// `pub use` is usually fine, but a project may wish to limit `pub use` instances to prevent
/// unintentional exports or to encourage placing exported items directly in public modules
/// ### Why restrict this?
/// A project may wish to limit `pub use` instances to prevent
/// unintentional exports, or to encourage placing exported items directly in public modules.
///
/// ### Example
/// ```no_run

View file

@ -9,7 +9,7 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for expressions that use the question mark operator and rejects them.
///
/// ### Why is this bad?
/// ### Why restrict this?
/// Sometimes code wants to avoid the question mark operator because for instance a local
/// block requires a macro to re-throw errors to attach additional information to the
/// error.

View file

@ -15,8 +15,10 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for raw string literals where a string literal can be used instead.
///
/// ### Why is this bad?
/// It's just unnecessary, but there are many cases where using a raw string literal is more
/// ### Why restrict this?
/// For consistent style by using simpler string literals whenever possible.
///
/// However, there are many cases where using a raw string literal is more
/// idiomatic than a string literal, so it's opt-in.
///
/// ### Example

View file

@ -46,7 +46,7 @@ declare_clippy_lint! {
/// Checks for slicing expressions which are equivalent to dereferencing the
/// value.
///
/// ### Why is this bad?
/// ### Why restrict this?
/// Some people may prefer to dereference rather than slice.
///
/// ### Example

View file

@ -11,7 +11,7 @@ declare_clippy_lint! {
/// ### What it does
/// Warns about needless / redundant type annotations.
///
/// ### Why is this bad?
/// ### Why restrict this?
/// Code without type annotations is shorter and in most cases
/// more idiomatic and easier to modify.
///

View file

@ -6,9 +6,11 @@ use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
/// Checks for usages of the `ref` keyword.
/// ### Why is this bad?
///
/// ### Why restrict this?
/// The `ref` keyword can be confusing for people unfamiliar with it, and often
/// it is more concise to use `&` instead.
///
/// ### Example
/// ```no_run
/// let opt = Some(5);

View file

@ -3,8 +3,8 @@ 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, is_inside_let_else, is_res_lang_ctor, path_res, path_to_local_id, span_contains_cfg,
span_find_starting_semi,
binary_expr_needs_parentheses, fn_def_id, is_from_proc_macro, is_inside_let_else, is_res_lang_ctor, path_res,
path_to_local_id, span_contains_cfg, span_find_starting_semi,
};
use core::ops::ControlFlow;
use rustc_errors::Applicability;
@ -129,7 +129,7 @@ enum RetReplacement<'tcx> {
Empty,
Block,
Unit,
IfSequence(Cow<'tcx, str>, Applicability),
NeedsPar(Cow<'tcx, str>, Applicability),
Expr(Cow<'tcx, str>, Applicability),
}
@ -139,13 +139,13 @@ impl<'tcx> RetReplacement<'tcx> {
Self::Empty | Self::Expr(..) => "remove `return`",
Self::Block => "replace `return` with an empty block",
Self::Unit => "replace `return` with a unit value",
Self::IfSequence(..) => "remove `return` and wrap the sequence with parentheses",
Self::NeedsPar(..) => "remove `return` and wrap the sequence with parentheses",
}
}
fn applicability(&self) -> Applicability {
match self {
Self::Expr(_, ap) | Self::IfSequence(_, ap) => *ap,
Self::Expr(_, ap) | Self::NeedsPar(_, ap) => *ap,
_ => Applicability::MachineApplicable,
}
}
@ -157,7 +157,7 @@ impl<'tcx> Display for RetReplacement<'tcx> {
Self::Empty => write!(f, ""),
Self::Block => write!(f, "{{}}"),
Self::Unit => write!(f, "()"),
Self::IfSequence(inner, _) => write!(f, "({inner})"),
Self::NeedsPar(inner, _) => write!(f, "({inner})"),
Self::Expr(inner, _) => write!(f, "{inner}"),
}
}
@ -244,7 +244,11 @@ impl<'tcx> LateLintPass<'tcx> for Return {
err.span_label(local.span, "unnecessary `let` binding");
if let Some(mut snippet) = snippet_opt(cx, initexpr.span) {
if !cx.typeck_results().expr_adjustments(retexpr).is_empty() {
if binary_expr_needs_parentheses(initexpr) {
if !has_enclosing_paren(&snippet) {
snippet = format!("({snippet})");
}
} else if !cx.typeck_results().expr_adjustments(retexpr).is_empty() {
if !has_enclosing_paren(&snippet) {
snippet = format!("({snippet})");
}
@ -349,8 +353,8 @@ fn check_final_expr<'tcx>(
let mut applicability = Applicability::MachineApplicable;
let (snippet, _) = snippet_with_context(cx, inner_expr.span, ret_span.ctxt(), "..", &mut applicability);
if expr_contains_conjunctive_ifs(inner_expr) {
RetReplacement::IfSequence(snippet, applicability)
if binary_expr_needs_parentheses(inner_expr) {
RetReplacement::NeedsPar(snippet, applicability)
} else {
RetReplacement::Expr(snippet, applicability)
}
@ -404,18 +408,6 @@ fn check_final_expr<'tcx>(
}
}
fn expr_contains_conjunctive_ifs<'tcx>(expr: &'tcx Expr<'tcx>) -> bool {
fn contains_if(expr: &Expr<'_>, on_if: bool) -> bool {
match expr.kind {
ExprKind::If(..) => on_if,
ExprKind::Binary(_, left, right) => contains_if(left, true) || contains_if(right, true),
_ => false,
}
}
contains_if(expr, false)
}
fn emit_return_lint(
cx: &LateContext<'_>,
ret_span: Span,

View file

@ -14,7 +14,7 @@ declare_clippy_lint! {
/// It lints if a struct has two methods with the same name:
/// one from a trait, another not from trait.
///
/// ### Why is this bad?
/// ### Why restrict this?
/// Confusing.
///
/// ### Example

View file

@ -11,8 +11,7 @@ declare_clippy_lint! {
/// Suggests moving the semicolon after a block to the inside of the block, after its last
/// expression.
///
/// ### Why is this bad?
///
/// ### Why restrict this?
/// For consistency it's best to have the semicolon inside/outside the block. Either way is fine
/// and this lint suggests inside the block.
/// Take a look at `semicolon_outside_block` for the other alternative.
@ -40,8 +39,7 @@ declare_clippy_lint! {
///
/// Suggests moving the semicolon from a block's final expression outside of the block.
///
/// ### Why is this bad?
///
/// ### Why restrict this?
/// For consistency it's best to have the semicolon inside/outside the block. Either way is fine
/// and this lint suggests outside the block.
/// Take a look at `semicolon_inside_block` for the other alternative.

View file

@ -15,10 +15,10 @@ declare_clippy_lint! {
/// Checks for bindings that shadow other bindings already in
/// scope, while just changing reference level or mutability.
///
/// ### Why is this bad?
/// Not much, in fact it's a very common pattern in Rust
/// code. Still, some may opt to avoid it in their code base, they can set this
/// lint to `Warn`.
/// ### Why restrict this?
/// To require that what are formally distinct variables be given distinct names.
///
/// See also `shadow_reuse` and `shadow_unrelated` for other restrictions on shadowing.
///
/// ### Example
/// ```no_run
@ -42,12 +42,13 @@ declare_clippy_lint! {
/// Checks for bindings that shadow other bindings already in
/// scope, while reusing the original value.
///
/// ### Why is this bad?
/// Not too much, in fact it's a common pattern in Rust
/// code. Still, some argue that name shadowing like this hurts readability,
/// ### Why restrict this?
/// Some argue that name shadowing like this hurts readability,
/// because a value may be bound to different things depending on position in
/// the code.
///
/// See also `shadow_same` and `shadow_unrelated` for other restrictions on shadowing.
///
/// ### Example
/// ```no_run
/// let x = 2;
@ -70,11 +71,14 @@ declare_clippy_lint! {
/// scope, either without an initialization or with one that does not even use
/// the original value.
///
/// ### Why is this bad?
/// Name shadowing can hurt readability, especially in
/// ### Why restrict this?
/// Shadowing a binding with a closely related one is part of idiomatic Rust,
/// but shadowing a binding by accident with an unrelated one may indicate a mistake.
///
/// Additionally, name shadowing in general can hurt readability, especially in
/// large code bases, because it is easy to lose track of the active binding at
/// any place in the code. This can be alleviated by either giving more specific
/// names to bindings or introducing more scopes to contain the bindings.
/// any place in the code. If linting against all shadowing is desired, you may wish
/// to use the `shadow_same` and `shadow_reuse` lints as well.
///
/// ### Example
/// ```no_run

View file

@ -13,13 +13,20 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for functions that are only used once. Does not lint tests.
///
/// ### Why is this bad?
/// It's usually not, splitting a function into multiple parts often improves readability and in
/// the case of generics, can prevent the compiler from duplicating the function dozens of
/// time; instead, only duplicating a thunk. But this can prevent segmentation across a
/// codebase, where many small functions are used only once.
/// ### Why restrict this?
/// If a function is only used once (perhaps because it used to be used more widely),
/// then the code could be simplified by moving that function's code into its caller.
///
/// Note: If this lint is used, prepare to allow this a lot.
/// However, there are reasons not to do this everywhere:
///
/// * Splitting a large function into multiple parts often improves readability
/// by giving names to its parts.
/// * A functions signature might serve a necessary purpose, such as constraining
/// the type of a closure passed to it.
/// * Generic functions might call non-generic functions to reduce duplication
/// in the produced machine code.
///
/// If this lint is used, prepare to `#[allow]` it a lot.
///
/// ### Example
/// ```no_run

View file

@ -9,11 +9,10 @@ declare_clippy_lint! {
/// Checks for lifetimes with names which are one character
/// long.
///
/// ### Why is this bad?
/// ### Why restrict this?
/// A single character is likely not enough to express the
/// purpose of a lifetime. Using a longer name can make code
/// easier to understand, especially for those who are new to
/// Rust.
/// easier to understand.
///
/// ### Known problems
/// Rust programmers and learning resources tend to use single

View file

@ -12,11 +12,9 @@ use rustc_span::{sym, Span};
declare_clippy_lint! {
/// ### What it does
///
/// Finds items imported through `std` when available through `core`.
///
/// ### Why is this bad?
///
/// ### Why restrict this?
/// Crates which have `no_std` compatibility may wish to ensure types are imported from core to ensure
/// disabling `std` does not cause the crate to fail to compile. This lint is also useful for crates
/// migrating to become `no_std` compatible.
@ -37,11 +35,9 @@ declare_clippy_lint! {
declare_clippy_lint! {
/// ### What it does
///
/// Finds items imported through `std` when available through `alloc`.
///
/// ### Why is this bad?
///
/// ### Why restrict this?
/// Crates which have `no_std` compatibility and require alloc may wish to ensure types are imported from
/// alloc to ensure disabling `std` does not cause the crate to fail to compile. This lint is also useful
/// for crates migrating to become `no_std` compatible.
@ -63,11 +59,9 @@ declare_clippy_lint! {
declare_clippy_lint! {
/// ### What it does
///
/// Finds items imported through `alloc` when available through `core`.
///
/// ### Why is this bad?
///
/// ### Why restrict this?
/// Crates which have `no_std` compatibility and may optionally require alloc may wish to ensure types are
/// imported from core to ensure disabling `alloc` does not cause the crate to fail to compile. This lint
/// is also useful for crates migrating to become `no_std` compatible.

View file

@ -45,10 +45,10 @@ declare_clippy_lint! {
/// `String`, but only if [`string_add_assign`](#string_add_assign) does *not*
/// match.
///
/// ### Why is this bad?
/// It's not bad in and of itself. However, this particular
/// ### Why restrict this?
/// This particular
/// `Add` implementation is asymmetric (the other operand need not be `String`,
/// but `x` does), while addition as mathematically defined is symmetric, also
/// but `x` does), while addition as mathematically defined is symmetric, and
/// the `String::push_str(_)` function is a perfectly good replacement.
/// Therefore, some dislike it and wish not to have it in their code.
///
@ -123,7 +123,7 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for slice operations on strings
///
/// ### Why is this bad?
/// ### Why restrict this?
/// UTF-8 characters span multiple bytes, and it is easy to inadvertently confuse character
/// counts and string indices. This may lead to panics, and should warrant some test cases
/// containing wide UTF-8 characters. This lint is most useful in code that should avoid
@ -364,10 +364,10 @@ declare_clippy_lint! {
/// ### What it does
/// This lint checks for `.to_string()` method calls on values of type `&str`.
///
/// ### Why is this bad?
/// ### Why restrict this?
/// The `to_string` method is also used on other types to convert them to a string.
/// When called on a `&str` it turns the `&str` into the owned variant `String`, which can be better
/// expressed with `.to_owned()`.
/// When called on a `&str` it turns the `&str` into the owned variant `String`, which can be
/// more specifically expressed with `.to_owned()`.
///
/// ### Example
/// ```no_run
@ -415,9 +415,10 @@ declare_clippy_lint! {
/// ### What it does
/// This lint checks for `.to_string()` method calls on values of type `String`.
///
/// ### Why is this bad?
/// ### Why restrict this?
/// The `to_string` method is also used on other types to convert them to a string.
/// When called on a `String` it only clones the `String`, which can be better expressed with `.clone()`.
/// When called on a `String` it only clones the `String`, which can be more specifically
/// expressed with `.clone()`.
///
/// ### Example
/// ```no_run

View file

@ -11,8 +11,10 @@ use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
/// Warns for a Bitwise XOR (`^`) operator being probably confused as a powering. It will not trigger if any of the numbers are not in decimal.
/// ### Why is this bad?
///
/// ### Why restrict this?
/// It's most probably a typo and may lead to unexpected behaviours.
///
/// ### Example
/// ```no_run
/// let x = 3_i32 ^ 4_i32;

View file

@ -11,9 +11,11 @@ declare_clippy_lint! {
/// ### What it does
/// Triggers when a testing function (marked with the `#[test]` attribute) isn't inside a testing module
/// (marked with `#[cfg(test)]`).
/// ### Why is this bad?
///
/// ### Why restrict this?
/// 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
/// ```no_run
/// #[test]

View file

@ -217,7 +217,7 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for `Rc<T>` and `Arc<T>` when `T` is a mutable buffer type such as `String` or `Vec`.
///
/// ### Why is this bad?
/// ### Why restrict this?
/// Expressions such as `Rc<String>` usually have no advantage over `Rc<str>`, since
/// it is larger and involves an extra level of indirection, and doesn't implement `Borrow<str>`.
///
@ -274,7 +274,7 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for `Rc<Mutex<T>>`.
///
/// ### Why is this bad?
/// ### Why restrict this?
/// `Rc` is used in single thread and `Mutex` is used in multi thread.
/// Consider using `Rc<RefCell<T>>` in single thread or `Arc<Mutex<T>>` in multi thread.
///

View file

@ -38,10 +38,9 @@ declare_clippy_lint! {
/// );
/// ```
///
/// ### Why is this bad?
/// Undocumented unsafe blocks and impls can make it difficult to
/// read and maintain code, as well as uncover unsoundness
/// and bugs.
/// ### Why restrict this?
/// Undocumented unsafe blocks and impls can make it difficult to read and maintain code.
/// Writing out the safety justification may help in discovering unsoundness or bugs.
///
/// ### Example
/// ```no_run
@ -67,7 +66,7 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for `// SAFETY: ` comments on safe code.
///
/// ### Why is this bad?
/// ### Why restrict this?
/// Safe code has no safety requirements, so there is no need to
/// describe safety invariants.
///

View file

@ -31,7 +31,7 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for non-ASCII characters in string and char literals.
///
/// ### Why is this bad?
/// ### Why restrict this?
/// Yeah, we know, the 90's called and wanted their charset
/// back. Even so, there still are editors and other programs out there that
/// don't work well with Unicode. So if the code is meant to be used

View file

@ -9,7 +9,7 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for imports ending in `::{self}`.
///
/// ### Why is this bad?
/// ### Why restrict this?
/// In most cases, this can be written much more cleanly by omitting `::{self}`.
///
/// ### Known problems

View file

@ -13,8 +13,10 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for functions of type `Result` that contain `expect()` or `unwrap()`
///
/// ### Why is this bad?
/// These functions promote recoverable errors to non-recoverable errors which may be undesirable in code bases which wish to avoid panics.
/// ### Why restrict this?
/// These functions promote recoverable errors to non-recoverable errors,
/// which may be undesirable in code bases which wish to avoid panics,
/// or be a bug in the specific function.
///
/// ### Known problems
/// This can cause false positives in functions that handle both recoverable and non recoverable errors.

View file

@ -32,7 +32,7 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for usage of `pub(<loc>)` with `in`.
///
/// ### Why is this bad?
/// ### Why restrict this?
/// Consistency. Use it or don't, just be consistent about it.
///
/// Also see the `pub_without_shorthand` lint for an alternative.
@ -57,7 +57,7 @@ declare_clippy_lint! {
/// Note: As you cannot write a module's path in `pub(<loc>)`, this will only trigger on
/// `pub(super)` and the like.
///
/// ### Why is this bad?
/// ### Why restrict this?
/// Consistency. Use it or don't, just be consistent about it.
///
/// Also see the `pub_with_shorthand` lint for an alternative.

View file

@ -66,7 +66,7 @@ declare_clippy_lint! {
/// Checks for printing on *stdout*. The purpose of this lint
/// is to catch debugging remnants.
///
/// ### Why is this bad?
/// ### Why restrict this?
/// People often print on *stdout* while debugging an
/// application and might forget to remove those prints afterward.
///
@ -88,7 +88,7 @@ declare_clippy_lint! {
/// Checks for printing on *stderr*. The purpose of this lint
/// is to catch debugging remnants.
///
/// ### Why is this bad?
/// ### Why restrict this?
/// People often print on *stderr* while debugging an
/// application and might forget to remove those prints afterward.
///
@ -110,15 +110,18 @@ declare_clippy_lint! {
/// Checks for usage of `Debug` formatting. The purpose of this
/// lint is to catch debugging remnants.
///
/// ### Why is this bad?
/// The purpose of the `Debug` trait is to facilitate
/// debugging Rust code. It should not be used in user-facing output.
/// ### Why restrict this?
/// The purpose of the `Debug` trait is to facilitate debugging Rust code,
/// and [no guarantees are made about its output][stability].
/// It should not be used in user-facing output.
///
/// ### Example
/// ```no_run
/// # let foo = "bar";
/// println!("{:?}", foo);
/// ```
///
/// [stability]: https://doc.rust-lang.org/stable/std/fmt/trait.Debug.html#stability
#[clippy::version = "pre 1.29.0"]
pub USE_DEBUG,
restriction,